/******************************************************************************* * Copyright (c) 2012-2017 Codenvy, S.A. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ package org.eclipse.che.api.machine.server.spi.tck; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import org.eclipse.che.api.core.ConflictException; import org.eclipse.che.api.core.NotFoundException; import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.core.notification.EventService; import org.eclipse.che.api.machine.server.event.BeforeRecipeRemovedEvent; import org.eclipse.che.api.machine.server.event.RecipePersistedEvent; import org.eclipse.che.api.machine.server.recipe.RecipeImpl; import org.eclipse.che.api.machine.server.spi.RecipeDao; import org.eclipse.che.commons.lang.NameGenerator; import org.eclipse.che.commons.test.tck.TckListener; import org.eclipse.che.commons.test.tck.repository.TckRepository; import org.eclipse.che.core.db.cascade.CascadeEventSubscriber; import org.eclipse.che.core.db.cascade.event.CascadeEvent; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import javax.inject.Inject; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import static java.util.Arrays.asList; import static org.mockito.Matchers.any; import static org.mockito.Mockito.doCallRealMethod; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; /** * Tests {@link RecipeDao} contract. * * @author Anton Korneta */ @Listeners(TckListener.class) @Test(suiteName = RecipeDaoTest.SUITE_NAME) public class RecipeDaoTest { public static final String SUITE_NAME = "RecipeDaoTck"; private static final int ENTRY_COUNT = 5; private List<RecipeImpl> recipes; @Inject private RecipeDao recipeDao; @Inject private TckRepository<RecipeImpl> tckRepository; @Inject private EventService eventService; @BeforeMethod public void setUp() throws Exception { recipes = new ArrayList<>(5); for (int i = 0; i < ENTRY_COUNT; i++) { recipes.add(createRecipe(i)); } tckRepository.createAll(recipes); } @AfterMethod public void cleanUp() throws Exception { tckRepository.removeAll(); } @Test(dependsOnMethods = "shouldGetRecipeById") public void shouldCreateRecipe() throws Exception { final RecipeImpl recipe = createRecipe(0); recipeDao.create(recipe); assertEquals(recipeDao.getById(recipe.getId()), recipe); } @Test(dependsOnMethods = "shouldThrowNotFoundExceptionWhenGettingNonExistingRecipe", expectedExceptions = NotFoundException.class) public void shouldNotCreateRecipeWhenSubscriberThrowsExceptionOnRecipeStoring() throws Exception { final RecipeImpl recipe = createRecipe(0); CascadeEventSubscriber<RecipePersistedEvent> subscriber = mockCascadeEventSubscriber(); doThrow(new ConflictException("error")).when(subscriber).onCascadeEvent(any()); eventService.subscribe(subscriber, RecipePersistedEvent.class); try { recipeDao.create(recipe); fail("RecipeDao#create had to throw conflict exception"); } catch (ConflictException ignored) { } eventService.unsubscribe(subscriber, RecipePersistedEvent.class); recipeDao.getById(recipe.getId()); } @Test(expectedExceptions = NullPointerException.class) public void shouldThrowNpeWhenCreateNullRecipe() throws Exception { recipeDao.create(null); } @Test(expectedExceptions = ConflictException.class) public void shouldThrowConflictExceptionWhenCreatingRecipeWithExistingId() throws Exception { recipeDao.create(recipes.get(0)); } @Test public void shouldUpdateRecipe() throws Exception { final RecipeImpl update = recipes.get(0).withName("updatedName"); assertEquals(recipeDao.update(update), update); } @Test public void shouldUpdateRecipeWithAllRelatedAttributes() throws Exception { final RecipeImpl update = recipes.get(0); update.withName("debian") .withCreator("userid_9") .withDescription("description") .withType("docker") .setScript("FROM codenvy/debian_jdk8"); recipeDao.update(update); assertEquals(recipeDao.getById(update.getId()), update); } @Test(expectedExceptions = NullPointerException.class) public void shouldThrowNpeWhenUpdatingRecipeNull() throws Exception { recipeDao.update(null); } @Test(expectedExceptions = NotFoundException.class) public void shouldThrowNotFoundExceptionWhenUpdatingNonExistingRecipe() throws Exception { recipeDao.update(createRecipe(7)); } @Test(expectedExceptions = NotFoundException.class, dependsOnMethods = "shouldThrowNotFoundExceptionWhenGettingNonExistingRecipe") public void shouldRemoveRecipe() throws Exception { final String existedId = recipes.get(0).getId(); recipeDao.remove(existedId); recipeDao.getById(existedId); } @Test(dependsOnMethods = "shouldGetRecipeById") public void shouldNotRemoveRecipeWhenSubscriberThrowsExceptionOnRecipeRemoving() throws Exception { final RecipeImpl recipe = recipes.get(0); CascadeEventSubscriber<BeforeRecipeRemovedEvent> subscriber = mockCascadeEventSubscriber(); doThrow(new ServerException("error")).when(subscriber).onCascadeEvent(any()); eventService.subscribe(subscriber, BeforeRecipeRemovedEvent.class); try { recipeDao.remove(recipe.getId()); fail("RecipeDao#remove had to throw server exception"); } catch (ServerException ignored) { } assertEquals(recipeDao.getById(recipe.getId()), recipe); eventService.unsubscribe(subscriber, BeforeRecipeRemovedEvent.class); } @Test(expectedExceptions = NullPointerException.class) public void shouldThrowNpeWhenRemovingRecipeIdNull() throws Exception { recipeDao.remove(null); } @Test public void shouldGetRecipeById() throws Exception { final RecipeImpl recipe = recipes.get(0); assertEquals(recipeDao.getById(recipe.getId()), recipe); } @Test(expectedExceptions = NullPointerException.class) public void shouldThrowNpeWhenGettingRecipeIdNull() throws Exception { recipeDao.getById(null); } @Test(expectedExceptions = NotFoundException.class) public void shouldThrowNotFoundExceptionWhenGettingNonExistingRecipe() throws Exception { recipeDao.getById("non-existing"); } @Test public void shouldFindRecipeByUser() throws Exception { final List<RecipeImpl> result = recipeDao.search(null, null, null, 0, recipes.size()); assertTrue(result.contains(recipes.get(0))); } @Test(dependsOnMethods = "shouldFindRecipeByUser") public void shouldFindingRecipesByTags() throws Exception { final List<String> tags = ImmutableList.of("search-by1", "search-by2"); recipes.get(0).getTags().addAll(tags); recipes.get(1).getTags().add(tags.get(0)); recipes.get(2).getTags().add(tags.get(1)); recipes.get(4).getTags().clear(); updateAll(); final List<RecipeImpl> result = recipeDao.search(null, tags, null, 0, recipes.size()); assertEquals(new HashSet<>(result), ImmutableSet.of(recipes.get(0))); } @Test(dependsOnMethods = "shouldFindRecipeByUser") public void shouldFindRecipeByType() throws Exception { final RecipeImpl recipe = recipes.get(0); final List<RecipeImpl> result = recipeDao.search(null, null, recipe.getType(), 0, recipes.size()); assertTrue(result.contains(recipe)); } @Test(dependsOnMethods = {"shouldFindRecipeByUser", "shouldFindingRecipesByTags", "shouldFindRecipeByType"}) public void shouldFindRecipeByUserTagsAndType() throws Exception { final RecipeImpl recipe = recipes.get(0); final List<RecipeImpl> result = recipeDao.search(null, recipe.getTags(), recipe.getType(), 0, 1); assertTrue(result.contains(recipe)); } private static RecipeImpl createRecipe(int index) { final String recipeId = NameGenerator.generate("recipeId", 5); return new RecipeImpl(recipeId, "recipeName" + index, "creator" + index, "dockerfile" + index, "script", new ArrayList<>(asList("tag1" + index, "tag2" + index)), "recipe description"); } private void updateAll() throws Exception { for (RecipeImpl recipe : recipes) { recipeDao.update(recipe); } } private <T extends CascadeEvent> CascadeEventSubscriber<T> mockCascadeEventSubscriber() { @SuppressWarnings("unchecked") CascadeEventSubscriber<T> subscriber = mock(CascadeEventSubscriber.class); doCallRealMethod().when(subscriber).onEvent(any()); return subscriber; } }