/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see .
*/
package org.alfresco.repo.index.shard;
import static org.junit.Assert.*;
import static org.mockito.Matchers.*;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.Serializable;
import java.net.UnknownHostException;
import java.util.HashSet;
import java.util.List;
import org.alfresco.repo.cache.DefaultSimpleCache;
import org.alfresco.repo.index.shard.ShardRegistryImpl.ShardStateCollector;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.attributes.AttributeService;
import org.alfresco.service.cmr.attributes.AttributeService.AttributeQueryCallback;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.SearchParameters;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.GUID;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
import org.mockito.Matchers;
/**
* @author Andy
*
*/
@RunWith(MockitoJUnitRunner.class)
public class ShardRegistryTest
{
private ShardRegistryImpl shardRegistry;
private DefaultSimpleCache shardStateCache = new DefaultSimpleCache();
private DefaultSimpleCache shardToGuidCache = new DefaultSimpleCache();
private @Mock AttributeService attributeService;
private @Mock TransactionService transactionService;
private @Mock RetryingTransactionHelper retryingTransactionHelper;
/**
*
*/
public ShardRegistryTest()
{
// TODO Auto-generated constructor stub
}
@Before
public void setUp() throws UnknownHostException
{
shardRegistry = new ShardRegistryImpl();
shardRegistry.setAttributeService(attributeService);
shardRegistry.setShardStateCache(shardStateCache);
shardRegistry.setShardToGuidCache(shardToGuidCache);
shardRegistry.setTransactionService(transactionService);
shardRegistry.setPurgeOnInit(false);
shardRegistry.setShardInstanceTimeoutInSeconds(30);
shardRegistry.setMaxAllowedReplicaTxCountDifference(10);
shardRegistry.init();
when(transactionService.getRetryingTransactionHelper()).thenReturn(retryingTransactionHelper);
final ArgumentCaptor argument = ArgumentCaptor.forClass(RetryingTransactionCallback.class);
when(retryingTransactionHelper.doInTransaction(argument.capture(), anyBoolean(), anyBoolean())).thenAnswer(
new Answer() {
public Object answer(InvocationOnMock invocation) {
try
{
argument.getValue().execute();
}
catch (Throwable e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
});
}
@Test
public void registerLocalShardState()
{
ShardState shardState1 = ShardStateBuilder.shardState().withMaster(true).withLastUpdated(System.currentTimeMillis())
.withShardInstance().withBaseUrl("/solr4/shard1").withHostName("meep").withPort(1234)
.withShard().withInstance(1)
.withFloc().withAddedStoreRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE).withHasContent(true).withNumberOfShards(2).withShardMethod(ShardMethodEnum.MOD_ACL_ID).withTemplate("default")
.endFloc().endShard().endShardInstance().build();
shardRegistry.registerShardState(shardState1);
assertEquals(1, shardToGuidCache.getKeys().size());
assertEquals(1, shardStateCache.getKeys().size());
assertEquals(shardState1, shardStateCache.get(shardState1.getShardInstance()));
String guid1 = shardToGuidCache.get(shardState1.getShardInstance());
verify(attributeService).setAttribute(shardState1, ".SHARD_STATE", guid1);
ShardState shardState2 = ShardStateBuilder.shardState().withMaster(true).withLastUpdated(System.currentTimeMillis())
.withShardInstance().withBaseUrl("/solr4/shard2").withHostName("meep").withPort(1234)
.withShard().withInstance(2)
.withFloc().withAddedStoreRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE).withHasContent(true).withNumberOfShards(2).withShardMethod(ShardMethodEnum.MOD_ACL_ID).withTemplate("default")
.endFloc().endShard().endShardInstance().build();
shardRegistry.registerShardState(shardState2);
assertEquals(2, shardToGuidCache.getKeys().size());
assertEquals(2, shardStateCache.getKeys().size());
assertEquals(shardState2, shardStateCache.get(shardState2.getShardInstance()));
String guid2 = shardToGuidCache.get(shardState2.getShardInstance());
verify(attributeService).setAttribute(shardState2, ".SHARD_STATE", guid2);
// and again
shardRegistry.registerShardState(shardState2);
assertEquals(2, shardToGuidCache.getKeys().size());
assertEquals(2, shardStateCache.getKeys().size());
assertEquals(shardState2, shardStateCache.get(shardState2.getShardInstance()));
verify(attributeService, times(2)).setAttribute(shardState2, ".SHARD_STATE", guid2);
SearchParameters sp = new SearchParameters();
sp.addStore(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE);
List slice = shardRegistry.getIndexSlice(sp);
assertEquals(2, slice.size());
assertTrue(slice.contains(shardState1.getShardInstance()));
assertTrue(slice.contains(shardState2.getShardInstance()));
}
@Test
public void testShardsExpire()
{
ShardState shardState1 = ShardStateBuilder.shardState().withMaster(true).withLastUpdated(System.currentTimeMillis())
.withShardInstance().withBaseUrl("/solr4/shard1").withHostName("meep").withPort(1234)
.withShard().withInstance(1)
.withFloc().withAddedStoreRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE).withHasContent(true).withNumberOfShards(2).withShardMethod(ShardMethodEnum.MOD_ACL_ID).withTemplate("default")
.endFloc().endShard().endShardInstance().build();
shardRegistry.registerShardState(shardState1);
assertEquals(1, shardToGuidCache.getKeys().size());
assertEquals(1, shardStateCache.getKeys().size());
assertEquals(shardState1, shardStateCache.get(shardState1.getShardInstance()));
String guid1 = shardToGuidCache.get(shardState1.getShardInstance());
verify(attributeService).setAttribute(shardState1, ".SHARD_STATE", guid1);
ShardState shardState2 = ShardStateBuilder.shardState().withMaster(true).withLastUpdated(System.currentTimeMillis())
.withShardInstance().withBaseUrl("/solr4/shard2").withHostName("meep").withPort(1234)
.withShard().withInstance(2)
.withFloc().withAddedStoreRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE).withHasContent(true).withNumberOfShards(2).withShardMethod(ShardMethodEnum.MOD_ACL_ID).withTemplate("default")
.endFloc().endShard().endShardInstance().build();
shardRegistry.registerShardState(shardState2);
assertEquals(2, shardToGuidCache.getKeys().size());
assertEquals(2, shardStateCache.getKeys().size());
assertEquals(shardState2, shardStateCache.get(shardState2.getShardInstance()));
String guid2 = shardToGuidCache.get(shardState2.getShardInstance());
verify(attributeService).setAttribute(shardState2, ".SHARD_STATE", guid2);
// and again
shardRegistry.registerShardState(shardState2);
assertEquals(2, shardToGuidCache.getKeys().size());
assertEquals(2, shardStateCache.getKeys().size());
assertEquals(shardState2, shardStateCache.get(shardState2.getShardInstance()));
verify(attributeService, times(2)).setAttribute(shardState2, ".SHARD_STATE", guid2);
SearchParameters sp = new SearchParameters();
sp.addStore(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE);
List slice = shardRegistry.getIndexSlice(sp);
assertEquals(2, slice.size());
assertTrue(slice.contains(shardState1.getShardInstance()));
assertTrue(slice.contains(shardState2.getShardInstance()));
// expire check
synchronized(this)
{
try
{
wait(40000);
}
catch (InterruptedException e)
{
fail("Failed to wait");
}
}
slice = shardRegistry.getIndexSlice(sp);
assertEquals(0, slice.size());
shardState1.setLastUpdated(System.currentTimeMillis());
shardRegistry.registerShardState(shardState1);
slice = shardRegistry.getIndexSlice(sp);
assertEquals(1, slice.size());
shardState2.setLastUpdated(System.currentTimeMillis());
shardRegistry.registerShardState(shardState2);
slice = shardRegistry.getIndexSlice(sp);
assertEquals(2, slice.size());
}
@Test
public void registerHalfPersisted()
{
final String guid1 = GUID.generate();
final ShardState shardState1 = ShardStateBuilder.shardState().withMaster(true).withLastUpdated(System.currentTimeMillis())
.withShardInstance().withBaseUrl("/solr4/shard1").withHostName("meep").withPort(1234)
.withShard().withInstance(1)
.withFloc().withAddedStoreRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE).withHasContent(true).withNumberOfShards(2).withShardMethod(ShardMethodEnum.MOD_ACL_ID).withTemplate("default")
.endFloc().endShard().endShardInstance().build();
doAnswer(new Answer