blob: 69c6977cd7e512afac12bf6d0e9c645e94908223 [file] [log] [blame]
// Copyright (C) 2020 The Android Open Source Project
//
// 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 com.googlesource.gerrit.plugins.zuul.util;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import com.google.gerrit.entities.Change;
import com.google.gerrit.extensions.client.ListChangesOption;
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.TopLevelResource;
import com.google.gerrit.server.restapi.change.ChangesCollection;
import com.google.gerrit.server.restapi.change.QueryChanges;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
public class NeededByFetcherTest {
private ChangesCollection changes;
private CommitMessageFetcher commitMessageFetcher;
private DependsOnExtractor dependsOnExtractor;
private Change.Key changeKey = getChangeKey(1);
private Map<Integer, ChangeInfo> changeInfos = new HashMap<>();
@Test
public void testFetchForChangeKeyNoResults() throws Exception {
List<ChangeInfo> searchResult = new ArrayList<>();
configureMocks(searchResult);
NeededByFetcher fetcher = createFetcher();
List<ChangeInfo> neededBy = fetcher.fetchForChangeKey(changeKey);
assertThat(neededBy).isEmpty();
}
@Test
public void testFetchForChangeKeySingleResult() throws Exception {
List<ChangeInfo> searchResult = new ArrayList<>();
searchResult.add(getChangeInfo(2));
configureMocks(searchResult);
NeededByFetcher fetcher = createFetcher();
List<ChangeInfo> neededBy = fetcher.fetchForChangeKey(changeKey);
assertThat(neededBy).containsExactly(getChangeInfo(2));
}
@Test
public void testFetchForChangeKeySingleResultUnmatchedEmpty() throws Exception {
List<ChangeInfo> searchResult = new ArrayList<>();
searchResult.add(getChangeInfo(2));
configureMocks(searchResult);
when(dependsOnExtractor.extract("commitMessage2")).thenReturn(new ArrayList<>());
NeededByFetcher fetcher = createFetcher();
List<ChangeInfo> neededBy = fetcher.fetchForChangeKey(changeKey);
assertThat(neededBy).isEmpty();
}
@Test
public void testFetchForChangeKeySingleResultUnmatchedDifferent() throws Exception {
List<ChangeInfo> searchResult = new ArrayList<>();
searchResult.add(getChangeInfo(2));
configureMocks(searchResult);
List<String> extracted = new ArrayList<>();
extracted.add(getChangeKey(3).toString());
when(dependsOnExtractor.extract("commitMessage2")).thenReturn(extracted);
NeededByFetcher fetcher = createFetcher();
List<ChangeInfo> neededBy = fetcher.fetchForChangeKey(changeKey);
assertThat(neededBy).isEmpty();
}
@Test
public void testFetchForChangeKeyMultipleResults() throws Exception {
List<ChangeInfo> searchResult = new ArrayList<>();
searchResult.add(getChangeInfo(2));
searchResult.add(getChangeInfo(3));
configureMocks(searchResult);
NeededByFetcher fetcher = createFetcher();
List<ChangeInfo> neededBy = fetcher.fetchForChangeKey(changeKey);
assertThat(neededBy).containsExactly(getChangeInfo(2), getChangeInfo(3));
}
@Test
public void testFetchForChangeKeyMultipleResultsSomeUnmatched() throws Exception {
List<ChangeInfo> searchResult = new ArrayList<>();
searchResult.add(getChangeInfo(2));
searchResult.add(getChangeInfo(3));
searchResult.add(getChangeInfo(4));
searchResult.add(getChangeInfo(5));
configureMocks(searchResult);
when(dependsOnExtractor.extract("commitMessage3")).thenReturn(new ArrayList<>());
when(dependsOnExtractor.extract("commitMessage4")).thenReturn(new ArrayList<>());
NeededByFetcher fetcher = createFetcher();
List<ChangeInfo> neededBy = fetcher.fetchForChangeKey(changeKey);
assertThat(neededBy).containsExactly(getChangeInfo(2), getChangeInfo(5));
}
/**
* Sets up mocks for a given search result.
*
* <p>Each search result is configured to have a `Depends-On` to the changeKey per default. To
* refine, override the extraction for ("commitMessage" + number) to the desired list of
* Change-Ids.
*
* @param searchResult The search result to configure.
* @throws Exception thrown upon issues.
*/
public void configureMocks(final List<ChangeInfo> searchResult) throws Exception {
QueryChanges queryChanges = mock(QueryChanges.class);
final AtomicBoolean addedQuery = new AtomicBoolean(false);
final AtomicBoolean addedOptionCurrentRevision = new AtomicBoolean(false);
final AtomicBoolean addedOptionCurrentCommit = new AtomicBoolean(false);
mockQueryChangesWithSwitch(queryChanges, addedOptionCurrentCommit)
.addOption(ListChangesOption.CURRENT_COMMIT);
mockQueryChangesWithSwitch(queryChanges, addedOptionCurrentRevision)
.addOption(ListChangesOption.CURRENT_REVISION);
mockQueryChangesWithSwitch(queryChanges, addedQuery)
.addQuery("message:" + changeKey + " -change:" + changeKey);
when(queryChanges.apply(TopLevelResource.INSTANCE))
.thenAnswer(
new Answer<Response<List<ChangeInfo>>>() {
@Override
public Response<List<ChangeInfo>> answer(InvocationOnMock invocation)
throws Throwable {
boolean ready =
addedOptionCurrentRevision.get()
&& addedOptionCurrentCommit.get()
&& addedQuery.get();
if (!ready) {
fail("executed query before all options were set");
}
return Response.ok(searchResult);
}
});
changes = mock(ChangesCollection.class);
when(changes.list()).thenReturn(queryChanges);
commitMessageFetcher = mock(CommitMessageFetcher.class);
when(commitMessageFetcher.fetch(any(ChangeInfo.class)))
.thenAnswer(
new Answer<String>() {
@Override
public String answer(InvocationOnMock invocation) throws Throwable {
ChangeInfo changeInfo = invocation.getArgument(0);
return "commitMessage" + changeInfo._number;
}
});
dependsOnExtractor = mock(DependsOnExtractor.class);
List<String> extractedMatchList = new ArrayList<>();
extractedMatchList.add(changeKey.toString());
when(dependsOnExtractor.extract(any(String.class))).thenReturn(extractedMatchList);
}
private QueryChanges mockQueryChangesWithSwitch(
QueryChanges queryChanges, AtomicBoolean booleanSwitch) {
return doAnswer(
new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
if (booleanSwitch.getAndSet(true)) {
fail("flag has already been set");
}
return null;
}
})
.when(queryChanges);
}
private Change.Key getChangeKey(int keyEnding) {
return Change.key("I0123456789abcdef0000000000000000000" + (10000 + keyEnding));
}
private ChangeInfo getChangeInfo(int keyEnding) {
return changeInfos.computeIfAbsent(
keyEnding,
neededKeyEnding -> {
ChangeInfo changeInfo = new ChangeInfo();
changeInfo.changeId = getChangeKey(neededKeyEnding).toString();
changeInfo._number = neededKeyEnding;
return changeInfo;
});
}
private NeededByFetcher createFetcher() {
return new NeededByFetcher(changes, commitMessageFetcher, dependsOnExtractor);
}
}