/* * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jetbrains.buildServer.server.rest.data; import com.intellij.openapi.util.Pair; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.function.Supplier; import jetbrains.buildServer.ServiceLocator; import jetbrains.buildServer.artifacts.RevisionRules; import jetbrains.buildServer.log.Loggable; import jetbrains.buildServer.responsibility.ResponsibilityFacadeEx; import jetbrains.buildServer.server.rest.ApiUrlBuilder; import jetbrains.buildServer.server.rest.PathTransformer; import jetbrains.buildServer.server.rest.data.investigations.InvestigationFinder; import jetbrains.buildServer.server.rest.data.problem.ProblemFinder; import jetbrains.buildServer.server.rest.data.problem.ProblemOccurrenceFinder; import jetbrains.buildServer.server.rest.data.problem.TestFinder; import jetbrains.buildServer.server.rest.data.problem.TestOccurrenceFinder; import jetbrains.buildServer.server.rest.errors.NotFoundException; import jetbrains.buildServer.server.rest.util.BeanContext; import jetbrains.buildServer.server.rest.util.BeanFactory; import jetbrains.buildServer.serverSide.ArtifactDependencyFactory; import jetbrains.buildServer.serverSide.CurrentProblemsManager; import jetbrains.buildServer.serverSide.SBuildType; import jetbrains.buildServer.serverSide.TestName2IndexImpl; import jetbrains.buildServer.serverSide.artifacts.SArtifactDependency; import jetbrains.buildServer.serverSide.identifiers.VcsRootIdentifiersManagerImpl; import jetbrains.buildServer.serverSide.impl.BaseServerTestCase; import jetbrains.buildServer.serverSide.impl.LogUtil; import jetbrains.buildServer.serverSide.mute.ProblemMutingService; import jetbrains.buildServer.serverSide.problems.BuildProblemManager; import jetbrains.buildServer.serverSide.versionedSettings.VersionedSettingsManager; import jetbrains.buildServer.util.ExceptionUtil; import jetbrains.buildServer.vcs.impl.VcsManagerImpl; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.testng.annotations.BeforeMethod; /** * Created by yaegor on 13/06/2015. */ public abstract class BaseFinderTest extends BaseServerTestCase{ protected static final String ARTIFACT_DEP_FILE_NAME = "aaa"; private Finder myFinder; protected VcsManagerImpl myVcsManager; protected PermissionChecker myPermissionChecker; protected ProjectFinder myProjectFinder; protected AgentFinder myAgentFinder; protected BuildTypeFinder myBuildTypeFinder; protected VcsRootFinder myVcsRootFinder; protected VcsRootInstanceFinder myVcsRootInstanceFinder; protected UserFinder myUserFinder; protected TestFinder myTestFinder; protected BuildPromotionFinder myBuildPromotionFinder; protected BuildFinder myBuildFinder; protected ProblemFinder myProblemFinder; protected ProblemOccurrenceFinder myProblemOccurrenceFinder; protected TestOccurrenceFinder myTestOccurrenceFinder; protected InvestigationFinder myInvestigationFinder; protected AgentPoolFinder myAgentPoolFinder; protected QueuedBuildFinder myQueuedBuildFinder; protected BranchFinder myBranchFinder; protected ChangeFinder myChangeFinder; protected UserGroupFinder myGroupFinder; protected TimeCondition myTimeCondition; static public BeanContext getBeanContext(final ServiceLocator serviceLocator) { final ApiUrlBuilder apiUrlBuilder = new ApiUrlBuilder(new PathTransformer() { public String transform(final String path) { return path; } }); final BeanFactory beanFactory = new BeanFactory(null); return new BeanContext(beanFactory, serviceLocator, apiUrlBuilder); } @Override @BeforeMethod public void setUp() throws Exception { super.setUp(); initFinders(); } protected void initFinders() { myVcsManager = myFixture.getVcsManager(); myFixture.addService(myVcsManager); myFixture.addService(myProjectManager); myPermissionChecker = new PermissionChecker(myServer.getSecurityContext(), myProjectManager); myFixture.addService(myPermissionChecker); myTimeCondition = new TimeCondition(myFixture); myFixture.addService(myTimeCondition); myProjectFinder = new ProjectFinder(myProjectManager, myPermissionChecker, myServer); myFixture.addService(myProjectFinder); myAgentFinder = new AgentFinder(myAgentManager, myFixture); myFixture.addService(myAgentFinder); myAgentPoolFinder = new AgentPoolFinder(myFixture.getAgentPoolManager(), myAgentFinder, myFixture); myFixture.addService(myAgentPoolFinder); myBuildTypeFinder = new BuildTypeFinder(myProjectManager, myProjectFinder, myAgentFinder, myPermissionChecker, myServer); myFixture.addService(myBuildTypeFinder); final VcsRootIdentifiersManagerImpl vcsRootIdentifiersManager = myFixture.getSingletonService(VcsRootIdentifiersManagerImpl.class); myVcsRootFinder = new VcsRootFinder(myVcsManager, myProjectFinder, myBuildTypeFinder, myProjectManager, vcsRootIdentifiersManager, myPermissionChecker); myFixture.addService(myVcsRootFinder); myVcsRootInstanceFinder = new VcsRootInstanceFinder(myVcsRootFinder, myVcsManager, myProjectFinder, myBuildTypeFinder, myProjectManager, myFixture.getSingletonService(VersionedSettingsManager.class), myTimeCondition, myPermissionChecker, myServer); myFixture.addService(myVcsRootInstanceFinder); myGroupFinder = new UserGroupFinder(getUserGroupManager()); myFixture.addService(myGroupFinder); myUserFinder = new UserFinder(getUserModelEx(), myGroupFinder, myProjectFinder, myTimeCondition, myFixture.getRolesManager(), myPermissionChecker, myServer.getSecurityContext(), myServer); myFixture.addService(myUserFinder); myBranchFinder = new BranchFinder(myBuildTypeFinder, myFixture); myBuildPromotionFinder = new BuildPromotionFinder(myFixture.getBuildPromotionManager(), myFixture.getBuildQueue(), myServer, myVcsRootFinder, myProjectFinder, myBuildTypeFinder, myUserFinder, myAgentFinder, myBranchFinder, myTimeCondition, myPermissionChecker, null, myFixture); myFixture.addService(myBuildPromotionFinder); myBuildFinder = new BuildFinder(myServer, myBuildTypeFinder, myProjectFinder, myUserFinder, myBuildPromotionFinder, myAgentFinder); myFixture.addService(myBuildFinder); final TestName2IndexImpl testName2Index = myFixture.getSingletonService(TestName2IndexImpl.class); final ProblemMutingService problemMutingService = myFixture.getSingletonService(ProblemMutingService.class); myTestFinder = new TestFinder(myProjectFinder, myBuildTypeFinder, myBuildPromotionFinder, myFixture.getTestManager(), testName2Index, myFixture.getCurrentProblemsManager(), problemMutingService); myFixture.addService(myTestFinder); final CurrentProblemsManager currentProblemsManager = myServer.getSingletonService(CurrentProblemsManager.class); myTestOccurrenceFinder = new TestOccurrenceFinder(myTestFinder, myBuildFinder, myBuildTypeFinder, myProjectFinder, myServer.getHistory(), currentProblemsManager); myFixture.addService(myTestOccurrenceFinder); final BuildProblemManager buildProblemManager = myFixture.getSingletonService(BuildProblemManager.class); myProblemFinder = new ProblemFinder(myProjectFinder, myBuildPromotionFinder, buildProblemManager, myProjectManager, myFixture, problemMutingService); myFixture.addService(myProblemFinder); myProblemOccurrenceFinder = new ProblemOccurrenceFinder(myProjectFinder, myBuildFinder, myProblemFinder, buildProblemManager, myProjectManager, myFixture); myFixture.addService(myProblemOccurrenceFinder); final ResponsibilityFacadeEx responsibilityFacade = myFixture.getResponsibilityFacadeEx(); myInvestigationFinder = new InvestigationFinder(myProjectFinder, myBuildTypeFinder, myProblemFinder, myTestFinder, myUserFinder, responsibilityFacade, responsibilityFacade, responsibilityFacade); myFixture.addService(myInvestigationFinder); myQueuedBuildFinder = new QueuedBuildFinder(myServer.getQueue(), myProjectFinder, myBuildTypeFinder, myUserFinder, myAgentFinder, myFixture.getBuildPromotionManager(), myServer); myFixture.addService(myQueuedBuildFinder); myChangeFinder = new ChangeFinder(myProjectFinder, myBuildFinder, myBuildPromotionFinder, myBuildTypeFinder, myVcsRootFinder, myVcsRootInstanceFinder, myUserFinder, myVcsManager, myFixture.getVcsHistory(), myBranchFinder, myFixture, myPermissionChecker); myFixture.addService(myChangeFinder); } public void setFinder(@NotNull Finder finder){ myFinder = finder; } public Finder getFinder() { return myFinder; } public void check(@Nullable final String locator, T... items) { check(locator, getEqualsMatcher(), myFinder, items); } @NotNull public Matcher getEqualsMatcher() { return new Matcher() { @Override public boolean matches(@NotNull final S o1, @NotNull final S o2) { return o1.equals(o2); } }; } public void checkCounts(@Nullable final String locator, int resultsCount, int maxProcessedCounts) { PagedSearchResult result = getFinder().getItems(locator); assertEquals("Wrong number of found items", resultsCount, result.myActualCount); if (result.myActuallyProcessedCount != null && result.myActuallyProcessedCount > maxProcessedCounts) { fail("Wrong number of processed items: " + result.myActuallyProcessedCount + ", while not more than " + maxProcessedCounts + " is expected"); } } public void check(@Nullable final String locator, @NotNull Matcher matcher, S... items) { check(locator, matcher, getFinder(), items); } public void check(@Nullable final String locator, @NotNull Matcher matcher, @NotNull final Finder finder, S... items) { check(locator, matcher, r -> getDescription(r), r -> getDescription(r), finder, items); } public void check(@Nullable final String locator, @NotNull Matcher matcher, @NotNull DescriptionProvider loggerActual, @NotNull DescriptionProvider loggerExpected, @NotNull final Finder finder, S... items) { check(locator, loggerActual, loggerExpected, finder, getDefaultMatchStrategy(locator, matcher, items), items); } public void check(@Nullable final String locator, @NotNull DescriptionProvider loggerActual, @NotNull DescriptionProvider loggerExpected, @NotNull final Finder finder, @NotNull final CollectionsMatchStrategy strategy, S... items) { final List result = finder.getItems(locator).myEntries; final String expected = getDescription(Arrays.asList(items), loggerExpected); final String actual = getDescription(result, loggerActual); assertEquals("For itemS locator \"" + locator + "\"\n" + "Expected:\n" + expected + "\n\n" + "Actual:\n" + actual, items.length, result.size()); strategy.matchCollection(items, result); //check single item retrieve if (locator != null) { strategy.matchSingle(items, () -> finder.getItem(locator)); } } protected SArtifactDependency addArtifactDependency(final SBuildType dependent, final SBuildType dependOn) { SArtifactDependency dep = myFixture.getSingletonService(ArtifactDependencyFactory.class).createArtifactDependency(dependOn, ARTIFACT_DEP_FILE_NAME, RevisionRules.LAST_FINISHED_RULE); dependent.addArtifactDependency(dep); return dep; } public static interface Matcher { boolean matches(@NotNull S s, @NotNull T t); } public static interface DescriptionProvider { String describe(@NotNull S s); } @NotNull protected OrderedMatcherStrategy getDefaultMatchStrategy(@Nullable final String locator, @NotNull final Matcher equalsMatcher, @NotNull final S[] items) { return new OrderedMatcherStrategy(equalsMatcher, new DescriptionProvider, Integer>>() { @Override public String describe(@NotNull final Pair, Integer> p) { return "Wrong item found for locator \"" + locator + "\" at position " + (p.getSecond() + 1) + "/" + items.length + "\n" + "Expected:\n" + Arrays.toString(items) + "\n" + "\nActual:\n" + p.first; } }, new DescriptionProvider>() { @Override public String describe(@NotNull final Pair p) { if (p.first == null) { return "No items should be found by locator \"" + locator + "\", but found: " + ((DescriptionProvider)BaseFinderTest::getDescription).describe(p.second); } else { return "While searching for single item with locator \"" + locator + "\"\n" + "Expected: " + ((DescriptionProvider)BaseFinderTest::getDescription).describe(p.first) + "\n" + "Actual: " + ((DescriptionProvider)BaseFinderTest::getDescription).describe(p.second); } } }); } protected static String getDescription(final U singleResult) { if (singleResult instanceof Loggable){ return LogUtil.describeInDetail(((Loggable)singleResult)); } return LogUtil.describe(singleResult); } public void checkExceptionOnItemsSearch(final Class exception, final String multipleSearchLocator) { checkException(exception, new Runnable() { public void run() { myFinder.getItems(multipleSearchLocator); } }, "searching for itemS with locator \"" + multipleSearchLocator + "\""); } public void checkExceptionOnItemSearch(final Class exception, final String singleSearchLocator) { checkException(exception, new Runnable() { public void run() { myFinder.getItem(singleSearchLocator); } }, "searching for item with locator \"" + singleSearchLocator + "\""); } @NotNull public static E checkException(final Class exception, final Runnable runnable, final String operationDescription) { final String details = operationDescription != null ? " while " + operationDescription : ""; try { runnable.run(); } catch (Throwable e) { if (exception.isAssignableFrom(e.getClass())) { return (E)e; } final StringBuilder exceptionDetails = new StringBuilder(); ExceptionUtil.dumpStacktrace(exceptionDetails, e); fail("Wrong exception type is thrown" + details + ".\n" + "Expected: " + exception.getName() + "\n" + "Actual : " + exceptionDetails.toString()); } fail("No exception is thrown" + details + ". Expected: " + exception.getName()); return null; //this is never reached } public static String getDescription(final List result) { return getDescription(result, s -> getDescription(s)); } public static String getDescription(final List result, @NotNull DescriptionProvider logger) { if (result == null) { return LogUtil.describe((Object)null); } final StringBuilder result1 = new StringBuilder(); final Iterator it = result.iterator(); while(it.hasNext()) { S item = it.next(); if (item != null) { result1.append("").append(logger.describe(item)).append(""); if (it.hasNext()) { result1.append("\n"); } } } return result1.toString(); } public interface CollectionsMatchStrategy { public void matchCollection(@NotNull final S[] items, @NotNull final List result); public void matchSingle(final S[] items, final Supplier singleResultSupplier); } public static class OrderedMatcherStrategy implements CollectionsMatchStrategy { @NotNull private final Matcher myMatcher; @NotNull private final DescriptionProvider, Integer>> myCollectionMatchDescriptionProvider; @NotNull private final DescriptionProvider> mySingleMatchDescriptionProvider; public OrderedMatcherStrategy(@NotNull final Matcher matcher, @NotNull final DescriptionProvider, Integer>> collectionMatchDescriptionProvider, @NotNull final DescriptionProvider> singleMatchDescriptionProvider) { myMatcher = matcher; myCollectionMatchDescriptionProvider = collectionMatchDescriptionProvider; mySingleMatchDescriptionProvider = singleMatchDescriptionProvider; } @Override public void matchCollection(@NotNull final S[] items, @NotNull final List result) { for (int i = 0; i < items.length; i++) { if (!myMatcher.matches(items[i], result.get(i))) { fail(myCollectionMatchDescriptionProvider.describe(Pair.create(result, i))); } } } @Override public void matchSingle(final S[] items, final Supplier singleResultSupplier) { if (items.length == 0) { try { R r = singleResultSupplier.get(); // should fail with NotFoundException fail(mySingleMatchDescriptionProvider.describe(Pair.create(null, r))); } catch (NotFoundException e) { //exception is expected } } else { R r = singleResultSupplier.get(); final S item = items[0]; if (!myMatcher.matches(item, r)) { fail(mySingleMatchDescriptionProvider.describe(Pair.create(item, r))); } } } } }