blob: 9a46632c305bbb76de4eacbcfa9c5dc1995dd5aa [file] [log] [blame]
// 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);
}
}
}