diff --git a/compute/cloud-client/src/main/java/compute/reservation/CreateSharedReservation.java b/compute/cloud-client/src/main/java/compute/reservation/CreateSharedReservation.java index 53052ee4d25..624965554a9 100644 --- a/compute/cloud-client/src/main/java/compute/reservation/CreateSharedReservation.java +++ b/compute/cloud-client/src/main/java/compute/reservation/CreateSharedReservation.java @@ -18,7 +18,9 @@ // [START compute_reservation_create_shared] import com.google.cloud.compute.v1.AllocationSpecificSKUReservation; +import com.google.cloud.compute.v1.InsertReservationRequest; import com.google.cloud.compute.v1.Operation; +import com.google.cloud.compute.v1.Operation.Status; import com.google.cloud.compute.v1.Reservation; import com.google.cloud.compute.v1.ReservationsClient; import com.google.cloud.compute.v1.ShareSettings; @@ -29,12 +31,6 @@ import java.util.concurrent.TimeoutException; public class CreateSharedReservation { - private final ReservationsClient reservationsClient; - - // Constructor to inject the ReservationsClient - public CreateSharedReservation(ReservationsClient reservationsClient) { - this.reservationsClient = reservationsClient; - } public static void main(String[] args) throws IOException, ExecutionException, InterruptedException, TimeoutException { @@ -48,62 +44,66 @@ public static void main(String[] args) // For more information visit this page: // https://cloud.google.com/compute/docs/instances/reservations-shared#shared_reservation_constraint String projectId = "YOUR_PROJECT_ID"; - // Zone in which the reservation resides. + // Zone in which to reserve resources. String zone = "us-central1-a"; // Name of the reservation to be created. String reservationName = "YOUR_RESERVATION_NAME"; // The URI of the global instance template to be used for creating the reservation. String instanceTemplateUri = String.format( - "projects/%s/global/instanceTemplates/YOUR_INSTANCE_TEMPLATE_NAME", projectId); + "projects/%s/global/instanceTemplates/%s", projectId, "YOUR_INSTANCE_TEMPLATE_NAME"); // Number of instances for which capacity needs to be reserved. int vmCount = 3; - // In your main method, create ReservationsClient - ReservationsClient client = ReservationsClient.create(); - // Create an instance of your class, passing in the client - CreateSharedReservation creator = new CreateSharedReservation(client); - creator.createSharedReservation(projectId, zone, reservationName, instanceTemplateUri, vmCount); + createSharedReservation(projectId, zone, reservationName, instanceTemplateUri, vmCount); } // Creates a shared reservation with the given name in the given zone. - public void createSharedReservation( - String projectId, String zone, - String reservationName, String instanceTemplateUri, int vmCount) - throws ExecutionException, InterruptedException, TimeoutException { + public static Status createSharedReservation( + String projectId, String zone, + String reservationName, String instanceTemplateUri, int vmCount) + throws ExecutionException, InterruptedException, TimeoutException, IOException { + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. + try (ReservationsClient reservationsClient = ReservationsClient.create()) { + ShareSettings shareSettings = ShareSettings.newBuilder() + .setShareType(String.valueOf(ShareSettings.ShareType.SPECIFIC_PROJECTS)) + // The IDs of projects that can consume this reservation. You can include up to + // 100 consumer projects. These projects must be in the same organization as + // the owner project. Don't include the owner project. + // By default, it is already allowed to consume the reservation. + .putProjectMap("CONSUMER_PROJECT_1", ShareSettingsProjectConfig.newBuilder().build()) + .putProjectMap("CONSUMER_PROJECT_2", ShareSettingsProjectConfig.newBuilder().build()) + .build(); - ShareSettings shareSettings = ShareSettings.newBuilder() - .setShareType(String.valueOf(ShareSettings.ShareType.SPECIFIC_PROJECTS)) - // The IDs of projects that can consume this reservation. You can include up to 100 - // consumer projects. These projects must be in the same organization as - // the owner project. Don't include the owner project. By default, it is already allowed - // to consume the reservation. - .putProjectMap("CONSUMER_PROJECT_ID_1", ShareSettingsProjectConfig.newBuilder().build()) - .putProjectMap("CONSUMER_PROJECT_ID_2", ShareSettingsProjectConfig.newBuilder().build()) - .build(); + Reservation reservationResource = + Reservation.newBuilder() + .setName(reservationName) + .setZone(zone) + .setSpecificReservationRequired(true) + .setShareSettings(shareSettings) + .setSpecificReservation( + AllocationSpecificSKUReservation.newBuilder() + .setCount(vmCount) + .setSourceInstanceTemplate(instanceTemplateUri) + .build()) + .build(); - // Create the reservation. - Reservation reservation = - Reservation.newBuilder() - .setName(reservationName) - .setZone(zone) - .setSpecificReservationRequired(true) - .setShareSettings(shareSettings) - .setSpecificReservation( - AllocationSpecificSKUReservation.newBuilder() - .setCount(vmCount) - .setSourceInstanceTemplate(instanceTemplateUri) - .build()) - .build(); + InsertReservationRequest request = + InsertReservationRequest.newBuilder() + .setProject(projectId) + .setZone(zone) + .setReservationResource(reservationResource) + .build(); - // Wait for the create reservation operation to complete. - Operation response = - this.reservationsClient.insertAsync(projectId, zone, reservation).get(3, TimeUnit.MINUTES); + Operation response = reservationsClient.insertAsync(request) + .get(3, TimeUnit.MINUTES); - if (response.hasError()) { - System.out.println("Reservation creation failed!" + response); - return; + if (response.hasError()) { + throw new Error("Reservation creation failed!!" + response); + } + return response.getStatus(); } - System.out.println("Reservation created. Operation Status: " + response.getStatus()); } } // [END compute_reservation_create_shared] diff --git a/compute/cloud-client/src/test/java/compute/reservation/ReservationIT.java b/compute/cloud-client/src/test/java/compute/reservation/ReservationIT.java index ab9575f067a..e94d2fee8b3 100644 --- a/compute/cloud-client/src/test/java/compute/reservation/ReservationIT.java +++ b/compute/cloud-client/src/test/java/compute/reservation/ReservationIT.java @@ -18,21 +18,23 @@ import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import com.google.api.gax.longrunning.OperationFuture; import com.google.api.gax.rpc.NotFoundException; -import com.google.cloud.compute.v1.AllocationSpecificSKUReservation; +import com.google.cloud.compute.v1.InsertReservationRequest; import com.google.cloud.compute.v1.Operation; import com.google.cloud.compute.v1.Operation.Status; import com.google.cloud.compute.v1.Reservation; import com.google.cloud.compute.v1.ReservationsClient; -import com.google.cloud.compute.v1.ShareSettings; -import com.google.cloud.compute.v1.ShareSettingsProjectConfig; import compute.CreateInstanceTemplate; import compute.CreateRegionalInstanceTemplate; import compute.DeleteInstanceTemplate; @@ -53,6 +55,7 @@ import org.junit.jupiter.api.Timeout; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import org.mockito.MockedStatic; @RunWith(JUnit4.class) @Timeout(value = 6, unit = TimeUnit.MINUTES) @@ -184,50 +187,26 @@ public void testCreateReservationWithRegionInstanceTemplate() @Test public void testCreateSharedReservation() - throws ExecutionException, InterruptedException, TimeoutException { - // Mock the ReservationsClient - ReservationsClient mockReservationsClient = mock(ReservationsClient.class); - - // This test require projects in the test environment to share reservation with, - // therefore the operation should be mocked. If you want to make a real test, - // please set the CONSUMER_PROJECT_ID_1 and CONSUMER_PROJECT_ID_2 accordingly. - // Make sure that base project has proper permissions to share reservations. - // See: https://cloud.google.com/compute/docs/instances/reservations-shared#shared_reservation_constraint - ShareSettings shareSettings = ShareSettings.newBuilder() - .setShareType(String.valueOf(ShareSettings.ShareType.SPECIFIC_PROJECTS)) - .putProjectMap("CONSUMER_PROJECT_ID_1", ShareSettingsProjectConfig.newBuilder().build()) - .putProjectMap("CONSUMER_PROJECT_ID_2", ShareSettingsProjectConfig.newBuilder().build()) - .build(); - - Reservation reservation = - Reservation.newBuilder() - .setName(RESERVATION_NAME_SHARED) - .setZone(ZONE) - .setSpecificReservationRequired(true) - .setShareSettings(shareSettings) - .setSpecificReservation( - AllocationSpecificSKUReservation.newBuilder() - .setCount(NUMBER_OF_VMS) - .setSourceInstanceTemplate(INSTANCE_TEMPLATE_SHARED_RESERV_URI) - .build()) - .build(); - - OperationFuture mockFuture = mock(OperationFuture.class); - when(mockReservationsClient.insertAsync(PROJECT_ID, ZONE, reservation)) - .thenReturn(mockFuture); - Operation mockOperation = mock(Operation.class); - when(mockFuture.get(3, TimeUnit.MINUTES)).thenReturn(mockOperation); - when(mockOperation.hasError()).thenReturn(false); - when(mockOperation.getStatus()).thenReturn(Status.DONE); - - // Create an instance, passing in the mock client - CreateSharedReservation creator = new CreateSharedReservation(mockReservationsClient); - - creator.createSharedReservation(PROJECT_ID, ZONE, - RESERVATION_NAME_SHARED, INSTANCE_TEMPLATE_SHARED_RESERV_URI, NUMBER_OF_VMS); - - verify(mockReservationsClient, times(1)) - .insertAsync(PROJECT_ID, ZONE, reservation); - assertThat(stdOut.toString()).contains("Reservation created. Operation Status: DONE"); + throws ExecutionException, InterruptedException, TimeoutException, IOException { + try (MockedStatic mockReservationsClient = + mockStatic(ReservationsClient.class)) { + ReservationsClient mockClient = mock(ReservationsClient.class); + OperationFuture mockFuture = mock(OperationFuture.class); + Operation mockOperation = mock(Operation.class); + + mockReservationsClient.when(ReservationsClient::create).thenReturn(mockClient); + when(mockClient.insertAsync(any(InsertReservationRequest.class))) + .thenReturn(mockFuture); + when(mockFuture.get(3, TimeUnit.MINUTES)).thenReturn(mockOperation); + when(mockOperation.getStatus()).thenReturn(Status.DONE); + + Status status = CreateSharedReservation.createSharedReservation(PROJECT_ID, ZONE, + RESERVATION_NAME_SHARED, INSTANCE_TEMPLATE_SHARED_RESERV_URI, NUMBER_OF_VMS); + + verify(mockClient, times(1)).insertAsync(any(InsertReservationRequest.class)); + verify(mockFuture, times(1)).get(anyLong(), any(TimeUnit.class)); + assertEquals(Status.DONE, status); + + } } } \ No newline at end of file