/* * Copyright © 2014-2016 Cask Data, Inc. * * 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 co.cask.cdap.data2.dataset2; import co.cask.cdap.api.common.Bytes; import co.cask.cdap.api.dataset.DatasetAdmin; import co.cask.cdap.api.dataset.DatasetDefinition; import co.cask.cdap.api.dataset.DatasetManagementException; import co.cask.cdap.api.dataset.DatasetProperties; import co.cask.cdap.api.dataset.DatasetSpecification; import co.cask.cdap.api.dataset.lib.PartitionedFileSetProperties; import co.cask.cdap.api.dataset.lib.Partitioning; import co.cask.cdap.api.dataset.module.DatasetDefinitionRegistry; import co.cask.cdap.api.dataset.module.DatasetModule; import co.cask.cdap.api.dataset.table.Table; import co.cask.cdap.common.app.RunIds; import co.cask.cdap.common.conf.CConfiguration; import co.cask.cdap.common.guice.ConfigModule; import co.cask.cdap.common.guice.LocationRuntimeModule; import co.cask.cdap.data2.audit.AuditModule; import co.cask.cdap.data2.audit.InMemoryAuditPublisher; import co.cask.cdap.data2.dataset2.lib.file.FileSetModule; import co.cask.cdap.data2.dataset2.lib.partitioned.PartitionedFileSetModule; import co.cask.cdap.data2.dataset2.lib.table.CoreDatasetsModule; import co.cask.cdap.data2.dataset2.module.lib.inmemory.InMemoryTableModule; import co.cask.cdap.data2.metadata.writer.LineageWriterDatasetFramework; import co.cask.cdap.data2.metadata.writer.NoOpLineageWriter; import co.cask.cdap.proto.DatasetSpecificationSummary; import co.cask.cdap.proto.Id; import co.cask.cdap.proto.NamespaceMeta; import co.cask.cdap.proto.ProgramType; import co.cask.cdap.proto.audit.AuditMessage; import co.cask.cdap.proto.audit.AuditPayload; import co.cask.cdap.proto.audit.AuditType; import co.cask.cdap.proto.audit.payload.access.AccessPayload; import co.cask.cdap.proto.audit.payload.access.AccessType; import co.cask.cdap.store.NamespaceStore; import co.cask.tephra.DefaultTransactionExecutor; import co.cask.tephra.TransactionAware; import co.cask.tephra.TransactionExecutor; import co.cask.tephra.TransactionExecutorFactory; import co.cask.tephra.inmemory.MinimalTxSystemClient; import co.cask.tephra.runtime.TransactionInMemoryModule; import com.google.common.collect.Maps; import com.google.inject.Guice; import com.google.inject.Injector; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; /** * */ public abstract class AbstractDatasetFrameworkTest { protected abstract DatasetFramework getFramework() throws DatasetManagementException; protected static final Map<String, DatasetModule> DEFAULT_MODULES; static { DEFAULT_MODULES = Maps.newLinkedHashMap(); DEFAULT_MODULES.put("orderedTable-memory", new InMemoryTableModule()); DEFAULT_MODULES.put("core", new CoreDatasetsModule()); } protected static final Id.Namespace NAMESPACE_ID = Id.Namespace.from("myspace"); private static final Id.DatasetModule IN_MEMORY = Id.DatasetModule.from(NAMESPACE_ID, "inMemory"); private static final Id.DatasetModule CORE = Id.DatasetModule.from(NAMESPACE_ID, "core"); private static final Id.DatasetModule FILE = Id.DatasetModule.from(NAMESPACE_ID, "file"); private static final Id.DatasetModule PFS = Id.DatasetModule.from(NAMESPACE_ID, "pfs"); private static final Id.DatasetModule KEY_VALUE = Id.DatasetModule.from(NAMESPACE_ID, "keyValue"); private static final Id.DatasetModule TWICE = Id.DatasetModule.from(NAMESPACE_ID, "embedTwice"); private static final Id.DatasetModule DOUBLE_KV = Id.DatasetModule.from(NAMESPACE_ID, "doubleKeyValue"); private static final Id.DatasetInstance MY_TABLE = Id.DatasetInstance.from(NAMESPACE_ID, "my_table"); private static final Id.DatasetInstance MY_TABLE2 = Id.DatasetInstance.from(NAMESPACE_ID, "my_table2"); private static final Id.DatasetInstance MY_DS = Id.DatasetInstance.from(NAMESPACE_ID, "myds"); private static final Id.DatasetType IN_MEMORY_TYPE = Id.DatasetType.from(NAMESPACE_ID, "table"); private static final Id.DatasetType SIMPLE_KV_TYPE = Id.DatasetType.from(NAMESPACE_ID, SimpleKVTable.class.getName()); private static final Id.DatasetType DOUBLE_KV_TYPE = Id.DatasetType.from(NAMESPACE_ID, DoubleWrappedKVTable.class.getName()); protected static final NamespaceStore NAMESPACE_STORE = new InMemoryNamespaceStore(); protected static DatasetDefinitionRegistryFactory registryFactory; protected static CConfiguration cConf; protected static TransactionExecutorFactory txExecutorFactory; protected static InMemoryAuditPublisher inMemoryAuditPublisher; @BeforeClass public static void setup() throws Exception { cConf = CConfiguration.create(); final Injector injector = Guice.createInjector( new ConfigModule(cConf), new LocationRuntimeModule().getInMemoryModules(), new TransactionInMemoryModule(), new AuditModule().getInMemoryModules()); txExecutorFactory = injector.getInstance(TransactionExecutorFactory.class); registryFactory = new DatasetDefinitionRegistryFactory() { @Override public DatasetDefinitionRegistry create() { DefaultDatasetDefinitionRegistry registry = new DefaultDatasetDefinitionRegistry(); injector.injectMembers(registry); return registry; } }; inMemoryAuditPublisher = injector.getInstance(InMemoryAuditPublisher.class); NAMESPACE_STORE.create(new NamespaceMeta.Builder().setName(NAMESPACE_ID).build()); } @Test public void testSimpleDataset() throws Exception { // Configuring Dataset types DatasetFramework framework = getFramework(); // system namespace has a module orderedTable-inMemory Assert.assertTrue(framework.hasSystemType("table")); // myspace namespace has no modules Assert.assertFalse(framework.hasType(IN_MEMORY_TYPE)); Assert.assertFalse(framework.hasType(SIMPLE_KV_TYPE)); // add module to namespace 'myspace' framework.addModule(KEY_VALUE, new SingleTypeModule(SimpleKVTable.class)); // make sure it got added to 'myspace' Assert.assertTrue(framework.hasType(SIMPLE_KV_TYPE)); // but not to 'system' Assert.assertFalse(framework.hasSystemType(SimpleKVTable.class.getName())); Assert.assertFalse(framework.hasInstance(MY_TABLE)); // Creating instance using a type from own namespace framework.addInstance(SimpleKVTable.class.getName(), MY_TABLE, DatasetProperties.EMPTY); // verify it got added to the right namespace Assert.assertTrue(framework.hasInstance(MY_TABLE)); // and not to the system namespace Assert.assertFalse(framework.hasInstance(Id.DatasetInstance.from(Id.Namespace.SYSTEM, "my_table"))); // Doing some admin and data ops DatasetAdmin admin = framework.getAdmin(MY_TABLE, null); Assert.assertNotNull(admin); final SimpleKVTable kvTable = framework.getDataset(MY_TABLE, DatasetDefinition.NO_ARGUMENTS, null); Assert.assertNotNull(kvTable); TransactionExecutor txnl = new DefaultTransactionExecutor(new MinimalTxSystemClient(), (TransactionAware) kvTable); txnl.execute(new TransactionExecutor.Subroutine() { @Override public void apply() throws Exception { kvTable.put("key1", "value1"); } }); txnl.execute(new TransactionExecutor.Subroutine() { @Override public void apply() throws Exception { Assert.assertEquals("value1", kvTable.get("key1")); } }); admin.truncate(); txnl.execute(new TransactionExecutor.Subroutine() { @Override public void apply() throws Exception { Assert.assertTrue(kvTable.get("key1") == null); } }); // cleanup framework.deleteInstance(MY_TABLE); framework.deleteModule(KEY_VALUE); // recreate instance without adding a module in 'myspace'. This should use types from default namespace framework.addInstance("table", MY_TABLE, DatasetProperties.EMPTY); // verify it got added to the right namespace Assert.assertTrue(framework.hasInstance(MY_TABLE)); admin = framework.getAdmin(MY_TABLE, null); Assert.assertNotNull(admin); final Table table = framework.getDataset(MY_TABLE, DatasetDefinition.NO_ARGUMENTS, null); Assert.assertNotNull(table); txnl.execute(new TransactionExecutor.Subroutine() { @Override public void apply() throws Exception { table.put(Bytes.toBytes("key1"), Bytes.toBytes("column1"), Bytes.toBytes("value1")); } }); txnl.execute(new TransactionExecutor.Subroutine() { @Override public void apply() throws Exception { Assert.assertEquals("value1", Bytes.toString(table.get(Bytes.toBytes("key1"), Bytes.toBytes("column1")))); } }); // cleanup framework.deleteInstance(MY_TABLE); } @Test public void testCompositeDataset() throws Exception { // Configuring Dataset types DatasetFramework framework = getFramework(); framework.addModule(IN_MEMORY, new InMemoryTableModule()); framework.addModule(CORE, new CoreDatasetsModule()); Assert.assertFalse(framework.hasSystemType(SimpleKVTable.class.getName())); Assert.assertFalse(framework.hasType(SIMPLE_KV_TYPE)); framework.addModule(KEY_VALUE, new SingleTypeModule(SimpleKVTable.class)); Assert.assertTrue(framework.hasType(SIMPLE_KV_TYPE)); Assert.assertFalse(framework.hasSystemType(SimpleKVTable.class.getName())); // Creating instance Assert.assertFalse(framework.hasInstance(MY_TABLE)); framework.addInstance(SimpleKVTable.class.getName(), MY_TABLE, DatasetProperties.EMPTY); Assert.assertTrue(framework.hasInstance(MY_TABLE)); testCompositeDataset(framework); // cleanup framework.deleteInstance(MY_TABLE); framework.deleteModule(KEY_VALUE); framework.deleteModule(CORE); framework.deleteModule(IN_MEMORY); } @Test public void testDoubleCompositeDataset() throws Exception { // Configuring Dataset types DatasetFramework framework = getFramework(); framework.addModule(IN_MEMORY, new InMemoryTableModule()); framework.addModule(CORE, new CoreDatasetsModule()); framework.addModule(KEY_VALUE, new SingleTypeModule(SimpleKVTable.class)); Assert.assertFalse(framework.hasSystemType(DoubleWrappedKVTable.class.getName())); Assert.assertFalse(framework.hasType(DOUBLE_KV_TYPE)); framework.addModule(DOUBLE_KV, new SingleTypeModule(DoubleWrappedKVTable.class)); Assert.assertTrue(framework.hasType(DOUBLE_KV_TYPE)); Assert.assertFalse(framework.hasSystemType(DoubleWrappedKVTable.class.getName())); // Creating instance Assert.assertFalse(framework.hasInstance(MY_TABLE)); framework.addInstance(DoubleWrappedKVTable.class.getName(), MY_TABLE, DatasetProperties.EMPTY); Assert.assertTrue(framework.hasInstance(MY_TABLE)); testCompositeDataset(framework); // cleanup framework.deleteInstance(MY_TABLE); framework.deleteModule(DOUBLE_KV); framework.deleteModule(KEY_VALUE); framework.deleteModule(CORE); framework.deleteModule(IN_MEMORY); } private void testCompositeDataset(DatasetFramework framework) throws Exception { // Doing some admin and data ops DatasetAdmin admin = framework.getAdmin(MY_TABLE, null); Assert.assertNotNull(admin); final KeyValueTable table = framework.getDataset(MY_TABLE, DatasetDefinition.NO_ARGUMENTS, null); Assert.assertNotNull(table); TransactionExecutor txnl = new DefaultTransactionExecutor(new MinimalTxSystemClient(), (TransactionAware) table); txnl.execute(new TransactionExecutor.Subroutine() { @Override public void apply() throws Exception { table.put("key1", "value1"); } }); txnl.execute(new TransactionExecutor.Subroutine() { @Override public void apply() throws Exception { Assert.assertEquals("value1", table.get("key1")); } }); admin.truncate(); txnl.execute(new TransactionExecutor.Subroutine() { @Override public void apply() throws Exception { Assert.assertEquals(null, table.get("key1")); } }); } @Test public void testMultipleTransitiveDependencies() throws DatasetManagementException, IOException { // Adding modules DatasetFramework framework = getFramework(); try { framework.addModule(IN_MEMORY, new InMemoryTableModule()); framework.addModule(CORE, new CoreDatasetsModule()); framework.addModule(FILE, new FileSetModule()); framework.addModule(PFS, new PartitionedFileSetModule()); framework.addModule(TWICE, new SingleTypeModule(EmbedsTableTwiceDataset.class)); // Creating an instances framework.addInstance(EmbedsTableTwiceDataset.class.getName(), MY_DS, PartitionedFileSetProperties.builder() .setPartitioning(Partitioning.builder().addStringField("x").build()) .build()); Assert.assertTrue(framework.hasInstance(MY_DS)); framework.getDataset(MY_DS, DatasetProperties.EMPTY.getProperties(), null); } finally { framework.deleteAllInstances(NAMESPACE_ID); framework.deleteAllModules(NAMESPACE_ID); } } @Test public void testBasicManagement() throws Exception { Id.DatasetType tableType = Id.DatasetType.from(NAMESPACE_ID, Table.class.getName()); // Adding modules DatasetFramework framework = getFramework(); framework.addModule(IN_MEMORY, new InMemoryTableModule()); framework.addModule(CORE, new CoreDatasetsModule()); framework.addModule(KEY_VALUE, new SingleTypeModule(SimpleKVTable.class)); // keyvalue has been added in the system namespace Assert.assertTrue(framework.hasSystemType(Table.class.getName())); Assert.assertFalse(framework.hasSystemType(SimpleKVTable.class.getName())); Assert.assertTrue(framework.hasType(tableType)); Assert.assertTrue(framework.hasType(SIMPLE_KV_TYPE)); // Creating instances framework.addInstance(Table.class.getName(), MY_TABLE, DatasetProperties.EMPTY); Assert.assertTrue(framework.hasInstance(MY_TABLE)); DatasetSpecification spec = framework.getDatasetSpec(MY_TABLE); Assert.assertNotNull(spec); Assert.assertEquals(MY_TABLE.getId(), spec.getName()); Assert.assertEquals(Table.class.getName(), spec.getType()); framework.addInstance(Table.class.getName(), MY_TABLE2, DatasetProperties.EMPTY); Assert.assertTrue(framework.hasInstance(MY_TABLE2)); // cleanup try { framework.deleteAllModules(NAMESPACE_ID); Assert.fail("should not delete modules: there are datasets using their types"); } catch (DatasetManagementException e) { // expected } // types are still there Assert.assertTrue(framework.hasType(tableType)); Assert.assertTrue(framework.hasType(SIMPLE_KV_TYPE)); framework.deleteAllInstances(NAMESPACE_ID); Assert.assertEquals(0, framework.getInstances(NAMESPACE_ID).size()); Assert.assertFalse(framework.hasInstance(MY_TABLE)); Assert.assertNull(framework.getDatasetSpec(MY_TABLE)); Assert.assertFalse(framework.hasInstance(MY_TABLE2)); Assert.assertNull(framework.getDatasetSpec(MY_TABLE2)); // now it should succeed framework.deleteAllModules(NAMESPACE_ID); Assert.assertTrue(framework.hasSystemType(Table.class.getName())); Assert.assertFalse(framework.hasType(tableType)); Assert.assertFalse(framework.hasType(SIMPLE_KV_TYPE)); } @Test public void testNamespaceCreationDeletion() throws DatasetManagementException { DatasetFramework framework = getFramework(); Id.Namespace namespace = Id.Namespace.from("yourspace"); framework.createNamespace(namespace); framework.deleteNamespace(namespace); } @Test @SuppressWarnings("ConstantConditions") public void testNamespaceInstanceIsolation() throws Exception { DatasetFramework framework = getFramework(); // create 2 namespaces Id.Namespace namespace1 = Id.Namespace.from("ns1"); Id.Namespace namespace2 = Id.Namespace.from("ns2"); NAMESPACE_STORE.create(new NamespaceMeta.Builder().setName(namespace1).build()); NAMESPACE_STORE.create(new NamespaceMeta.Builder().setName(namespace2).build()); framework.createNamespace(namespace1); framework.createNamespace(namespace2); // create 2 tables, one in each namespace. both tables have the same name. Id.DatasetInstance table1ID = Id.DatasetInstance.from(namespace1, "table"); Id.DatasetInstance table2ID = Id.DatasetInstance.from(namespace2, "table"); // have slightly different properties so that we can distinguish between them framework.addInstance(Table.class.getName(), table1ID, DatasetProperties.builder().add("tag", "table1").build()); framework.addInstance(Table.class.getName(), table2ID, DatasetProperties.builder().add("tag", "table2").build()); // perform some data operations to make sure they are not the same underlying table final Table table1 = framework.getDataset(table1ID, Maps.<String, String>newHashMap(), null); final Table table2 = framework.getDataset(table2ID, Maps.<String, String>newHashMap(), null); TransactionExecutor txnl = new DefaultTransactionExecutor(new MinimalTxSystemClient(), (TransactionAware) table1, (TransactionAware) table2); txnl.execute(new TransactionExecutor.Subroutine() { @Override public void apply() throws Exception { table1.put(Bytes.toBytes("rowkey"), Bytes.toBytes("column"), Bytes.toBytes("val1")); table2.put(Bytes.toBytes("rowkey"), Bytes.toBytes("column"), Bytes.toBytes("val2")); } }); // check data is different, which means they are different underlying tables txnl.execute(new TransactionExecutor.Subroutine() { @Override public void apply() throws Exception { Assert.assertEquals("val1", Bytes.toString(table1.get(Bytes.toBytes("rowkey"), Bytes.toBytes("column")))); Assert.assertEquals("val2", Bytes.toString(table2.get(Bytes.toBytes("rowkey"), Bytes.toBytes("column")))); } }); // check get all in a namespace only includes those in that namespace Collection<DatasetSpecificationSummary> specs = framework.getInstances(namespace1); Assert.assertEquals(1, specs.size()); Assert.assertEquals("table1", specs.iterator().next().getProperties().get("tag")); specs = framework.getInstances(namespace2); Assert.assertEquals(1, specs.size()); Assert.assertEquals("table2", specs.iterator().next().getProperties().get("tag")); // delete one instance and make sure the other still exists framework.deleteInstance(table1ID); Assert.assertFalse(framework.hasInstance(table1ID)); Assert.assertTrue(framework.hasInstance(table2ID)); // delete all instances in one namespace and make sure the other still exists framework.addInstance(Table.class.getName(), table1ID, DatasetProperties.EMPTY); framework.deleteAllInstances(namespace1); Assert.assertTrue(framework.hasInstance(table2ID)); // delete one namespace and make sure the other still exists framework.deleteNamespace(namespace1); Assert.assertTrue(framework.hasInstance(table2ID)); } @Test public void testNamespaceModuleIsolation() throws Exception { DatasetFramework framework = getFramework(); // create 2 namespaces Id.Namespace namespace1 = Id.Namespace.from("ns1"); Id.Namespace namespace2 = Id.Namespace.from("ns2"); NAMESPACE_STORE.create(new NamespaceMeta.Builder().setName(namespace1).build()); NAMESPACE_STORE.create(new NamespaceMeta.Builder().setName(namespace2).build()); framework.createNamespace(namespace1); framework.createNamespace(namespace2); // add modules in each namespace, with one module that shares the same name Id.DatasetModule simpleModuleNs1 = Id.DatasetModule.from(namespace1, SimpleKVTable.class.getName()); Id.DatasetModule simpleModuleNs2 = Id.DatasetModule.from(namespace2, SimpleKVTable.class.getName()); Id.DatasetModule doubleModuleNs2 = Id.DatasetModule.from(namespace2, DoubleWrappedKVTable.class.getName()); DatasetModule module1 = new SingleTypeModule(SimpleKVTable.class); DatasetModule module2 = new SingleTypeModule(DoubleWrappedKVTable.class); framework.addModule(simpleModuleNs1, module1); framework.addModule(simpleModuleNs2, module1); framework.addModule(doubleModuleNs2, module2); // check that we can add instances of datasets in those modules framework.addInstance(SimpleKVTable.class.getName(), Id.DatasetInstance.from(namespace1, "kv1"), DatasetProperties.EMPTY); framework.addInstance(SimpleKVTable.class.getName(), Id.DatasetInstance.from(namespace2, "kv1"), DatasetProperties.EMPTY); // check that only namespace2 can add an instance of this type, since the module should only be in namespace2 framework.addInstance(DoubleWrappedKVTable.class.getName(), Id.DatasetInstance.from(namespace2, "kv2"), DatasetProperties.EMPTY); try { framework.addInstance(DoubleWrappedKVTable.class.getName(), Id.DatasetInstance.from(namespace2, "kv2"), DatasetProperties.EMPTY); Assert.fail(); } catch (Exception e) { // expected } // check that deleting all modules from namespace2 does not affect namespace1 framework.deleteAllInstances(namespace2); framework.deleteAllModules(namespace2); // should still be able to add an instance in namespace1 framework.addInstance(SimpleKVTable.class.getName(), Id.DatasetInstance.from(namespace1, "kv3"), DatasetProperties.EMPTY); // but not in namespace2 try { framework.addInstance(SimpleKVTable.class.getName(), Id.DatasetInstance.from(namespace2, "kv3"), DatasetProperties.EMPTY); Assert.fail(); } catch (Exception e) { // expected } // add back modules to namespace2 framework.addModule(simpleModuleNs2, module1); framework.addModule(doubleModuleNs2, module2); // check that deleting a single module from namespace1 does not affect namespace2 framework.deleteAllInstances(namespace1); framework.deleteModule(simpleModuleNs1); // should still be able to add an instance in namespace2 framework.addInstance(DoubleWrappedKVTable.class.getName(), Id.DatasetInstance.from(namespace2, "kv1"), DatasetProperties.EMPTY); // but not in namespace1 try { framework.addInstance(SimpleKVTable.class.getName(), Id.DatasetInstance.from(namespace1, "kv1"), DatasetProperties.EMPTY); Assert.fail(); } catch (Exception e) { // expected } } @Test public void testAuditPublish() throws Exception { // Clear all audit messages inMemoryAuditPublisher.popMessages(); List<AuditMessage> expectedMessages = new ArrayList<>(); // Adding modules DatasetFramework framework = getFramework(); framework.addModule(IN_MEMORY, new InMemoryTableModule()); // Creating instances framework.addInstance(Table.class.getName(), MY_TABLE, DatasetProperties.EMPTY); expectedMessages.add(new AuditMessage(0, MY_TABLE.toEntityId(), "", AuditType.CREATE, AuditPayload.EMPTY_PAYLOAD)); framework.addInstance(Table.class.getName(), MY_TABLE2, DatasetProperties.EMPTY); expectedMessages.add(new AuditMessage(0, MY_TABLE2.toEntityId(), "", AuditType.CREATE, AuditPayload.EMPTY_PAYLOAD)); // Update instance framework.updateInstance(MY_TABLE, DatasetProperties.EMPTY); expectedMessages.add(new AuditMessage(0, MY_TABLE.toEntityId(), "", AuditType.UPDATE, AuditPayload.EMPTY_PAYLOAD)); // Access instance Id.Run runId = new Id.Run(Id.Program.from("ns", "app", ProgramType.FLOW, "flow"), RunIds.generate().getId()); LineageWriterDatasetFramework lineageFramework = new LineageWriterDatasetFramework(framework, new NoOpLineageWriter()); lineageFramework.initContext(runId); lineageFramework.setAuditPublisher(inMemoryAuditPublisher); lineageFramework.getDataset(MY_TABLE, null, getClass().getClassLoader()); expectedMessages.add(new AuditMessage(0, MY_TABLE.toEntityId(), "", AuditType.ACCESS, new AccessPayload(AccessType.UNKNOWN, runId.toEntityId()))); // Truncate instance framework.truncateInstance(MY_TABLE); expectedMessages.add(new AuditMessage(0, MY_TABLE.toEntityId(), "", AuditType.TRUNCATE, AuditPayload.EMPTY_PAYLOAD)); // Delete instance framework.deleteInstance(MY_TABLE); expectedMessages.add(new AuditMessage(0, MY_TABLE.toEntityId(), "", AuditType.DELETE, AuditPayload.EMPTY_PAYLOAD)); // Delete all instances in a namespace framework.deleteAllInstances(MY_TABLE2.getNamespace()); expectedMessages.add(new AuditMessage(0, MY_TABLE2.toEntityId(), "", AuditType.DELETE, AuditPayload.EMPTY_PAYLOAD)); Assert.assertEquals(expectedMessages, inMemoryAuditPublisher.popMessages()); // cleanup framework.deleteModule(IN_MEMORY); } }