blob: 6907898a6ccfa31466f9e38663db4d0c3554ae02 [file] [log] [blame]
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF 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 org.apache.qpid.server.store;
import java.io.File;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.apache.qpid.server.model.ConfiguredObject;
import org.apache.qpid.server.model.Queue;
import org.apache.qpid.server.store.handler.ConfiguredObjectRecordHandler;
import org.apache.qpid.server.util.ServerScopedRuntimeException;
import org.apache.qpid.test.utils.QpidTestCase;
import org.apache.qpid.test.utils.TestFileUtils;
import org.apache.qpid.util.FileUtils;
import org.mockito.ArgumentMatcher;
import org.mockito.InOrder;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.argThat;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.times;
public class JsonFileConfigStoreTest extends QpidTestCase
{
private JsonFileConfigStore _store;
private HashMap<String, Object> _configurationStoreSettings;
private ConfiguredObject<?> _virtualHost;
private File _storeLocation;
private ConfiguredObjectRecordHandler _handler;
private static final UUID ANY_UUID = UUID.randomUUID();
private static final Map<String, Object> ANY_MAP = new HashMap<String, Object>();
@Override
public void setUp() throws Exception
{
super.setUp();
_virtualHost = mock(ConfiguredObject.class);
when(_virtualHost.getName()).thenReturn(getName());
_storeLocation = TestFileUtils.createTestDirectory("json", true);
_configurationStoreSettings = new HashMap<String, Object>();
_configurationStoreSettings.put(JsonFileConfigStore.STORE_TYPE, JsonFileConfigStore.TYPE);
_configurationStoreSettings.put(JsonFileConfigStore.STORE_PATH, _storeLocation.getAbsolutePath());
_store = new JsonFileConfigStore();
_handler = mock(ConfiguredObjectRecordHandler.class);
when(_handler.handle(any(ConfiguredObjectRecord.class))).thenReturn(true);
}
@Override
public void tearDown() throws Exception
{
try
{
super.tearDown();
}
finally
{
FileUtils.delete(_storeLocation, true);
}
}
public void testNoStorePath() throws Exception
{
_configurationStoreSettings.put(JsonFileConfigStore.STORE_PATH, null);
try
{
_store.openConfigurationStore(_virtualHost, _configurationStoreSettings);
fail("Store should not successfully configure if there is no path set");
}
catch (ServerScopedRuntimeException e)
{
// pass
}
}
public void testInvalidStorePath() throws Exception
{
_configurationStoreSettings.put(JsonFileConfigStore.STORE_PATH, System.getProperty("file.separator"));
try
{
_store.openConfigurationStore(_virtualHost, _configurationStoreSettings);
fail("Store should not successfully configure if there is an invalid path set");
}
catch (ServerScopedRuntimeException e)
{
// pass
}
}
public void testVisitEmptyStore()
{
_store.openConfigurationStore(_virtualHost, _configurationStoreSettings);
_store.visitConfiguredObjectRecords(_handler);
InOrder inorder = inOrder(_handler);
inorder.verify(_handler).begin(eq(0));
inorder.verify(_handler,never()).handle(any(ConfiguredObjectRecord.class));
inorder.verify(_handler).end();
_store.closeConfigurationStore();
}
public void testUpdatedConfigVersionIsRetained() throws Exception
{
final int NEW_CONFIG_VERSION = 42;
when(_handler.end()).thenReturn(NEW_CONFIG_VERSION);
_store.openConfigurationStore(_virtualHost, _configurationStoreSettings);
_store.visitConfiguredObjectRecords(_handler);
_store.closeConfigurationStore();
_store.openConfigurationStore(_virtualHost, _configurationStoreSettings);
_store.visitConfiguredObjectRecords(_handler);
InOrder inorder = inOrder(_handler);
// first time the config version should be the initial version - 0
inorder.verify(_handler).begin(eq(0));
// second time the config version should be the updated version
inorder.verify(_handler).begin(eq(NEW_CONFIG_VERSION));
_store.closeConfigurationStore();
}
public void testCreateObject() throws Exception
{
_store.openConfigurationStore(_virtualHost, _configurationStoreSettings);
final UUID queueId = new UUID(0, 1);
final String queueType = Queue.class.getSimpleName();
final Map<String,Object> queueAttr = Collections.singletonMap("name", (Object) "q1");
_store.create(new ConfiguredObjectRecordImpl(queueId, queueType, queueAttr));
_store.closeConfigurationStore();
_store.openConfigurationStore(_virtualHost, _configurationStoreSettings);
_store.visitConfiguredObjectRecords(_handler);
verify(_handler, times(1)).handle(matchesRecord(queueId, queueType, queueAttr));
_store.closeConfigurationStore();
}
public void testCreateAndUpdateObject() throws Exception
{
_store.openConfigurationStore(_virtualHost, _configurationStoreSettings);
final UUID queueId = new UUID(0, 1);
final String queueType = Queue.class.getSimpleName();
Map<String,Object> queueAttr = Collections.singletonMap("name", (Object) "q1");
_store.create(new ConfiguredObjectRecordImpl(queueId, queueType, queueAttr));
queueAttr = new HashMap<String,Object>(queueAttr);
queueAttr.put("owner", "theowner");
_store.update(false, new ConfiguredObjectRecordImpl(queueId, queueType, queueAttr));
_store.closeConfigurationStore();
_store.openConfigurationStore(_virtualHost, _configurationStoreSettings);
_store.visitConfiguredObjectRecords(_handler);
verify(_handler, times(1)).handle(matchesRecord(queueId, queueType, queueAttr));
_store.closeConfigurationStore();
}
public void testCreateAndRemoveObject() throws Exception
{
_store.openConfigurationStore(_virtualHost, _configurationStoreSettings);
final UUID queueId = new UUID(0, 1);
final String queueType = Queue.class.getSimpleName();
Map<String,Object> queueAttr = Collections.singletonMap("name", (Object) "q1");
final ConfiguredObjectRecordImpl record = new ConfiguredObjectRecordImpl(queueId, queueType, queueAttr);
_store.create(record);
_store.remove(record);
_store.closeConfigurationStore();
_store.openConfigurationStore(_virtualHost, _configurationStoreSettings);
_store.visitConfiguredObjectRecords(_handler);
verify(_handler, never()).handle(any(ConfiguredObjectRecord.class));
_store.closeConfigurationStore();
}
public void testCreateUnknownObjectType() throws Exception
{
_store.openConfigurationStore(_virtualHost, _configurationStoreSettings);
try
{
_store.create(new ConfiguredObjectRecordImpl(UUID.randomUUID(), "wibble", Collections.<String, Object>emptyMap()));
fail("Should not be able to create instance of type wibble");
}
catch (StoreException e)
{
// pass
}
}
public void testTwoObjectsWithSameId() throws Exception
{
_store.openConfigurationStore(_virtualHost, _configurationStoreSettings);
final UUID id = UUID.randomUUID();
_store.create(new ConfiguredObjectRecordImpl(id, "Queue", Collections.<String, Object>emptyMap()));
try
{
_store.create(new ConfiguredObjectRecordImpl(id, "Exchange", Collections.<String, Object>emptyMap()));
fail("Should not be able to create two objects with same id");
}
catch (StoreException e)
{
// pass
}
}
public void testChangeTypeOfObject() throws Exception
{
_store.openConfigurationStore(_virtualHost, _configurationStoreSettings);
final UUID id = UUID.randomUUID();
_store.create(new ConfiguredObjectRecordImpl(id, "Queue", Collections.<String, Object>emptyMap()));
_store.closeConfigurationStore();
_store.openConfigurationStore(_virtualHost, _configurationStoreSettings);
try
{
_store.update(false, new ConfiguredObjectRecordImpl(id, "Exchange", Collections.<String, Object>emptyMap()));
fail("Should not be able to update object to different type");
}
catch (StoreException e)
{
// pass
}
}
public void testLockFileGuaranteesExclusiveAccess() throws Exception
{
_store.openConfigurationStore(_virtualHost, _configurationStoreSettings);
JsonFileConfigStore secondStore = new JsonFileConfigStore();
try
{
secondStore.openConfigurationStore(_virtualHost, _configurationStoreSettings);
fail("Should not be able to open a second store with the same path");
}
catch(ServerScopedRuntimeException e)
{
// pass
}
_store.closeConfigurationStore();
secondStore.openConfigurationStore(_virtualHost, _configurationStoreSettings);
}
public void testCreatedNestedObjects() throws Exception
{
_store.openConfigurationStore(_virtualHost, _configurationStoreSettings);
final UUID queueId = new UUID(0, 1);
final UUID queue2Id = new UUID(1, 1);
final Map<String, Object> EMPTY_ATTR = Collections.emptyMap();
final UUID exchangeId = new UUID(0, 2);
final UUID bindingId = new UUID(0, 3);
final UUID binding2Id = new UUID(1, 3);
final ConfiguredObjectRecordImpl queueRecord = new ConfiguredObjectRecordImpl(queueId, "Queue", EMPTY_ATTR);
_store.create(queueRecord);
final ConfiguredObjectRecordImpl queue2Record = new ConfiguredObjectRecordImpl(queue2Id, "Queue", EMPTY_ATTR);
_store.create(queue2Record);
final ConfiguredObjectRecordImpl exchangeRecord = new ConfiguredObjectRecordImpl(exchangeId, "Exchange", EMPTY_ATTR);
_store.create(exchangeRecord);
Map<String,ConfiguredObjectRecord> bindingParents = new HashMap<String, ConfiguredObjectRecord>();
bindingParents.put("Exchange", exchangeRecord);
bindingParents.put("Queue", queueRecord);
final ConfiguredObjectRecordImpl bindingRecord =
new ConfiguredObjectRecordImpl(bindingId, "Binding", EMPTY_ATTR, bindingParents);
Map<String,ConfiguredObjectRecord> binding2Parents = new HashMap<String, ConfiguredObjectRecord>();
binding2Parents.put("Exchange", exchangeRecord);
binding2Parents.put("Queue", queue2Record);
final ConfiguredObjectRecordImpl binding2Record =
new ConfiguredObjectRecordImpl(binding2Id, "Binding", EMPTY_ATTR, binding2Parents);
_store.update(true, bindingRecord, binding2Record);
_store.closeConfigurationStore();
_store.openConfigurationStore(_virtualHost, _configurationStoreSettings);
_store.visitConfiguredObjectRecords(_handler);
verify(_handler).handle(matchesRecord(queueId, "Queue", EMPTY_ATTR));
verify(_handler).handle(matchesRecord(queue2Id, "Queue", EMPTY_ATTR));
verify(_handler).handle(matchesRecord(exchangeId, "Exchange", EMPTY_ATTR));
verify(_handler).handle(matchesRecord(bindingId, "Binding", EMPTY_ATTR));
verify(_handler).handle(matchesRecord(binding2Id, "Binding", EMPTY_ATTR));
_store.closeConfigurationStore();
}
private ConfiguredObjectRecord matchesRecord(UUID id, String type, Map<String, Object> attributes)
{
return argThat(new ConfiguredObjectMatcher(id, type, attributes));
}
private static class ConfiguredObjectMatcher extends ArgumentMatcher<ConfiguredObjectRecord>
{
private final Map<String,Object> _matchingMap;
private final UUID _id;
private final String _name;
private ConfiguredObjectMatcher(final UUID id, final String type, final Map<String, Object> matchingMap)
{
_id = id;
_name = type;
_matchingMap = matchingMap;
}
@Override
public boolean matches(final Object argument)
{
if(argument instanceof ConfiguredObjectRecord)
{
ConfiguredObjectRecord binding = (ConfiguredObjectRecord) argument;
Map<String,Object> arg = new HashMap<String, Object>(binding.getAttributes());
arg.remove("createdBy");
arg.remove("createdTime");
return (_id == ANY_UUID || _id.equals(binding.getId()))
&& _name.equals(binding.getType())
&& (_matchingMap == ANY_MAP || arg.equals(_matchingMap));
}
return false;
}
}
}