diff --git a/iam/snippets/src/test/java/CreateServiceAccountIT.java b/iam/snippets/src/test/java/CreateServiceAccountIT.java new file mode 100644 index 00000000000..278d0d1db99 --- /dev/null +++ b/iam/snippets/src/test/java/CreateServiceAccountIT.java @@ -0,0 +1,79 @@ +/* Copyright 2025 Google LLC + * + * 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. + */ + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertNotNull; + +import com.google.cloud.testing.junit4.MultipleAttemptsRule; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class CreateServiceAccountIT { + + private static final String PROJECT_ID = System.getenv("GOOGLE_CLOUD_PROJECT"); + private ByteArrayOutputStream bout; + private String serviceAccountName; + private final PrintStream originalOut = System.out; + + @Rule public MultipleAttemptsRule multipleAttemptsRule = new MultipleAttemptsRule(3); + + private static void requireEnvVar(String varName) { + assertNotNull( + System.getenv(varName), + String.format("Environment variable '%s' is required to perform these tests.", varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("GOOGLE_CLOUD_PROJECT"); + } + + @Before + public void beforeTest() { + bout = new ByteArrayOutputStream(); + System.setOut(new PrintStream(bout)); + + // Set up test + serviceAccountName = Util.generateServiceAccountName(); + } + + @After + public void tearDown() throws IOException { + // Cleanup test + Util.tearDownTest_deleteServiceAccount(PROJECT_ID, serviceAccountName); + + System.out.flush(); + System.setOut(originalOut); + } + + @Test + public void testCreateServiceAccount() throws IOException { + // Act + CreateServiceAccount.createServiceAccount(PROJECT_ID, serviceAccountName); + + // Assert + assertThat(bout.toString()).contains("Created service account: " + serviceAccountName); + } +} diff --git a/iam/snippets/src/test/java/CreateServiceAccountKeyIT.java b/iam/snippets/src/test/java/CreateServiceAccountKeyIT.java new file mode 100644 index 00000000000..cd1305d0148 --- /dev/null +++ b/iam/snippets/src/test/java/CreateServiceAccountKeyIT.java @@ -0,0 +1,80 @@ +/* Copyright 2025 Google LLC + * + * 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. + */ + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertNotNull; + +import com.google.cloud.testing.junit4.MultipleAttemptsRule; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class CreateServiceAccountKeyIT { + + private static final String PROJECT_ID = System.getenv("GOOGLE_CLOUD_PROJECT"); + private ByteArrayOutputStream bout; + private String serviceAccountName; + private final PrintStream originalOut = System.out; + + @Rule public MultipleAttemptsRule multipleAttemptsRule = new MultipleAttemptsRule(3); + + private static void requireEnvVar(String varName) { + assertNotNull( + System.getenv(varName), + String.format("Environment variable '%s' is required to perform these tests.", varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("GOOGLE_CLOUD_PROJECT"); + } + + @Before + public void beforeTest() throws IOException, InterruptedException { + bout = new ByteArrayOutputStream(); + System.setOut(new PrintStream(bout)); + + // Set up test + serviceAccountName = Util.generateServiceAccountName(); + Util.setUpTest_createServiceAccount(PROJECT_ID, serviceAccountName); + } + + @After + public void tearDown() throws IOException { + // Cleanup test + Util.tearDownTest_deleteServiceAccount(PROJECT_ID, serviceAccountName); + + System.out.flush(); + System.setOut(originalOut); + } + + @Test + public void testCreateServiceAccountKey() throws IOException, InterruptedException { + // Act + CreateServiceAccountKey.createKey(PROJECT_ID, serviceAccountName); + + // Assert + assertThat(bout.toString()).contains("Key created successfully"); + } +} diff --git a/iam/snippets/src/test/java/DeleteServiceAccountIT.java b/iam/snippets/src/test/java/DeleteServiceAccountIT.java new file mode 100644 index 00000000000..d5dc32a9374 --- /dev/null +++ b/iam/snippets/src/test/java/DeleteServiceAccountIT.java @@ -0,0 +1,77 @@ +/* Copyright 2025 Google LLC + * + * 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. + */ + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertNotNull; + +import com.google.cloud.testing.junit4.MultipleAttemptsRule; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class DeleteServiceAccountIT { + + private static final String PROJECT_ID = System.getenv("GOOGLE_CLOUD_PROJECT"); + private ByteArrayOutputStream bout; + private String serviceAccountName; + private final PrintStream originalOut = System.out; + + @Rule public MultipleAttemptsRule multipleAttemptsRule = new MultipleAttemptsRule(3); + + private static void requireEnvVar(String varName) { + assertNotNull( + System.getenv(varName), + String.format("Environment variable '%s' is required to perform these tests.", varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("GOOGLE_CLOUD_PROJECT"); + } + + @Before + public void beforeTest() throws IOException, InterruptedException { + bout = new ByteArrayOutputStream(); + System.setOut(new PrintStream(bout)); + + // Set up test + serviceAccountName = Util.generateServiceAccountName(); + Util.setUpTest_createServiceAccount(PROJECT_ID, serviceAccountName); + } + + @After + public void tearDown() throws IOException { + System.out.flush(); + System.setOut(originalOut); + } + + @Test + public void testDeleteServiceAccount() throws IOException, InterruptedException { + // Act + DeleteServiceAccount.deleteServiceAccount(PROJECT_ID, serviceAccountName); + + // Assert + assertThat(bout.toString()).contains("Deleted service account: " + serviceAccountName); + } +} diff --git a/iam/snippets/src/test/java/DeleteServiceAccountKeyIT.java b/iam/snippets/src/test/java/DeleteServiceAccountKeyIT.java new file mode 100644 index 00000000000..2dcaf83175e --- /dev/null +++ b/iam/snippets/src/test/java/DeleteServiceAccountKeyIT.java @@ -0,0 +1,86 @@ +/* Copyright 2025 Google LLC + * + * 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. + */ + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertNotNull; + +import com.google.cloud.testing.junit4.MultipleAttemptsRule; +import com.google.iam.admin.v1.ServiceAccountKey; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class DeleteServiceAccountKeyIT { + + private static final String PROJECT_ID = System.getenv("GOOGLE_CLOUD_PROJECT"); + private ByteArrayOutputStream bout; + private String serviceAccountName; + private String serviceAccountKeyId; + private final PrintStream originalOut = System.out; + + @Rule public MultipleAttemptsRule multipleAttemptsRule = new MultipleAttemptsRule(3); + + private static void requireEnvVar(String varName) { + assertNotNull( + System.getenv(varName), + String.format("Environment variable '%s' is required to perform these tests.", varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("GOOGLE_CLOUD_PROJECT"); + } + + @Before + public void beforeTest() throws IOException, InterruptedException { + bout = new ByteArrayOutputStream(); + System.setOut(new PrintStream(bout)); + + // Set up test + serviceAccountName = Util.generateServiceAccountName(); + Util.setUpTest_createServiceAccount(PROJECT_ID, serviceAccountName); + ServiceAccountKey setupKey = + Util.setUpTest_createServiceAccountKey(PROJECT_ID, serviceAccountName); + serviceAccountKeyId = Util.getServiceAccountKeyIdFromKey(setupKey); + } + + @After + public void tearDown() throws IOException { + // Cleanup test + Util.tearDownTest_deleteServiceAccount(PROJECT_ID, serviceAccountName); + + System.out.flush(); + System.setOut(originalOut); + } + + @Test + public void testDeleteServiceAccountKey() throws IOException, InterruptedException { + // Act + DeleteServiceAccountKey.deleteKey(PROJECT_ID, serviceAccountName, serviceAccountKeyId); + + // Assert + String got = bout.toString(); + assertThat(got).contains("Deleted key: " + serviceAccountKeyId); + } +} diff --git a/iam/snippets/src/test/java/DenyIT.java b/iam/snippets/src/test/java/DenyIT.java index ff946675dfe..c35f8aa17e7 100644 --- a/iam/snippets/src/test/java/DenyIT.java +++ b/iam/snippets/src/test/java/DenyIT.java @@ -37,7 +37,6 @@ public class DenyIT { private static final String PROJECT_ID = System.getenv("IAM_PROJECT_ID"); - private static final String GOOGLE_APPLICATION_CREDENTIALS = System.getenv("IAM_CREDENTIALS"); private static String POLICY_ID; private ByteArrayOutputStream stdOut; @@ -55,7 +54,6 @@ public static void setUp() final PrintStream out = System.out; ByteArrayOutputStream stdOut = new ByteArrayOutputStream(); System.setOut(new PrintStream(stdOut)); - requireEnvVar("IAM_CREDENTIALS"); requireEnvVar("IAM_PROJECT_ID"); POLICY_ID = "limit-project-deletion" + UUID.randomUUID(); diff --git a/iam/snippets/src/test/java/DisableServiceAccountIT.java b/iam/snippets/src/test/java/DisableServiceAccountIT.java new file mode 100644 index 00000000000..5854f860420 --- /dev/null +++ b/iam/snippets/src/test/java/DisableServiceAccountIT.java @@ -0,0 +1,98 @@ +/* Copyright 2025 Google LLC + * + * 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. + */ + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import com.google.cloud.testing.junit4.MultipleAttemptsRule; +import com.google.iam.admin.v1.ServiceAccount; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class DisableServiceAccountIT { + + private static final String PROJECT_ID = System.getenv("GOOGLE_CLOUD_PROJECT"); + private ByteArrayOutputStream bout; + private String serviceAccountName; + private final PrintStream originalOut = System.out; + + @Rule public MultipleAttemptsRule multipleAttemptsRule = new MultipleAttemptsRule(3); + + private static void requireEnvVar(String varName) { + assertNotNull( + System.getenv(varName), + String.format("Environment variable '%s' is required to perform these tests.", varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("GOOGLE_CLOUD_PROJECT"); + } + + @Before + public void beforeTest() throws IOException, InterruptedException { + bout = new ByteArrayOutputStream(); + System.setOut(new PrintStream(bout)); + + // Set up test + serviceAccountName = Util.generateServiceAccountName(); + Util.setUpTest_createServiceAccount(PROJECT_ID, serviceAccountName); + } + + @After + public void tearDown() throws IOException { + // Cleanup test + Util.tearDownTest_deleteServiceAccount(PROJECT_ID, serviceAccountName); + + System.out.flush(); + System.setOut(originalOut); + } + + @Test + public void testDisableServiceAccount() throws IOException, InterruptedException { + // Act + DisableServiceAccount.disableServiceAccount(PROJECT_ID, serviceAccountName); + + // Assert + waitForDisableServiceAccountOperation(PROJECT_ID, serviceAccountName); + ServiceAccount serviceAccount = Util.test_getServiceAccount(PROJECT_ID, serviceAccountName); + assertTrue(serviceAccount.getDisabled()); + } + + private static void waitForDisableServiceAccountOperation( + String projectId, String serviceAccountName) throws IOException, InterruptedException { + boolean isAccountDisabled = false; + long time = 1000; + long timeLimit = 60000; + while (!isAccountDisabled && time <= timeLimit) { + ServiceAccount serviceAccount = Util.test_getServiceAccount(projectId, serviceAccountName); + isAccountDisabled = serviceAccount.getDisabled(); + if (!isAccountDisabled) { + Thread.sleep(time); + time *= 2; + } + } + } +} diff --git a/iam/snippets/src/test/java/DisableServiceAccountKeyIT.java b/iam/snippets/src/test/java/DisableServiceAccountKeyIT.java new file mode 100644 index 00000000000..e90b78717a7 --- /dev/null +++ b/iam/snippets/src/test/java/DisableServiceAccountKeyIT.java @@ -0,0 +1,106 @@ +/* Copyright 2025 Google LLC + * + * 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. + */ + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import com.google.cloud.testing.junit4.MultipleAttemptsRule; +import com.google.iam.admin.v1.ServiceAccountKey; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class DisableServiceAccountKeyIT { + + private static final String PROJECT_ID = System.getenv("GOOGLE_CLOUD_PROJECT"); + private ByteArrayOutputStream bout; + private String serviceAccountName; + private String serviceAccountKeyId; + private final PrintStream originalOut = System.out; + + @Rule public MultipleAttemptsRule multipleAttemptsRule = new MultipleAttemptsRule(3); + + private static void requireEnvVar(String varName) { + assertNotNull( + System.getenv(varName), + String.format("Environment variable '%s' is required to perform these tests.", varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("GOOGLE_CLOUD_PROJECT"); + } + + @Before + public void beforeTest() throws IOException, InterruptedException { + bout = new ByteArrayOutputStream(); + System.setOut(new PrintStream(bout)); + + // Set up test + serviceAccountName = Util.generateServiceAccountName(); + Util.setUpTest_createServiceAccount(PROJECT_ID, serviceAccountName); + ServiceAccountKey setupKey = + Util.setUpTest_createServiceAccountKey(PROJECT_ID, serviceAccountName); + serviceAccountKeyId = Util.getServiceAccountKeyIdFromKey(setupKey); + } + + @After + public void tearDown() throws IOException { + // Cleanup test + Util.tearDownTest_deleteServiceAccount(PROJECT_ID, serviceAccountName); + + System.out.flush(); + System.setOut(originalOut); + } + + @Test + public void testDisableServiceAccountKey() throws IOException, InterruptedException { + // Act + DisableServiceAccountKey.disableServiceAccountKey( + PROJECT_ID, serviceAccountName, serviceAccountKeyId); + + // Assert + waitForDisableServiceAccountKeyOperation(PROJECT_ID, serviceAccountName, serviceAccountKeyId); + ServiceAccountKey key = + Util.test_getServiceAccountKey(PROJECT_ID, serviceAccountName, serviceAccountKeyId); + assertTrue(key.getDisabled()); + } + + private void waitForDisableServiceAccountKeyOperation( + String projectId, String serviceAccountName, String serviceAccountKeyId) + throws IOException, InterruptedException { + boolean isKeyDisabled = false; + long time = 1000; + long timeLimit = 60000; + while (!isKeyDisabled && time <= timeLimit) { + ServiceAccountKey key = + Util.test_getServiceAccountKey(projectId, serviceAccountName, serviceAccountKeyId); + isKeyDisabled = key.getDisabled(); + if (!isKeyDisabled) { + Thread.sleep(time); + time *= 2; + } + } + } +} diff --git a/iam/snippets/src/test/java/EnableServiceAccountIT.java b/iam/snippets/src/test/java/EnableServiceAccountIT.java new file mode 100644 index 00000000000..a7158dfecac --- /dev/null +++ b/iam/snippets/src/test/java/EnableServiceAccountIT.java @@ -0,0 +1,99 @@ +/* Copyright 2025 Google LLC + * + * 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. + */ + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; + +import com.google.cloud.testing.junit4.MultipleAttemptsRule; +import com.google.iam.admin.v1.ServiceAccount; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class EnableServiceAccountIT { + + private static final String PROJECT_ID = System.getenv("GOOGLE_CLOUD_PROJECT"); + private ByteArrayOutputStream bout; + private String serviceAccountName; + private final PrintStream originalOut = System.out; + + @Rule public MultipleAttemptsRule multipleAttemptsRule = new MultipleAttemptsRule(3); + + private static void requireEnvVar(String varName) { + assertNotNull( + System.getenv(varName), + String.format("Environment variable '%s' is required to perform these tests.", varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("GOOGLE_CLOUD_PROJECT"); + } + + @Before + public void beforeTest() throws IOException, InterruptedException { + bout = new ByteArrayOutputStream(); + System.setOut(new PrintStream(bout)); + + // Set up test + serviceAccountName = Util.generateServiceAccountName(); + Util.setUpTest_createServiceAccount(PROJECT_ID, serviceAccountName); + Util.setUpTest_disableServiceAccount(PROJECT_ID, serviceAccountName); + } + + @After + public void tearDown() throws IOException { + // Cleanup test + Util.tearDownTest_deleteServiceAccount(PROJECT_ID, serviceAccountName); + + System.out.flush(); + System.setOut(originalOut); + } + + @Test + public void testEnableServiceAccount() throws IOException, InterruptedException { + // Act + EnableServiceAccount.enableServiceAccount(PROJECT_ID, serviceAccountName); + + // Assert + waitForEnableServiceAccountOperation(PROJECT_ID, serviceAccountName); + ServiceAccount serviceAccount = Util.test_getServiceAccount(PROJECT_ID, serviceAccountName); + assertFalse(serviceAccount.getDisabled()); + } + + private static void waitForEnableServiceAccountOperation( + String projectId, String serviceAccountName) throws IOException, InterruptedException { + boolean isAccountDisabled = true; + long time = 1000; + long timeLimit = 60000; + while (isAccountDisabled && time <= timeLimit) { + ServiceAccount serviceAccount = Util.test_getServiceAccount(projectId, serviceAccountName); + isAccountDisabled = serviceAccount.getDisabled(); + if (isAccountDisabled) { + Thread.sleep(time); + time *= 2; + } + } + } +} diff --git a/iam/snippets/src/test/java/EnableServiceAccountKeyIT.java b/iam/snippets/src/test/java/EnableServiceAccountKeyIT.java new file mode 100644 index 00000000000..5a4c9973dc6 --- /dev/null +++ b/iam/snippets/src/test/java/EnableServiceAccountKeyIT.java @@ -0,0 +1,107 @@ +/* Copyright 2025 Google LLC + * + * 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. + */ + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; + +import com.google.cloud.testing.junit4.MultipleAttemptsRule; +import com.google.iam.admin.v1.ServiceAccountKey; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class EnableServiceAccountKeyIT { + + private static final String PROJECT_ID = System.getenv("GOOGLE_CLOUD_PROJECT"); + private ByteArrayOutputStream bout; + private String serviceAccountName; + private String serviceAccountKeyId; + private final PrintStream originalOut = System.out; + + @Rule public MultipleAttemptsRule multipleAttemptsRule = new MultipleAttemptsRule(3); + + private static void requireEnvVar(String varName) { + assertNotNull( + System.getenv(varName), + String.format("Environment variable '%s' is required to perform these tests.", varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("GOOGLE_CLOUD_PROJECT"); + } + + @Before + public void beforeTest() throws IOException, InterruptedException { + bout = new ByteArrayOutputStream(); + System.setOut(new PrintStream(bout)); + + // Set up test + serviceAccountName = Util.generateServiceAccountName(); + Util.setUpTest_createServiceAccount(PROJECT_ID, serviceAccountName); + ServiceAccountKey setupKey = + Util.setUpTest_createServiceAccountKey(PROJECT_ID, serviceAccountName); + serviceAccountKeyId = Util.getServiceAccountKeyIdFromKey(setupKey); + Util.setUpTest_disableServiceAccountKey(PROJECT_ID, serviceAccountName, serviceAccountKeyId); + } + + @After + public void tearDown() throws IOException { + // Cleanup test + Util.tearDownTest_deleteServiceAccount(PROJECT_ID, serviceAccountName); + + System.out.flush(); + System.setOut(originalOut); + } + + @Test + public void testEnableServiceAccountKey() throws IOException, InterruptedException { + // Act + EnableServiceAccountKey.enableServiceAccountKey( + PROJECT_ID, serviceAccountName, serviceAccountKeyId); + + // Assert + waitForEnableServiceAccountKeyOperation(PROJECT_ID, serviceAccountName, serviceAccountKeyId); + ServiceAccountKey key = + Util.test_getServiceAccountKey(PROJECT_ID, serviceAccountName, serviceAccountKeyId); + assertFalse(key.getDisabled()); + } + + private void waitForEnableServiceAccountKeyOperation( + String projectId, String serviceAccountName, String serviceAccountKeyId) + throws IOException, InterruptedException { + boolean isKeyDisabled = true; + long time = 1000; + long timeLimit = 60000; + while (isKeyDisabled && time <= timeLimit) { + ServiceAccountKey key = + Util.test_getServiceAccountKey(projectId, serviceAccountName, serviceAccountKeyId); + isKeyDisabled = key.getDisabled(); + if (isKeyDisabled) { + Thread.sleep(time); + time *= 2; + } + } + } +} diff --git a/iam/snippets/src/test/java/GetServiceAccountIT.java b/iam/snippets/src/test/java/GetServiceAccountIT.java new file mode 100644 index 00000000000..f0bed012ec1 --- /dev/null +++ b/iam/snippets/src/test/java/GetServiceAccountIT.java @@ -0,0 +1,81 @@ +/* Copyright 2025 Google LLC + * + * 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. + */ + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertNotNull; + +import com.google.cloud.testing.junit4.MultipleAttemptsRule; +import com.google.iam.admin.v1.ServiceAccount; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class GetServiceAccountIT { + + private static final String PROJECT_ID = System.getenv("GOOGLE_CLOUD_PROJECT"); + private ByteArrayOutputStream bout; + private String serviceAccountName; + private final PrintStream originalOut = System.out; + + @Rule public MultipleAttemptsRule multipleAttemptsRule = new MultipleAttemptsRule(3); + + private static void requireEnvVar(String varName) { + assertNotNull( + System.getenv(varName), + String.format("Environment variable '%s' is required to perform these tests.", varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("GOOGLE_CLOUD_PROJECT"); + } + + @Before + public void beforeTest() throws IOException, InterruptedException { + bout = new ByteArrayOutputStream(); + System.setOut(new PrintStream(bout)); + + // Set up test + serviceAccountName = Util.generateServiceAccountName(); + Util.setUpTest_createServiceAccount(PROJECT_ID, serviceAccountName); + } + + @After + public void tearDown() throws IOException { + // Cleanup test + Util.tearDownTest_deleteServiceAccount(PROJECT_ID, serviceAccountName); + + System.out.flush(); + System.setOut(originalOut); + } + + @Test + public void testGetServiceAccount() throws IOException, InterruptedException { + // Act + ServiceAccount account = GetServiceAccount.getServiceAccount(PROJECT_ID, serviceAccountName); + + // Assert + assertThat(account.getName()).contains(serviceAccountName); + } +} diff --git a/iam/snippets/src/test/java/GetServiceAccountKeyIT.java b/iam/snippets/src/test/java/GetServiceAccountKeyIT.java new file mode 100644 index 00000000000..994966728af --- /dev/null +++ b/iam/snippets/src/test/java/GetServiceAccountKeyIT.java @@ -0,0 +1,87 @@ +/* Copyright 2025 Google LLC + * + * 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. + */ + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertNotNull; + +import com.google.cloud.testing.junit4.MultipleAttemptsRule; +import com.google.iam.admin.v1.ServiceAccountKey; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class GetServiceAccountKeyIT { + + private static final String PROJECT_ID = System.getenv("GOOGLE_CLOUD_PROJECT"); + private ByteArrayOutputStream bout; + private String serviceAccountName; + private String serviceAccountKeyId; + private final PrintStream originalOut = System.out; + + @Rule public MultipleAttemptsRule multipleAttemptsRule = new MultipleAttemptsRule(3); + + private static void requireEnvVar(String varName) { + assertNotNull( + System.getenv(varName), + String.format("Environment variable '%s' is required to perform these tests.", varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("GOOGLE_CLOUD_PROJECT"); + } + + @Before + public void beforeTest() throws IOException, InterruptedException { + bout = new ByteArrayOutputStream(); + System.setOut(new PrintStream(bout)); + + // Set up test + serviceAccountName = Util.generateServiceAccountName(); + Util.setUpTest_createServiceAccount(PROJECT_ID, serviceAccountName); + ServiceAccountKey setupKey = + Util.setUpTest_createServiceAccountKey(PROJECT_ID, serviceAccountName); + serviceAccountKeyId = Util.getServiceAccountKeyIdFromKey(setupKey); + } + + @After + public void tearDown() throws IOException { + // Cleanup test + Util.tearDownTest_deleteServiceAccount(PROJECT_ID, serviceAccountName); + + System.out.flush(); + System.setOut(originalOut); + } + + @Test + public void testGetServiceAccountKey() throws IOException, InterruptedException { + // Act + ServiceAccountKey key = + GetServiceAccountKey.getServiceAccountKey( + PROJECT_ID, serviceAccountName, serviceAccountKeyId); + + // Assert + assertThat(key.getName()).contains(serviceAccountKeyId); + } +} diff --git a/iam/snippets/src/test/java/ListServiceAccountKeysIT.java b/iam/snippets/src/test/java/ListServiceAccountKeysIT.java new file mode 100644 index 00000000000..df6257a1ef7 --- /dev/null +++ b/iam/snippets/src/test/java/ListServiceAccountKeysIT.java @@ -0,0 +1,91 @@ +/* Copyright 2025 Google LLC + * + * 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. + */ + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import com.google.cloud.testing.junit4.MultipleAttemptsRule; +import com.google.iam.admin.v1.ServiceAccountKey; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.List; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class ListServiceAccountKeysIT { + + private static final String PROJECT_ID = System.getenv("GOOGLE_CLOUD_PROJECT"); + private ByteArrayOutputStream bout; + private String serviceAccountName; + private String serviceAccountKeyId; + private final PrintStream originalOut = System.out; + + @Rule public MultipleAttemptsRule multipleAttemptsRule = new MultipleAttemptsRule(3); + + private static void requireEnvVar(String varName) { + assertNotNull( + System.getenv(varName), + String.format("Environment variable '%s' is required to perform these tests.", varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("GOOGLE_CLOUD_PROJECT"); + } + + @Before + public void beforeTest() throws IOException, InterruptedException { + bout = new ByteArrayOutputStream(); + System.setOut(new PrintStream(bout)); + + // Set up test + serviceAccountName = Util.generateServiceAccountName(); + Util.setUpTest_createServiceAccount(PROJECT_ID, serviceAccountName); + ServiceAccountKey setupKey = + Util.setUpTest_createServiceAccountKey(PROJECT_ID, serviceAccountName); + serviceAccountKeyId = Util.getServiceAccountKeyIdFromKey(setupKey); + } + + @After + public void tearDown() throws IOException { + // Cleanup test + Util.tearDownTest_deleteServiceAccount(PROJECT_ID, serviceAccountName); + + System.out.flush(); + System.setOut(originalOut); + } + + @Test + public void testListServiceAccountKeys() throws IOException, InterruptedException { + // Act + List keys = ListServiceAccountKeys.listKeys(PROJECT_ID, serviceAccountName); + + // Assert + assertFalse(keys.isEmpty()); + assertTrue( + keys.stream() + .map(ServiceAccountKey::getName) + .anyMatch(keyName -> keyName.contains(serviceAccountKeyId))); + } +} diff --git a/iam/snippets/src/test/java/ListServiceAccountsIT.java b/iam/snippets/src/test/java/ListServiceAccountsIT.java new file mode 100644 index 00000000000..1b6c492470e --- /dev/null +++ b/iam/snippets/src/test/java/ListServiceAccountsIT.java @@ -0,0 +1,80 @@ +/* Copyright 2025 Google LLC + * + * 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. + */ + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertNotNull; + +import com.google.cloud.testing.junit4.MultipleAttemptsRule; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class ListServiceAccountsIT { + + private static final String PROJECT_ID = System.getenv("GOOGLE_CLOUD_PROJECT"); + private ByteArrayOutputStream bout; + private String serviceAccountName; + private final PrintStream originalOut = System.out; + + @Rule public MultipleAttemptsRule multipleAttemptsRule = new MultipleAttemptsRule(3); + + private static void requireEnvVar(String varName) { + assertNotNull( + System.getenv(varName), + String.format("Environment variable '%s' is required to perform these tests.", varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("GOOGLE_CLOUD_PROJECT"); + } + + @Before + public void beforeTest() throws IOException, InterruptedException { + bout = new ByteArrayOutputStream(); + System.setOut(new PrintStream(bout)); + + // Set up test + serviceAccountName = Util.generateServiceAccountName(); + Util.setUpTest_createServiceAccount(PROJECT_ID, serviceAccountName); + } + + @After + public void tearDown() throws IOException { + // Cleanup test + Util.tearDownTest_deleteServiceAccount(PROJECT_ID, serviceAccountName); + + System.out.flush(); + System.setOut(originalOut); + } + + @Test + public void testListServiceAccounts() throws IOException, InterruptedException { + // Act + ListServiceAccounts.listServiceAccounts(PROJECT_ID); + + // Assert + assertThat(bout.toString()).contains(serviceAccountName); + } +} diff --git a/iam/snippets/src/test/java/QuickstartTests.java b/iam/snippets/src/test/java/QuickstartTests.java index 22ae8dc2858..8e65d509468 100644 --- a/iam/snippets/src/test/java/QuickstartTests.java +++ b/iam/snippets/src/test/java/QuickstartTests.java @@ -32,6 +32,7 @@ import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -41,13 +42,13 @@ public class QuickstartTests { private static final String PROJECT_ID = System.getenv("GOOGLE_CLOUD_PROJECT"); private static final String SERVICE_ACCOUNT = - "iam-test-account-" + UUID.randomUUID().toString().split("-")[0]; + "iam-test-account-" + UUID.randomUUID().toString().split("-")[0]; private String serviceAccountEmail; private static void requireEnvVar(String varName) { assertNotNull( - System.getenv(varName), - String.format("Environment variable '%s' is required to perform these tests.", varName)); + System.getenv(varName), + String.format("Environment variable '%s' is required to perform these tests.", varName)); } @BeforeClass @@ -60,11 +61,10 @@ public static void checkRequirements() { @Before public void setUp() throws IOException { try (IAMClient iamClient = IAMClient.create()) { - ServiceAccount serviceAccount = ServiceAccount - .newBuilder() - .setDisplayName("test-display-name") - .build(); - CreateServiceAccountRequest request = CreateServiceAccountRequest.newBuilder() + ServiceAccount serviceAccount = + ServiceAccount.newBuilder().setDisplayName("test-display-name").build(); + CreateServiceAccountRequest request = + CreateServiceAccountRequest.newBuilder() .setName(ProjectName.of(PROJECT_ID).toString()) .setAccountId(SERVICE_ACCOUNT) .setServiceAccount(serviceAccount) @@ -80,13 +80,15 @@ public void setUp() throws IOException { public void tearDown() throws IOException { try (IAMClient iamClient = IAMClient.create()) { String serviceAccountName = SERVICE_ACCOUNT + "@" + PROJECT_ID + ".iam.gserviceaccount.com"; - DeleteServiceAccountRequest request = DeleteServiceAccountRequest.newBuilder() + DeleteServiceAccountRequest request = + DeleteServiceAccountRequest.newBuilder() .setName(ServiceAccountName.of(PROJECT_ID, serviceAccountName).toString()) .build(); iamClient.deleteServiceAccount(request); } } + @Ignore("TODO: remove after resolving https://github.com/GoogleCloudPlatform/java-docs-samples/issues/10082") @Test public void testQuickstart() throws Exception { String member = "serviceAccount:" + serviceAccountEmail; diff --git a/iam/snippets/src/test/java/RenameServiceAccountIT.java b/iam/snippets/src/test/java/RenameServiceAccountIT.java new file mode 100644 index 00000000000..24ebca5d6aa --- /dev/null +++ b/iam/snippets/src/test/java/RenameServiceAccountIT.java @@ -0,0 +1,85 @@ +/* Copyright 2025 Google LLC + * + * 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. + */ + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertNotNull; + +import com.google.cloud.testing.junit4.MultipleAttemptsRule; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class RenameServiceAccountIT { + + private static final String PROJECT_ID = System.getenv("GOOGLE_CLOUD_PROJECT"); + private ByteArrayOutputStream bout; + private String serviceAccountName; + private String newServiceAccountName; + private final PrintStream originalOut = System.out; + + @Rule public MultipleAttemptsRule multipleAttemptsRule = new MultipleAttemptsRule(3); + + private static void requireEnvVar(String varName) { + assertNotNull( + System.getenv(varName), + String.format("Environment variable '%s' is required to perform these tests.", varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("GOOGLE_CLOUD_PROJECT"); + } + + @Before + public void beforeTest() throws IOException, InterruptedException { + bout = new ByteArrayOutputStream(); + System.setOut(new PrintStream(bout)); + + // Set up test + serviceAccountName = Util.generateServiceAccountName(); + newServiceAccountName = "new-" + Util.generateServiceAccountName(); + Util.setUpTest_createServiceAccount(PROJECT_ID, serviceAccountName); + } + + @After + public void tearDown() throws IOException { + // Cleanup test + Util.tearDownTest_deleteServiceAccount(PROJECT_ID, serviceAccountName); + + System.out.flush(); + System.setOut(originalOut); + } + + @Test + public void testRenameServiceAccount() throws IOException, InterruptedException { + // Act + RenameServiceAccount.renameServiceAccount( + PROJECT_ID, serviceAccountName, newServiceAccountName); + + // Assert + String outString = bout.toString(); + assertThat(outString).contains("Updated display name for"); + assertThat(outString).contains("to: " + newServiceAccountName); + } +} diff --git a/iam/snippets/src/test/java/RoleIT.java b/iam/snippets/src/test/java/RoleIT.java index 5330d4c3d1b..f68e5b0a0dc 100644 --- a/iam/snippets/src/test/java/RoleIT.java +++ b/iam/snippets/src/test/java/RoleIT.java @@ -38,7 +38,6 @@ public class RoleIT { private ByteArrayOutputStream bout; private static final String projectId = System.getenv("IAM_PROJECT_ID"); - private static final String GOOGLE_APPLICATION_CREDENTIALS = System.getenv("IAM_CREDENTIALS"); private static final String _suffix = UUID.randomUUID().toString().substring(0, 6); private static final String roleId = "testRole" + _suffix; private static final String roleName = "projects/" + projectId + "/roles/" + roleId; @@ -57,7 +56,6 @@ public static void checkRequirements() throws IOException { ByteArrayOutputStream stdOut = new ByteArrayOutputStream(); requireEnvVar("IAM_PROJECT_ID"); - requireEnvVar("IAM_CREDENTIALS"); stdOut.close(); System.setOut(out); diff --git a/iam/snippets/src/test/java/ServiceAccountTests.java b/iam/snippets/src/test/java/ServiceAccountTests.java deleted file mode 100644 index 9d612bf3d98..00000000000 --- a/iam/snippets/src/test/java/ServiceAccountTests.java +++ /dev/null @@ -1,216 +0,0 @@ -/* Copyright 2018 Google LLC - * - * 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. - */ - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.core.StringContains.containsString; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import com.google.cloud.iam.admin.v1.IAMClient; -import com.google.cloud.testing.junit4.MultipleAttemptsRule; -import com.google.iam.admin.v1.ServiceAccount; -import com.google.iam.admin.v1.ServiceAccountKey; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.PrintStream; -import java.util.List; -import java.util.UUID; -import org.junit.After; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.FixMethodOrder; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; -import org.junit.runners.MethodSorters; - -@RunWith(JUnit4.class) -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class ServiceAccountTests { - - private static final String PROJECT_ID = System.getenv("GOOGLE_CLOUD_PROJECT"); - private static final String SERVICE_ACCOUNT = - "service-account-" + UUID.randomUUID().toString().substring(0, 8); - private static String SERVICE_ACCOUNT_KEY_ID; - private ByteArrayOutputStream bout; - private final PrintStream originalOut = System.out; - - @Rule public MultipleAttemptsRule multipleAttemptsRule = new MultipleAttemptsRule(3); - - private static void requireEnvVar(String varName) { - assertNotNull( - System.getenv(varName), - String.format("Environment variable '%s' is required to perform these tests.", varName)); - } - - @BeforeClass - public static void checkRequirements() { - requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); - requireEnvVar("GOOGLE_CLOUD_PROJECT"); - } - - @Before - public void beforeTest() { - bout = new ByteArrayOutputStream(); - System.setOut(new PrintStream(bout)); - } - - @After - public void tearDown() { - System.setOut(originalOut); - bout.reset(); - } - - @Test - public void stage1_testServiceAccountCreate() throws IOException { - ServiceAccount serviceAccount = CreateServiceAccount - .createServiceAccount(PROJECT_ID, SERVICE_ACCOUNT); - String got = bout.toString(); - assertThat(got, containsString("Created service account: " + SERVICE_ACCOUNT)); - assertNotNull(serviceAccount); - assertThat(serviceAccount.getName(), containsString(SERVICE_ACCOUNT)); - - } - - @Test - public void stage1_testServiceAccountsList() throws IOException { - IAMClient.ListServiceAccountsPagedResponse response = - ListServiceAccounts.listServiceAccounts(PROJECT_ID); - - assertTrue(response.iterateAll().iterator().hasNext()); - } - - @Test - public void stage2_testServiceAccountRename() throws IOException { - String renameTo = "your-new-display-name"; - ServiceAccount serviceAccount = RenameServiceAccount - .renameServiceAccount(PROJECT_ID, SERVICE_ACCOUNT, renameTo); - String got = bout.toString(); - assertThat(got, containsString("Updated display name")); - assertThat(got, containsString(renameTo)); - assertNotNull(serviceAccount); - assertThat(renameTo, containsString(serviceAccount.getDisplayName())); - } - - @Test - public void stage2_testServiceAccountGet() throws IOException { - ServiceAccount account = GetServiceAccount.getServiceAccount(PROJECT_ID, SERVICE_ACCOUNT); - - assertTrue(account.getName().contains(SERVICE_ACCOUNT)); - assertEquals(PROJECT_ID, account.getProjectId()); - } - - @Test - public void stage2_testServiceAccountKeyCreate() throws IOException { - ServiceAccountKey key = CreateServiceAccountKey.createKey(PROJECT_ID, SERVICE_ACCOUNT); - SERVICE_ACCOUNT_KEY_ID = key.getName() - .substring(key.getName().lastIndexOf("/") + 1) - .trim(); - - assertNotNull(SERVICE_ACCOUNT_KEY_ID); - } - - @Test - public void stage2_testServiceAccountKeyGet() throws IOException { - ServiceAccountKey key = GetServiceAccountKey - .getServiceAccountKey(PROJECT_ID, SERVICE_ACCOUNT, SERVICE_ACCOUNT_KEY_ID); - - assertTrue(key.getName().contains(SERVICE_ACCOUNT_KEY_ID)); - assertTrue(key.getName().contains(PROJECT_ID)); - assertTrue(key.getName().contains(SERVICE_ACCOUNT)); - } - - @Test - public void stage2_testServiceAccountKeysList() throws IOException { - List keys = ListServiceAccountKeys.listKeys(PROJECT_ID, SERVICE_ACCOUNT); - - assertNotEquals(0, keys.size()); - assertTrue(keys.stream() - .map(ServiceAccountKey::getName) - .anyMatch(keyName -> keyName.contains(SERVICE_ACCOUNT_KEY_ID))); - } - - @Test - public void stage2_testServiceAccountKeyDisable() throws IOException { - DisableServiceAccountKey - .disableServiceAccountKey(PROJECT_ID, SERVICE_ACCOUNT, SERVICE_ACCOUNT_KEY_ID); - ServiceAccountKey key = GetServiceAccountKey - .getServiceAccountKey(PROJECT_ID, SERVICE_ACCOUNT, SERVICE_ACCOUNT_KEY_ID); - - assertTrue(key.getName().contains(SERVICE_ACCOUNT_KEY_ID)); - assertTrue(key.getDisabled()); - } - - @Test - public void stage2_testServiceAccountKeyEnable() throws IOException { - EnableServiceAccountKey - .enableServiceAccountKey(PROJECT_ID, SERVICE_ACCOUNT, SERVICE_ACCOUNT_KEY_ID); - ServiceAccountKey key = GetServiceAccountKey - .getServiceAccountKey(PROJECT_ID, SERVICE_ACCOUNT, SERVICE_ACCOUNT_KEY_ID); - - assertTrue(key.getName().contains(SERVICE_ACCOUNT_KEY_ID)); - assertFalse(key.getDisabled()); - } - - @Test - public void stage3_testServiceAccountKeyDelete() throws IOException { - DeleteServiceAccountKey.deleteKey(PROJECT_ID, SERVICE_ACCOUNT, SERVICE_ACCOUNT_KEY_ID); - String got = bout.toString(); - assertThat(got, containsString("Deleted key:")); - - bout.reset(); - ListServiceAccountKeys.listKeys(PROJECT_ID, SERVICE_ACCOUNT); - got = bout.toString(); - assertThat(got, !containsString(SERVICE_ACCOUNT_KEY_ID).matches(got)); - } - - @Test - public void stage4_testDisableServiceAccount() throws IOException { - DisableServiceAccount.disableServiceAccount(PROJECT_ID, SERVICE_ACCOUNT); - ServiceAccount serviceAccount = GetServiceAccount - .getServiceAccount(PROJECT_ID, SERVICE_ACCOUNT); - - assertTrue(serviceAccount.getName().contains(SERVICE_ACCOUNT)); - assertEquals(PROJECT_ID, serviceAccount.getProjectId()); - assertTrue(SERVICE_ACCOUNT, serviceAccount.getDisabled()); - } - - @Test - public void stage5_testEnableServiceAccount() throws IOException { - EnableServiceAccount.enableServiceAccount(PROJECT_ID, SERVICE_ACCOUNT); - ServiceAccount serviceAccount = GetServiceAccount - .getServiceAccount(PROJECT_ID, SERVICE_ACCOUNT); - - assertTrue(serviceAccount.getName().contains(SERVICE_ACCOUNT)); - assertEquals(PROJECT_ID, serviceAccount.getProjectId()); - assertFalse(SERVICE_ACCOUNT, serviceAccount.getDisabled()); - } - - @Test - public void stage6_testServiceAccountDelete() throws IOException { - DeleteServiceAccount.deleteServiceAccount(PROJECT_ID, SERVICE_ACCOUNT); - String got = bout.toString(); - assertThat(got, containsString("Deleted service account:")); - - bout.reset(); - ListServiceAccounts.listServiceAccounts(PROJECT_ID); - got = bout.toString(); - assertThat(got, !containsString(SERVICE_ACCOUNT).matches(got)); - } -} diff --git a/iam/snippets/src/test/java/Util.java b/iam/snippets/src/test/java/Util.java new file mode 100644 index 00000000000..6cadf79df3f --- /dev/null +++ b/iam/snippets/src/test/java/Util.java @@ -0,0 +1,223 @@ +/* Copyright 2025 Google LLC + * + * 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. + */ + +import com.google.cloud.iam.admin.v1.IAMClient; +import com.google.iam.admin.v1.CreateServiceAccountKeyRequest; +import com.google.iam.admin.v1.CreateServiceAccountRequest; +import com.google.iam.admin.v1.DeleteServiceAccountKeyRequest; +import com.google.iam.admin.v1.DeleteServiceAccountRequest; +import com.google.iam.admin.v1.DisableServiceAccountRequest; +import com.google.iam.admin.v1.GetServiceAccountKeyRequest; +import com.google.iam.admin.v1.KeyName; +import com.google.iam.admin.v1.ListServiceAccountKeysRequest; +import com.google.iam.admin.v1.ProjectName; +import com.google.iam.admin.v1.ServiceAccount; +import com.google.iam.admin.v1.ServiceAccountKey; +import com.google.iam.admin.v1.ServiceAccountName; +import java.io.IOException; +import java.util.List; +import java.util.UUID; + +public class Util { + public static ServiceAccount setUpTest_createServiceAccount( + String projectId, String serviceAccountName) throws IOException, InterruptedException { + + ServiceAccount serviceAccount = + ServiceAccount.newBuilder().setDisplayName("service-account-test").build(); + CreateServiceAccountRequest request = + CreateServiceAccountRequest.newBuilder() + .setName(ProjectName.of(projectId).toString()) + .setAccountId(serviceAccountName) + .setServiceAccount(serviceAccount) + .build(); + try (IAMClient iamClient = IAMClient.create()) { + serviceAccount = iamClient.createServiceAccount(request); + } + awaitForServiceAccountCreation(projectId, serviceAccountName); + return serviceAccount; + } + + public static void setUpTest_disableServiceAccount(String projectId, String serviceAccountName) + throws IOException { + String email = String.format("%s@%s.iam.gserviceaccount.com", serviceAccountName, projectId); + + try (IAMClient iamClient = IAMClient.create()) { + iamClient.disableServiceAccount( + DisableServiceAccountRequest.newBuilder() + .setName(String.format("projects/%s/serviceAccounts/%s", projectId, email)) + .build()); + } + } + + public static void tearDownTest_deleteServiceAccount(String projectId, String serviceAccountName) + throws IOException { + try (IAMClient client = IAMClient.create()) { + String accountName = ServiceAccountName.of(projectId, serviceAccountName).toString(); + String accountEmail = String.format("%s@%s.iam.gserviceaccount.com", accountName, projectId); + DeleteServiceAccountRequest request = + DeleteServiceAccountRequest.newBuilder().setName(accountEmail).build(); + client.deleteServiceAccount(request); + } + } + + public static IAMClient.ListServiceAccountsPagedResponse test_listServiceAccounts( + String projectId) throws IOException { + try (IAMClient iamClient = IAMClient.create()) { + return iamClient.listServiceAccounts(String.format("projects/%s", projectId)); + } + } + + public static ServiceAccount test_getServiceAccount(String projectId, String serviceAccountName) + throws IOException { + String email = String.format("%s@%s.iam.gserviceaccount.com", serviceAccountName, projectId); + String accountFullName = String.format("projects/%s/serviceAccounts/%s", projectId, email); + try (IAMClient iamClient = IAMClient.create()) { + return iamClient.getServiceAccount(accountFullName); + } + } + + public static ServiceAccountKey setUpTest_createServiceAccountKey( + String projectId, String serviceAccountName) throws IOException, InterruptedException { + awaitForServiceAccountCreation(projectId, serviceAccountName); + String email = String.format("%s@%s.iam.gserviceaccount.com", serviceAccountName, projectId); + try (IAMClient iamClient = IAMClient.create()) { + CreateServiceAccountKeyRequest req = + CreateServiceAccountKeyRequest.newBuilder() + .setName(String.format("projects/%s/serviceAccounts/%s", projectId, email)) + .build(); + ServiceAccountKey createdKey = iamClient.createServiceAccountKey(req); + String serviceAccountKeyId = getServiceAccountKeyIdFromKey(createdKey); + awaitForServiceAccountKeyCreation(projectId, serviceAccountName, serviceAccountKeyId); + + return createdKey; + } + } + + public static void setUpTest_disableServiceAccountKey( + String projectId, String serviceAccountName, String serviceAccountKeyId) + throws IOException, InterruptedException { + String email = String.format("%s@%s.iam.gserviceaccount.com", serviceAccountName, projectId); + String name = + String.format( + "projects/%s/serviceAccounts/%s/keys/%s", projectId, email, serviceAccountKeyId); + try (IAMClient iamClient = IAMClient.create()) { + iamClient.disableServiceAccountKey(name); + } + awaitForServiceAccountKeyDisabling(projectId, serviceAccountName, serviceAccountKeyId); + } + + public static String getServiceAccountKeyIdFromKey(ServiceAccountKey key) { + return key.getName().substring(key.getName().lastIndexOf("/") + 1).trim(); + } + + public static void tearDownTest_deleteServiceAccountKey( + String projectId, String serviceAccountName, String serviceAccountKeyId) throws IOException { + String accountEmail = + String.format("%s@%s.iam.gserviceaccount.com", serviceAccountName, projectId); + String name = KeyName.of(projectId, accountEmail, serviceAccountKeyId).toString(); + + DeleteServiceAccountKeyRequest request = + DeleteServiceAccountKeyRequest.newBuilder().setName(name).build(); + + try (IAMClient iamClient = IAMClient.create()) { + iamClient.deleteServiceAccountKey(request); + } + } + + public static List test_listServiceAccountKeys( + String projectId, String serviceAccountName) throws IOException { + String email = String.format("%s@%s.iam.gserviceaccount.com", serviceAccountName, projectId); + ListServiceAccountKeysRequest request = + ListServiceAccountKeysRequest.newBuilder() + .setName(String.format("projects/%s/serviceAccounts/%s", projectId, email)) + .build(); + + try (IAMClient iamClient = IAMClient.create()) { + return iamClient.listServiceAccountKeys(request).getKeysList(); + } + } + + public static ServiceAccountKey test_getServiceAccountKey( + String projectId, String serviceAccountName, String serviceAccountKeyId) throws IOException { + String email = String.format("%s@%s.iam.gserviceaccount.com", serviceAccountName, projectId); + String name = + String.format( + "projects/%s/serviceAccounts/%s/keys/%s", projectId, email, serviceAccountKeyId); + try (IAMClient iamClient = IAMClient.create()) { + return iamClient.getServiceAccountKey( + GetServiceAccountKeyRequest.newBuilder().setName(name).build()); + } + } + + public static String generateServiceAccountName() { + return "service-account-" + UUID.randomUUID().toString().substring(0, 8); + } + + private static void awaitForServiceAccountCreation(String projectId, String serviceAccountName) + throws InterruptedException { + boolean isAccountCreated = false; + long time = 1000; + long timeLimit = 60000; + while (!isAccountCreated) { + try { + test_getServiceAccount(projectId, serviceAccountName); + isAccountCreated = true; + } catch (Exception e) { + if (time > timeLimit) { + break; + } + Thread.sleep(time); + time *= 2; + } + } + } + + private static void awaitForServiceAccountKeyCreation( + String projectId, String serviceAccountName, String serviceAccountKeyId) + throws InterruptedException { + boolean isAccountCreated = false; + long time = 1000; + long timeLimit = 60000; + while (!isAccountCreated) { + try { + test_getServiceAccountKey(projectId, serviceAccountName, serviceAccountKeyId); + isAccountCreated = true; + } catch (Exception e) { + if (time > timeLimit) { + break; + } + Thread.sleep(time); + time *= 2; + } + } + } + + private static void awaitForServiceAccountKeyDisabling( + String projectId, String serviceAccountName, String serviceAccountKeyId) + throws IOException, InterruptedException { + boolean isKeyDisabled = false; + long time = 1000; + long timeLimit = 60000; + while (!isKeyDisabled && time <= timeLimit) { + ServiceAccountKey key = + test_getServiceAccountKey(projectId, serviceAccountName, serviceAccountKeyId); + isKeyDisabled = key.getDisabled(); + if (!isKeyDisabled) { + Thread.sleep(time); + time *= 2; + } + } + } +}