From 21cb8f4d7edbe167dba68eab29a3c5fd589a6bd0 Mon Sep 17 00:00:00 2001 From: Alek Boninski Date: Tue, 12 Jun 2018 13:16:16 +0300 Subject: [PATCH] [VBV-2022] [BE] Populate favorite images on startup + Add method to return all FavorteImage states from json file + Add states to ComputeInitialBootService ++ Create condition to not populate favorite images if it is a test case ++ Rewrite tests for FavoriteImagesService so they conform to the initial population of the default images ++ Implement test case for the initial population of favorite images +++ Fix checkstyle issues +++ Generate default images self link based on name and registry +++ Remove unneeded tests Change-Id: I8bf71aeaa1dd075d0fc5b832393fd92c74de577c Reviewed-on: https://bellevue-ci.eng.vmware.com:8080/35885 Upgrade-Verified: jenkins Closures-Verified: jenkins Bellevue-Verified: jenkins CS-Verified: jenkins Reviewed-by: Georgi Muleshkov --- .../admiral/common/ManagementUriParts.java | 1 + .../common/AbstractInitialBootService.java | 5 ++ .../host/ComputeInitialBootService.java | 56 +++++++++++++++- .../host/HostInitComputeServicesConfig.java | 4 +- .../service/FavoriteImageFactoryService.java | 22 +++--- .../FavoriteImagePopulateFlagService.java | 67 +++++++++++++++++++ .../image/service/FavoriteImagesService.java | 52 +++++++++++++- .../host/ComputeInitialBootServiceTest.java | 24 +++++++ .../FavoriteImagePopulateFlagServiceTest.java | 54 +++++++++++++++ .../service/FavoriteImagesServiceTest.java | 53 +++++++++++++-- 10 files changed, 319 insertions(+), 19 deletions(-) create mode 100644 compute/src/main/java/com/vmware/admiral/image/service/FavoriteImagePopulateFlagService.java create mode 100644 compute/src/test/java/com/vmware/admiral/image/service/FavoriteImagePopulateFlagServiceTest.java diff --git a/common/src/main/java/com/vmware/admiral/common/ManagementUriParts.java b/common/src/main/java/com/vmware/admiral/common/ManagementUriParts.java index 9d202167d..f6406fe28 100644 --- a/common/src/main/java/com/vmware/admiral/common/ManagementUriParts.java +++ b/common/src/main/java/com/vmware/admiral/common/ManagementUriParts.java @@ -28,6 +28,7 @@ public interface ManagementUriParts { String INSTANCE_TYPE_PROFILES = CONFIG + "/instance-types"; String MIGRATION = CONFIG + "/migration"; String UNIQUE_PROPERTIES = CONFIG + "/unique-properties"; + String FAVORITE_IMAGES_FLAG = CONFIG + "/should-populate-favorites"; String COMPOSITE_DESCRIPTION_UPGRADE_TRANSFORM_PATH = UPGRADE_TRANSFORM_PREFIX + "/composite-descriptions"; diff --git a/common/src/main/java/com/vmware/admiral/service/common/AbstractInitialBootService.java b/common/src/main/java/com/vmware/admiral/service/common/AbstractInitialBootService.java index 7462d69f8..0f1160192 100644 --- a/common/src/main/java/com/vmware/admiral/service/common/AbstractInitialBootService.java +++ b/common/src/main/java/com/vmware/admiral/service/common/AbstractInitialBootService.java @@ -53,6 +53,11 @@ protected void initInstances(Operation post, boolean checkIfExists, boolean self ServiceDocument... states) { if (states == null || states.length == 0) { post.complete(); + logInfo("Finish initial boot service: %s", getSelfLink()); + if (selfDelete) { + logInfo("Stopping initial boot service: %s", getSelfLink()); + sendRequest(Operation.createDelete(getUri())); + } return; } final AtomicInteger countDown = new AtomicInteger(states.length); diff --git a/compute/src/main/java/com/vmware/admiral/host/ComputeInitialBootService.java b/compute/src/main/java/com/vmware/admiral/host/ComputeInitialBootService.java index d2208a28c..ceb527fa8 100644 --- a/compute/src/main/java/com/vmware/admiral/host/ComputeInitialBootService.java +++ b/compute/src/main/java/com/vmware/admiral/host/ComputeInitialBootService.java @@ -23,9 +23,14 @@ import com.vmware.admiral.compute.container.HostVolumeListDataCollection; import com.vmware.admiral.compute.container.SystemContainerDescriptions; import com.vmware.admiral.compute.kubernetes.KubernetesEntityDataCollection; +import com.vmware.admiral.image.service.FavoriteImagePopulateFlagService; +import com.vmware.admiral.image.service.FavoriteImagePopulateFlagService.FavoriteImagePopulateFlag; +import com.vmware.admiral.image.service.FavoriteImagesService; +import com.vmware.admiral.image.service.FavoriteImagesService.FavoriteImage; import com.vmware.admiral.service.common.AbstractInitialBootService; import com.vmware.xenon.common.Operation; import com.vmware.xenon.common.ServiceDocument; +import com.vmware.xenon.common.UriUtils; /** * Initial boot service for creating system default documents for the common module. @@ -39,11 +44,40 @@ public void handlePost(Operation post) { SystemContainerDescriptions.buildCoreAgentContainerDescription()); ArrayList states = new ArrayList<>(); + ArrayList defaultFavoriteImageStates = new ArrayList<>(); + + /** + * Operation to retrieve the flag which tells whether or not to add the default + * favorite images. In case the images should not be added, initInstances is called + * to complete the deletion of the ComputeInitialBootService. + */ + Operation populateDefaultFavoriteImages = Operation + .createGet(UriUtils.buildUri(getHost(), + FavoriteImagePopulateFlagService.FAVORITE_IMAGE_POPULATE_FLAG_LINK)) + .setReferer(getSelfLink()) + .addPragmaDirective(Operation.PRAGMA_DIRECTIVE_QUEUE_FOR_SERVICE_AVAILABILITY) + .setCompletion((o, e) -> { + if (e != null) { + logInfo("Could not retrieve shouldPopulate images flag."); + } else { + FavoriteImagePopulateFlag flag = o.hasBody() ? o.getBody(FavoriteImagePopulateFlag.class) : null; + if (flag != null && flag.shouldPopulate) { + //Add the default favorite image states to the list. + defaultFavoriteImageStates.addAll(FavoriteImagesService.buildDefaultFavoriteImages(getHost())); + flag.shouldPopulate = Boolean.FALSE; + sendRequest(updateShouldPopulateFlagState(flag)); + } + } + initInstances(post, defaultFavoriteImageStates.toArray( + new ServiceDocument[defaultFavoriteImageStates.size()])); + }); + states.add(ContainerHostDataCollectionService.buildDefaultStateInstance()); states.add(KubernetesEntityDataCollection.buildDefaultStateInstance()); states.add(HostContainerListDataCollection.buildDefaultStateInstance()); states.add(HostNetworkListDataCollection.buildDefaultStateInstance()); states.add(HostVolumeListDataCollection.buildDefaultStateInstance()); + states.add(FavoriteImagePopulateFlagService.buildDefaultStateInstance()); if (DeploymentProfileConfig.getInstance().isTest()) { states.add(GroupResourcePlacementService.buildDefaultResourcePool()); @@ -52,6 +86,26 @@ public void handlePost(Operation post) { } } - initInstances(post, states.toArray(new ServiceDocument[states.size()])); + /** + * Initialize default instances without deleting the initial boot service. + */ + initInstances(post, true, false, states.toArray(new ServiceDocument[states.size()])); + /** + * Check whether adding the default favorite images is needed and do so if yes. + */ + sendRequest(populateDefaultFavoriteImages); } + + /** + * Updates the state of the shouldPopulate flag. + * + * @param flagState The new state of the flag. + * @return The update operation to be invoked. + */ + private Operation updateShouldPopulateFlagState(FavoriteImagePopulateFlag flagState) { + return Operation.createPut(UriUtils.buildUri(getHost(),flagState.documentSelfLink)) + .setReferer(getSelfLink()) + .setBody(flagState); + } + } diff --git a/compute/src/main/java/com/vmware/admiral/host/HostInitComputeServicesConfig.java b/compute/src/main/java/com/vmware/admiral/host/HostInitComputeServicesConfig.java index 49d9ab859..17dff431a 100644 --- a/compute/src/main/java/com/vmware/admiral/host/HostInitComputeServicesConfig.java +++ b/compute/src/main/java/com/vmware/admiral/host/HostInitComputeServicesConfig.java @@ -86,6 +86,7 @@ import com.vmware.admiral.compute.pks.PKSEndpointService; import com.vmware.admiral.compute.util.DanglingDescriptionsCleanupService; import com.vmware.admiral.image.service.FavoriteImageFactoryService; +import com.vmware.admiral.image.service.FavoriteImagePopulateFlagService; import com.vmware.admiral.image.service.FavoriteImagesService; import com.vmware.photon.controller.model.resources.ComputeDescriptionService; import com.vmware.photon.controller.model.resources.ComputeService; @@ -148,7 +149,8 @@ public static void startServices(ServiceHost host, boolean startMockContainerHos ReplicationControllerService.class, ReplicaSetService.class, PKSEndpointService.class, - FavoriteImagesService.class); + FavoriteImagesService.class, + FavoriteImagePopulateFlagService.class); startServices(host, ContainerHostService.class); diff --git a/compute/src/main/java/com/vmware/admiral/image/service/FavoriteImageFactoryService.java b/compute/src/main/java/com/vmware/admiral/image/service/FavoriteImageFactoryService.java index a19f5cb0a..317d2f620 100644 --- a/compute/src/main/java/com/vmware/admiral/image/service/FavoriteImageFactoryService.java +++ b/compute/src/main/java/com/vmware/admiral/image/service/FavoriteImageFactoryService.java @@ -36,15 +36,6 @@ public FavoriteImageFactoryService() { super(FavoriteImage.class); } - /** - * Thrown when the image which is to be added to favorites is already added. - */ - public class FavoriteImageAlreadyExistsException extends Exception { - public FavoriteImageAlreadyExistsException(String message) { - super(message); - } - } - /** * Thrown when the registry an image belongs to is either not global or disabled, * or both. @@ -103,6 +94,12 @@ private void completeOrFailOperationForImage(Operation post) { queryTask.querySpec.query.addBooleanClause(nameClause); queryTask.querySpec.query.addBooleanClause(registryClause); + + if (imageToFavorite.tenantLinks != null && !imageToFavorite.tenantLinks.isEmpty()) { + Query tenantLinkClause = QueryUtil.addTenantClause(imageToFavorite.tenantLinks); + queryTask.querySpec.query.addBooleanClause(tenantLinkClause); + } + QueryUtil.addExpandOption(queryTask); List existingFavorites = new LinkedList<>(); @@ -116,9 +113,10 @@ private void completeOrFailOperationForImage(Operation post) { if (existingFavorites.isEmpty()) { completeOrFailOperationForRegistry(post, imageToFavorite.registry); } else { - post.setStatusCode(Operation.STATUS_CODE_BAD_REQUEST); - post.fail(new FavoriteImageAlreadyExistsException("Image " + - "already exists as favorite")); + //If the image is already added, add the existing image state to the POST body + post.setStatusCode(Operation.STATUS_CODE_NOT_MODIFIED); + post.setBody(existingFavorites.get(0)); + post.complete(); } } }); diff --git a/compute/src/main/java/com/vmware/admiral/image/service/FavoriteImagePopulateFlagService.java b/compute/src/main/java/com/vmware/admiral/image/service/FavoriteImagePopulateFlagService.java new file mode 100644 index 000000000..e6dfa5c94 --- /dev/null +++ b/compute/src/main/java/com/vmware/admiral/image/service/FavoriteImagePopulateFlagService.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2018 VMware, Inc. All Rights Reserved. + * + * This product is licensed to you under the Apache License, Version 2.0 (the "License"). + * You may not use this product except in compliance with the License. + * + * This product may include a number of subcomponents with separate copyright notices + * and license terms. Your use of these subcomponents is subject to the terms and + * conditions of the subcomponent's license, as noted in the LICENSE file. + */ + +package com.vmware.admiral.image.service; + +import com.vmware.admiral.common.ManagementUriParts; +import com.vmware.xenon.common.LocalizableValidationException; +import com.vmware.xenon.common.Operation; +import com.vmware.xenon.common.ServiceDocument; +import com.vmware.xenon.common.StatefulService; +import com.vmware.xenon.common.UriUtils; + +public class FavoriteImagePopulateFlagService extends StatefulService { + public static final String FACTORY_LINK = ManagementUriParts.FAVORITE_IMAGES_FLAG; + public static final String FAVORITE_IMAGE_POPULATE_FLAG_ID = "flag"; + public static final String FAVORITE_IMAGE_POPULATE_FLAG_LINK = UriUtils + .buildUriPath(FACTORY_LINK, FAVORITE_IMAGE_POPULATE_FLAG_ID); + + public FavoriteImagePopulateFlagService() { + super(FavoriteImagePopulateFlag.class); + super.toggleOption(ServiceOption.PERSISTENCE, true); + super.toggleOption(ServiceOption.REPLICATION, true); + super.toggleOption(ServiceOption.OWNER_SELECTION, true); + super.toggleOption(ServiceOption.IDEMPOTENT_POST, true); + } + + public static FavoriteImagePopulateFlag buildDefaultStateInstance() { + FavoriteImagePopulateFlag state = new FavoriteImagePopulateFlag(); + state.documentSelfLink = FAVORITE_IMAGE_POPULATE_FLAG_LINK; + state.shouldPopulate = Boolean.TRUE; + state.shouldPopulateInEmbedded = Boolean.TRUE; + return state; + } + + public static class FavoriteImagePopulateFlag extends ServiceDocument { + public Boolean shouldPopulate; + public Boolean shouldPopulateInEmbedded; + } + + @Override + public void handlePost(Operation post) { + if (!post.hasBody()) { + post.fail(new IllegalArgumentException("body is required")); + return; + } + + FavoriteImagePopulateFlag initState = post.getBody(FavoriteImagePopulateFlag.class); + if (initState.documentSelfLink == null + || !initState.documentSelfLink + .endsWith(FAVORITE_IMAGE_POPULATE_FLAG_ID)) { + post.fail(new LocalizableValidationException( + "Only one instance of favorite image populate shouldPopulate can be started", + "compute.should-populte-flag.single")); + return; + } + + post.setBody(initState).complete(); + } +} diff --git a/compute/src/main/java/com/vmware/admiral/image/service/FavoriteImagesService.java b/compute/src/main/java/com/vmware/admiral/image/service/FavoriteImagesService.java index 4fed33c0e..dfa0c1592 100644 --- a/compute/src/main/java/com/vmware/admiral/image/service/FavoriteImagesService.java +++ b/compute/src/main/java/com/vmware/admiral/image/service/FavoriteImagesService.java @@ -11,14 +11,27 @@ package com.vmware.admiral.image.service; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; import java.util.Objects; +import java.util.function.Function; +import java.util.logging.Level; + +import com.google.gson.JsonSyntaxException; import com.vmware.admiral.common.ManagementUriParts; +import com.vmware.admiral.common.util.FileUtil; import com.vmware.admiral.service.common.MultiTenantDocument; +import com.vmware.xenon.common.ServiceHost; import com.vmware.xenon.common.StatefulService; +import com.vmware.xenon.common.UriUtils; +import com.vmware.xenon.common.Utils; public class FavoriteImagesService extends StatefulService { public static final String FACTORY_LINK = ManagementUriParts.FAVORITE_IMAGES; + private static final String POPULAR_IMAGES_FILE = "/popular-images.json"; public FavoriteImagesService() { super(FavoriteImage.class); @@ -26,6 +39,40 @@ public FavoriteImagesService() { super.toggleOption(ServiceOption.REPLICATION, true); super.toggleOption(ServiceOption.OWNER_SELECTION, true); super.toggleOption(ServiceOption.INSTRUMENTATION, true); + super.toggleOption(ServiceOption.IDEMPOTENT_POST, true); + } + + public static List buildDefaultFavoriteImages(ServiceHost host) { + List images = new ArrayList<>(); + try { + List jsonImages = Utils.fromJson(FileUtil.getClasspathResourceAsString(POPULAR_IMAGES_FILE), List.class); + + host.log(Level.INFO, "Default favorite images loaded."); + + Function createSelfLink = state -> { + return UriUtils.buildUriPath(FavoriteImagesService.FACTORY_LINK, + new StringBuilder().append(state.registry.replaceFirst("https?://", "") + .replaceAll("\\.", "-")) + .append('-') + .append(state.name.replaceAll("/", "-") + .replaceAll("\\.", "-")) + .toString()); + }; + + jsonImages.forEach(i -> { + Map imgObj = (Map) i; + FavoriteImage state = new FavoriteImage(); + state.name = imgObj.get(FavoriteImage.FIELD_NAME_NAME); + state.description = imgObj.get(FavoriteImage.FIELD_NAME_DESCRIPTION); + state.registry = imgObj.get(FavoriteImage.FIELD_NAME_REGISTRY); + state.documentSelfLink = createSelfLink.apply(state); + images.add(state); + }); + } catch (NullPointerException | JsonSyntaxException e) { + host.log(Level.WARNING, "Unable to load default favorite images. " + + "Either the file is missing or it is malformed"); + } + return images; } public static class FavoriteImage extends MultiTenantDocument { @@ -52,9 +99,12 @@ public boolean equals(Object obj) { return false; } FavoriteImage i = (FavoriteImage) obj; + boolean tenantLinkClause = (i.tenantLinks != null ? i.tenantLinks : Collections.emptyList()).equals( + (this.tenantLinks != null ? this.tenantLinks : Collections.emptyList())); + return i.name.equals(this.name) && i.registry.equals(this.registry) && - i.description.equals(this.description); + tenantLinkClause; } } } diff --git a/compute/src/test/java/com/vmware/admiral/host/ComputeInitialBootServiceTest.java b/compute/src/test/java/com/vmware/admiral/host/ComputeInitialBootServiceTest.java index d00def606..33c0ad407 100644 --- a/compute/src/test/java/com/vmware/admiral/host/ComputeInitialBootServiceTest.java +++ b/compute/src/test/java/com/vmware/admiral/host/ComputeInitialBootServiceTest.java @@ -15,6 +15,9 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.util.List; import org.junit.After; import org.junit.Test; @@ -34,6 +37,10 @@ import com.vmware.admiral.compute.container.SystemContainerDescriptions; import com.vmware.admiral.compute.kubernetes.KubernetesEntityDataCollection; import com.vmware.admiral.compute.kubernetes.KubernetesEntityDataCollection.KubernetesEntityDataCollectionState; +import com.vmware.admiral.image.service.FavoriteImagePopulateFlagService; +import com.vmware.admiral.image.service.FavoriteImagePopulateFlagService.FavoriteImagePopulateFlag; +import com.vmware.admiral.image.service.FavoriteImagesService; +import com.vmware.admiral.image.service.FavoriteImagesService.FavoriteImage; import com.vmware.photon.controller.model.resources.ResourcePoolService.ResourcePoolState; import com.vmware.xenon.common.TaskState.TaskStage; @@ -181,4 +188,21 @@ public void testDefaultResourcePoolServiceCreatedOnStartUp() throws Throwable { assertEquals(GroupResourcePlacementService.DEFAULT_RESOURCE_POOL_ID, resourcePoolState.id); } + @Test + public void testDefaultFavoriteImagesCreatedOnStartUp() throws Throwable { + List defaultImages = FavoriteImagesService.buildDefaultFavoriteImages(host); + List favoriteImages = getDocumentsOfType(FavoriteImage.class); + + assertEquals(defaultImages.size(), favoriteImages.size()); + + favoriteImages.forEach(i -> { + assertTrue(defaultImages.contains(i)); + }); + + FavoriteImagePopulateFlag shouldPopulateFlag = getDocument(FavoriteImagePopulateFlag.class, + FavoriteImagePopulateFlagService.FAVORITE_IMAGE_POPULATE_FLAG_LINK); + + assertFalse(shouldPopulateFlag.shouldPopulate); + } + } diff --git a/compute/src/test/java/com/vmware/admiral/image/service/FavoriteImagePopulateFlagServiceTest.java b/compute/src/test/java/com/vmware/admiral/image/service/FavoriteImagePopulateFlagServiceTest.java new file mode 100644 index 000000000..fcc2f8a5e --- /dev/null +++ b/compute/src/test/java/com/vmware/admiral/image/service/FavoriteImagePopulateFlagServiceTest.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2018 VMware, Inc. All Rights Reserved. + * + * This product is licensed to you under the Apache License, Version 2.0 (the "License"). + * You may not use this product except in compliance with the License. + * + * This product may include a number of subcomponents with separate copyright notices + * and license terms. Your use of these subcomponents is subject to the terms and + * conditions of the subcomponent's license, as noted in the LICENSE file. + */ + +package com.vmware.admiral.image.service; + +import static org.junit.Assert.assertFalse; + +import org.junit.Before; +import org.junit.Test; + +import com.vmware.admiral.compute.container.ComputeBaseTest; +import com.vmware.admiral.image.service.FavoriteImagePopulateFlagService.FavoriteImagePopulateFlag; +import com.vmware.xenon.common.LocalizableValidationException; + +public class FavoriteImagePopulateFlagServiceTest extends ComputeBaseTest { + + @Before + public void SetUp() throws Throwable { + waitForServiceAvailability(FavoriteImagePopulateFlagService.FACTORY_LINK); + } + + @Test(expected = IllegalArgumentException.class) + public void testPostStateWithoutBody() throws Throwable { + doPost(null, FavoriteImagePopulateFlagService.FAVORITE_IMAGE_POPULATE_FLAG_LINK); + } + + @Test(expected = LocalizableValidationException.class) + public void testPostSecondState() throws Throwable { + FavoriteImagePopulateFlag state = new FavoriteImagePopulateFlag(); + state.shouldPopulate = Boolean.TRUE; + state.shouldPopulateInEmbedded = Boolean.TRUE; + doPost(state, FavoriteImagePopulateFlagService.FAVORITE_IMAGE_POPULATE_FLAG_LINK); + } + + @Test + public void testPutState() throws Throwable { + FavoriteImagePopulateFlag state = new FavoriteImagePopulateFlag(); + state.shouldPopulate = Boolean.FALSE; + state.shouldPopulateInEmbedded = Boolean.FALSE; + state.documentSelfLink = FavoriteImagePopulateFlagService.FAVORITE_IMAGE_POPULATE_FLAG_LINK; + FavoriteImagePopulateFlag response = doPut(state); + + assertFalse(response.shouldPopulate); + assertFalse(response.shouldPopulateInEmbedded); + } +} \ No newline at end of file diff --git a/compute/src/test/java/com/vmware/admiral/image/service/FavoriteImagesServiceTest.java b/compute/src/test/java/com/vmware/admiral/image/service/FavoriteImagesServiceTest.java index 9e5c54d63..9a374f8d9 100644 --- a/compute/src/test/java/com/vmware/admiral/image/service/FavoriteImagesServiceTest.java +++ b/compute/src/test/java/com/vmware/admiral/image/service/FavoriteImagesServiceTest.java @@ -45,7 +45,10 @@ public void setUp() throws Throwable { } @Before - public void initObjects() { + public void initObjects() throws Throwable { + + cleanUpFavoriteImages(); + nginxImage = new FavoriteImage(); nginxImage.name = "library/nginx"; nginxImage.description = "Official build of Nginx."; @@ -64,6 +67,11 @@ public void initObjects() { } + @Test + public void testNoAddedFavoriteImages() throws Throwable { + checkImages(); + } + @Test public void testAddAndRemoveImageFromFavorites() throws Throwable { FavoriteImage imageState = addImageToFavorites(nginxImage).getBody(FavoriteImage.class); @@ -125,7 +133,7 @@ public void testAddImageToFavoritesDisabledRegistry() throws Throwable { checkImages(); } - @Test(expected = Exception.class) + @Test public void testAddExistingImageToFavorites() throws Throwable { FavoriteImage nginxImageState = addImageToFavorites(nginxImage) .getBody(FavoriteImage.class); @@ -133,9 +141,9 @@ public void testAddExistingImageToFavorites() throws Throwable { validateImage(nginxImage, nginxImageState); checkImages(nginxImage); - Operation operationResponse = addImageToFavorites(nginxImage); + FavoriteImage newNginxImageState = addImageToFavorites(nginxImage).getBody(FavoriteImage.class); - assertEquals(Operation.STATUS_CODE_BAD_REQUEST, operationResponse.getStatusCode()); + assertEquals(nginxImageState.documentSelfLink, newNginxImageState.documentSelfLink); checkImages(nginxImage); removeImageFromFavorites(nginxImageState); @@ -143,6 +151,29 @@ public void testAddExistingImageToFavorites() throws Throwable { checkImages(); } + @Test + public void testAddRemoveImageFromFavoritesWithTenantLinks() throws Throwable { + List tenantLinks = new LinkedList<>(); + tenantLinks.add("/projects/qe"); + + FavoriteImage nginxWithTenantLink = new FavoriteImage(); + nginxWithTenantLink.name = nginxImage.name; + nginxWithTenantLink.description = nginxImage.description; + nginxWithTenantLink.registry = nginxImage.registry; + nginxWithTenantLink.tenantLinks = tenantLinks; + + FavoriteImage nginxImageState = addImageToFavorites(nginxImage).getBody(FavoriteImage.class); + FavoriteImage nginxWithTenantLinkState = addImageToFavorites(nginxWithTenantLink).getBody(FavoriteImage.class); + + checkImages(nginxImage, nginxWithTenantLink); + + removeImageFromFavorites(nginxWithTenantLinkState); + checkImages(nginxImage); + + removeImageFromFavorites(nginxImageState); + checkImages(); + } + @Test public void testFavoriteImageEquals() { FavoriteImage img1 = new FavoriteImage(); @@ -172,6 +203,20 @@ public void testFavoriteImageEquals() { assertEquals(img1.hashCode(), img2.hashCode()); } + private void cleanUpFavoriteImages() throws Throwable { + + List images = getDocumentsOfType(FavoriteImage.class); + + images.forEach(i -> { + try { + host.log(Level.INFO, "Removing default image " + i.name); + removeImageFromFavorites(i); + } catch (Throwable throwable) { + throwable.printStackTrace(); + } + }); + } + private void checkImages(FavoriteImage... expectedImages) throws Throwable { List favorites = getDocumentsOfType(FavoriteImage.class);