| // Copyright (C) 2018 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.google.gerrit.git.testing; |
| |
| import static com.google.common.base.Preconditions.checkArgument; |
| import static com.google.common.truth.Fact.fact; |
| import static com.google.common.truth.Truth.assertAbout; |
| import static com.google.gerrit.git.testing.PushResultSubject.RemoteRefUpdateSubject.refs; |
| |
| import com.google.common.annotations.VisibleForTesting; |
| import com.google.common.base.Splitter; |
| import com.google.common.base.Strings; |
| import com.google.common.base.Throwables; |
| import com.google.common.collect.ImmutableMap; |
| import com.google.common.collect.Maps; |
| import com.google.common.truth.FailureMetadata; |
| import com.google.common.truth.StreamSubject; |
| import com.google.common.truth.Subject; |
| import com.google.gerrit.common.Nullable; |
| import org.eclipse.jgit.transport.PushResult; |
| import org.eclipse.jgit.transport.RemoteRefUpdate; |
| |
| public class PushResultSubject extends Subject { |
| public static PushResultSubject assertThat(PushResult actual) { |
| return assertAbout(PushResultSubject::new).that(actual); |
| } |
| |
| private final PushResult pushResult; |
| |
| private PushResultSubject(FailureMetadata metadata, PushResult pushResult) { |
| super(metadata, pushResult); |
| this.pushResult = pushResult; |
| } |
| |
| public void hasNoMessages() { |
| isNotNull(); |
| check("hasNoMessages()").that(Strings.nullToEmpty(getTrimmedMessages())).isEqualTo(""); |
| } |
| |
| public void hasMessages(String... expectedLines) { |
| checkArgument(expectedLines.length > 0, "use hasNoMessages()"); |
| isNotNull(); |
| check("getTrimmedMessages()") |
| .that(getTrimmedMessages()) |
| .isEqualTo(String.join("\n", expectedLines)); |
| } |
| |
| public void containsMessages(String... expectedLines) { |
| checkArgument(expectedLines.length > 0, "use hasNoMessages()"); |
| isNotNull(); |
| Iterable<String> got = Splitter.on("\n").split(getTrimmedMessages()); |
| check("getTrimmedMessages()").that(got).containsAtLeastElementsIn(expectedLines).inOrder(); |
| } |
| |
| private String getTrimmedMessages() { |
| return trimMessages(pushResult.getMessages()); |
| } |
| |
| @VisibleForTesting |
| @Nullable |
| static String trimMessages(@Nullable String msg) { |
| if (msg == null) { |
| return null; |
| } |
| int idx = msg.indexOf("Processing changes:"); |
| if (idx >= 0) { |
| msg = msg.substring(0, idx); |
| } |
| return msg.trim(); |
| } |
| |
| public void hasProcessed(ImmutableMap<String, Integer> expected) { |
| isNotNull(); |
| ImmutableMap<String, Integer> actual; |
| String messages = pushResult.getMessages(); |
| try { |
| actual = parseProcessed(messages); |
| } catch (RuntimeException e) { |
| failWithActual( |
| fact( |
| "failed to parse \"Processing changes\" line from messages, reason:", |
| Throwables.getStackTraceAsString(e))); |
| return; |
| } |
| check("processedCommands()").that(actual).containsExactlyEntriesIn(expected).inOrder(); |
| } |
| |
| @VisibleForTesting |
| static ImmutableMap<String, Integer> parseProcessed(@Nullable String messages) { |
| if (messages == null) { |
| return ImmutableMap.of(); |
| } |
| String toSplit = messages.trim(); |
| String prefix = "Processing changes: "; |
| int idx = toSplit.lastIndexOf(prefix); |
| if (idx < 0) { |
| return ImmutableMap.of(); |
| } |
| toSplit = toSplit.substring(idx + prefix.length()); |
| if (toSplit.equals("done")) { |
| return ImmutableMap.of(); |
| } |
| String done = ", done"; |
| if (toSplit.endsWith(done)) { |
| toSplit = toSplit.substring(0, toSplit.length() - done.length()); |
| } |
| return ImmutableMap.copyOf( |
| Maps.transformValues( |
| Splitter.on(',').trimResults().withKeyValueSeparator(':').split(toSplit), |
| // trimResults() doesn't trim values in the map. |
| v -> Integer.parseInt(v.trim()))); |
| } |
| |
| public RemoteRefUpdateSubject ref(String refName) { |
| isNotNull(); |
| return check("getRemoteUpdate(%s)", refName) |
| .about(refs()) |
| .that(pushResult.getRemoteUpdate(refName)); |
| } |
| |
| public RemoteRefUpdateSubject onlyRef(String refName) { |
| isNotNull(); |
| check("setOfRefs()") |
| .about(StreamSubject.streams()) |
| .that(pushResult.getRemoteUpdates().stream().map(RemoteRefUpdate::getRemoteName)) |
| .containsExactly(refName); |
| return ref(refName); |
| } |
| |
| public static class RemoteRefUpdateSubject extends Subject { |
| private final RemoteRefUpdate remoteRefUpdate; |
| |
| private RemoteRefUpdateSubject(FailureMetadata metadata, RemoteRefUpdate remoteRefUpdate) { |
| super(metadata, remoteRefUpdate); |
| this.remoteRefUpdate = remoteRefUpdate; |
| } |
| |
| static Factory<RemoteRefUpdateSubject, RemoteRefUpdate> refs() { |
| return RemoteRefUpdateSubject::new; |
| } |
| |
| public void hasStatus(RemoteRefUpdate.Status status) { |
| isNotNull(); |
| RemoteRefUpdate u = remoteRefUpdate; |
| check("getStatus()") |
| .withMessage( |
| "status message: %s", u.getMessage() != null ? ": " + u.getMessage() : "<emtpy>") |
| .that(u.getStatus()) |
| .isEqualTo(status); |
| } |
| |
| public void hasNoMessage() { |
| isNotNull(); |
| check("getMessage()").that(remoteRefUpdate.getMessage()).isNull(); |
| } |
| |
| public void hasMessage(String expected) { |
| isNotNull(); |
| check("getMessage()").that(remoteRefUpdate.getMessage()).isEqualTo(expected); |
| } |
| |
| public void isOk() { |
| isNotNull(); |
| hasStatus(RemoteRefUpdate.Status.OK); |
| } |
| |
| public void isRejected(String expectedMessage) { |
| isNotNull(); |
| hasStatus(RemoteRefUpdate.Status.REJECTED_OTHER_REASON); |
| hasMessage(expectedMessage); |
| } |
| } |
| } |