| // 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.entities.converter; |
| |
| import static com.google.common.truth.Truth.assertThat; |
| import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; |
| import static com.google.gerrit.proto.testing.SerializedClassSubject.assertThatSerializedClass; |
| |
| import com.google.common.collect.ImmutableMap; |
| import com.google.gerrit.entities.Account; |
| import com.google.gerrit.entities.BranchNameKey; |
| import com.google.gerrit.entities.Change; |
| import com.google.gerrit.entities.PatchSet; |
| import com.google.gerrit.entities.Project; |
| import com.google.gerrit.proto.Entities; |
| import com.google.gerrit.proto.testing.SerializedClassSubject; |
| import java.lang.reflect.Type; |
| import java.time.Instant; |
| import org.junit.Test; |
| |
| public class ChangeProtoConverterTest { |
| private final ChangeProtoConverter changeProtoConverter = ChangeProtoConverter.INSTANCE; |
| private static final String TEST_SERVER_ID = "test-server-id"; |
| |
| @Test |
| public void allValuesConvertedToProto() { |
| Change change = |
| new Change( |
| Change.key("change 1"), |
| Change.id(14), |
| Account.id(35), |
| BranchNameKey.create(Project.nameKey("project 67"), "branch 74"), |
| Instant.ofEpochMilli(987654L)); |
| change.setServerId(TEST_SERVER_ID); |
| change.setLastUpdatedOn(Instant.ofEpochMilli(1234567L)); |
| change.setStatus(Change.Status.MERGED); |
| change.setCurrentPatchSet( |
| PatchSet.id(Change.id(14), 23), "subject XYZ", "original subject ABC"); |
| change.setTopic("my topic"); |
| change.setSubmissionId("submission ID 234"); |
| change.setPrivate(true); |
| change.setWorkInProgress(true); |
| change.setReviewStarted(true); |
| change.setRevertOf(Change.id(180)); |
| |
| Entities.Change proto = changeProtoConverter.toProto(change); |
| |
| Entities.Change expectedProto = |
| Entities.Change.newBuilder() |
| .setChangeId(Entities.Change_Id.newBuilder().setId(14)) |
| .setChangeKey(Entities.Change_Key.newBuilder().setId("change 1")) |
| .setCreatedOn(987654L) |
| .setLastUpdatedOn(1234567L) |
| .setOwnerAccountId(Entities.Account_Id.newBuilder().setId(35)) |
| .setDest( |
| Entities.Branch_NameKey.newBuilder() |
| .setProject(Entities.Project_NameKey.newBuilder().setName("project 67")) |
| .setBranch("refs/heads/branch 74")) |
| .setStatus(Change.STATUS_MERGED) |
| .setCurrentPatchSetId(23) |
| .setSubject("subject XYZ") |
| .setTopic("my topic") |
| .setOriginalSubject("original subject ABC") |
| .setSubmissionId("submission ID 234") |
| .setIsPrivate(true) |
| .setWorkInProgress(true) |
| .setReviewStarted(true) |
| .setRevertOf(Entities.Change_Id.newBuilder().setId(180)) |
| .setServerId(TEST_SERVER_ID) |
| .build(); |
| assertThat(proto).isEqualTo(expectedProto); |
| } |
| |
| @Test |
| public void mandatoryValuesConvertedToProto() { |
| Change change = |
| new Change( |
| Change.key("change 1"), |
| Change.id(14), |
| Account.id(35), |
| BranchNameKey.create(Project.nameKey("project 67"), "branch-74"), |
| Instant.ofEpochMilli(987654L)); |
| |
| Entities.Change proto = changeProtoConverter.toProto(change); |
| |
| Entities.Change expectedProto = |
| Entities.Change.newBuilder() |
| .setChangeId(Entities.Change_Id.newBuilder().setId(14)) |
| .setChangeKey(Entities.Change_Key.newBuilder().setId("change 1")) |
| .setCreatedOn(987654L) |
| // Defaults to createdOn if not set. |
| .setLastUpdatedOn(987654L) |
| .setOwnerAccountId(Entities.Account_Id.newBuilder().setId(35)) |
| .setDest( |
| Entities.Branch_NameKey.newBuilder() |
| .setProject(Entities.Project_NameKey.newBuilder().setName("project 67")) |
| .setBranch("refs/heads/branch-74")) |
| // Default values which can't be unset. |
| .setCurrentPatchSetId(0) |
| .setStatus(Change.STATUS_NEW) |
| .setIsPrivate(false) |
| .setWorkInProgress(false) |
| .setReviewStarted(false) |
| .build(); |
| assertThat(proto).isEqualTo(expectedProto); |
| } |
| |
| // This test documents a special behavior which is necessary to ensure binary compatibility. |
| @Test |
| public void currentPatchSetIsAlwaysSetWhenConvertedToProto() { |
| Change change = |
| new Change( |
| Change.key("change 1"), |
| Change.id(14), |
| Account.id(35), |
| BranchNameKey.create(Project.nameKey("project 67"), "branch-74"), |
| Instant.ofEpochMilli(987654L)); |
| change.setServerId(TEST_SERVER_ID); |
| // O as ID actually means that no current patch set is present. |
| change.setCurrentPatchSet(PatchSet.id(Change.id(14), 0), null, null); |
| |
| Entities.Change proto = changeProtoConverter.toProto(change); |
| |
| Entities.Change expectedProto = |
| Entities.Change.newBuilder() |
| .setChangeId(Entities.Change_Id.newBuilder().setId(14)) |
| .setChangeKey(Entities.Change_Key.newBuilder().setId("change 1")) |
| .setCreatedOn(987654L) |
| // Defaults to createdOn if not set. |
| .setLastUpdatedOn(987654L) |
| .setOwnerAccountId(Entities.Account_Id.newBuilder().setId(35)) |
| .setDest( |
| Entities.Branch_NameKey.newBuilder() |
| .setProject(Entities.Project_NameKey.newBuilder().setName("project 67")) |
| .setBranch("refs/heads/branch-74")) |
| .setCurrentPatchSetId(0) |
| // Default values which can't be unset. |
| .setStatus(Change.STATUS_NEW) |
| .setIsPrivate(false) |
| .setWorkInProgress(false) |
| .setReviewStarted(false) |
| .setServerId(TEST_SERVER_ID) |
| .build(); |
| assertThat(proto).isEqualTo(expectedProto); |
| } |
| |
| // This test documents a special behavior which is necessary to ensure binary compatibility. |
| @Test |
| public void originalSubjectIsNotAutomaticallySetToSubjectWhenConvertedToProto() { |
| Change change = |
| new Change( |
| Change.key("change 1"), |
| Change.id(14), |
| Account.id(35), |
| BranchNameKey.create(Project.nameKey("project 67"), "branch-74"), |
| Instant.ofEpochMilli(987654L)); |
| change.setServerId(TEST_SERVER_ID); |
| change.setCurrentPatchSet(PatchSet.id(Change.id(14), 23), "subject ABC", null); |
| |
| Entities.Change proto = changeProtoConverter.toProto(change); |
| |
| Entities.Change expectedProto = |
| Entities.Change.newBuilder() |
| .setChangeId(Entities.Change_Id.newBuilder().setId(14)) |
| .setChangeKey(Entities.Change_Key.newBuilder().setId("change 1")) |
| .setCreatedOn(987654L) |
| // Defaults to createdOn if not set. |
| .setLastUpdatedOn(987654L) |
| .setOwnerAccountId(Entities.Account_Id.newBuilder().setId(35)) |
| .setDest( |
| Entities.Branch_NameKey.newBuilder() |
| .setProject(Entities.Project_NameKey.newBuilder().setName("project 67")) |
| .setBranch("refs/heads/branch-74")) |
| .setCurrentPatchSetId(23) |
| .setSubject("subject ABC") |
| // Default values which can't be unset. |
| .setStatus(Change.STATUS_NEW) |
| .setIsPrivate(false) |
| .setWorkInProgress(false) |
| .setReviewStarted(false) |
| .setServerId(TEST_SERVER_ID) |
| .build(); |
| assertThat(proto).isEqualTo(expectedProto); |
| } |
| |
| @Test |
| public void allValuesConvertedToProtoAndBackAgainExceptNullServerId() { |
| Change change = |
| new Change( |
| Change.key("change 1"), |
| Change.id(14), |
| Account.id(35), |
| BranchNameKey.create(Project.nameKey("project 67"), "branch-74"), |
| Instant.ofEpochMilli(987654L)); |
| change.setServerId(null); |
| change.setLastUpdatedOn(Instant.ofEpochMilli(1234567L)); |
| change.setStatus(Change.Status.MERGED); |
| change.setCurrentPatchSet( |
| PatchSet.id(Change.id(14), 23), "subject XYZ", "original subject ABC"); |
| change.setTopic("my topic"); |
| change.setSubmissionId("submission ID 234"); |
| change.setPrivate(true); |
| change.setWorkInProgress(true); |
| change.setReviewStarted(true); |
| change.setRevertOf(Change.id(180)); |
| |
| Change convertedChange = changeProtoConverter.fromProto(changeProtoConverter.toProto(change)); |
| assertEqualChange(convertedChange, change); |
| } |
| |
| @Test |
| public void mandatoryValuesConvertedToProtoAndBackAgain() { |
| Change change = |
| new Change( |
| Change.key("change 1"), |
| Change.id(14), |
| Account.id(35), |
| BranchNameKey.create(Project.nameKey("project 67"), "branch-74"), |
| Instant.ofEpochMilli(987654L)); |
| |
| Change convertedChange = changeProtoConverter.fromProto(changeProtoConverter.toProto(change)); |
| assertEqualChange(convertedChange, change); |
| } |
| |
| // We need this special test as some values are only optional in the protobuf definition but can |
| // never be unset in our entity object. |
| @Test |
| public void protoWithOnlyRequiredValuesCanBeConvertedBack() { |
| Entities.Change proto = |
| Entities.Change.newBuilder().setChangeId(Entities.Change_Id.newBuilder().setId(14)).build(); |
| Change change = changeProtoConverter.fromProto(proto); |
| |
| assertThat(change.getChangeId()).isEqualTo(14); |
| // Values which can't be null according to ReviewDb's column definition but which are optional. |
| assertThat(change.getKey()).isNull(); |
| assertThat(change.getOwner()).isNull(); |
| assertThat(change.getDest()).isNull(); |
| assertThat(change.getCreatedOn()).isEqualTo(Instant.EPOCH); |
| assertThat(change.getLastUpdatedOn()).isEqualTo(Instant.EPOCH); |
| assertThat(change.getSubject()).isNull(); |
| assertThat(change.currentPatchSetId()).isNull(); |
| // Default values for unset protobuf fields which can't be unset in the entity object. |
| assertThat(change.isNew()).isTrue(); |
| assertThat(change.isPrivate()).isFalse(); |
| assertThat(change.isWorkInProgress()).isFalse(); |
| assertThat(change.hasReviewStarted()).isFalse(); |
| } |
| |
| @Test |
| public void unsetLastUpdatedOnIsAutomaticallySetToCreatedOnWhenConvertedBack() { |
| Entities.Change proto = |
| Entities.Change.newBuilder() |
| .setChangeId(Entities.Change_Id.newBuilder().setId(14)) |
| .setChangeKey(Entities.Change_Key.newBuilder().setId("change 1")) |
| .setCreatedOn(987654L) |
| .setOwnerAccountId(Entities.Account_Id.newBuilder().setId(35)) |
| .setDest( |
| Entities.Branch_NameKey.newBuilder() |
| .setProject(Entities.Project_NameKey.newBuilder().setName("project 67")) |
| .setBranch("branch 74")) |
| .build(); |
| Change change = changeProtoConverter.fromProto(proto); |
| |
| assertThat(change.getLastUpdatedOn()).isEqualTo(Instant.ofEpochMilli(987654L)); |
| } |
| |
| /** See {@link SerializedClassSubject} for background and what to do if this test fails. */ |
| @Test |
| public void fieldsExistAsExpected() { |
| assertThatSerializedClass(Change.class) |
| .hasFields( |
| ImmutableMap.<String, Type>builder() |
| .put("changeId", Change.Id.class) |
| .put("serverId", String.class) |
| .put("changeKey", Change.Key.class) |
| .put("createdOn", Instant.class) |
| .put("lastUpdatedOn", Instant.class) |
| .put("owner", Account.Id.class) |
| .put("dest", BranchNameKey.class) |
| .put("status", char.class) |
| .put("currentPatchSetId", int.class) |
| .put("subject", String.class) |
| .put("topic", String.class) |
| .put("originalSubject", String.class) |
| .put("submissionId", String.class) |
| .put("isPrivate", boolean.class) |
| .put("workInProgress", boolean.class) |
| .put("reviewStarted", boolean.class) |
| .put("revertOf", Change.Id.class) |
| .put("cherryPickOf", PatchSet.Id.class) |
| .build()); |
| } |
| |
| // Unfortunately, Change doesn't implement equals(). Remove this method when we switch Change to |
| // an AutoValue. |
| private static void assertEqualChange(Change change, Change expectedChange) { |
| assertThat(change.getChangeId()).isEqualTo(expectedChange.getChangeId()); |
| assertThat(change.getServerId()).isEqualTo(expectedChange.getServerId()); |
| assertThat(change.getKey()).isEqualTo(expectedChange.getKey()); |
| assertThat(change.getCreatedOn()).isEqualTo(expectedChange.getCreatedOn()); |
| assertThat(change.getLastUpdatedOn()).isEqualTo(expectedChange.getLastUpdatedOn()); |
| assertThat(change.getOwner()).isEqualTo(expectedChange.getOwner()); |
| assertThat(change.getDest()).isEqualTo(expectedChange.getDest()); |
| assertThat(change.getStatus()).isEqualTo(expectedChange.getStatus()); |
| assertThat(change.currentPatchSetId()).isEqualTo(expectedChange.currentPatchSetId()); |
| assertThat(change.getSubject()).isEqualTo(expectedChange.getSubject()); |
| assertThat(change.getTopic()).isEqualTo(expectedChange.getTopic()); |
| assertThat(change.getOriginalSubject()).isEqualTo(expectedChange.getOriginalSubject()); |
| assertThat(change.getSubmissionId()).isEqualTo(expectedChange.getSubmissionId()); |
| assertThat(change.isPrivate()).isEqualTo(expectedChange.isPrivate()); |
| assertThat(change.isWorkInProgress()).isEqualTo(expectedChange.isWorkInProgress()); |
| assertThat(change.hasReviewStarted()).isEqualTo(expectedChange.hasReviewStarted()); |
| assertThat(change.getRevertOf()).isEqualTo(expectedChange.getRevertOf()); |
| } |
| } |