/* * Copyright 2014 WANdisco * * WANdisco licenses this file to you 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 c5db.log; import c5db.C5CommonTestUtil; import c5db.interfaces.LogModule; import c5db.interfaces.log.Reader; import c5db.interfaces.log.SequentialEntry; import c5db.interfaces.replication.QuorumConfiguration; import c5db.interfaces.replication.ReplicatorEntry; import c5db.interfaces.replication.ReplicatorLog; import c5db.replication.generated.LogEntry; import c5db.util.ExceptionHandlingBatchExecutor; import c5db.util.FiberSupplier; import c5db.util.JUnitRuleFiberExceptions; import com.google.common.collect.Sets; import org.jetlang.core.BatchExecutor; import org.jetlang.core.RunnableExecutor; import org.jetlang.core.RunnableExecutorImpl; import org.jetlang.fibers.ThreadFiber; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import java.nio.file.Path; import java.util.List; import java.util.stream.Collectors; import static c5db.interfaces.log.SequentialEntryIterable.SequentialEntryIterator; import static c5db.interfaces.log.SequentialEntryIterableMatchers.isIteratorContainingInOrder; import static c5db.replication.ReplicatorTestUtil.entries; import static org.hamcrest.MatcherAssert.assertThat; public class OLogReaderTest { @Rule public JUnitRuleFiberExceptions throwableHandler = new JUnitRuleFiberExceptions(); private static final String QUORUM_ID = "q"; private final Path baseTestPath = new C5CommonTestUtil().getDataTestDir("o-log-reader-test"); private final FiberSupplier fiberSupplier = makeFiberSupplier(); private final LogModule logModule = new LogService(baseTestPath, fiberSupplier); // initialized after module starts private ReplicatorLog log; @Before public void startLogModule() throws Exception { logModule.startAndWait(); log = logModule.getReplicatorLog(QUORUM_ID).get(); } @After public void shutDownModule() throws Exception { logModule.stopAndWait(); } @Test(timeout = 3000) public void iteratesOverLoggedEntriesWithinASinglePersistence() throws Exception { List<LogEntry> entries = someConsecutiveLogEntries(); havingLogged(entries); Reader<OLogEntry> reader = logModule.getLogReader(QUORUM_ID, new OLogEntry.Codec()); try (SequentialEntryIterator<OLogEntry> iterator = iteratorOfFirstLogInReader(reader)) { assertThat(iterator, isIteratorContainingInOrder(oLogEntries(entries))); } } @Test(timeout = 3000) public void iteratesOverLoggedEntriesWithAnIteratorThatSkipsQuorumConfigurationEntries() throws Exception { List<LogEntry> entries = someEntriesInterspersedWithConfigurationEntries(); havingLogged(entries); Reader<ReplicatorEntry> reader = logModule.getLogReader(QUORUM_ID, new OLogToReplicatorEntryCodec()); try (SequentialEntryIterator<ReplicatorEntry> iterator = iteratorOfFirstLogInReader(reader)) { assertThat(iterator, isIteratorContainingInOrder(justDataEntries(entries))); } } private <E extends SequentialEntry> SequentialEntryIterator<E> iteratorOfFirstLogInReader(Reader<E> reader) throws Exception { return reader.getLogList().get(0).get(); } private void havingLogged(List<LogEntry> entries) throws Exception { log.logEntries(entries).get(); } private List<OLogEntry> oLogEntries(List<LogEntry> entries) { return entries.stream() .map(OLogEntry::fromProtostuff) .collect(Collectors.toList()); } private List<ReplicatorEntry> justDataEntries(List<LogEntry> entries) { return entries.stream() .filter((logEntry) -> logEntry.getQuorumConfiguration() == null) .map((logEntry) -> new ReplicatorEntry(logEntry.getIndex(), logEntry.getDataList())) .collect(Collectors.toList()); } private List<LogEntry> someConsecutiveLogEntries() { return entries() .term(7) .indexes(1, 2, 3, 4, 5, 6) .build(); } private List<LogEntry> someEntriesInterspersedWithConfigurationEntries() { return entries() .term(777) .configurationAndSeqNum(someConfiguration(), 1) .seqNums(2, 3) .configurationAndSeqNum(someConfiguration(), 4) .seqNums(5) .build(); } private QuorumConfiguration someConfiguration() { return QuorumConfiguration.of(Sets.newHashSet(1L, 2L, 3L)); } private FiberSupplier makeFiberSupplier() { return (throwableHandler) -> { BatchExecutor batchExecutor = new ExceptionHandlingBatchExecutor(throwableHandler); RunnableExecutor runnableExecutor = new RunnableExecutorImpl(batchExecutor); return new ThreadFiber(runnableExecutor, "o-log-reader-test-thread", false); }; } }