blob: 904de9a487c8a607cb40ad2e63413fb14484a2a2 [file] [log] [blame]
// Copyright (C) 2023 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.rest.config;
import static com.google.common.truth.Truth.assertThat;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.UseLocalDisk;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.index.Index;
import com.google.gerrit.index.IndexType;
import com.google.gerrit.server.config.ConfigResource;
import com.google.gerrit.server.config.IndexResource;
import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.index.account.AccountIndexDefinition;
import com.google.gerrit.server.index.change.ChangeIndexDefinition;
import com.google.gerrit.server.index.group.GroupIndexDefinition;
import com.google.gerrit.server.index.project.ProjectIndexDefinition;
import com.google.gerrit.server.restapi.config.SnapshotIndex;
import com.google.gerrit.server.restapi.config.SnapshotIndexes;
import com.google.gerrit.server.restapi.config.SnapshotInfo;
import com.google.gerrit.testing.SystemPropertiesTestRule;
import com.google.inject.Inject;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Collection;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.junit.ClassRule;
import org.junit.Test;
public class IndexSnapshotsIT extends AbstractDaemonTest {
@ClassRule
public static SystemPropertiesTestRule systemProperties =
new SystemPropertiesTestRule(IndexType.SYS_PROP, "lucene");
@Inject private SnapshotIndex snapshotIndex;
@Inject private SnapshotIndexes snapshotIndexes;
@Inject private AccountIndexDefinition accountIndexDefinition;
@Inject private ChangeIndexDefinition changeIndexDefinition;
@Inject private GroupIndexDefinition groupIndexDefinition;
@Inject private ProjectIndexDefinition projectIndexDefinition;
@Inject private SitePaths sitePaths;
@Test
@UseLocalDisk
public void createAccountsIndexSnapshot() throws Exception {
Query query = new TermQuery(new Term("is", "active"));
createAndVerifySnapshot(new IndexResource(accountIndexDefinition), "accounts", query);
}
@Test
@UseLocalDisk
public void createFullSnapshot() throws Exception {
File snapshot = createSnapshotOfAllIndexes();
File[] members = snapshot.listFiles();
for (File member : members) {
assertThat(member.isDirectory()).isTrue();
verifyIndexCanBeOpen(member);
}
}
@Test
@UseLocalDisk
public void createChangesIndexSnapshot() throws Exception {
Query query = new TermQuery(new Term("status", "open"));
createAndVerifySnapshot(new IndexResource(changeIndexDefinition), "changes", query);
}
@Test
@UseLocalDisk
public void createGroupsIndexSnapshot() throws Exception {
Query query = new TermQuery(new Term("is", "active"));
createAndVerifySnapshot(new IndexResource(groupIndexDefinition), "groups", query);
}
@Test
@UseLocalDisk
public void createProjectsIndexSnapshot() throws Exception {
Query query = new TermQuery(new Term("name", "foo"));
createAndVerifySnapshot(new IndexResource(projectIndexDefinition), "projects", query);
}
private File createAndVerifySnapshot(IndexResource rsrc, String prefix, Query query)
throws IOException {
File snapshot = createSnapshot(rsrc);
File[] subdirs = snapshot.listFiles();
Collection<? extends Index<?, ?>> indexes =
rsrc.getIndexDefinition().getIndexCollection().getWriteIndexes();
assertThat(subdirs).hasLength(indexes.size());
for (Index<?, ?> i : indexes) {
String indexDirName = String.format("%s_%04d", prefix, i.getSchema().getVersion());
File[] result = snapshot.listFiles((d, n) -> n.equals(indexDirName));
assertThat(result).hasLength(1);
File accountsIndexSnapshot = result[0];
openIndexAndQuery(accountsIndexSnapshot, query);
}
return snapshot;
}
private File createSnapshot(IndexResource rsrc) throws IOException {
Response<?> rsp = snapshotIndex.apply(rsrc, new SnapshotIndex.Input());
return verifySnapshot(rsp);
}
private File createSnapshotOfAllIndexes() throws IOException {
Response<?> rsp = snapshotIndexes.apply(new ConfigResource(), new SnapshotIndexes.Input());
return verifySnapshot(rsp);
}
private File verifySnapshot(Response<?> rsp) {
assertThat(rsp.value()).isInstanceOf(SnapshotInfo.class);
SnapshotInfo snapshotInfo = (SnapshotInfo) rsp.value();
Path snapshotDir = sitePaths.index_dir.resolve("snapshots").resolve(snapshotInfo.id);
File snapshot = snapshotDir.toFile();
assertThat(snapshot.exists()).isTrue();
assertThat(snapshot.isDirectory()).isTrue();
return snapshot;
}
private void verifyIndexCanBeOpen(File indexDir) throws IOException {
createIndex(indexDir).tryOpen();
}
private void openIndexAndQuery(File indexDir, Query query) throws IOException {
BaseIndex index = createIndex(indexDir);
index.openAndQuery(query);
}
private BaseIndex createIndex(File indexDir) {
BaseIndex index;
if (indexDir.getName().startsWith("changes")) {
index = new ChangeIndex(indexDir);
} else {
index = new SimpleIndex(indexDir);
}
return index;
}
private abstract static class BaseIndex {
protected File indexDir;
BaseIndex(File indexDir) {
this.indexDir = indexDir;
}
abstract void tryOpen() throws IOException;
abstract void openAndQuery(Query query) throws IOException;
}
private static class SimpleIndex extends BaseIndex {
SimpleIndex(File indexDir) {
super(indexDir);
}
@Override
void tryOpen() throws IOException {
Directory index = FSDirectory.open(indexDir.toPath());
try (IndexReader reader = DirectoryReader.open(index)) {}
}
@Override
void openAndQuery(Query query) throws IOException {
Directory index = FSDirectory.open(indexDir.toPath());
try (IndexReader reader = DirectoryReader.open(index)) {
IndexSearcher searcher = new IndexSearcher(reader);
TopDocs result = searcher.search(query, 10);
System.out.printf("query result length = %d\n", result.scoreDocs.length);
}
}
}
private static class ChangeIndex extends BaseIndex {
private SimpleIndex open;
private SimpleIndex closed;
ChangeIndex(File indexDir) {
super(indexDir);
File[] subDirs = indexDir.listFiles();
for (File subDir : subDirs) {
String name = subDir.getName();
if (name.equals("open")) {
this.open = new SimpleIndex(subDir);
} else if (name.equals("closed")) {
this.closed = new SimpleIndex(subDir);
} else {
throw new IllegalStateException("Unexpected subdir in changes index " + name);
}
}
}
@Override
void tryOpen() throws IOException {
open.tryOpen();
closed.tryOpen();
}
@Override
void openAndQuery(Query query) throws IOException {
open.openAndQuery(query);
closed.openAndQuery(query);
}
}
}