package de.axone.cache.ng; import static de.axone.cache.ng.CacheNGAssert.*; import static de.axone.cache.ng.CacheNGTestHelpers.*; import static de.axone.cache.ng.CacheNGTest_Implementations.*; import static org.assertj.core.api.Assertions.*; import java.util.HashSet; import java.util.List; import java.util.Set; import org.testng.annotations.Test; import de.axone.cache.ng.CacheNG.CacheEventListener; import de.axone.cache.ng.CacheNGTestHelpers.RN; import de.axone.cache.ng.CacheNGTestHelpers.TArticle; import de.axone.cache.ng.CacheNGTestHelpers.Tid; import de.axone.cache.ng.CacheNGTest_ArticleListForTid.TestAccessor_ArticleForTid; import de.axone.cache.ng.CacheNGTest_ArticleListForTid.TestMapTidToArticle; @Test( groups="cacheng.query" ) public class CacheNGTest_ArticleListForSearchQuery { TestMapTidToArticle data = new TestMapTidToArticle(); { data.addArticle( TArticle.build( A12345 ) ); data.addArticle( TArticle.build( A12346 ) ); } static int i=1; TestSearchQuery_Tid t1 = new TestSearchQuery_Tid( tid( "t1" ) ), t1_ = new TestSearchQuery_Tid( tid( "t"+i ) ), t2 = new TestSearchQuery_Tid( tid( "t2" ) ) ; public void euqalsAndHashCode(){ assertThat( t1 ) .isEqualTo( t1_ ) .isNotEqualTo( t2 ) .is( havingSameHashCodeAs( t1_ ) ) .isNot( havingSameHashCodeAs( t2 ) ) ; } public void storeAndRetreiveQuery(){ Set<TestSearchQuery_Tid> set = new HashSet<>(); set.add( t1 ); assertThat( set ).containsOnly( t1 ).hasSize( 1 ); set.add( t2 ); assertThat( set ).containsOnly( t1, t2 ).hasSize( 2 ); set.add( t1_ ); assertThat( set ).containsOnly( t1, t2 ).hasSize( 2 ); set.remove( t1_ ); assertThat( set ).containsOnly( t2 ).hasSize( 1 ); set.remove( t2 ); assertThat( set ).isEmpty(); } public void cacheArticlesForQueries(){ TestAccessor_ArticleForTid forTid = new TestAccessor_ArticleForTid( data ); CacheNG.AutomaticClient<Tid, List<TArticle>> autoForTid = new AutomaticClientImpl<>( new CacheHashMap<>( RN.TID_LARTICLE ) ); TestAccessor_ArticleForQuery forQuery = new TestAccessor_ArticleForQuery( autoForTid, forTid ); CacheNG.AutomaticClient<TestSearchQuery, List<TArticle>> autoForQuery = new AutomaticClientImpl<>( new CacheHashMap<>( RN.SQTID_LARTICLE ) ); TestSearchQuery_Tid q = new TestSearchQuery_Tid( T123 ); assertThat( autoForQuery ).hasNotCached( q ); List<TArticle> arts = autoForQuery.fetch( q, forQuery ); assertThat( autoForQuery ).hasCached( q ); assertThat( arts ).are( havingTid( T123 ) ); // On import of articles: diff oldtids/newtids // Invalidation is done only on the article's tids autoForQuery.invalidate( q ); // Invalidation must propagate to top assertThat( autoForQuery ).hasNotCached( q ); } public void invalidateSearchQueryByInvalidatingTid(){ TestAccessor_ArticleForTid forTid = new TestAccessor_ArticleForTid( data ); CacheHashMap<Tid,List<TArticle>> cacheForTid = new CacheHashMap<>( RN.TID_LARTICLE ); CacheNG.AutomaticClient<Tid, List<TArticle>> autoForTid = new AutomaticClientImpl<>( cacheForTid ); TestAccessor_ArticleForQuery forQuery = new TestAccessor_ArticleForQuery( autoForTid, forTid ); CacheHashMap<TestSearchQuery, List<TArticle>> cacheForQuery = new CacheHashMap<>( RN.SQTID_LARTICLE ); CacheNG.AutomaticClient<TestSearchQuery, List<TArticle>> autoForQuery = new AutomaticClientImpl<>( cacheForQuery ); cacheForTid.registerListener( new TidToQueryBridge( cacheForQuery ) ); TestSearchQuery_Tid q1 = new TestSearchQuery_Tid( T123 ), q2 = new TestSearchQuery_Tid( T234 ); assertThat( autoForQuery ).hasNotCached( q1 ); List<TArticle> arts = autoForQuery.fetch( q1, forQuery ); assertThat( arts ).are( havingTid( T123 ) ); assertThat( autoForQuery ).hasCached( q1 ); arts = autoForQuery.fetch( q2, forQuery ); assertThat( arts ).are( havingTid( T234 ) ); assertThat( autoForQuery ).hasCached( q2 ); autoForQuery.invalidate( q2 ); assertThat( autoForQuery ) .hasNotCached( q2 ) // Now q2 is not cached anymore ... .hasCached( q1 ); // ... but q1 still is // Invalidating the Tid ... autoForTid.invalidate( T123 ); //... invalidates the Query assertThat( autoForQuery ) .hasNotCached( q1 ); } interface TestSearchQuery { public List<TArticle> execute( CacheNG.AutomaticClient<Tid,List<TArticle>> data, CacheNG.SingleValueAccessor<Tid,List<TArticle>> accessor ); } static class TestSearchQuery_Tid implements TestSearchQuery { final Tid tid; public TestSearchQuery_Tid( Tid tid ) { this.tid = tid; } @Override public List<TArticle> execute( CacheNG.AutomaticClient<Tid,List<TArticle>> data, CacheNG.SingleValueAccessor<Tid,List<TArticle>> accessor ){ return data.fetch( tid, accessor ); } @Override public int hashCode() { return tid.hashCode(); } @Override public boolean equals( Object obj ) { if( this == obj ) return true; if( obj == null ) return false; if( !( obj instanceof TestSearchQuery_Tid ) ) return false; TestSearchQuery_Tid other = (TestSearchQuery_Tid) obj; return tid.equals( other.tid ); } } static class TidToQueryBridge extends CacheNG.CacheBridge<Tid,TestSearchQuery>{ public TidToQueryBridge( CacheEventListener<TestSearchQuery> target ) { super( target ); } @Override protected TestSearchQuery_Tid bridge( Tid tid ) { return new TestSearchQuery_Tid( tid ); } } static class TestAccessor_ArticleForQuery implements CacheNG.SingleValueAccessor<TestSearchQuery, List<TArticle>> { private final CacheNG.AutomaticClient<Tid,List<TArticle>> data; private final CacheNG.SingleValueAccessor<Tid,List<TArticle>> accessor; public TestAccessor_ArticleForQuery( CacheNG.AutomaticClient<Tid,List<TArticle>> data, CacheNG.SingleValueAccessor<Tid,List<TArticle>> accessor ) { this.data = data; this.accessor = accessor; } @Override public List<TArticle> fetch( TestSearchQuery identifier ) { return identifier.execute( data, accessor ); } } }