com.google.gerrit.acceptance.server.change.ConsistencyCheckerIT.java Source code

Java tutorial

Introduction

Here is the source code for com.google.gerrit.acceptance.server.change.ConsistencyCheckerIT.java

Source

// Copyright (C) 2014 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.acceptance.server.change;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.truth.Truth.assertThat;
import static com.google.gerrit.testutil.TestChanges.newChange;
import static com.google.gerrit.testutil.TestChanges.newPatchSet;
import static java.util.Collections.singleton;

import com.google.common.base.Function;
import com.google.common.collect.Lists;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.NoHttpd;
import com.google.gerrit.common.FooterConstants;
import com.google.gerrit.extensions.api.changes.FixInput;
import com.google.gerrit.extensions.common.ProblemInfo;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.change.ConsistencyChecker;
import com.google.gerrit.testutil.TestChanges;
import com.google.inject.Inject;
import com.google.inject.Provider;

import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.revwalk.RevCommit;
import org.junit.Before;
import org.junit.Test;

import java.util.List;

@NoHttpd
public class ConsistencyCheckerIT extends AbstractDaemonTest {
    @Inject
    private Provider<ConsistencyChecker> checkerProvider;

    private RevCommit tip;
    private Account.Id adminId;
    private ConsistencyChecker checker;

    @Before
    public void setUp() throws Exception {
        // Ignore client clone of project; repurpose as server-side TestRepository.
        testRepo = new TestRepository<>((InMemoryRepository) repoManager.openRepository(project));
        tip = testRepo.getRevWalk().parseCommit(testRepo.getRepository().getRef("HEAD").getObjectId());
        adminId = admin.getId();
        checker = checkerProvider.get();
    }

    @Test
    public void validNewChange() throws Exception {
        Change c = insertChange();
        insertPatchSet(c);
        incrementPatchSet(c);
        insertPatchSet(c);
        assertProblems(c);
    }

    @Test
    public void validMergedChange() throws Exception {
        Change c = insertChange();
        c.setStatus(Change.Status.MERGED);
        insertPatchSet(c);
        incrementPatchSet(c);

        incrementPatchSet(c);
        RevCommit commit2 = testRepo.branch(c.currentPatchSetId().toRefName()).commit().parent(tip).create();
        PatchSet ps2 = newPatchSet(c.currentPatchSetId(), commit2, adminId);
        db.patchSets().insert(singleton(ps2));

        testRepo.branch(c.getDest().get()).update(commit2);
        assertProblems(c);
    }

    @Test
    public void missingOwner() throws Exception {
        Change c = newChange(project, new Account.Id(2));
        db.changes().insert(singleton(c));
        RevCommit commit = testRepo.branch(c.currentPatchSetId().toRefName()).commit().parent(tip).create();
        PatchSet ps = newPatchSet(c.currentPatchSetId(), commit, adminId);
        db.patchSets().insert(singleton(ps));

        assertProblems(c, "Missing change owner: 2");
    }

