/** * Copyright 2014 Sunny Gleason and original author or authors * * 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 io.kazuki.v0.store.journal; import static io.kazuki.v0.internal.helper.TestHelper.dump; import static io.kazuki.v0.internal.helper.TestHelper.isEmptyIter; import static io.kazuki.v0.internal.helper.TestHelper.isIterOfLength; import static io.kazuki.v0.internal.helper.TestHelper.isNotEmptyIter; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.number.OrderingComparison.lessThanOrEqualTo; import io.kazuki.v0.internal.helper.Configurations; import io.kazuki.v0.internal.helper.TestSupport; import io.kazuki.v0.store.Foo; import io.kazuki.v0.store.guice.KazukiModule; import io.kazuki.v0.store.jdbi.JdbiDataSourceConfiguration; import io.kazuki.v0.store.keyvalue.KeyValueIterable; import io.kazuki.v0.store.keyvalue.KeyValueIterator; import io.kazuki.v0.store.keyvalue.KeyValuePair; import io.kazuki.v0.store.keyvalue.KeyValueStoreIteration.SortDirection; import io.kazuki.v0.store.lifecycle.Lifecycle; import io.kazuki.v0.store.management.ComponentDescriptor; import io.kazuki.v0.store.management.KazukiComponent; import io.kazuki.v0.store.management.KazukiManager; import io.kazuki.v0.store.schema.SchemaStore; import io.kazuki.v0.store.schema.TypeValidation; import io.kazuki.v0.store.sequence.VersionImpl; import java.io.File; import java.util.LinkedHashMap; import java.util.Map; import org.hamcrest.Matchers; import org.junit.Assert; import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.name.Names; public class PartitionedJournalStoreSmokeTest extends TestSupport { private Injector inject; private JdbiDataSourceConfiguration config; private String dbName; private Lifecycle lifecycle; private SchemaStore manager; private JournalStore journal; @BeforeTest(alwaysRun = true) public void setUp() throws Exception { config = Configurations.getJdbi().build(); dbName = config.getJdbcUrl().substring("jdbc:h2:".length()); inject = Guice.createInjector(new KazukiModule.Builder("foo") .withJdbiConfiguration("foo", Configurations.getJdbi().build()) .withSequenceServiceConfiguration("foo", Configurations.getSequence("foo", "foostore").build()) .withJournalStoreConfiguration( "foo", Configurations.getKeyValue("foo", "foostore").withDataType("foo") .withPartitionSize(10L).build()).build()); lifecycle = inject.getInstance(com.google.inject.Key.get(Lifecycle.class, Names.named("foo"))); manager = inject.getInstance(com.google.inject.Key.get(SchemaStore.class, Names.named("foo"))); journal = inject.getInstance(com.google.inject.Key.get(JournalStore.class, Names.named("foo"))); new File(dbName + ".h2.db").delete(); new File(dbName + ".trace.db").delete(); new File(dbName + ".lock.db").delete(); lifecycle.init(); lifecycle.start(); lifecycle.stop(); lifecycle.shutdown(); lifecycle.init(); lifecycle.start(); } @AfterTest(alwaysRun = true) public void tearDown() throws Exception { lifecycle.stop(); lifecycle.shutdown(); String dbName = config.getJdbcUrl().substring("jdbc:h2:".length()); new File(dbName + ".h2.db").delete(); new File(dbName + ".trace.db").delete(); new File(dbName + ".lock.db").delete(); } @Test(singleThreaded = true) public void testDemo() throws Exception { KazukiManager kzManager = inject.getBinding(com.google.inject.Key.get(KazukiManager.class, Names.named("foo"))) .getProvider().get(); Map<Class, Object> components = new LinkedHashMap<Class, Object>(); for (ComponentDescriptor desc : kzManager.getComponents()) { components.put(desc.getClazz(), desc.getInstance()); } Assert.assertEquals(components.get(Lifecycle.class), ((KazukiComponent) lifecycle) .getComponentDescriptor().getInstance()); Assert.assertEquals(components.get(JournalStore.class), ((KazukiComponent) journal) .getComponentDescriptor().getInstance()); Assert.assertEquals(components.get(SchemaStore.class), ((KazukiComponent) manager) .getComponentDescriptor().getInstance()); assertThat(manager.retrieveSchema("foo"), Matchers.nullValue()); assertThat(journal.getAllPartitions().iterator(), isEmptyIter()); assertThat(manager.createSchema("foo", Foo.FOO_SCHEMA), is(VersionImpl.valueOf("$schema:3#2f73aea89adc5337"))); assertThat(manager.retrieveSchema("foo"), notNullValue()); log.info(dump(journal.getActivePartition())); assertThat(journal.getActivePartition(), nullValue()); try (KeyValueIterator<PartitionInfoSnapshot> theIter = journal.getAllPartitions().iterator()) { assertThat(theIter, isEmptyIter()); } for (int i = 0; i < 100; i++) { journal.append("foo", Foo.class, new Foo("k" + i, "v" + i), TypeValidation.STRICT); if ((i + 1) % 10 != 0) { assertThat(journal.getActivePartition(), notNullValue()); assertThat(journal.getActivePartition().getMinId(), lessThanOrEqualTo(i + 1L)); assertThat(journal.getActivePartition().getMaxId(), is(i + 1L)); } else { assertThat(journal.getActivePartition(), nullValue()); } } try (KeyValueIterator<PartitionInfoSnapshot> piter = journal.getAllPartitions().iterator()) { assertThat(piter, isNotEmptyIter()); log.info("PARTITIONS:"); while (piter.hasNext()) { PartitionInfoSnapshot snap = piter.next(); log.info(" - part - " + dump(snap) + " " + snap.getSize()); assertThat(snap.getSize(), is(10L)); } } Long[][] configs = { {0L, null, 100L}, {0L, 0L, 0L}, {0L, 10L, 10L}, {0L, 20L, 20L}, {11L, 19L, 19L}, {89L, 12L, 11L}, {89L, null, 11L}, {89L, 0L, 0L}}; for (Long[] config : configs) { try (KeyValueIterator<KeyValuePair<Foo>> theIter = journal.entriesAbsolute("foo", Foo.class, SortDirection.ASCENDING, config[0], config[1]) .iterator()) { assertThat(theIter, isIterOfLength(config[2].intValue())); } } try (KeyValueIterator<PartitionInfoSnapshot> theIter = journal.getAllPartitions().iterator()) { assertThat(theIter, isIterOfLength(10)); } journal.append("foo", Foo.class, new Foo("k100", "v100"), TypeValidation.STRICT); assertThat(journal.getActivePartition().getPartitionId(), is("PartitionInfo-foo-foostore:11")); log.info("RELATIVE ITER TEST:"); for (int i = 0; i < 10; i++) { try (KeyValueIterator<KeyValuePair<Foo>> iter = journal.entriesRelative("foo", Foo.class, SortDirection.ASCENDING, Long.valueOf(i * 10), 10L).iterator()) { assertThat(iter, isNotEmptyIter()); int j = 0; while (iter.hasNext()) { Foo foo = iter.next().getValue(); assertThat(foo, notNullValue()); log.info("i=" + i + ",j=" + j + ",foo=" + dump(foo)); j += 1; } assertThat(j, is(10)); } try (KeyValueIterator<KeyValuePair<Foo>> iter = journal.entriesRelative("foo", Foo.class, SortDirection.DESCENDING, Long.valueOf(i * 10), 10L).iterator()) { assertThat(iter, isNotEmptyIter()); int j = 10; while (iter.hasNext()) { Foo foo = iter.next().getValue(); assertThat(foo, notNullValue()); log.info("i=" + i + ",j=" + j + ",foo=" + dump(foo)); j -= 1; } assertThat(j, is(0)); } } log.info("ABSOLUTE ITER TEST:"); for (int i = 0; i < 10; i++) { try (KeyValueIterator<KeyValuePair<Foo>> iter = journal.entriesAbsolute("foo", Foo.class, SortDirection.ASCENDING, Long.valueOf(i * 10), 10L).iterator()) { assertThat(iter, isNotEmptyIter()); int j = 0; while (iter.hasNext()) { Foo foo = iter.next().getValue(); assertThat(foo, notNullValue()); log.info("i=" + i + ",j=" + j + ",foo=" + dump(foo)); j += 1; } assertThat(j, is(10)); } } try (KeyValueIterator<PartitionInfoSnapshot> theIter = journal.getAllPartitions().iterator()) { assertThat(journal.dropPartition(theIter.next().getPartitionId()), is(true)); } log.info("PARTITIONS:"); try (KeyValueIterable<PartitionInfoSnapshot> piter2 = journal.getAllPartitions()) { for (PartitionInfoSnapshot snap : piter2) { log.info(" - part - " + dump(snap)); } } try (KeyValueIterator<PartitionInfoSnapshot> theIter = journal.getAllPartitions().iterator()) { assertThat(theIter, isIterOfLength(10)); } Long[][] absConfigs = { {0L, 10L, 0L}, {10L, 10L, 10L}, {10L, 20L, 20L}, {90L, 10L, 10L}, {90L, 20L, 11L}}; for (Long[] config : absConfigs) { try (KeyValueIterator<KeyValuePair<Foo>> theIter = journal.entriesAbsolute("foo", Foo.class, SortDirection.ASCENDING, config[0], config[1]) .iterator()) { assertThat(theIter, isIterOfLength(config[2].intValue())); } } Long[][] relConfigs = { {0L, null, 91L}, {1L, null, 90L}, {0L, 10L, 10L}, {0L, 20L, 20L}, {11L, 79L, 79L}, {11L, null, 80L}, {10L, 10L, 10L}, {5L, 10L, 10L}, {80L, 10L, 10L}, {90L, 10L, 1L},}; for (Long[] config : relConfigs) { try (KeyValueIterator<KeyValuePair<Foo>> theIter = journal.entriesRelative("foo", Foo.class, SortDirection.ASCENDING, config[0], config[1]) .iterator()) { assertThat(theIter, isIterOfLength(config[2].intValue())); } try (KeyValueIterator<KeyValuePair<Foo>> theIter = journal.entriesRelative("foo", Foo.class, SortDirection.DESCENDING, config[2], config[1]) .iterator()) { int limit = 91 - config[2].intValue(); if (config[1] != null) { limit = Math.min(limit, config[1].intValue()); } assertThat(theIter, isIterOfLength(limit)); } } lifecycle.stop(); lifecycle.shutdown(); lifecycle.init(); lifecycle.start(); for (Long[] config : absConfigs) { try (KeyValueIterator<KeyValuePair<Foo>> theIter = journal.entriesAbsolute("foo", Foo.class, SortDirection.ASCENDING, config[0], config[1]) .iterator()) { assertThat(theIter, isIterOfLength(config[2].intValue())); } } for (Long[] config : relConfigs) { try (KeyValueIterator<KeyValuePair<Foo>> theIter = journal.entriesRelative("foo", Foo.class, SortDirection.ASCENDING, config[0], config[1]) .iterator()) { assertThat(theIter, isIterOfLength(config[2].intValue())); } try (KeyValueIterator<KeyValuePair<Foo>> theIter = journal.entriesRelative("foo", Foo.class, SortDirection.DESCENDING, config[2], config[1]) .iterator()) { int limit = 91 - config[2].intValue(); if (config[1] != null) { limit = Math.min(limit, config[1].intValue()); } assertThat(theIter, isIterOfLength(limit)); } } journal.append("foo", Foo.class, new Foo("ab", "ac"), TypeValidation.STRICT); try (KeyValueIterator<KeyValuePair<Foo>> theIter = journal.entriesAbsolute("foo", Foo.class, SortDirection.ASCENDING, 10L, null).iterator()) { assertThat(theIter, isIterOfLength(92)); } try (KeyValueIterator<KeyValuePair<Foo>> theIter = journal.entriesRelative("foo", Foo.class, SortDirection.ASCENDING, 0L, null).iterator()) { assertThat(theIter, isIterOfLength(92)); } } }