/*
* Copyright (c) 2017 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.example;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertTrue;
import com.google.api.client.googleapis.json.GoogleJsonError;
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Integration (system) tests for {@link Snippets}.
*/
@RunWith(JUnit4.class)
@SuppressWarnings("checkstyle:abbreviationaswordinname")
public class SnippetsIT {
static final String PROJECT_ID = System.getenv("GOOGLE_CLOUD_PROJECT");
static final String KEY_RING_ID = "test-snippets-key-ring";
static final String CRYPTO_KEY_ID = "test-snippets-crypto-key";
static final String TEST_USER = "serviceAccount:"
+ "131304031188-compute@developer.gserviceaccount.com";
static final String TEST_ROLE = "roles/viewer";
static final String ENCRYPT_STRING = "Everyone shall sit under their own vine and fig tree";
private static PrintStream realOut;
private ByteArrayOutputStream bout;
private PrintStream out;
@BeforeClass
public static void setUpClass() throws Exception {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
PrintStream out = new PrintStream(bout);
realOut = System.out;
System.setOut(out);
// Since you can't delete keyrings & cryptokeys atm, these tests assume they already exist.
// Use the snippets functions to create them.
try {
Snippets.createKeyRing(PROJECT_ID, KEY_RING_ID);
// Since there's no way to delete keyrings atm, have two branches - one for the first time the
// test is run, one for after the key already exists
assertThat(bout.toString()).contains("keyRings/" + KEY_RING_ID);
} catch (GoogleJsonResponseException e) {
GoogleJsonError error = e.getDetails();
assertThat(error.getCode()).isEqualTo(409);
assertThat(error.getMessage()).contains("keyRings/" + KEY_RING_ID);
}
try {
Snippets.createCryptoKey(PROJECT_ID, KEY_RING_ID, CRYPTO_KEY_ID);
// Since there's no way to delete keyrings atm, have two branches - one for the first time the
// test is run, one for after the key already exists
assertThat(bout.toString()).contains(String.format(
"keyRings/%s/cryptoKeys/%s", KEY_RING_ID, CRYPTO_KEY_ID));
} catch (GoogleJsonResponseException e) {
GoogleJsonError error = e.getDetails();
assertThat(error.getCode()).isEqualTo(409);
assertThat(error.getMessage()).contains(String.format(
"keyRings/%s/cryptoKeys/%s", KEY_RING_ID, CRYPTO_KEY_ID));
}
}
/**
* Destroys all the keys created during this test run.
*/
@AfterClass
public static void tearDownClass() throws Exception {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
PrintStream out = new PrintStream(bout);
System.setOut(out);
String stdout;
try {
Snippets.listCryptoKeyVersions(PROJECT_ID, KEY_RING_ID, CRYPTO_KEY_ID);
stdout = bout.toString();
} finally {
System.setOut(realOut);
}
String[] lines = stdout.split("\n");
Pattern keyVersion = Pattern.compile(
".*cryptoKeyVersions/(\\d+)\",\"state\":\"(EN|DIS)ABLED\".*",
Pattern.DOTALL | Pattern.MULTILINE);
for (String line : lines) {
Matcher matcher = keyVersion.matcher(line);
if (!matcher.matches()) {
continue;
}
String version = matcher.group(1);
Snippets.destroyCryptoKeyVersion(PROJECT_ID, KEY_RING_ID, CRYPTO_KEY_ID, version);
}
}
@Before
public void setUp() throws Exception {
bout = new ByteArrayOutputStream();
out = new PrintStream(bout);
System.setOut(out);
Snippets.createCryptoKeyVersion(PROJECT_ID, KEY_RING_ID, CRYPTO_KEY_ID);
}
@After
public void tearDown() {
System.setOut(realOut);
}
@Test
public void listKeyRings_printsKeyRing() throws Exception {
Snippets.listKeyRings(PROJECT_ID);
assertThat(bout.toString()).contains(String.format("keyRings/%s", KEY_RING_ID));
}
@Test
public void listCryptoKeys_printsCryptoKeys() throws Exception {
Snippets.listCryptoKeys(PROJECT_ID, KEY_RING_ID);
assertThat(bout.toString()).contains(
String.format("keyRings/%s/cryptoKeys/%s", KEY_RING_ID, CRYPTO_KEY_ID));
}
@Test
public void listCryptoKeyVersions_printsVersions() throws Exception {
Snippets.listCryptoKeyVersions(PROJECT_ID, KEY_RING_ID, CRYPTO_KEY_ID);
assertThat(bout.toString()).containsMatch(String.format(
"keyRings/%s/cryptoKeys/%s/cryptoKeyVersions/\\d+\",\"state\":\"ENABLED\"",
KEY_RING_ID, CRYPTO_KEY_ID));
}
@Test
public void disableCryptoKeyVersion_disables() throws Exception {
Snippets.listCryptoKeyVersions(PROJECT_ID, KEY_RING_ID, CRYPTO_KEY_ID);
Matcher matcher = Pattern.compile(".*cryptoKeyVersions/(\\d+)\",\"state\":\"ENABLED\".*",
Pattern.DOTALL | Pattern.MULTILINE).matcher(bout.toString().trim());
assertTrue(matcher.matches());
String version = matcher.group(1);
Snippets.disableCryptoKeyVersion(PROJECT_ID, KEY_RING_ID, CRYPTO_KEY_ID, version);
assertThat(bout.toString()).containsMatch(String.format(
"keyRings/%s/cryptoKeys/%s/cryptoKeyVersions/%s\",\"state\":\"DISABLED\"",
KEY_RING_ID, CRYPTO_KEY_ID, version));
}
@Test
public void destroyCryptoKeyVersion_destroys() throws Exception {
Snippets.listCryptoKeyVersions(PROJECT_ID, KEY_RING_ID, CRYPTO_KEY_ID);
Matcher matcher = Pattern.compile(".*cryptoKeyVersions/(\\d+)\",\"state\":\"ENABLED\".*",
Pattern.DOTALL | Pattern.MULTILINE).matcher(bout.toString().trim());
assertTrue(matcher.matches());
String version = matcher.group(1);
Snippets.destroyCryptoKeyVersion(PROJECT_ID, KEY_RING_ID, CRYPTO_KEY_ID, version);
assertThat(bout.toString()).containsMatch(String.format(
"keyRings/%s/cryptoKeys/%s/cryptoKeyVersions/%s\",\"state\":\"DESTROY_SCHEDULED\"",
KEY_RING_ID, CRYPTO_KEY_ID, version));
}
@Test
public void addAndRemoveMemberToCryptoKeyPolicy_addsDisplaysAndRemoves() throws Exception {
// Make sure the policy doesn't already have our test user
Snippets.getCryptoKeyPolicy(PROJECT_ID, KEY_RING_ID, CRYPTO_KEY_ID);
assertThat(bout.toString()).doesNotContainMatch(TEST_USER);
try {
// Add the test user, and make sure the policy has it
Snippets.addMemberToCryptoKeyPolicy(
PROJECT_ID, KEY_RING_ID, CRYPTO_KEY_ID, TEST_USER, TEST_ROLE);
Snippets.getCryptoKeyPolicy(PROJECT_ID, KEY_RING_ID, CRYPTO_KEY_ID);
assertThat(bout.toString()).containsMatch(TEST_USER);
// Now remove the test user, and make sure the policy no longer has it
bout.reset();
} finally {
Snippets.removeMemberFromCryptoKeyPolicy(
PROJECT_ID, KEY_RING_ID, CRYPTO_KEY_ID, TEST_USER, TEST_ROLE);
}
assertThat(bout.toString()).doesNotContainMatch("Response:.*" + TEST_USER);
bout.reset();
Snippets.getCryptoKeyPolicy(PROJECT_ID, KEY_RING_ID, CRYPTO_KEY_ID);
assertThat(bout.toString()).doesNotContainMatch(TEST_USER);
}
@Test
public void addAndRemoveMemberToKeyRingPolicy_addsDisplaysAndRemoves() throws Exception {
// Make sure the policy doesn't already have our test user
Snippets.getKeyRingPolicy(PROJECT_ID, KEY_RING_ID);
assertThat(bout.toString()).doesNotContainMatch(TEST_USER);
try {
// Add the test user, and make sure the policy has it
Snippets.addMemberToKeyRingPolicy(
PROJECT_ID, KEY_RING_ID, TEST_USER, TEST_ROLE);
Snippets.getKeyRingPolicy(PROJECT_ID, KEY_RING_ID);
assertThat(bout.toString()).containsMatch(TEST_USER);
// Now remove the test user, and make sure the policy no longer has it
bout.reset();
} finally {
Snippets.removeMemberFromKeyRingPolicy(
PROJECT_ID, KEY_RING_ID, TEST_USER, TEST_ROLE);
}
assertThat(bout.toString()).doesNotContainMatch("Response:.*" + TEST_USER);
bout.reset();
Snippets.getKeyRingPolicy(PROJECT_ID, KEY_RING_ID);
assertThat(bout.toString()).doesNotContainMatch(TEST_USER);
}
@Test
public void encryptDecrypt_encryptsAndDecrypts() throws Exception {
// Get an enabled crypto key version, since the primary version is likely disabled
Snippets.listCryptoKeyVersions(PROJECT_ID, KEY_RING_ID, CRYPTO_KEY_ID);
Matcher matcher = Pattern.compile(".*cryptoKeyVersions/(\\d+)\",\"state\":\"ENABLED\".*",
Pattern.DOTALL | Pattern.MULTILINE).matcher(bout.toString().trim());
assertTrue(matcher.matches());
String version = matcher.group(1);
byte[] encrypted = CryptFile.encrypt(
PROJECT_ID, KEY_RING_ID, CRYPTO_KEY_ID, version, ENCRYPT_STRING.getBytes());
assertThat(new String(encrypted)).isNotEqualTo(ENCRYPT_STRING);
byte[] decrypted = CryptFile.decrypt(
PROJECT_ID, KEY_RING_ID, CRYPTO_KEY_ID, encrypted);
assertThat(new String(decrypted)).isEqualTo(ENCRYPT_STRING);
}
}