blob: 512aac98934f9cbcfe5268e641d0d6d938a9c5a2 [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.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());
}
}