package com.feedly.cassandra.dao; import static org.junit.Assert.*; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import me.prettyprint.cassandra.serializers.BytesArraySerializer; import me.prettyprint.cassandra.serializers.DynamicCompositeSerializer; import me.prettyprint.hector.api.beans.DynamicComposite; import me.prettyprint.hector.api.beans.Row; import me.prettyprint.hector.api.factory.HFactory; import me.prettyprint.hector.api.query.RangeSlicesQuery; import org.junit.After; import org.junit.Before; import org.junit.Test; import com.feedly.cassandra.PersistenceManager; import com.feedly.cassandra.entity.enhance.IndexedBean; import com.feedly.cassandra.test.CassandraServiceTestBase; public class OfflineRepairStrategyTest extends CassandraServiceTestBase { PersistenceManager _pm; IndexedBeanDao _dao; private OfflineRepairStrategy _strategy; @Before public void before() { _pm = new PersistenceManager(); _dao = new IndexedBeanDao(); _dao.setKeyspaceFactory(_pm); _strategy = new OfflineRepairStrategy(); _strategy.init(); _dao.setStaleValueIndexStrategy(_strategy); _dao.init(); configurePersistenceManager(_pm); _pm.setPackagePrefixes(new String[] {IndexedBean.class.getPackage().getName()}); _pm.init(); } @After public void after() { _strategy.destroy(); } @Test public void testRepair() { int numBeans = 20; List<IndexedBean> beans = new ArrayList<IndexedBean>(); for(int i = 0; i < numBeans; i++) { IndexedBean idxBean = new IndexedBean(); idxBean.setRowKey(new Long(i)); idxBean.setCharVal((char) ('a' + i)); idxBean.setIntVal(i); idxBean.setLongVal(i/2L); idxBean.setStrVal("strval"); idxBean.setStrVal2(null); beans.add(idxBean); } _dao.mput(beans); for(IndexedBean bean : beans.subList(6, 12)) { bean.setStrVal2(null); bean.setLongVal(-1L); } _dao.mput(beans); IndexedBean tmpl = new IndexedBean(); tmpl.setLongVal(0L); IndexedBean endtmpl = new IndexedBean(); endtmpl.setLongVal(100L); //access incorrect values to trigger repair _dao.mfindBetween(tmpl, endtmpl); _strategy.destroy(); //waits for offline execution to complete...the rest of test method should not create any more stale entries! //incorrect values accessed, check repair was performed (size of index is == to row count) BytesArraySerializer bas = BytesArraySerializer.get(); DynamicCompositeSerializer cas = new DynamicCompositeSerializer(); RangeSlicesQuery<DynamicComposite,DynamicComposite,byte[]> query = HFactory.createRangeSlicesQuery(keyspace, cas, cas, bas); query.setKeys(null, null); query.setColumnFamily("indexedbean_idx"); query.setRange(null, null, false, 100); Row<DynamicComposite, DynamicComposite, byte[]> row = null; Iterator<Row<DynamicComposite, DynamicComposite, byte[]>> iterator = query.execute().get().iterator(); while(iterator.hasNext()) { row = iterator.next(); if(row.getKey().size() == 2 && row.getKey().get(0).equals("longVal")) break; else row = null; } assertEquals(numBeans, row.getColumnSlice().getColumns().size()); //check all values are accessible tmpl.setLongVal(-1L); List<IndexedBean> actuals = new ArrayList<IndexedBean>(_dao.mfind(tmpl)); Collections.sort(actuals); assertEquals(beans.subList(6, 12), actuals); for(int i = 0; i < numBeans; i += 2) { if(i >= 6 && i <=12) continue; tmpl = new IndexedBean(); tmpl.setLongVal(i/2L); actuals = new ArrayList<IndexedBean>(_dao.mfind(tmpl)); Collections.sort(actuals); assertEquals(beans.subList(i, i+2), actuals); } } }