blob: ddb2c3e518117f15d0adc2d3f8cec2c91bbf48bb [file] [log] [blame]
// Copyright (C) 2017 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.googlesource.gerrit.plugins.events.fsstore;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import junit.framework.TestCase;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class FsStoreTest extends TestCase {
private static String dir = "events-FsStore";
private static Path base;
private Path myBase;
private FsStore store;
private String submitMarker = "";
private long count = 1000;
Map<String, Long> reported = new HashMap<String, Long>();
@Override
@Before
public void setUp() throws Exception {
myBase = base;
if (myBase == null) {
myBase = Files.createTempDirectory(dir);
}
store = new FsStore(myBase);
}
@After
public void tearDown() throws Exception {
Fs.tryRecursiveDelete(myBase);
}
@Test
public void testUUIDInit() throws IOException {
UUID uuid = store.getUuid();
FsStore store2 = new FsStore(myBase);
assertEquals(uuid, store2.getUuid());
}
@Test
public void testHeadInit() throws IOException {
assertEquals(0, store.getHead());
FsStore store2 = new FsStore(myBase);
assertEquals(0, store2.getHead());
}
@Test
public void testTailInit() throws IOException {
assertEquals(0, store.getTail());
FsStore store2 = new FsStore(myBase);
assertEquals(0, store2.getTail());
}
@Test
public void testGetInit() throws IOException {
assertEquals(null, store.get(1));
}
@Test
public void testAdd() throws IOException {
add();
}
public void add() throws IOException {
long next = store.getHead() + 1;
assertEquals(0, get(next));
add(next);
assertEquals(next, get(next));
assertEquals(next, store.getHead());
assertEquals(1, store.getTail());
FsStore store2 = new FsStore(myBase);
assertEquals(next, store2.getHead());
assertEquals(1, store2.getTail());
}
private void add(long l) throws IOException {
store.add("" + l);
}
private long get(long i) throws IOException {
String g = store.get(i);
return g == null ? 0 : Long.parseLong(g);
}
@Test
public void testAddAgain() throws IOException {
add();
add();
add();
}
@Test
public void testTrim() throws IOException {
add();
add();
add();
assertEquals(1, store.getTail());
store.trim(1);
assertEquals(2, store.getTail());
assertEquals(0, get(1)); // just deleted
assertEquals(2, get(2)); // beyond deleted
store.trim(2);
assertEquals(3, store.getTail());
assertEquals(0, get(2)); // just deleted
assertEquals(3, get(3)); // beyond deleted
store.trim(3);
assertEquals(3, store.getTail());
assertEquals(3, get(3)); // cannot delete head
}
@Test
public void testCount() throws Exception {
for (long i = 0; i < count; i++) {
add();
}
}
public void count(String id) throws Exception {
for (long i = 1; i <= count; i++) {
store.add(id + " " + i);
System.out.print(submitMarker);
}
}
public boolean verify(String id, long head) throws Exception {
Set<Long> found = new HashSet<Long>();
long stop = store.getHead();
long mine = 1;
for (long i = head + 1; i <= stop; i++) {
String event = store.get(i);
if (event != null) {
String split[] = event.split(" ");
if (split != null && id.equals(split[0])) {
long n = Long.parseLong(split[1]);
if (!found.add(n)) {
report("duplicate", n, i);
}
if (mine != n) {
report("ouf of order", n, i);
}
mine++;
}
} else {
report("gap", mine, i);
}
}
for (long i = 1; i <= count; i++) {
if (!found.contains(i)) {
report("missing", i, -1);
}
}
boolean error = false;
error |= reportTotal("duplicate");
error |= reportTotal("out of order");
error |= reportTotal("missing");
error |= reportTotal("gap");
return error;
}
private void report(String type, long n, long i) {
Long cnt = reported.get(type);
if (cnt == null) {
System.out.println("First " + type + ": " + n + " pos(" + i + ")");
cnt = (long) 0;
}
reported.put(type, ++cnt);
}
private boolean reportTotal(String type) {
Long cnt = reported.get(type);
if (cnt != null) {
System.out.println("Total " + type + "s: " + cnt);
return true;
}
return false;
}
/**
* First, make the junit jar easily available
*
* <p>ln -s ~/.m2/repository/junit/junit/4.8.1/junit-4.8.1.jar target
*
* <p>To run type:
*
* <p>java -cp target/classes:target/test-classes:target/junit-4.8.1.jar \
* com.googlesource.gerrit.plugins.events.fsstore.FsStoreTest \ [dir [count [store-id]]]
*
* <p>Note: if you do not specify <dir>, it will create a directory under /tmp
*
* <p>Performance: NFS(Fast,Lowlatency,SSDs), 1 worker, count=1000, ~6s ~6ms/event
*
* <p>Local(spinning) 5 workers count=100K 11m38.512s find events|wc -l 2s rm -rf 10s
*/
public static void main(String[] argv) throws Exception {
if (argv.length > 0) {
base = Paths.get(argv[0]);
}
FsStoreTest t = new FsStoreTest();
if (argv.length > 1) {
t.count = Long.parseLong(argv[1]);
}
String id = UUID.randomUUID().toString();
t.submitMarker = ".";
if (argv.length > 2) {
id = argv[2];
t.submitMarker += id + ".";
}
t.setUp();
long head = t.store.getHead();
t.count(id);
if (t.verify(id, head)) {
System.out.println("\nFAIL");
System.exit(1);
}
System.out.println("\nPASS");
}
}