diff options
Diffstat (limited to 'javatests/com/google/gerrit/server/notedb/ChangeNotesStateTest.java')
-rw-r--r-- | javatests/com/google/gerrit/server/notedb/ChangeNotesStateTest.java | 946 |
1 files changed, 946 insertions, 0 deletions
diff --git a/javatests/com/google/gerrit/server/notedb/ChangeNotesStateTest.java b/javatests/com/google/gerrit/server/notedb/ChangeNotesStateTest.java new file mode 100644 index 0000000000..7b41ba3624 --- /dev/null +++ b/javatests/com/google/gerrit/server/notedb/ChangeNotesStateTest.java @@ -0,0 +1,946 @@ +// 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.server.notedb; + +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; +import static com.google.gerrit.reviewdb.server.ReviewDbCodecs.APPROVAL_CODEC; +import static com.google.gerrit.reviewdb.server.ReviewDbCodecs.MESSAGE_CODEC; +import static com.google.gerrit.reviewdb.server.ReviewDbCodecs.PATCH_SET_CODEC; +import static com.google.gerrit.server.cache.serialize.ProtoCacheSerializers.toByteString; +import static com.google.gerrit.server.cache.testing.SerializedClassSubject.assertThatSerializedClass; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableListMultimap; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableTable; +import com.google.common.collect.Iterables; +import com.google.gerrit.common.data.SubmitRecord; +import com.google.gerrit.common.data.SubmitRequirement; +import com.google.gerrit.mail.Address; +import com.google.gerrit.reviewdb.client.Account; +import com.google.gerrit.reviewdb.client.Change; +import com.google.gerrit.reviewdb.client.ChangeMessage; +import com.google.gerrit.reviewdb.client.Comment; +import com.google.gerrit.reviewdb.client.LabelId; +import com.google.gerrit.reviewdb.client.PatchSet; +import com.google.gerrit.reviewdb.client.PatchSetApproval; +import com.google.gerrit.reviewdb.client.RevId; +import com.google.gerrit.server.ReviewerByEmailSet; +import com.google.gerrit.server.ReviewerSet; +import com.google.gerrit.server.ReviewerStatusUpdate; +import com.google.gerrit.server.cache.proto.Cache.ChangeNotesStateProto; +import com.google.gerrit.server.cache.proto.Cache.ChangeNotesStateProto.ChangeColumnsProto; +import com.google.gerrit.server.cache.proto.Cache.ChangeNotesStateProto.ReviewerByEmailSetEntryProto; +import com.google.gerrit.server.cache.proto.Cache.ChangeNotesStateProto.ReviewerSetEntryProto; +import com.google.gerrit.server.cache.proto.Cache.ChangeNotesStateProto.ReviewerStatusUpdateProto; +import com.google.gerrit.server.cache.serialize.ProtoCacheSerializers.ObjectIdConverter; +import com.google.gerrit.server.notedb.ChangeNotesState.ChangeColumns; +import com.google.gerrit.server.notedb.ChangeNotesState.Serializer; +import com.google.gwtorm.client.KeyUtil; +import com.google.gwtorm.server.StandardKeyEncoder; +import com.google.inject.TypeLiteral; +import com.google.protobuf.ByteString; +import java.lang.reflect.Type; +import java.sql.Timestamp; +import java.util.List; +import java.util.Map; +import org.eclipse.jgit.lib.ObjectId; +import org.junit.Before; +import org.junit.Test; + +public class ChangeNotesStateTest { + static { + KeyUtil.setEncoderImpl(new StandardKeyEncoder()); + } + + private static final Change.Id ID = new Change.Id(123); + private static final ObjectId SHA = + ObjectId.fromString("1234567812345678123456781234567812345678"); + private static final ByteString SHA_BYTES = ObjectIdConverter.create().toByteString(SHA); + private static final String CHANGE_KEY = "Iabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"; + + private ChangeColumns cols; + private ChangeColumnsProto colsProto; + + @Before + public void setUp() throws Exception { + cols = + ChangeColumns.builder() + .changeKey(new Change.Key(CHANGE_KEY)) + .createdOn(new Timestamp(123456L)) + .lastUpdatedOn(new Timestamp(234567L)) + .owner(new Account.Id(1000)) + .branch("refs/heads/master") + .subject("Test change") + .isPrivate(false) + .workInProgress(false) + .reviewStarted(true) + .build(); + colsProto = toProto(newBuilder().build()).getColumns(); + } + + private ChangeNotesState.Builder newBuilder() { + return ChangeNotesState.Builder.empty(ID).metaId(SHA).columns(cols); + } + + @Test + public void serializeChangeKey() throws Exception { + assertRoundTrip( + newBuilder() + .columns( + cols.toBuilder() + .changeKey(new Change.Key("Ieeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee")) + .build()) + .build(), + ChangeNotesStateProto.newBuilder() + .setMetaId(SHA_BYTES) + .setChangeId(ID.get()) + .setColumns( + colsProto.toBuilder().setChangeKey("Ieeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee")) + .build()); + } + + @Test + public void serializeCreatedOn() throws Exception { + assertRoundTrip( + newBuilder().columns(cols.toBuilder().createdOn(new Timestamp(98765L)).build()).build(), + ChangeNotesStateProto.newBuilder() + .setMetaId(SHA_BYTES) + .setChangeId(ID.get()) + .setColumns(colsProto.toBuilder().setCreatedOn(98765L)) + .build()); + } + + @Test + public void serializeLastUpdatedOn() throws Exception { + assertRoundTrip( + newBuilder().columns(cols.toBuilder().lastUpdatedOn(new Timestamp(98765L)).build()).build(), + ChangeNotesStateProto.newBuilder() + .setMetaId(SHA_BYTES) + .setChangeId(ID.get()) + .setColumns(colsProto.toBuilder().setLastUpdatedOn(98765L)) + .build()); + } + + @Test + public void serializeOwner() throws Exception { + assertRoundTrip( + newBuilder().columns(cols.toBuilder().owner(new Account.Id(7777)).build()).build(), + ChangeNotesStateProto.newBuilder() + .setMetaId(SHA_BYTES) + .setChangeId(ID.get()) + .setColumns(colsProto.toBuilder().setOwner(7777)) + .build()); + } + + @Test + public void serializeBranch() throws Exception { + assertRoundTrip( + newBuilder().columns(cols.toBuilder().branch("refs/heads/bar").build()).build(), + ChangeNotesStateProto.newBuilder() + .setMetaId(SHA_BYTES) + .setChangeId(ID.get()) + .setColumns(colsProto.toBuilder().setBranch("refs/heads/bar")) + .build()); + } + + @Test + public void serializeSubject() throws Exception { + assertRoundTrip( + newBuilder().columns(cols.toBuilder().subject("A different test change").build()).build(), + ChangeNotesStateProto.newBuilder() + .setMetaId(SHA_BYTES) + .setChangeId(ID.get()) + .setColumns(colsProto.toBuilder().setSubject("A different test change")) + .build()); + } + + @Test + public void serializeCurrentPatchSetId() throws Exception { + assertRoundTrip( + newBuilder() + .columns(cols.toBuilder().currentPatchSetId(new PatchSet.Id(ID, 2)).build()) + .build(), + ChangeNotesStateProto.newBuilder() + .setMetaId(SHA_BYTES) + .setChangeId(ID.get()) + .setColumns(colsProto.toBuilder().setCurrentPatchSetId(2).setHasCurrentPatchSetId(true)) + .build()); + } + + @Test + public void serializeNullTopic() throws Exception { + assertRoundTrip( + newBuilder().columns(cols.toBuilder().topic(null).build()).build(), + ChangeNotesStateProto.newBuilder() + .setMetaId(SHA_BYTES) + .setChangeId(ID.get()) + .setColumns(colsProto) + .build()); + } + + @Test + public void serializeEmptyTopic() throws Exception { + ChangeNotesState state = newBuilder().columns(cols.toBuilder().topic("").build()).build(); + assertRoundTrip( + state, + ChangeNotesStateProto.newBuilder() + .setMetaId(SHA_BYTES) + .setChangeId(ID.get()) + .setColumns(colsProto.toBuilder().setTopic("").setHasTopic(true)) + .build()); + } + + @Test + public void serializeNonEmptyTopic() throws Exception { + ChangeNotesState state = newBuilder().columns(cols.toBuilder().topic("topic").build()).build(); + assertRoundTrip( + state, + ChangeNotesStateProto.newBuilder() + .setMetaId(SHA_BYTES) + .setChangeId(ID.get()) + .setColumns(colsProto.toBuilder().setTopic("topic").setHasTopic(true)) + .build()); + } + + @Test + public void serializeOriginalSubject() throws Exception { + assertRoundTrip( + newBuilder() + .columns(cols.toBuilder().originalSubject("The first patch set").build()) + .build(), + ChangeNotesStateProto.newBuilder() + .setMetaId(SHA_BYTES) + .setChangeId(ID.get()) + .setColumns( + colsProto + .toBuilder() + .setOriginalSubject("The first patch set") + .setHasOriginalSubject(true)) + .build()); + } + + @Test + public void serializeSubmissionId() throws Exception { + assertRoundTrip( + newBuilder().columns(cols.toBuilder().submissionId("xyz").build()).build(), + ChangeNotesStateProto.newBuilder() + .setMetaId(SHA_BYTES) + .setChangeId(ID.get()) + .setColumns(colsProto.toBuilder().setSubmissionId("xyz").setHasSubmissionId(true)) + .build()); + } + + @Test + public void serializeAssignee() throws Exception { + assertRoundTrip( + newBuilder().columns(cols.toBuilder().assignee(new Account.Id(2000)).build()).build(), + ChangeNotesStateProto.newBuilder() + .setMetaId(SHA_BYTES) + .setChangeId(ID.get()) + .setColumns(colsProto.toBuilder().setAssignee(2000).setHasAssignee(true)) + .build()); + } + + @Test + public void serializeStatus() throws Exception { + assertRoundTrip( + newBuilder().columns(cols.toBuilder().status(Change.Status.MERGED).build()).build(), + ChangeNotesStateProto.newBuilder() + .setMetaId(SHA_BYTES) + .setChangeId(ID.get()) + .setColumns(colsProto.toBuilder().setStatus("MERGED").setHasStatus(true)) + .build()); + } + + @Test + public void serializeIsPrivate() throws Exception { + assertRoundTrip( + newBuilder().columns(cols.toBuilder().isPrivate(true).build()).build(), + ChangeNotesStateProto.newBuilder() + .setMetaId(SHA_BYTES) + .setChangeId(ID.get()) + .setColumns(colsProto.toBuilder().setIsPrivate(true)) + .build()); + } + + @Test + public void serializeIsWorkInProgress() throws Exception { + assertRoundTrip( + newBuilder().columns(cols.toBuilder().workInProgress(true).build()).build(), + ChangeNotesStateProto.newBuilder() + .setMetaId(SHA_BYTES) + .setChangeId(ID.get()) + .setColumns(colsProto.toBuilder().setWorkInProgress(true)) + .build()); + } + + @Test + public void serializeHasReviewStarted() throws Exception { + assertRoundTrip( + newBuilder().columns(cols.toBuilder().reviewStarted(true).build()).build(), + ChangeNotesStateProto.newBuilder() + .setMetaId(SHA_BYTES) + .setChangeId(ID.get()) + .setColumns(colsProto.toBuilder().setReviewStarted(true)) + .build()); + } + + @Test + public void serializeRevertOf() throws Exception { + assertRoundTrip( + newBuilder().columns(cols.toBuilder().revertOf(new Change.Id(999)).build()).build(), + ChangeNotesStateProto.newBuilder() + .setMetaId(SHA_BYTES) + .setChangeId(ID.get()) + .setColumns(colsProto.toBuilder().setRevertOf(999).setHasRevertOf(true)) + .build()); + } + + @Test + public void serializePastAssignees() throws Exception { + assertRoundTrip( + newBuilder() + .pastAssignees(ImmutableSet.of(new Account.Id(2002), new Account.Id(2001))) + .build(), + ChangeNotesStateProto.newBuilder() + .setMetaId(SHA_BYTES) + .setChangeId(ID.get()) + .setColumns(colsProto) + .addPastAssignee(2002) + .addPastAssignee(2001) + .build()); + } + + @Test + public void serializeHashtags() throws Exception { + assertRoundTrip( + newBuilder().hashtags(ImmutableSet.of("tag2", "tag1")).build(), + ChangeNotesStateProto.newBuilder() + .setMetaId(SHA_BYTES) + .setChangeId(ID.get()) + .setColumns(colsProto) + .addHashtag("tag2") + .addHashtag("tag1") + .build()); + } + + @Test + public void serializePatchSets() throws Exception { + PatchSet ps1 = new PatchSet(new PatchSet.Id(ID, 1)); + ps1.setUploader(new Account.Id(2000)); + ps1.setRevision(new RevId("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")); + ps1.setCreatedOn(cols.createdOn()); + ByteString ps1Bytes = toByteString(ps1, PATCH_SET_CODEC); + assertThat(ps1Bytes.size()).isEqualTo(66); + + PatchSet ps2 = new PatchSet(new PatchSet.Id(ID, 2)); + ps2.setUploader(new Account.Id(3000)); + ps2.setRevision(new RevId("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb")); + ps2.setCreatedOn(cols.lastUpdatedOn()); + ByteString ps2Bytes = toByteString(ps2, PATCH_SET_CODEC); + assertThat(ps2Bytes.size()).isEqualTo(66); + assertThat(ps2Bytes).isNotEqualTo(ps1Bytes); + + assertRoundTrip( + newBuilder() + .patchSets(ImmutableMap.of(ps2.getId(), ps2, ps1.getId(), ps1).entrySet()) + .build(), + ChangeNotesStateProto.newBuilder() + .setMetaId(SHA_BYTES) + .setChangeId(ID.get()) + .setColumns(colsProto) + .addPatchSet(ps2Bytes) + .addPatchSet(ps1Bytes) + .build()); + } + + @Test + public void serializeApprovals() throws Exception { + PatchSetApproval a1 = + new PatchSetApproval( + new PatchSetApproval.Key( + new PatchSet.Id(ID, 1), new Account.Id(2001), new LabelId("Code-Review")), + (short) 1, + new Timestamp(1212L)); + ByteString a1Bytes = toByteString(a1, APPROVAL_CODEC); + assertThat(a1Bytes.size()).isEqualTo(43); + + PatchSetApproval a2 = + new PatchSetApproval( + new PatchSetApproval.Key( + new PatchSet.Id(ID, 1), new Account.Id(2002), new LabelId("Verified")), + (short) -1, + new Timestamp(3434L)); + ByteString a2Bytes = toByteString(a2, APPROVAL_CODEC); + assertThat(a2Bytes.size()).isEqualTo(49); + assertThat(a2Bytes).isNotEqualTo(a1Bytes); + + assertRoundTrip( + newBuilder() + .approvals( + ImmutableListMultimap.of(a2.getPatchSetId(), a2, a1.getPatchSetId(), a1).entries()) + .build(), + ChangeNotesStateProto.newBuilder() + .setMetaId(SHA_BYTES) + .setChangeId(ID.get()) + .setColumns(colsProto) + .addApproval(a2Bytes) + .addApproval(a1Bytes) + .build()); + } + + @Test + public void serializeReviewers() throws Exception { + assertRoundTrip( + newBuilder() + .reviewers( + ReviewerSet.fromTable( + ImmutableTable.<ReviewerStateInternal, Account.Id, Timestamp>builder() + .put(ReviewerStateInternal.CC, new Account.Id(2001), new Timestamp(1212L)) + .put( + ReviewerStateInternal.REVIEWER, + new Account.Id(2002), + new Timestamp(3434L)) + .build())) + .build(), + ChangeNotesStateProto.newBuilder() + .setMetaId(SHA_BYTES) + .setChangeId(ID.get()) + .setColumns(colsProto) + .addReviewer( + ReviewerSetEntryProto.newBuilder() + .setState("CC") + .setAccountId(2001) + .setTimestamp(1212L)) + .addReviewer( + ReviewerSetEntryProto.newBuilder() + .setState("REVIEWER") + .setAccountId(2002) + .setTimestamp(3434L)) + .build()); + } + + @Test + public void serializeReviewersByEmail() throws Exception { + assertRoundTrip( + newBuilder() + .reviewersByEmail( + ReviewerByEmailSet.fromTable( + ImmutableTable.<ReviewerStateInternal, Address, Timestamp>builder() + .put( + ReviewerStateInternal.CC, + new Address("Name1", "email1@example.com"), + new Timestamp(1212L)) + .put( + ReviewerStateInternal.REVIEWER, + new Address("Name2", "email2@example.com"), + new Timestamp(3434L)) + .build())) + .build(), + ChangeNotesStateProto.newBuilder() + .setMetaId(SHA_BYTES) + .setChangeId(ID.get()) + .setColumns(colsProto) + .addReviewerByEmail( + ReviewerByEmailSetEntryProto.newBuilder() + .setState("CC") + .setAddress("Name1 <email1@example.com>") + .setTimestamp(1212L)) + .addReviewerByEmail( + ReviewerByEmailSetEntryProto.newBuilder() + .setState("REVIEWER") + .setAddress("Name2 <email2@example.com>") + .setTimestamp(3434L)) + .build()); + } + + @Test + public void serializeReviewersByEmailWithNullName() throws Exception { + ChangeNotesState actual = + assertRoundTrip( + newBuilder() + .reviewersByEmail( + ReviewerByEmailSet.fromTable( + ImmutableTable.of( + ReviewerStateInternal.CC, + new Address("emailonly@example.com"), + new Timestamp(1212L)))) + .build(), + ChangeNotesStateProto.newBuilder() + .setMetaId(SHA_BYTES) + .setChangeId(ID.get()) + .setColumns(colsProto) + .addReviewerByEmail( + ReviewerByEmailSetEntryProto.newBuilder() + .setState("CC") + .setAddress("emailonly@example.com") + .setTimestamp(1212L)) + .build()); + + // Address doesn't consider the name field in equals, so we have to check it manually. + // TODO(dborowitz): Fix Address#equals. + ImmutableSet<Address> ccs = actual.reviewersByEmail().byState(ReviewerStateInternal.CC); + assertThat(ccs).hasSize(1); + Address address = Iterables.getOnlyElement(ccs); + assertThat(address.getName()).isNull(); + assertThat(address.getEmail()).isEqualTo("emailonly@example.com"); + } + + @Test + public void serializePendingReviewers() throws Exception { + assertRoundTrip( + newBuilder() + .pendingReviewers( + ReviewerSet.fromTable( + ImmutableTable.<ReviewerStateInternal, Account.Id, Timestamp>builder() + .put(ReviewerStateInternal.CC, new Account.Id(2001), new Timestamp(1212L)) + .put( + ReviewerStateInternal.REVIEWER, + new Account.Id(2002), + new Timestamp(3434L)) + .build())) + .build(), + ChangeNotesStateProto.newBuilder() + .setMetaId(SHA_BYTES) + .setChangeId(ID.get()) + .setColumns(colsProto) + .addPendingReviewer( + ReviewerSetEntryProto.newBuilder() + .setState("CC") + .setAccountId(2001) + .setTimestamp(1212L)) + .addPendingReviewer( + ReviewerSetEntryProto.newBuilder() + .setState("REVIEWER") + .setAccountId(2002) + .setTimestamp(3434L)) + .build()); + } + + @Test + public void serializePendingReviewersByEmail() throws Exception { + assertRoundTrip( + newBuilder() + .pendingReviewersByEmail( + ReviewerByEmailSet.fromTable( + ImmutableTable.<ReviewerStateInternal, Address, Timestamp>builder() + .put( + ReviewerStateInternal.CC, + new Address("Name1", "email1@example.com"), + new Timestamp(1212L)) + .put( + ReviewerStateInternal.REVIEWER, + new Address("Name2", "email2@example.com"), + new Timestamp(3434L)) + .build())) + .build(), + ChangeNotesStateProto.newBuilder() + .setMetaId(SHA_BYTES) + .setChangeId(ID.get()) + .setColumns(colsProto) + .addPendingReviewerByEmail( + ReviewerByEmailSetEntryProto.newBuilder() + .setState("CC") + .setAddress("Name1 <email1@example.com>") + .setTimestamp(1212L)) + .addPendingReviewerByEmail( + ReviewerByEmailSetEntryProto.newBuilder() + .setState("REVIEWER") + .setAddress("Name2 <email2@example.com>") + .setTimestamp(3434L)) + .build()); + } + + @Test + public void serializeAllPastReviewers() throws Exception { + assertRoundTrip( + newBuilder() + .allPastReviewers(ImmutableList.of(new Account.Id(2002), new Account.Id(2001))) + .build(), + ChangeNotesStateProto.newBuilder() + .setMetaId(SHA_BYTES) + .setChangeId(ID.get()) + .setColumns(colsProto) + .addPastReviewer(2002) + .addPastReviewer(2001) + .build()); + } + + @Test + public void serializeReviewerUpdates() throws Exception { + assertRoundTrip( + newBuilder() + .reviewerUpdates( + ImmutableList.of( + ReviewerStatusUpdate.create( + new Timestamp(1212L), + new Account.Id(1000), + new Account.Id(2002), + ReviewerStateInternal.CC), + ReviewerStatusUpdate.create( + new Timestamp(3434L), + new Account.Id(1000), + new Account.Id(2001), + ReviewerStateInternal.REVIEWER))) + .build(), + ChangeNotesStateProto.newBuilder() + .setMetaId(SHA_BYTES) + .setChangeId(ID.get()) + .setColumns(colsProto) + .addReviewerUpdate( + ReviewerStatusUpdateProto.newBuilder() + .setDate(1212L) + .setUpdatedBy(1000) + .setReviewer(2002) + .setState("CC")) + .addReviewerUpdate( + ReviewerStatusUpdateProto.newBuilder() + .setDate(3434L) + .setUpdatedBy(1000) + .setReviewer(2001) + .setState("REVIEWER")) + .build()); + } + + @Test + public void serializeSubmitRecords() throws Exception { + SubmitRecord sr1 = new SubmitRecord(); + sr1.status = SubmitRecord.Status.OK; + + SubmitRecord sr2 = new SubmitRecord(); + sr2.status = SubmitRecord.Status.FORCED; + + assertRoundTrip( + newBuilder().submitRecords(ImmutableList.of(sr2, sr1)).build(), + ChangeNotesStateProto.newBuilder() + .setMetaId(SHA_BYTES) + .setChangeId(ID.get()) + .setColumns(colsProto) + .addSubmitRecord("{\"status\":\"FORCED\"}") + .addSubmitRecord("{\"status\":\"OK\"}") + .build()); + } + + @Test + public void serializeChangeMessages() throws Exception { + ChangeMessage m1 = + new ChangeMessage( + new ChangeMessage.Key(ID, "uuid1"), + new Account.Id(1000), + new Timestamp(1212L), + new PatchSet.Id(ID, 1)); + ByteString m1Bytes = toByteString(m1, MESSAGE_CODEC); + assertThat(m1Bytes.size()).isEqualTo(35); + + ChangeMessage m2 = + new ChangeMessage( + new ChangeMessage.Key(ID, "uuid2"), + new Account.Id(2000), + new Timestamp(3434L), + new PatchSet.Id(ID, 2)); + ByteString m2Bytes = toByteString(m2, MESSAGE_CODEC); + assertThat(m2Bytes.size()).isEqualTo(35); + assertThat(m2Bytes).isNotEqualTo(m1Bytes); + + assertRoundTrip( + newBuilder().changeMessages(ImmutableList.of(m2, m1)).build(), + ChangeNotesStateProto.newBuilder() + .setMetaId(SHA_BYTES) + .setChangeId(ID.get()) + .setColumns(colsProto) + .addChangeMessage(m2Bytes) + .addChangeMessage(m1Bytes) + .build()); + } + + @Test + public void serializePublishedComments() throws Exception { + Comment c1 = + new Comment( + new Comment.Key("uuid1", "file1", 1), + new Account.Id(1001), + new Timestamp(1212L), + (short) 1, + "message 1", + "serverId", + false); + c1.setRevId(new RevId("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")); + String c1Json = Serializer.GSON.toJson(c1); + + Comment c2 = + new Comment( + new Comment.Key("uuid2", "file2", 2), + new Account.Id(1002), + new Timestamp(3434L), + (short) 2, + "message 2", + "serverId", + true); + c2.setRevId(new RevId("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb")); + String c2Json = Serializer.GSON.toJson(c2); + + assertRoundTrip( + newBuilder() + .publishedComments( + ImmutableListMultimap.of(new RevId(c2.revId), c2, new RevId(c1.revId), c1)) + .build(), + ChangeNotesStateProto.newBuilder() + .setMetaId(SHA_BYTES) + .setChangeId(ID.get()) + .setColumns(colsProto) + .addPublishedComment(c2Json) + .addPublishedComment(c1Json) + .build()); + } + + @Test + public void serializeReadOnlyUntil() throws Exception { + assertRoundTrip( + newBuilder().readOnlyUntil(new Timestamp(1212L)).build(), + ChangeNotesStateProto.newBuilder() + .setMetaId(SHA_BYTES) + .setChangeId(ID.get()) + .setColumns(colsProto) + .setReadOnlyUntil(1212L) + .setHasReadOnlyUntil(true) + .build()); + } + + @Test + public void changeNotesStateMethods() throws Exception { + assertThatSerializedClass(ChangeNotesState.class) + .hasAutoValueMethods( + ImmutableMap.<String, Type>builder() + .put("metaId", ObjectId.class) + .put("changeId", Change.Id.class) + .put("columns", ChangeColumns.class) + .put("pastAssignees", new TypeLiteral<ImmutableSet<Account.Id>>() {}.getType()) + .put("hashtags", new TypeLiteral<ImmutableSet<String>>() {}.getType()) + .put( + "patchSets", + new TypeLiteral<ImmutableList<Map.Entry<PatchSet.Id, PatchSet>>>() {}.getType()) + .put( + "approvals", + new TypeLiteral< + ImmutableList<Map.Entry<PatchSet.Id, PatchSetApproval>>>() {}.getType()) + .put("reviewers", ReviewerSet.class) + .put("reviewersByEmail", ReviewerByEmailSet.class) + .put("pendingReviewers", ReviewerSet.class) + .put("pendingReviewersByEmail", ReviewerByEmailSet.class) + .put("allPastReviewers", new TypeLiteral<ImmutableList<Account.Id>>() {}.getType()) + .put( + "reviewerUpdates", + new TypeLiteral<ImmutableList<ReviewerStatusUpdate>>() {}.getType()) + .put("submitRecords", new TypeLiteral<ImmutableList<SubmitRecord>>() {}.getType()) + .put("changeMessages", new TypeLiteral<ImmutableList<ChangeMessage>>() {}.getType()) + .put( + "publishedComments", + new TypeLiteral<ImmutableListMultimap<RevId, Comment>>() {}.getType()) + .put("readOnlyUntil", Timestamp.class) + .build()); + } + + @Test + public void changeColumnsMethods() throws Exception { + assertThatSerializedClass(ChangeColumns.class) + .hasAutoValueMethods( + ImmutableMap.<String, Type>builder() + .put("changeKey", Change.Key.class) + .put("createdOn", Timestamp.class) + .put("lastUpdatedOn", Timestamp.class) + .put("owner", Account.Id.class) + .put("branch", String.class) + .put("currentPatchSetId", PatchSet.Id.class) + .put("subject", String.class) + .put("topic", String.class) + .put("originalSubject", String.class) + .put("submissionId", String.class) + .put("assignee", Account.Id.class) + .put("status", Change.Status.class) + .put("isPrivate", boolean.class) + .put("workInProgress", boolean.class) + .put("reviewStarted", boolean.class) + .put("revertOf", Change.Id.class) + .put("toBuilder", ChangeNotesState.ChangeColumns.Builder.class) + .build()); + } + + @Test + public void patchSetFields() throws Exception { + assertThatSerializedClass(PatchSet.class) + .hasFields( + ImmutableMap.<String, Type>builder() + .put("id", PatchSet.Id.class) + .put("revision", RevId.class) + .put("uploader", Account.Id.class) + .put("createdOn", Timestamp.class) + .put("groups", String.class) + .put("pushCertificate", String.class) + .put("description", String.class) + .build()); + } + + @Test + public void patchSetApprovalFields() throws Exception { + assertThatSerializedClass(PatchSetApproval.Key.class) + .hasFields( + ImmutableMap.<String, Type>builder() + .put("patchSetId", PatchSet.Id.class) + .put("accountId", Account.Id.class) + .put("categoryId", LabelId.class) + .build()); + assertThatSerializedClass(PatchSetApproval.class) + .hasFields( + ImmutableMap.<String, Type>builder() + .put("key", PatchSetApproval.Key.class) + .put("value", short.class) + .put("granted", Timestamp.class) + .put("tag", String.class) + .put("realAccountId", Account.Id.class) + .put("postSubmit", boolean.class) + .build()); + } + + @Test + public void reviewerSetFields() throws Exception { + assertThatSerializedClass(ReviewerSet.class) + .hasFields( + ImmutableMap.of( + "table", + new TypeLiteral< + ImmutableTable< + ReviewerStateInternal, Account.Id, Timestamp>>() {}.getType(), + "accounts", new TypeLiteral<ImmutableSet<Account.Id>>() {}.getType())); + } + + @Test + public void reviewerByEmailSetFields() throws Exception { + assertThatSerializedClass(ReviewerByEmailSet.class) + .hasFields( + ImmutableMap.of( + "table", + new TypeLiteral< + ImmutableTable<ReviewerStateInternal, Address, Timestamp>>() {}.getType(), + "users", new TypeLiteral<ImmutableSet<Address>>() {}.getType())); + } + + @Test + public void reviewerStatusUpdateMethods() throws Exception { + assertThatSerializedClass(ReviewerStatusUpdate.class) + .hasAutoValueMethods( + ImmutableMap.of( + "date", Timestamp.class, + "updatedBy", Account.Id.class, + "reviewer", Account.Id.class, + "state", ReviewerStateInternal.class)); + } + + @Test + public void submitRecordFields() throws Exception { + assertThatSerializedClass(SubmitRecord.class) + .hasFields( + ImmutableMap.of( + "status", + SubmitRecord.Status.class, + "labels", + new TypeLiteral<List<SubmitRecord.Label>>() {}.getType(), + "requirements", + new TypeLiteral<List<SubmitRequirement>>() {}.getType(), + "errorMessage", + String.class)); + assertThatSerializedClass(SubmitRecord.Label.class) + .hasFields( + ImmutableMap.of( + "label", String.class, + "status", SubmitRecord.Label.Status.class, + "appliedBy", Account.Id.class)); + assertThatSerializedClass(SubmitRequirement.class) + .hasAutoValueMethods( + ImmutableMap.of( + "fallbackText", String.class, + "type", String.class, + "data", new TypeLiteral<ImmutableMap<String, String>>() {}.getType())); + } + + @Test + public void changeMessageFields() throws Exception { + assertThatSerializedClass(ChangeMessage.Key.class) + .hasFields(ImmutableMap.of("changeId", Change.Id.class, "uuid", String.class)); + assertThatSerializedClass(ChangeMessage.class) + .hasFields( + ImmutableMap.<String, Type>builder() + .put("key", ChangeMessage.Key.class) + .put("author", Account.Id.class) + .put("writtenOn", Timestamp.class) + .put("message", String.class) + .put("patchset", PatchSet.Id.class) + .put("tag", String.class) + .put("realAuthor", Account.Id.class) + .build()); + } + + @Test + public void commentFields() throws Exception { + assertThatSerializedClass(Comment.Key.class) + .hasFields( + ImmutableMap.of( + "uuid", String.class, "filename", String.class, "patchSetId", int.class)); + assertThatSerializedClass(Comment.Identity.class).hasFields(ImmutableMap.of("id", int.class)); + assertThatSerializedClass(Comment.Range.class) + .hasFields( + ImmutableMap.of( + "startLine", int.class, + "startChar", int.class, + "endLine", int.class, + "endChar", int.class)); + assertThatSerializedClass(Comment.class) + .hasFields( + ImmutableMap.<String, Type>builder() + .put("key", Comment.Key.class) + .put("lineNbr", int.class) + .put("author", Comment.Identity.class) + .put("realAuthor", Comment.Identity.class) + .put("writtenOn", Timestamp.class) + .put("side", short.class) + .put("message", String.class) + .put("parentUuid", String.class) + .put("range", Comment.Range.class) + .put("tag", String.class) + .put("revId", String.class) + .put("serverId", String.class) + .put("unresolved", boolean.class) + .put("legacyFormat", boolean.class) + .build()); + } + + private static ChangeNotesStateProto toProto(ChangeNotesState state) throws Exception { + return ChangeNotesStateProto.parseFrom(Serializer.INSTANCE.serialize(state)); + } + + private static ChangeNotesState assertRoundTrip( + ChangeNotesState state, ChangeNotesStateProto expectedProto) throws Exception { + ChangeNotesStateProto actualProto = toProto(state); + assertThat(actualProto).isEqualTo(expectedProto); + ChangeNotesState actual = Serializer.INSTANCE.deserialize(Serializer.INSTANCE.serialize(state)); + assertThat(actual).isEqualTo(state); + // It's possible that ChangeNotesState contains objects which implement equals without taking + // into account all fields. Return the actual deserialized instance so that callers can perform + // additional assertions if necessary. + return actual; + } +} |