    @Test
    public void missingRepo() throws Exception {
        Change c = newChange(new Project.NameKey("otherproject"), adminId);
        db.changes().insert(singleton(c));
        insertMissingPatchSet(c, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef");
        assertProblems(c, "Destination repository not found: otherproject");
    }

    @Test
    public void invalidRevision() throws Exception {
        Change c = insertChange();

        db.patchSets().insert(
                singleton(newPatchSet(c.currentPatchSetId(), "fooooooooooooooooooooooooooooooooooooooo", adminId)));
        incrementPatchSet(c);
        insertPatchSet(c);

        assertProblems(c, "Invalid revision on patch set 1:" + " fooooooooooooooooooooooooooooooooooooooo");
    }

    // No test for ref existing but object missing; InMemoryRepository won't let
    // us do such a thing.

    @Test
    public void patchSetObjectAndRefMissing() throws Exception {
        Change c = insertChange();
        PatchSet ps = newPatchSet(c.currentPatchSetId(),
                ObjectId.fromString("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"), adminId);
        db.patchSets().insert(singleton(ps));

        assertProblems(c, "Ref missing: " + ps.getId().toRefName(),
                "Object missing: patch set 1: deadbeefdeadbeefdeadbeefdeadbeefdeadbeef");
    }

    @Test
    public void patchSetObjectAndRefMissingWithFix() throws Exception {
        Change c = insertChange();
        PatchSet ps = newPatchSet(c.currentPatchSetId(),
                ObjectId.fromString("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"), adminId);
        db.patchSets().insert(singleton(ps));

        String refName = ps.getId().toRefName();
        List<ProblemInfo> problems = checker.check(c, new FixInput()).problems();
        ProblemInfo p = problems.get(0);
        assertThat(p.message).isEqualTo("Ref missing: " + refName);
        assertThat(p.status).isNull();
    }

    @Test
    public void patchSetRefMissing() throws Exception {
        Change c = insertChange();
        PatchSet ps = insertPatchSet(c);
        String refName = ps.getId().toRefName();
        testRepo.update("refs/other/foo", ObjectId.fromString(ps.getRevision().get()));
        deleteRef(refName);

        assertProblems(c, "Ref missing: " + refName);
    }

    @Test
    public void patchSetRefMissingWithFix() throws Exception {
        Change c = insertChange();
        PatchSet ps = insertPatchSet(c);
        String refName = ps.getId().toRefName();
        testRepo.update("refs/other/foo", ObjectId.fromString(ps.getRevision().get()));
        deleteRef(refName);

        List<ProblemInfo> problems = checker.check(c, new FixInput()).problems();
        ProblemInfo p = problems.get(0);
        assertThat(p.message).isEqualTo("Ref missing: " + refName);
        assertThat(p.status).isEqualTo(ProblemInfo.Status.FIXED);
        assertThat(p.outcome).isEqualTo("Repaired patch set ref");

        assertThat(testRepo.getRepository().getRef(refName).getObjectId().name()).isEqualTo(ps.getRevision().get());
    }

    @Test
    public void patchSetObjectAndRefMissingWithDeletingPatchSet() throws Exception {
        Change c = insertChange();
        PatchSet ps1 = insertPatchSet(c);
        incrementPatchSet(c);
        PatchSet ps2 = insertMissingPatchSet(c, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef");

        FixInput fix = new FixInput();
        fix.deletePatchSetIfCommitMissing = true;
        List<ProblemInfo> problems = checker.check(c, fix).problems();
        assertThat(problems).hasSize(2);
        ProblemInfo p = problems.get(0);
        assertThat(p.message).isEqualTo("Ref missing: " + ps2.getId().toRefName());
        assertThat(p.status).isNull();
        p = problems.get(1);
        assertThat(p.message).isEqualTo("Object missing: patch set 2: deadbeefdeadbeefdeadbeefdeadbeefdeadbeef");
        assertThat(p.status).isEqualTo(ProblemInfo.Status.FIXED);
        assertThat(p.outcome).isEqualTo("Deleted patch set");

        c = db.changes().get(c.getId());
        assertThat(c.currentPatchSetId().get()).isEqualTo(1);
        assertThat(db.patchSets().get(ps1.getId())).isNotNull();
        assertThat(db.patchSets().get(ps2.getId())).isNull();
    }

    @Test
    public void patchSetMultipleObjectsMissingWithDeletingPatchSets() throws Exception {
        Change c = insertChange();
        PatchSet ps1 = insertPatchSet(c);

        incrementPatchSet(c);
        PatchSet ps2 = insertMissingPatchSet(c, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef");

        incrementPatchSet(c);
        PatchSet ps3 = insertPatchSet(c);

        incrementPatchSet(c);
        PatchSet ps4 = insertMissingPatchSet(c, "c0ffeeeec0ffeeeec0ffeeeec0ffeeeec0ffeeee");

        FixInput fix = new FixInput();
        fix.deletePatchSetIfCommitMissing = true;
        List<ProblemInfo> problems = checker.check(c, fix).problems();
        assertThat(problems).hasSize(4);

        ProblemInfo p = problems.get(0);
        assertThat(p.message).isEqualTo("Ref missing: " + ps4.getId().toRefName());
        assertThat(p.status).isNull();

        p = problems.get(1);
        assertThat(p.message).isEqualTo("Object missing: patch set 4: c0ffeeeec0ffeeeec0ffeeeec0ffeeeec0ffeeee");
        assertThat(p.status).isEqualTo(ProblemInfo.Status.FIXED);
        assertThat(p.outcome).isEqualTo("Deleted patch set");

        p = problems.get(2);
        assertThat(p.message).isEqualTo("Ref missing: " + ps2.getId().toRefName());
        assertThat(p.status).isNull();

        p = problems.get(3);
        assertThat(p.message).isEqualTo("Object missing: patch set 2: deadbeefdeadbeefdeadbeefdeadbeefdeadbeef");
        assertThat(p.status).isEqualTo(ProblemInfo.Status.FIXED);
        assertThat(p.outcome).isEqualTo("Deleted patch set");

        c = db.changes().get(c.getId());
        assertThat(c.currentPatchSetId().get()).isEqualTo(3);
        assertThat(db.patchSets().get(ps1.getId())).isNotNull();
        assertThat(db.patchSets().get(ps2.getId())).isNull();
        assertThat(db.patchSets().get(ps3.getId())).isNotNull();
        assertThat(db.patchSets().get(ps4.getId())).isNull();
    }

    @Test
    public void onlyPatchSetObjectMissingWithFix() throws Exception {
        Change c = insertChange();
        PatchSet ps1 = insertMissingPatchSet(c, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef");

        FixInput fix = new FixInput();
        fix.deletePatchSetIfCommitMissing = true;
        List<ProblemInfo> problems = checker.check(c, fix).problems();
        assertThat(problems).hasSize(2);
        ProblemInfo p = problems.get(0);
        assertThat(p.message).isEqualTo("Ref missing: " + ps1.getId().toRefName());
        assertThat(p.status).isNull();
        p = problems.get(1);
        assertThat(p.message).isEqualTo("Object missing: patch set 1: deadbeefdeadbeefdeadbeefdeadbeefdeadbeef");
        assertThat(p.status).isEqualTo(ProblemInfo.Status.FIX_FAILED);
        assertThat(p.outcome).isEqualTo("Cannot delete patch set; no patch sets would remain");

        c = db.changes().get(c.getId());
        assertThat(c.currentPatchSetId().get()).isEqualTo(1);
        assertThat(db.patchSets().get(ps1.getId())).isNotNull();
    }

    @Test
    public void currentPatchSetMissing() throws Exception {
        Change c = insertChange();
        assertProblems(c, "Current patch set 1 not found");
    }

    @Test
    public void duplicatePatchSetRevisions() throws Exception {
        Change c = insertChange();
        PatchSet ps1 = insertPatchSet(c);
        String rev = ps1.getRevision().get();
        incrementPatchSet(c);
        PatchSet ps2 = insertMissingPatchSet(c, rev);
        updatePatchSetRef(ps2);

        assertProblems(c, "Multiple patch sets pointing to " + rev + ": [1, 2]");
    }

    @Test
    public void missingDestRef() throws Exception {
        String ref = "refs/heads/master";
        // Detach head so we're allowed to delete ref.
        testRepo.reset(testRepo.getRepository().getRef(ref).getObjectId());
        RefUpdate ru = testRepo.getRepository().updateRef(ref);
        ru.setForceUpdate(true);
        assertThat(ru.delete()).isEqualTo(RefUpdate.Result.FORCED);
        Change c = insertChange();
        RevCommit commit = testRepo.commit().create();
        PatchSet ps = newPatchSet(c.currentPatchSetId(), commit, adminId);
        updatePatchSetRef(ps);
        db.patchSets().insert(singleton(ps));

        assertProblems(c, "Destination ref not found (may be new branch): " + ref);
    }

    @Test
    public void mergedChangeIsNotMerged() throws Exception {
        Change c = insertChange();
        c.setStatus(Change.Status.MERGED);
        PatchSet ps = insertPatchSet(c);
        String rev = ps.getRevision().get();

        assertProblems(c, "Patch set 1 (" + rev + ") is not merged into destination ref" + " refs/heads/master ("
                + tip.name() + "), but change status is MERGED");
    }

    @Test
    public void newChangeIsMerged() throws Exception {
        Change c = insertChange();
        RevCommit commit = testRepo.branch(c.currentPatchSetId().toRefName()).commit().parent(tip).create();
        PatchSet ps = newPatchSet(c.currentPatchSetId(), commit, adminId);
        db.patchSets().insert(singleton(ps));
        testRepo.branch(c.getDest().get()).update(commit);

        assertProblems(c, "Patch set 1 (" + commit.name() + ") is merged into destination ref"
                + " refs/heads/master (" + commit.name() + "), but change status is NEW");
    }

    @Test
    public void newChangeIsMergedWithFix() throws Exception {
        Change c = insertChange();
        RevCommit commit = testRepo.branch(c.currentPatchSetId().toRefName()).commit().parent(tip).create();
        PatchSet ps = newPatchSet(c.currentPatchSetId(), commit, adminId);
        db.patchSets().insert(singleton(ps));
        testRepo.branch(c.getDest().get()).update(commit);

        List<ProblemInfo> problems = checker.check(c, new FixInput()).problems();
        assertThat(problems).hasSize(1);
        ProblemInfo p = problems.get(0);
        assertThat(p.message).isEqualTo("Patch set 1 (" + commit.name() + ") is merged into destination ref"
                + " refs/heads/master (" + commit.name() + "), but change status is NEW");
        assertThat(p.status).isEqualTo(ProblemInfo.Status.FIXED);
        assertThat(p.outcome).isEqualTo("Marked change as merged");

        c = db.changes().get(c.getId());
        assertThat(c.getStatus()).isEqualTo(Change.Status.MERGED);
        assertProblems(c);
    }

    @Test
    public void expectedMergedCommitIsLatestPatchSet() throws Exception {
        Change c = insertChange();
        c.setStatus(Change.Status.MERGED);
        PatchSet ps = insertPatchSet(c);
        RevCommit commit = parseCommit(ps);
        testRepo.update(c.getDest().get(), commit);

        FixInput fix = new FixInput();
        fix.expectMergedAs = commit.name();
        assertThat(checker.check(c, fix).problems()).isEmpty();
    }

    @Test
    public void expectedMergedCommitNotMergedIntoDestination() throws Exception {
        Change c = insertChange();
        c.setStatus(Change.Status.MERGED);
        PatchSet ps = insertPatchSet(c);
        RevCommit commit = parseCommit(ps);
        testRepo.update(c.getDest().get(), commit);

        FixInput fix = new FixInput();
        RevCommit other = testRepo.commit().message(commit.getFullMessage()).create();
        fix.expectMergedAs = other.name();
        List<ProblemInfo> problems = checker.check(c, fix).problems();
        assertThat(problems).hasSize(1);
        ProblemInfo p = problems.get(0);
        assertThat(p.message).isEqualTo("Expected merged commit " + other.name()
                + " is not merged into destination ref refs/heads/master" + " (" + commit.name() + ")");
    }

    @Test
    public void createNewPatchSetForExpectedMergeCommitWithNoChangeId() throws Exception {
        Change c = insertChange();
        c.setStatus(Change.Status.MERGED);
        RevCommit parent = testRepo.branch(c.getDest().get()).commit().message("parent").create();
        PatchSet ps = insertPatchSet(c);
        RevCommit commit = parseCommit(ps);

        RevCommit mergedAs = testRepo.commit().parent(parent).message(commit.getShortMessage()).create();
        testRepo.getRevWalk().parseBody(mergedAs);
        assertThat(mergedAs.getFooterLines(FooterConstants.CHANGE_ID)).isEmpty();
        testRepo.update(c.getDest().get(), mergedAs);

        assertProblems(c, "Patch set 1 (" + commit.name() + ") is not merged into"
                + " destination ref refs/heads/master (" + mergedAs.name() + "), but change status is MERGED");

        FixInput fix = new FixInput();
        fix.expectMergedAs = mergedAs.name();
        List<ProblemInfo> problems = checker.check(c, fix).problems();
        assertThat(problems).hasSize(1);
        ProblemInfo p = problems.get(0);
        assertThat(p.message).isEqualTo("No patch set found for merged commit " + mergedAs.name());
        assertThat(p.status).isEqualTo(ProblemInfo.Status.FIXED);
        assertThat(p.outcome).isEqualTo("Inserted as patch set 2");

        c = db.changes().get(c.getId());
        PatchSet.Id psId2 = new PatchSet.Id(c.getId(), 2);
        assertThat(c.currentPatchSetId()).isEqualTo(psId2);
        assertThat(db.patchSets().get(psId2).getRevision().get()).isEqualTo(mergedAs.name());

        assertProblems(c);
    }

    @Test
    public void createNewPatchSetForExpectedMergeCommitWithChangeId() throws Exception {
        Change c = insertChange();
        c.setStatus(Change.Status.MERGED);
        RevCommit parent = testRepo.branch(c.getDest().get()).commit().message("parent").create();
        PatchSet ps = insertPatchSet(c);
        RevCommit commit = parseCommit(ps);

        RevCommit mergedAs = testRepo.commit().parent(parent)
                .message(commit.getShortMessage() + "\n" + "\n" + "Change-Id: " + c.getKey().get() + "\n").create();
        testRepo.getRevWalk().parseBody(mergedAs);
        assertThat(mergedAs.getFooterLines(FooterConstants.CHANGE_ID)).containsExactly(c.getKey().get());
        testRepo.update(c.getDest().get(), mergedAs);

        assertProblems(c, "Patch set 1 (" + commit.name() + ") is not merged into"
                + " destination ref refs/heads/master (" + mergedAs.name() + "), but change status is MERGED");

        FixInput fix = new FixInput();
        fix.expectMergedAs = mergedAs.name();
        List<ProblemInfo> problems = checker.check(c, fix).problems();
        assertThat(problems).hasSize(1);
        ProblemInfo p = problems.get(0);
        assertThat(p.message).isEqualTo("No patch set found for merged commit " + mergedAs.name());
        assertThat(p.status).isEqualTo(ProblemInfo.Status.FIXED);
        assertThat(p.outcome).isEqualTo("Inserted as patch set 2");

        c = db.changes().get(c.getId());
        PatchSet.Id psId2 = new PatchSet.Id(c.getId(), 2);
        assertThat(c.currentPatchSetId()).isEqualTo(psId2);
        assertThat(db.patchSets().get(psId2).getRevision().get()).isEqualTo(mergedAs.name());

        assertProblems(c);
    }

    @Test
    public void expectedMergedCommitIsOldPatchSetOfSameChange() throws Exception {
        Change c = insertChange();
        c.setStatus(Change.Status.MERGED);
        PatchSet ps1 = insertPatchSet(c);
        String rev1 = ps1.getRevision().get();
        incrementPatchSet(c);
        PatchSet ps2 = insertPatchSet(c);
        testRepo.branch(c.getDest().get()).update(parseCommit(ps1));

        FixInput fix = new FixInput();
        fix.expectMergedAs = rev1;
        List<ProblemInfo> problems = checker.check(c, fix).problems();
        assertThat(problems).hasSize(1);
        ProblemInfo p = problems.get(0);
        assertThat(p.message).isEqualTo("Expected merged commit " + rev1 + " corresponds to patch set "
                + ps1.getId() + ", which is not the current patch set " + ps2.getId());
    }

    @Test
    public void expectedMergedCommitWithMismatchedChangeId() throws Exception {
        Change c = insertChange();
        c.setStatus(Change.Status.MERGED);
        RevCommit parent = testRepo.branch(c.getDest().get()).commit().message("parent").create();
        PatchSet ps = insertPatchSet(c);
        RevCommit commit = parseCommit(ps);

        String badId = "I0000000000000000000000000000000000000000";
        RevCommit mergedAs = testRepo.commit().parent(parent)
                .message(commit.getShortMessage() + "\n" + "\n" + "Change-Id: " + badId + "\n").create();
        testRepo.getRevWalk().parseBody(mergedAs);
        testRepo.update(c.getDest().get(), mergedAs);

        FixInput fix = new FixInput();
        fix.expectMergedAs = mergedAs.name();
        List<ProblemInfo> problems = checker.check(c, fix).problems();
        assertThat(problems).hasSize(1);
        ProblemInfo p = problems.get(0);
        assertThat(p.message).isEqualTo("Expected merged commit " + mergedAs.name() + " has Change-Id: " + badId
                + ", but expected " + c.getKey().get());
    }

    @Test
    public void expectedMergedCommitMatchesMultiplePatchSets() throws Exception {
        Change c1 = insertChange();
        c1.setStatus(Change.Status.MERGED);
        insertPatchSet(c1);

        RevCommit commit = testRepo.branch(c1.getDest().get()).commit().create();
        Change c2 = insertChange();
        PatchSet ps2 = newPatchSet(c2.currentPatchSetId(), commit, adminId);
        updatePatchSetRef(ps2);
        db.patchSets().insert(singleton(ps2));

        Change c3 = insertChange();
        PatchSet ps3 = newPatchSet(c3.currentPatchSetId(), commit, adminId);
        updatePatchSetRef(ps3);
        db.patchSets().insert(singleton(ps3));

        FixInput fix = new FixInput();
        fix.expectMergedAs = commit.name();
        List<ProblemInfo> problems = checker.check(c1, fix).problems();
        assertThat(problems).hasSize(1);
        ProblemInfo p = problems.get(0);
        assertThat(p.message).isEqualTo(
                "Multiple patch sets for expected merged commit " + commit.name() + ": [" + ps2 + ", " + ps3 + "]");
    }

    private Change insertChange() throws Exception {
        Change c = newChange(project, adminId);
        db.changes().insert(singleton(c));
        return c;
    }

    private void incrementPatchSet(Change c) throws Exception {
        TestChanges.incrementPatchSet(c);
        db.changes().upsert(singleton(c));
    }

    private PatchSet insertPatchSet(Change c) throws Exception {
        db.changes().upsert(singleton(c));
        RevCommit commit = testRepo.branch(c.currentPatchSetId().toRefName()).commit().parent(tip)
                .message("Change " + c.getId().get()).create();
        PatchSet ps = newPatchSet(c.currentPatchSetId(), commit, adminId);
        updatePatchSetRef(ps);
        db.patchSets().insert(singleton(ps));
        return ps;
    }

    private PatchSet insertMissingPatchSet(Change c, String id) throws Exception {
        PatchSet ps = newPatchSet(c.currentPatchSetId(), ObjectId.fromString(id), adminId);
        db.patchSets().insert(singleton(ps));
        return ps;
    }

    private void updatePatchSetRef(PatchSet ps) throws Exception {
        testRepo.update(ps.getId().toRefName(), ObjectId.fromString(ps.getRevision().get()));
    }

    private void deleteRef(String refName) throws Exception {
        RefUpdate ru = testRepo.getRepository().updateRef(refName, true);
        ru.setForceUpdate(true);
        assertThat(ru.delete()).isEqualTo(RefUpdate.Result.FORCED);
    }

    private RevCommit parseCommit(PatchSet ps) throws Exception {
        RevCommit commit = testRepo.getRevWalk().parseCommit(ObjectId.fromString(ps.getRevision().get()));
        testRepo.getRevWalk().parseBody(commit);
        return commit;
    }

    private void assertProblems(Change c, String... expected) {
        assertThat(Lists.transform(checker.check(c).problems(), new Function<ProblemInfo, String>() {
            @Override
            public String apply(ProblemInfo in) {
                checkArgument(in.status == null, "Status is not null: " + in.message);
                return in.message;
            }
        })).containsExactly((Object[]) expected);
    }
}