summaryrefslogtreecommitdiffstats
path: root/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/notedb/NoteDbPrimaryIT.java
diff options
context:
space:
mode:
Diffstat (limited to 'gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/notedb/NoteDbPrimaryIT.java')
-rw-r--r--gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/notedb/NoteDbPrimaryIT.java530
1 files changed, 0 insertions, 530 deletions
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/notedb/NoteDbPrimaryIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/notedb/NoteDbPrimaryIT.java
deleted file mode 100644
index 01f3d19cc8..0000000000
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/notedb/NoteDbPrimaryIT.java
+++ /dev/null
@@ -1,530 +0,0 @@
-// Copyright (C) 2016 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.notedb;
-
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assert_;
-import static com.google.common.truth.Truth8.assertThat;
-import static com.google.common.truth.TruthJUnit.assume;
-import static com.google.gerrit.server.notedb.ChangeNoteUtil.formatTime;
-import static com.google.gerrit.server.notedb.NoteDbChangeState.PrimaryStorage.REVIEW_DB;
-import static java.util.concurrent.TimeUnit.DAYS;
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import static java.util.concurrent.TimeUnit.SECONDS;
-import static java.util.stream.Collectors.toList;
-
-import com.github.rholder.retry.Retryer;
-import com.github.rholder.retry.RetryerBuilder;
-import com.github.rholder.retry.StopStrategies;
-import com.google.common.base.Throwables;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
-import com.google.gerrit.acceptance.AbstractDaemonTest;
-import com.google.gerrit.acceptance.NoHttpd;
-import com.google.gerrit.acceptance.PushOneCommit;
-import com.google.gerrit.common.Nullable;
-import com.google.gerrit.common.TimeUtil;
-import com.google.gerrit.extensions.api.changes.DraftInput;
-import com.google.gerrit.extensions.api.changes.ReviewInput;
-import com.google.gerrit.extensions.api.changes.ReviewInput.CommentInput;
-import com.google.gerrit.extensions.client.ChangeStatus;
-import com.google.gerrit.extensions.common.ApprovalInfo;
-import com.google.gerrit.extensions.common.ChangeInfo;
-import com.google.gerrit.extensions.common.CommentInfo;
-import com.google.gerrit.extensions.restapi.RestApiException;
-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.RefNames;
-import com.google.gerrit.reviewdb.server.ReviewDbUtil;
-import com.google.gerrit.server.ChangeMessagesUtil;
-import com.google.gerrit.server.CommentsUtil;
-import com.google.gerrit.server.InternalUser;
-import com.google.gerrit.server.config.AllUsersName;
-import com.google.gerrit.server.git.RepoRefCache;
-import com.google.gerrit.server.notedb.ChangeBundle;
-import com.google.gerrit.server.notedb.ChangeBundleReader;
-import com.google.gerrit.server.notedb.ChangeNotes;
-import com.google.gerrit.server.notedb.ChangeUpdate;
-import com.google.gerrit.server.notedb.NoteDbChangeState;
-import com.google.gerrit.server.notedb.NoteDbChangeState.PrimaryStorage;
-import com.google.gerrit.server.notedb.PrimaryStorageMigrator;
-import com.google.gerrit.server.notedb.TestChangeRebuilderWrapper;
-import com.google.gerrit.server.update.RetryHelper;
-import com.google.gerrit.testutil.ConfigSuite;
-import com.google.gerrit.testutil.NoteDbMode;
-import com.google.gerrit.testutil.TestTimeUtil;
-import com.google.gwtorm.server.OrmException;
-import com.google.gwtorm.server.OrmRuntimeException;
-import com.google.inject.Inject;
-import com.google.inject.util.Providers;
-import java.sql.Timestamp;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Optional;
-import org.eclipse.jgit.lib.Config;
-import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.revwalk.RevCommit;
-import org.eclipse.jgit.revwalk.RevWalk;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-@NoHttpd
-public class NoteDbPrimaryIT extends AbstractDaemonTest {
- @ConfigSuite.Default
- public static Config defaultConfig() {
- Config cfg = new Config();
- cfg.setString("notedb", null, "concurrentWriterTimeout", "0s");
- cfg.setString("notedb", null, "primaryStorageMigrationTimeout", "1d");
- cfg.setBoolean("noteDb", null, "testRebuilderWrapper", true);
- return cfg;
- }
-
- @Inject private AllUsersName allUsers;
- @Inject private ChangeBundleReader bundleReader;
- @Inject private CommentsUtil commentsUtil;
- @Inject private TestChangeRebuilderWrapper rebuilderWrapper;
- @Inject private ChangeNotes.Factory changeNotesFactory;
- @Inject private ChangeUpdate.Factory updateFactory;
- @Inject private InternalUser.Factory internalUserFactory;
- @Inject private RetryHelper retryHelper;
-
- private PrimaryStorageMigrator migrator;
-
- @Before
- public void setUp() throws Exception {
- assume().that(NoteDbMode.get()).isEqualTo(NoteDbMode.READ_WRITE);
- db = ReviewDbUtil.unwrapDb(db);
- TestTimeUtil.resetWithClockStep(1, SECONDS);
- migrator = newMigrator(null);
- }
-
- private PrimaryStorageMigrator newMigrator(
- @Nullable Retryer<NoteDbChangeState> ensureRebuiltRetryer) {
- return new PrimaryStorageMigrator(
- cfg,
- Providers.of(db),
- repoManager,
- allUsers,
- rebuilderWrapper,
- ensureRebuiltRetryer,
- changeNotesFactory,
- queryProvider,
- updateFactory,
- internalUserFactory,
- retryHelper);
- }
-
- @After
- public void tearDown() {
- TestTimeUtil.useSystemTime();
- }
-
- @Test
- public void updateChange() throws Exception {
- PushOneCommit.Result r = createChange();
- Change.Id id = r.getChange().getId();
- setNoteDbPrimary(id);
-
- gApi.changes().id(id.get()).current().review(ReviewInput.approve());
- gApi.changes().id(id.get()).current().submit();
-
- ChangeInfo info = gApi.changes().id(id.get()).get();
- assertThat(info.status).isEqualTo(ChangeStatus.MERGED);
- ApprovalInfo approval = Iterables.getOnlyElement(info.labels.get("Code-Review").all);
- assertThat(approval._accountId).isEqualTo(admin.id.get());
- assertThat(approval.value).isEqualTo(2);
- assertThat(info.messages).hasSize(3);
- assertThat(Iterables.getLast(info.messages).message)
- .isEqualTo("Change has been successfully merged by " + admin.fullName);
-
- ChangeNotes notes = notesFactory.create(db, project, id);
- assertThat(notes.getChange().getStatus()).isEqualTo(Change.Status.MERGED);
- assertThat(notes.getChange().getNoteDbState())
- .isEqualTo(NoteDbChangeState.NOTE_DB_PRIMARY_STATE);
-
- // Writes weren't reflected in ReviewDb.
- assertThat(db.changes().get(id).getStatus()).isEqualTo(Change.Status.NEW);
- assertThat(db.patchSetApprovals().byChange(id)).isEmpty();
- assertThat(db.changeMessages().byChange(id)).hasSize(1);
- }
-
- @Test
- public void deleteDraftComment() throws Exception {
- PushOneCommit.Result r = createChange();
- Change.Id id = r.getChange().getId();
- setNoteDbPrimary(id);
-
- DraftInput din = new DraftInput();
- din.path = PushOneCommit.FILE_NAME;
- din.line = 1;
- din.message = "A comment";
- gApi.changes().id(id.get()).current().createDraft(din);
-
- CommentInfo di =
- Iterables.getOnlyElement(
- gApi.changes().id(id.get()).current().drafts().get(PushOneCommit.FILE_NAME));
- assertThat(di.message).isEqualTo(din.message);
-
- assertThat(db.patchComments().draftByChangeFileAuthor(id, din.path, admin.id)).isEmpty();
-
- gApi.changes().id(id.get()).current().draft(di.id).delete();
- assertThat(gApi.changes().id(id.get()).current().drafts()).isEmpty();
- }
-
- @Test
- public void deleteVote() throws Exception {
- PushOneCommit.Result r = createChange();
- Change.Id id = r.getChange().getId();
- setNoteDbPrimary(id);
-
- gApi.changes().id(id.get()).current().review(ReviewInput.approve());
- List<ApprovalInfo> approvals = gApi.changes().id(id.get()).get().labels.get("Code-Review").all;
- assertThat(approvals).hasSize(1);
- assertThat(approvals.get(0).value).isEqualTo(2);
-
- gApi.changes().id(id.get()).reviewer(admin.id.toString()).deleteVote("Code-Review");
-
- approvals = gApi.changes().id(id.get()).get().labels.get("Code-Review").all;
- assertThat(approvals).hasSize(1);
- assertThat(approvals.get(0).value).isEqualTo(0);
- }
-
- @Test
- public void deleteVoteViaReview() throws Exception {
- PushOneCommit.Result r = createChange();
- Change.Id id = r.getChange().getId();
- setNoteDbPrimary(id);
-
- gApi.changes().id(id.get()).current().review(ReviewInput.approve());
- List<ApprovalInfo> approvals = gApi.changes().id(id.get()).get().labels.get("Code-Review").all;
- assertThat(approvals).hasSize(1);
- assertThat(approvals.get(0).value).isEqualTo(2);
-
- gApi.changes().id(id.get()).current().review(ReviewInput.noScore());
-
- approvals = gApi.changes().id(id.get()).get().labels.get("Code-Review").all;
- assertThat(approvals).hasSize(1);
- assertThat(approvals.get(0).value).isEqualTo(0);
- }
-
- @Test
- public void deleteReviewer() throws Exception {
- PushOneCommit.Result r = createChange();
- Change.Id id = r.getChange().getId();
- setNoteDbPrimary(id);
-
- gApi.changes().id(id.get()).addReviewer(user.id.toString());
- assertThat(getReviewers(id)).containsExactly(user.id);
- gApi.changes().id(id.get()).reviewer(user.id.toString()).remove();
- assertThat(getReviewers(id)).isEmpty();
- }
-
- @Test
- public void readOnlyReviewDb() throws Exception {
- PushOneCommit.Result r = createChange();
- Change.Id id = r.getChange().getId();
- testReadOnly(id);
- }
-
- @Test
- public void readOnlyNoteDb() throws Exception {
- PushOneCommit.Result r = createChange();
- Change.Id id = r.getChange().getId();
- setNoteDbPrimary(id);
- testReadOnly(id);
- }
-
- private void testReadOnly(Change.Id id) throws Exception {
- Timestamp before = TimeUtil.nowTs();
- Timestamp until = new Timestamp(before.getTime() + 1000 * 3600);
-
- // Set read-only.
- Change c = db.changes().get(id);
- assertThat(c).named("change " + id).isNotNull();
- NoteDbChangeState state = NoteDbChangeState.parse(c);
- state = state.withReadOnlyUntil(until);
- c.setNoteDbState(state.toString());
- db.changes().update(Collections.singleton(c));
-
- assertThat(gApi.changes().id(id.get()).get().subject).isEqualTo(PushOneCommit.SUBJECT);
- assertThat(gApi.changes().id(id.get()).get().topic).isNull();
- try {
- gApi.changes().id(id.get()).topic("a-topic");
- assert_().fail("expected read-only exception");
- } catch (RestApiException e) {
- Optional<Throwable> oe =
- Throwables.getCausalChain(e).stream()
- .filter(x -> x instanceof OrmRuntimeException)
- .findFirst();
- assertThat(oe).named("OrmRuntimeException in causal chain of " + e).isPresent();
- assertThat(oe.get().getMessage()).contains("read-only");
- }
- assertThat(gApi.changes().id(id.get()).get().topic).isNull();
-
- TestTimeUtil.setClock(new Timestamp(until.getTime() + 1000));
- assertThat(gApi.changes().id(id.get()).get().subject).isEqualTo(PushOneCommit.SUBJECT);
- gApi.changes().id(id.get()).topic("a-topic");
- assertThat(gApi.changes().id(id.get()).get().topic).isEqualTo("a-topic");
- }
-
- @Test
- public void migrateToNoteDb() throws Exception {
- testMigrateToNoteDb(createChange().getChange().getId());
- }
-
- @Test
- public void migrateToNoteDbWithRebuildingFirst() throws Exception {
- PushOneCommit.Result r = createChange();
- Change.Id id = r.getChange().getId();
-
- Change c = db.changes().get(id);
- c.setNoteDbState("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef");
- db.changes().update(Collections.singleton(c));
- testMigrateToNoteDb(id);
- }
-
- private void testMigrateToNoteDb(Change.Id id) throws Exception {
- assertThat(PrimaryStorage.of(db.changes().get(id))).isEqualTo(PrimaryStorage.REVIEW_DB);
- migrator.migrateToNoteDbPrimary(id);
- assertNoteDbPrimary(id);
-
- gApi.changes().id(id.get()).topic("a-topic");
- assertThat(gApi.changes().id(id.get()).get().topic).isEqualTo("a-topic");
- assertThat(db.changes().get(id).getTopic()).isNull();
- }
-
- @Test
- public void migrateToNoteDbFailsRebuildingOnceAndRetries() throws Exception {
- Change.Id id = createChange().getChange().getId();
-
- Change c = db.changes().get(id);
- c.setNoteDbState("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef");
- db.changes().update(Collections.singleton(c));
- rebuilderWrapper.failNextUpdate();
-
- migrator =
- newMigrator(
- RetryerBuilder.<NoteDbChangeState>newBuilder()
- .retryIfException()
- .withStopStrategy(StopStrategies.neverStop())
- .build());
- migrator.migrateToNoteDbPrimary(id);
- assertNoteDbPrimary(id);
- }
-
- @Test
- public void migrateToNoteDbFailsRebuildingAndStops() throws Exception {
- Change.Id id = createChange().getChange().getId();
-
- Change c = db.changes().get(id);
- c.setNoteDbState("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef");
- db.changes().update(Collections.singleton(c));
- rebuilderWrapper.failNextUpdate();
-
- migrator =
- newMigrator(
- RetryerBuilder.<NoteDbChangeState>newBuilder()
- .retryIfException()
- .withStopStrategy(StopStrategies.stopAfterAttempt(1))
- .build());
- exception.expect(OrmException.class);
- exception.expectMessage("Retrying failed");
- migrator.migrateToNoteDbPrimary(id);
- }
-
- @Test
- public void migrateToNoteDbMissingOldState() throws Exception {
- PushOneCommit.Result r = createChange();
- Change.Id id = r.getChange().getId();
-
- Change c = db.changes().get(id);
- c.setNoteDbState(null);
- db.changes().update(Collections.singleton(c));
-
- exception.expect(OrmRuntimeException.class);
- exception.expectMessage("no note_db_state");
- migrator.migrateToNoteDbPrimary(id);
- }
-
- @Test
- public void migrateToNoteDbLeaseExpires() throws Exception {
- TestTimeUtil.resetWithClockStep(2, DAYS);
- exception.expect(OrmRuntimeException.class);
- exception.expectMessage("read-only lease");
- migrator.migrateToNoteDbPrimary(createChange().getChange().getId());
- }
-
- @Test
- public void migrateToNoteDbAlreadyReadOnly() throws Exception {
- PushOneCommit.Result r = createChange();
- Change.Id id = r.getChange().getId();
-
- Change c = db.changes().get(id);
- NoteDbChangeState state = NoteDbChangeState.parse(c);
- Timestamp until = new Timestamp(TimeUtil.nowMs() + MILLISECONDS.convert(1, DAYS));
- state = state.withReadOnlyUntil(until);
- c.setNoteDbState(state.toString());
- db.changes().update(Collections.singleton(c));
-
- exception.expect(OrmRuntimeException.class);
- exception.expectMessage("read-only until " + until);
- migrator.migrateToNoteDbPrimary(id);
- }
-
- @Test
- public void migrateToNoteDbAlreadyMigrated() throws Exception {
- PushOneCommit.Result r = createChange();
- Change.Id id = r.getChange().getId();
-
- assertThat(PrimaryStorage.of(db.changes().get(id))).isEqualTo(PrimaryStorage.REVIEW_DB);
- migrator.migrateToNoteDbPrimary(id);
- assertNoteDbPrimary(id);
-
- migrator.migrateToNoteDbPrimary(id);
- assertNoteDbPrimary(id);
- }
-
- @Test
- public void rebuildReviewDb() throws Exception {
- Change c = createChange().getChange().change();
- Change.Id id = c.getId();
-
- CommentInput cin = new CommentInput();
- cin.line = 1;
- cin.message = "Published comment";
- ReviewInput rin = ReviewInput.approve();
- rin.comments = ImmutableMap.of(PushOneCommit.FILE_NAME, ImmutableList.of(cin));
- gApi.changes().id(id.get()).current().review(ReviewInput.approve());
-
- DraftInput din = new DraftInput();
- din.path = PushOneCommit.FILE_NAME;
- din.line = 1;
- din.message = "Draft comment";
- gApi.changes().id(id.get()).current().createDraft(din);
- gApi.changes().id(id.get()).current().review(ReviewInput.approve());
- gApi.changes().id(id.get()).current().createDraft(din);
-
- assertThat(db.changeMessages().byChange(id)).isNotEmpty();
- assertThat(db.patchSets().byChange(id)).isNotEmpty();
- assertThat(db.patchSetApprovals().byChange(id)).isNotEmpty();
- assertThat(db.patchComments().byChange(id)).isNotEmpty();
-
- ChangeBundle noteDbBundle =
- ChangeBundle.fromNotes(commentsUtil, notesFactory.create(db, project, id));
-
- setNoteDbPrimary(id);
-
- db.changeMessages().delete(db.changeMessages().byChange(id));
- db.patchSets().delete(db.patchSets().byChange(id));
- db.patchSetApprovals().delete(db.patchSetApprovals().byChange(id));
- db.patchComments().delete(db.patchComments().byChange(id));
- ChangeMessage bogusMessage =
- ChangeMessagesUtil.newMessage(
- c.currentPatchSetId(),
- identifiedUserFactory.create(admin.getId()),
- TimeUtil.nowTs(),
- "some message",
- null);
- db.changeMessages().insert(Collections.singleton(bogusMessage));
-
- rebuilderWrapper.rebuildReviewDb(db, project, id);
-
- assertThat(db.changeMessages().byChange(id)).isNotEmpty();
- assertThat(db.patchSets().byChange(id)).isNotEmpty();
- assertThat(db.patchSetApprovals().byChange(id)).isNotEmpty();
- assertThat(db.patchComments().byChange(id)).isNotEmpty();
-
- ChangeBundle reviewDbBundle = bundleReader.fromReviewDb(ReviewDbUtil.unwrapDb(db), id);
- assertThat(reviewDbBundle.differencesFrom(noteDbBundle)).isEmpty();
- }
-
- @Test
- public void rebuildReviewDbRequiresNoteDbPrimary() throws Exception {
- Change.Id id = createChange().getChange().getId();
-
- exception.expect(OrmException.class);
- exception.expectMessage("primary storage of " + id + " is REVIEW_DB");
- rebuilderWrapper.rebuildReviewDb(db, project, id);
- }
-
- @Test
- public void migrateBackToReviewDbPrimary() throws Exception {
- Change c = createChange().getChange().change();
- Change.Id id = c.getId();
-
- migrator.migrateToNoteDbPrimary(id);
- assertNoteDbPrimary(id);
-
- gApi.changes().id(id.get()).topic("new-topic");
- assertThat(gApi.changes().id(id.get()).topic()).isEqualTo("new-topic");
- assertThat(db.changes().get(id).getTopic()).isNotEqualTo("new-topic");
-
- migrator.migrateToReviewDbPrimary(id, null);
- ObjectId metaId;
- try (Repository repo = repoManager.openRepository(c.getProject());
- RevWalk rw = new RevWalk(repo)) {
- metaId = repo.exactRef(RefNames.changeMetaRef(id)).getObjectId();
- RevCommit commit = rw.parseCommit(metaId);
- rw.parseBody(commit);
- assertThat(commit.getFullMessage())
- .contains("Read-only-until: " + formatTime(serverIdent.get(), new Timestamp(0)));
- }
- NoteDbChangeState state = NoteDbChangeState.parse(db.changes().get(id));
- assertThat(state.getPrimaryStorage()).isEqualTo(PrimaryStorage.REVIEW_DB);
- assertThat(state.getChangeMetaId()).isEqualTo(metaId);
- assertThat(gApi.changes().id(id.get()).topic()).isEqualTo("new-topic");
- assertThat(db.changes().get(id).getTopic()).isEqualTo("new-topic");
-
- ChangeNotes notes = notesFactory.create(db, project, id);
- assertThat(notes.getRevision()).isEqualTo(metaId); // No rebuilding, change was up to date.
- assertThat(notes.getReadOnlyUntil()).isNotNull();
-
- gApi.changes().id(id.get()).topic("reviewdb-topic");
- assertThat(db.changes().get(id).getTopic()).isEqualTo("reviewdb-topic");
- }
-
- private void setNoteDbPrimary(Change.Id id) throws Exception {
- Change c = db.changes().get(id);
- assertThat(c).named("change " + id).isNotNull();
- NoteDbChangeState state = NoteDbChangeState.parse(c);
- assertThat(state.getPrimaryStorage()).named("storage of " + id).isEqualTo(REVIEW_DB);
-
- try (Repository changeRepo = repoManager.openRepository(c.getProject());
- Repository allUsersRepo = repoManager.openRepository(allUsers)) {
- assertThat(state.isUpToDate(new RepoRefCache(changeRepo), new RepoRefCache(allUsersRepo)))
- .named("change " + id + " up to date")
- .isTrue();
- }
-
- c.setNoteDbState(NoteDbChangeState.NOTE_DB_PRIMARY_STATE);
- db.changes().update(Collections.singleton(c));
- }
-
- private void assertNoteDbPrimary(Change.Id id) throws Exception {
- assertThat(PrimaryStorage.of(db.changes().get(id))).isEqualTo(PrimaryStorage.NOTE_DB);
- }
-
- private List<Account.Id> getReviewers(Change.Id id) throws Exception {
- return gApi.changes().id(id.get()).get().reviewers.values().stream()
- .flatMap(Collection::stream)
- .map(a -> new Account.Id(a._accountId))
- .collect(toList());
- }
-}