/**
* Copyright 2016 Hortonworks.
*
* 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.hortonworks.registries.storage;
import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;
import com.hortonworks.registries.common.QueryParam;
import com.hortonworks.registries.storage.exception.AlreadyExistsException;
import com.hortonworks.registries.storage.exception.StorageException;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public abstract class AbstractStoreManagerTest {
protected static final Logger log = LoggerFactory.getLogger(AbstractStoreManagerTest.class);
@Rule
public TestName testName = new TestName();
@Rule
public TestWatcher watchman = new TestWatcher() {
@Override
public void starting(final Description method) {
log.info("RUNNING TEST [{}] ", method.getMethodName());
}
};
// To test a new Storable entity type, add it to this list in the implementation of the method setStorableTests
protected List<StorableTest> storableTests;
@Before
public void setup() {
setStorableTests();
for (StorableTest test : storableTests) {
test.setStorageManager(getStorageManager());
}
}
// Method that sets the list of CRUD tests to be run
protected abstract void setStorableTests();
/**
* @return When we add a new implementation for StorageManager interface we will also add a corresponding test implementation
* which will extends this class and implement this method.
* <p>
* Essentially we are going to run the same test defined in this class for every single implementation of StorageManager.
*/
protected abstract StorageManager getStorageManager();
// ================ TEST METHODS ================
// Test methods use the widely accepted naming convention [UnitOfWork_StateUnderTest_ExpectedBehavior]
@Test
public void testCrud_AllStorableEntities_NoExceptions() {
for (StorableTest test : storableTests) {
try {
test.init();
test.test();
} finally {
test.close();
}
}
}
// UnequalExistingStorable => Storable that has the same StorableKey but does NOT verify .equals()
@Test(expected = AlreadyExistsException.class)
public void testAdd_UnequalExistingStorable_AlreadyExistsException() {
for (StorableTest test : storableTests) {
Storable storable1 = test.getStorableList().get(0);
Storable storable2 = test.getStorableList().get(1);
Assert.assertEquals(storable1.getStorableKey(), storable2.getStorableKey());
Assert.assertNotEquals(storable1, storable2);
getStorageManager().add(storable1);
getStorageManager().add(storable2); // should throw exception
}
}
// EqualExistingStorable => Storable that has the same StorableKey and verifies .equals()
@Test
public void testAdd_EqualExistingStorable_NoOperation() {
for (StorableTest test : storableTests) {
Storable storable1 = test.getStorableList().get(0);
getStorageManager().add(storable1);
getStorageManager().addOrUpdate(storable1);
Assert.assertEquals(storable1, getStorageManager().get(storable1.getStorableKey()));
}
}
@Test
public void testRemove_NonExistentStorable_null() {
for (StorableTest test : storableTests) {
Storable removed = getStorageManager().remove(test.getStorableList().get(0).getStorableKey());
Assert.assertNull(removed);
}
}
@Test(expected = StorageException.class)
public void testList_NonexistentNameSpace_StorageException() {
Assert.assertTrue(getStorageManager().list("NONEXISTENT_NAME_SPACE").isEmpty());
}
@Test
public void testFind_NullQueryParams_AllEntries() {
for (StorableTest test : storableTests) {
test.addAllToStorage();
Collection<Storable> allExisting = getStorageManager().list(test.getNameSpace());
Collection<Storable> allMatchingQueryParamsFilter = getStorageManager().find(test.getNameSpace(), null);
assertIterators(allExisting, allMatchingQueryParamsFilter);
}
}
public void assertIterators(Collection collection1, Collection collection2) {
Assert.assertTrue(Iterators.elementsEqual(collection1.iterator(), collection2.iterator()));
}
@Test
public void testFindOrderBy() {
for (StorableTest test : storableTests) {
test.addAllToStorage();
List<QueryParam> queryParams = Collections.emptyList();
Collection<? extends Storable> allExisting = getStorageManager().list(test.getNameSpace());
ArrayList<? extends Storable> sortedStorables = Lists.newArrayList(allExisting);
sortedStorables.sort((Comparator<Storable>) (storable1, storable2) -> (int) (storable2.getId() - storable1.getId()));
List<OrderByField> orderByFields = Lists.newArrayList(OrderByField.of("id", true));
final Collection<Storable> allMatchingOrderByFilter = getStorageManager().find(test.getNameSpace(), queryParams, orderByFields);
System.out.println("allMatchingOrderByFilter = " + allMatchingOrderByFilter);
System.out.println("sortedStorables = " + sortedStorables);
assertIterators(sortedStorables, allMatchingOrderByFilter);
}
}
@Test
public void testFind_NonExistentQueryParams_EmptyList() {
for (StorableTest test : storableTests) {
test.addAllToStorage();
List<QueryParam> queryParams = new ArrayList<QueryParam>() {
{
add(new QueryParam("NON_EXISTING_FIELD_1", "NON_EXISTING_VAL_1"));
add(new QueryParam("NON_EXISTING_FIELD_2", "NON_EXISTING_VAL_2"));
}
};
final Collection<Storable> allMatchingQueryParamsFilter = getStorageManager().find(test.getNameSpace(), queryParams);
assertIterators(Collections.EMPTY_LIST, allMatchingQueryParamsFilter);
}
}
@Test
public void testNextId_AutoincrementColumn_IdPlusOne() throws Exception {
for (StorableTest test : storableTests) {
// Device does not have auto_increment, and therefore there is no concept of nextId and should throw exception
doTestNextId_AutoincrementColumn_IdPlusOne(test);
}
}
protected void doTestNextId_AutoincrementColumn_IdPlusOne(StorableTest test) throws SQLException {
Long actualNextId = getStorageManager().nextId(test.getNameSpace());
Long expectedNextId = actualNextId;
Assert.assertEquals(expectedNextId, actualNextId);
addAndAssertNextId(test, 0, ++expectedNextId);
addAndAssertNextId(test, 2, ++expectedNextId);
addAndAssertNextId(test, 2, expectedNextId);
addAndAssertNextId(test, 3, ++expectedNextId);
}
protected void addAndAssertNextId(StorableTest test, int idx, Long expectedId) throws SQLException {
getStorageManager().addOrUpdate(test.getStorableList().get(idx));
Long nextId = getStorageManager().nextId(test.getNameSpace());
Assert.assertEquals(expectedId, nextId);
}
}