EMMA Coverage Report (generated Thu Jan 20 11:39:44 EST 2011)
[all classes][com.hammurapi.common.store.tests]

COVERAGE SUMMARY FOR SOURCE FILE [LocalStoreTests.java]

nameclass, %method, %block, %line, %
LocalStoreTests.java100% (19/19)94%  (58/62)93%  (2413/2585)93%  (390.3/420)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class LocalStoreTests$10100% (1/1)100% (2/2)74%  (17/23)71%  (5/7)
execute (LocalStore, Transaction, Integer): void 100% (1/1)57%  (8/14)60%  (3/5)
LocalStoreTests$10 (LocalStoreTests, AtomicInteger): void 100% (1/1)100% (9/9)100% (2/2)
     
class LocalStoreTests$1TestTask100% (1/1)100% (2/2)81%  (85/105)66%  (11.2/17)
run (): void 100% (1/1)72%  (52/72)52%  (6.2/12)
LocalStoreTests$1TestTask (LocalStoreTests, long, int, AtomicInteger, AtomicI... 100% (1/1)100% (33/33)100% (5/5)
     
class LocalStoreTests100% (1/1)90%  (19/21)93%  (1836/1976)94%  (325.8/346)
testUniqueIndex (): void 0%   (0/1)0%   (0/63)0%   (0/9)
testViewPut (): void 0%   (0/1)0%   (0/50)0%   (0/8)
testIndex (): void 100% (1/1)94%  (209/223)93%  (35.4/38)
testGetMulti (): void 100% (1/1)98%  (162/166)99%  (24.7/25)
testQuery (): void 100% (1/1)98%  (134/137)99%  (19.9/20)
testUpdate (): void 100% (1/1)98%  (134/137)99%  (19.9/20)
testMultiQuery (): void 100% (1/1)98%  (145/148)99%  (19.9/20)
LocalStoreTests (): void 100% (1/1)100% (18/18)100% (2/2)
setUp (): void 100% (1/1)100% (5/5)100% (2/2)
tearDown (): void 100% (1/1)100% (4/4)100% (2/2)
testCaching (): void 100% (1/1)100% (92/92)100% (22/22)
testDuplicate (): void 100% (1/1)100% (57/57)100% (12/12)
testGet (): void 100% (1/1)100% (89/89)100% (14/14)
testGetAll (): void 100% (1/1)100% (59/59)100% (11/11)
testGetWithExtractAndSort (): void 100% (1/1)100% (178/178)100% (33/33)
testLocalTrackingServiceJoin (): void 100% (1/1)100% (74/74)100% (14/14)
testNoCaching (): void 100% (1/1)100% (96/96)100% (23/23)
testObservable (): void 100% (1/1)100% (133/133)100% (30/30)
testPutGet (): void 100% (1/1)100% (38/38)100% (8/8)
testValidator (): void 100% (1/1)100% (115/115)100% (18/18)
testView (): void 100% (1/1)100% (94/94)100% (15/15)
     
class LocalStoreTests$TestSet100% (1/1)71%  (5/7)96%  (152/158)93%  (27/29)
getMaxTransactionAmount (): BigDecimal 0%   (0/1)0%   (0/3)0%   (0/1)
getMinTransactionAmount (): BigDecimal 0%   (0/1)0%   (0/3)0%   (0/1)
LocalStoreTests$TestSet (LocalStoreTests, int, int): void 100% (1/1)100% (140/140)100% (23/23)
getAccounts (): Collection 100% (1/1)100% (3/3)100% (1/1)
getMaxAccountBalance (): BigDecimal 100% (1/1)100% (3/3)100% (1/1)
getMinAccountBalance (): BigDecimal 100% (1/1)100% (3/3)100% (1/1)
getNumberOfTransactions (): int 100% (1/1)100% (3/3)100% (1/1)
     
class LocalStoreTests$1100% (1/1)100% (2/2)100% (15/15)100% (3/3)
LocalStoreTests$1 (LocalStoreTests, double, TimeUnit, boolean, int []): void 100% (1/1)100% (10/10)100% (2/2)
extractInternal (LocalStore, Map, Account []): BigDecimal 100% (1/1)100% (5/5)100% (1/1)
     
class LocalStoreTests$11100% (1/1)100% (2/2)100% (27/27)100% (3/3)
LocalStoreTests$11 (LocalStoreTests, double, TimeUnit, boolean, int [], BigDe... 100% (1/1)100% (13/13)100% (2/2)
extractInternal (LocalStore, Map, Account []): Boolean 100% (1/1)100% (14/14)100% (1/1)
     
class LocalStoreTests$12100% (1/1)100% (2/2)100% (46/46)100% (8/8)
LocalStoreTests$12 (LocalStoreTests, AtomicInteger, AtomicInteger): void 100% (1/1)100% (12/12)100% (2/2)
execute (LocalStore, Store$Handle): Runnable 100% (1/1)100% (34/34)100% (6/6)
     
class LocalStoreTests$13100% (1/1)100% (2/2)100% (18/18)100% (3/3)
LocalStoreTests$13 (LocalStoreTests, double, TimeUnit, boolean, int []): void 100% (1/1)100% (10/10)100% (2/2)
extractInternal (LocalStore, Map, Account []): Boolean 100% (1/1)100% (8/8)100% (1/1)
     
class LocalStoreTests$14100% (1/1)100% (2/2)100% (18/18)100% (3/3)
LocalStoreTests$14 (LocalStoreTests, double, TimeUnit, boolean, int []): void 100% (1/1)100% (10/10)100% (2/2)
extractInternal (LocalStore, Map, Account []): Boolean 100% (1/1)100% (8/8)100% (1/1)
     
class LocalStoreTests$15100% (1/1)100% (2/2)100% (15/15)100% (3/3)
LocalStoreTests$15 (LocalStoreTests, double, TimeUnit, boolean, int []): void 100% (1/1)100% (10/10)100% (2/2)
extractInternal (LocalStore, Map, Account []): String 100% (1/1)100% (5/5)100% (1/1)
     
class LocalStoreTests$16100% (1/1)100% (2/2)100% (18/18)100% (3/3)
LocalStoreTests$16 (LocalStoreTests, double, TimeUnit, boolean, int []): void 100% (1/1)100% (10/10)100% (2/2)
extractInternal (LocalStore, Map, Account []): Boolean 100% (1/1)100% (8/8)100% (1/1)
     
class LocalStoreTests$2100% (1/1)100% (2/2)100% (19/19)100% (3/3)
LocalStoreTests$2 (LocalStoreTests, double, TimeUnit, boolean, int [], boolea... 100% (1/1)100% (13/13)100% (2/2)
extractInternal (LocalStore, Map, Account []): Boolean 100% (1/1)100% (6/6)100% (1/1)
     
class LocalStoreTests$3100% (1/1)100% (2/2)100% (27/27)100% (3/3)
LocalStoreTests$3 (LocalStoreTests, double, TimeUnit, boolean, int [], BigDec... 100% (1/1)100% (13/13)100% (2/2)
extractInternal (LocalStore, Map, Account []): Boolean 100% (1/1)100% (14/14)100% (1/1)
     
class LocalStoreTests$4100% (1/1)100% (2/2)100% (15/15)100% (3/3)
LocalStoreTests$4 (LocalStoreTests, double, TimeUnit, boolean, int []): void 100% (1/1)100% (10/10)100% (2/2)
extractInternal (LocalStore, Map, Account []): Iterable 100% (1/1)100% (5/5)100% (1/1)
     
class LocalStoreTests$5100% (1/1)100% (2/2)100% (12/12)100% (3/3)
LocalStoreTests$5 (LocalStoreTests): void 100% (1/1)100% (6/6)100% (2/2)
compare (Transaction, Transaction): int 100% (1/1)100% (6/6)100% (1/1)
     
class LocalStoreTests$6100% (1/1)100% (2/2)100% (27/27)100% (3/3)
LocalStoreTests$6 (LocalStoreTests, double, TimeUnit, boolean, int [], BigDec... 100% (1/1)100% (13/13)100% (2/2)
extractInternal (LocalStore, Map, Account []): Boolean 100% (1/1)100% (14/14)100% (1/1)
     
class LocalStoreTests$7100% (1/1)100% (2/2)100% (24/24)100% (5/5)
LocalStoreTests$7 (LocalStoreTests, AtomicInteger, AtomicInteger): void 100% (1/1)100% (12/12)100% (2/2)
execute (LocalStore, Account, Integer): void 100% (1/1)100% (12/12)100% (3/3)
     
class LocalStoreTests$8100% (1/1)100% (2/2)100% (27/27)100% (3/3)
LocalStoreTests$8 (LocalStoreTests, double, TimeUnit, boolean, int [], BigDec... 100% (1/1)100% (13/13)100% (2/2)
extractInternal (LocalStore, Map, Account []): Boolean 100% (1/1)100% (14/14)100% (1/1)
     
class LocalStoreTests$9100% (1/1)100% (2/2)100% (15/15)100% (3/3)
LocalStoreTests$9 (LocalStoreTests, double, TimeUnit, boolean, int []): void 100% (1/1)100% (10/10)100% (2/2)
extractInternal (LocalStore, Map, Account []): Iterable 100% (1/1)100% (5/5)100% (1/1)

1package com.hammurapi.common.store.tests;
2 
3import static org.junit.Assert.assertEquals;
4import static org.junit.Assert.assertNotNull;
5import static org.junit.Assert.assertNotSame;
6import static org.junit.Assert.assertSame;
7import static org.junit.Assert.assertTrue;
8 
9import java.math.BigDecimal;
10import java.util.ArrayList;
11import java.util.Collection;
12import java.util.Comparator;
13import java.util.Date;
14import java.util.LinkedList;
15import java.util.List;
16import java.util.Map;
17import java.util.Random;
18import java.util.concurrent.ExecutorService;
19import java.util.concurrent.Executors;
20import java.util.concurrent.atomic.AtomicBoolean;
21import java.util.concurrent.atomic.AtomicInteger;
22 
23import org.junit.After;
24import org.junit.Before;
25import org.junit.Test;
26 
27import com.hammurapi.common.SimpleObservableConverter;
28import com.hammurapi.common.concurrent.LocalTrackingExecutorService;
29import com.hammurapi.common.extract.tests.Account;
30import com.hammurapi.common.extract.tests.AccountNumberExtractor;
31import com.hammurapi.common.extract.tests.ObservableAccount;
32import com.hammurapi.common.extract.tests.Transaction;
33import com.hammurapi.extract.AbstractExtractor;
34import com.hammurapi.extract.AbstractPredicate;
35import com.hammurapi.extract.Constant;
36import com.hammurapi.extract.Extractor;
37import com.hammurapi.extract.ExtractorFactory;
38import com.hammurapi.extract.LessEqual;
39import com.hammurapi.extract.Predicate;
40import com.hammurapi.store.Index;
41import com.hammurapi.store.MultiIndex;
42import com.hammurapi.store.Store;
43import com.hammurapi.store.Store.Handle;
44import com.hammurapi.store.Store.ViewType;
45import com.hammurapi.store.StoreException;
46import com.hammurapi.store.local.LocalStore;
47import com.hammurapi.store.local.LocalStoreBase.Config;
48import com.hammurapi.store.local.LocalStoreImpl;
49 
50public class LocalStoreTests {                
51        
52        private static final String HAMMURAPI_GROUP = "Hammurapi Group";
53        private ExecutorService executorService;
54 
55        @Before
56        public void setUp() throws Exception {
57                executorService = Executors.newFixedThreadPool(10);
58        }
59 
60        @After
61        public void tearDown() throws Exception {
62                executorService.shutdown();
63        }
64        
65        @Test
66        public void testPutGet() {
67                Config<Account, Integer, LocalStore<Account, Integer>> config = new Config<Account, Integer, LocalStore<Account, Integer>>();
68                config.setPrimaryKeyExtractor(new AccountNumberExtractor());
69                config.setExecutorService(executorService);
70                LocalStore<Account, Integer> store = new LocalStoreImpl<Account,Integer>(config);
71                
72                Account account = new Account(HAMMURAPI_GROUP, 123, null);
73                store.put(account);
74                assertSame(account, store.getByPrimaryKey(123));                                
75        }
76        
77        @Test
78        public void testDuplicate() {
79                Config<Account, Integer, LocalStore<Account, Integer>> config = new Config<Account, Integer, LocalStore<Account, Integer>>();
80                config.setPrimaryKeyExtractor(new AccountNumberExtractor());
81                config.setExecutorService(executorService);                
82                LocalStore<Account, Integer> store = new LocalStoreImpl<Account,Integer>(config);
83                
84                Account account = new Account(HAMMURAPI_GROUP, 123, null);
85                store.put(account);
86                
87                Account account2 = new Account(HAMMURAPI_GROUP, 123, null);
88                store.put(account2);
89                Account result = store.getByPrimaryKey(123);
90                assertNotSame(account, result);
91                assertSame(account2, result);                
92                
93        }
94        
95        @Test
96        public void testGetAll() {
97                Config<Account, Integer, LocalStore<Account, Integer>> config = new Config<Account, Integer, LocalStore<Account, Integer>>();
98                config.setPrimaryKeyExtractor(new AccountNumberExtractor());
99                config.setExecutorService(executorService);                
100                LocalStore<Account, Integer> store = new LocalStoreImpl<Account,Integer>(config);
101                
102                store.put(new Account(HAMMURAPI_GROUP, 123, null));                
103                store.put(new Account(HAMMURAPI_GROUP, 456, null));
104 
105                int cnt = 0;
106                for (Account a: store) {
107                        ++cnt;
108                }
109                
110                assertEquals(cnt, 2);                
111        }
112        
113        private Extractor<Account, BigDecimal, LocalStore<Account, Integer>> balanceExtractor = new AbstractExtractor<Account, BigDecimal, LocalStore<Account, Integer>>(0, null, false, 0) {
114 
115                @Override
116                protected BigDecimal extractInternal(
117                                LocalStore<Account, Integer> context,
118                                Map<LocalStore<Account, Integer>, Map<Extractor<Account, ? super BigDecimal, LocalStore<Account, Integer>>, ? super BigDecimal>> cache,
119                                Account... obj) {
120                        return obj[0].getBalance();
121                }
122                
123        };
124        
125        @Test
126        public void testGet() {
127                Config<Account, Integer, LocalStore<Account, Integer>> config = new Config<Account, Integer, LocalStore<Account, Integer>>();
128                config.setPrimaryKeyExtractor(new AccountNumberExtractor());
129                config.setExecutorService(executorService);                
130                LocalStore<Account, Integer> store = new LocalStoreImpl<Account,Integer>(config);
131                
132                store.put(new Account(HAMMURAPI_GROUP, 123, new BigDecimal(1580.00)));                
133                store.put(new Account(HAMMURAPI_GROUP, 456, new BigDecimal(330.67)));                
134                
135                int cnt = 0;
136                Constant<Account, BigDecimal, LocalStore<Account, Integer>> constant = new Constant<Account, BigDecimal, LocalStore<Account, Integer>>(new BigDecimal(330.67));
137                Predicate<Account, LocalStore<Account, Integer>> balancePredicate = new LessEqual<Account, BigDecimal, LocalStore<Account, Integer>>(-1, null, balanceExtractor, constant);
138                for (Account a: store.get(balancePredicate)) {
139                        ++cnt;
140                        assertEquals(constant.getValue(), a.getBalance());
141                }
142                
143                assertEquals(cnt, 1);                
144        }
145        
146        @Test
147        public void testValidator() {
148                Config<Account, Integer, LocalStore<Account, Integer>> config = new Config<Account, Integer, LocalStore<Account, Integer>>();
149                config.setPrimaryKeyExtractor(new AccountNumberExtractor());
150                config.setExecutorService(executorService);                
151                LocalStore<Account, Integer> store = new LocalStoreImpl<Account,Integer>(config);
152                
153                final boolean[] ok = {true};
154                
155                Predicate<Account, LocalStore<Account, Integer>> validator = new AbstractPredicate<Account, LocalStore<Account, Integer>>(0, null, false, 0) {
156 
157                        @Override
158                        protected Boolean extractInternal(
159                                        LocalStore<Account, Integer> context,
160                                        Map<LocalStore<Account, Integer>, Map<Extractor<Account, ? super Boolean, LocalStore<Account, Integer>>, ? super Boolean>> cache,
161                                        Account... obj) {
162                                return ok[0];
163                        }
164                };                
165                
166                store.put(new Account(HAMMURAPI_GROUP, 123, new BigDecimal(1580.00)), validator);                
167                store.put(new Account(HAMMURAPI_GROUP, 456, new BigDecimal(330.67)));                
168 
169                // Verify two accounts in the store.
170                int cnt =  0;
171                for (Account a: store.getAll()) {
172                        ++cnt;
173                }
174                assertEquals(2, cnt);
175                
176                // Invalidate the first one
177                ok[0] = false;
178                
179                cnt =  0;
180                for (Account a: store.getAll()) {
181                        ++cnt;
182                }
183                assertEquals(1, cnt);
184                
185        }
186        
187        @Test
188        public void testCaching() {
189                Config<Account, Integer, LocalStore<Account, Integer>> config = new Config<Account, Integer, LocalStore<Account, Integer>>();
190                config.setPrimaryKeyExtractor(new AccountNumberExtractor());
191                config.setExecutorService(executorService);                
192                LocalStore<Account, Integer> store = new LocalStoreImpl<Account,Integer>(config);
193                
194                Account account = new Account(HAMMURAPI_GROUP, 123, new BigDecimal(1580.00));
195                Handle<Account, Integer, LocalStore<Account, Integer>> handle = store.put(account);
196                
197                Extractor<Account,BigDecimal, LocalStore<Account, Integer>> balanceExtractor = ExtractorFactory.INSTANCE.createExtractor(
198                                "java",
199                                "account.getBalance()", 
200                                new String[] {"account"}, 
201                                new Class[] {Account.class},
202                                BigDecimal.class, 
203                                Store.class, 
204                                this.getClass().getClassLoader());
205 
206                assertNotNull("Extractor is null, check classpath for java extractors", balanceExtractor);
207                BigDecimal balance = handle.extract(balanceExtractor);
208                assertEquals(new BigDecimal(1580.00), balance);
209                assertEquals(1, account.getNumberOfBalanceInquiries());
210                balance = handle.extract(balanceExtractor);
211                assertEquals(new BigDecimal(1580.00), balance);
212                assertEquals(1, account.getNumberOfBalanceInquiries());
213        }
214        
215        @Test
216        public void testObservable() {
217                Config<Account, Integer, LocalStore<Account, Integer>> config = new Config<Account, Integer, LocalStore<Account, Integer>>();
218                config.setPrimaryKeyExtractor(new AccountNumberExtractor());
219                config.setExecutorService(executorService);                
220                config.setObservableConverter(new SimpleObservableConverter<Account>());
221                LocalStore<Account, Integer> store = new LocalStoreImpl<Account,Integer>(config);
222                
223                ObservableAccount account = new ObservableAccount(HAMMURAPI_GROUP, 123, new BigDecimal(1580.00));
224                Handle<Account, Integer, LocalStore<Account, Integer>> handle = store.put(account);
225                assertEquals(1, account.countObservers());                
226                
227                Extractor<Account,BigDecimal, LocalStore<Account, Integer>> balanceExtractor = ExtractorFactory.INSTANCE.createExtractor(
228                                "java",
229                                "account.getBalance()", 
230                                new String[] {"account"}, 
231                                new Class[] {Account.class},
232                                BigDecimal.class, 
233                                Store.class, 
234                                this.getClass().getClassLoader());
235                
236                assertNotNull("Extractor is null, check classpath for java extractors", balanceExtractor);
237                BigDecimal balance = handle.extract(balanceExtractor);
238                assertEquals(new BigDecimal(1580.00), balance);
239                assertEquals(1, account.getNumberOfBalanceInquiries());
240                balance = handle.extract(balanceExtractor);
241                assertEquals(new BigDecimal(1580.00), balance);
242                assertEquals(1, account.getNumberOfBalanceInquiries());
243                
244                // Update balance, retrieve
245                account.setBalance(new BigDecimal(33.00));
246                BigDecimal newBalance = handle.extract(balanceExtractor);
247                assertEquals(new BigDecimal(33.00), newBalance);
248                assertEquals(2, account.getNumberOfBalanceInquiries());
249                
250                store.remove(account);
251                assertEquals(0, account.countObservers());
252        }
253        
254        @Test
255        public void testNoCaching() {
256                Config<Account, Integer, LocalStore<Account, Integer>> config = new Config<Account, Integer, LocalStore<Account, Integer>>();
257                config.setPrimaryKeyExtractor(new AccountNumberExtractor());
258                config.setExecutorService(executorService);
259                config.setCacheExtracted(false);
260                LocalStore<Account, Integer> store = new LocalStoreImpl<Account,Integer>(config);
261                
262                Account account = new Account(HAMMURAPI_GROUP, 123, new BigDecimal(1580.00));
263                Handle<Account, Integer, LocalStore<Account, Integer>> handle = store.put(account);
264                
265                Extractor<Account,BigDecimal, LocalStore<Account, Integer>> balanceExtractor = ExtractorFactory.INSTANCE.createExtractor(
266                                "jxpath",
267                                "$account/balance", 
268                                new String[] {"account"}, 
269                                new Class[] {Account.class},
270                                BigDecimal.class, 
271                                store.getClass(), 
272                                this.getClass().getClassLoader());
273 
274                assertNotNull("Extractor is null, check classpath for java extractors", balanceExtractor);
275                BigDecimal balance = handle.extract(balanceExtractor);
276                assertEquals(new BigDecimal(1580.00), balance);
277                assertEquals(1, account.getNumberOfBalanceInquiries());
278                balance = handle.extract(balanceExtractor);
279                assertEquals(new BigDecimal(1580.00), balance);
280                assertEquals(2, account.getNumberOfBalanceInquiries());
281        }
282        
283        @Test
284        public void testGetWithExtractAndSort() {
285                Config<Account, Integer, LocalStore<Account, Integer>> config = new Config<Account, Integer, LocalStore<Account, Integer>>();
286                config.setPrimaryKeyExtractor(new AccountNumberExtractor());
287                config.setExecutorService(executorService);                
288                LocalStore<Account, Integer> store = new LocalStoreImpl<Account,Integer>(config);
289                
290                store.put(new Account(HAMMURAPI_GROUP, 789, new BigDecimal(23000.33)));                
291                store.put(new Account(HAMMURAPI_GROUP, 888, new BigDecimal(31580.00)));                
292                store.put(new Account(HAMMURAPI_GROUP, 123, new BigDecimal(1580.00)));                
293                store.put(new Account(HAMMURAPI_GROUP, 456, new BigDecimal(330.67)));
294                
295                // Extract by account number, order by balance.
296                Predicate<Account, LocalStore<Account, Integer>> predicate = ExtractorFactory.INSTANCE.createPredicate(
297                                "javascript",
298                                "account.getNumber()!=123", 
299                                new String[] {"account"}, 
300                                new Class[] {Account.class},
301                                store.getClass(), 
302                                this.getClass().getClassLoader());
303                
304                assertNotNull("Predicate is null, check language name", predicate);
305                
306                Extractor<Account,BigDecimal, LocalStore<Account, Integer>> balanceExtractor = ExtractorFactory.INSTANCE.createExtractor(
307                                "jxpath",
308                                "$account/balance", 
309                                new String[] {"account"}, 
310                                new Class[] {Account.class},
311                                BigDecimal.class, 
312                                store.getClass(), 
313                                this.getClass().getClassLoader());
314                
315                assertNotNull(balanceExtractor);
316 
317                List<BigDecimal> results = new ArrayList<BigDecimal>();
318                for (BigDecimal balance: store.get(predicate, balanceExtractor, true, null)) {
319                        results.add(balance);
320                }
321 
322                assertEquals(3, results.size());
323                assertEquals(new BigDecimal(330.67), results.get(0));
324                assertEquals(new BigDecimal(23000.33), results.get(1));                
325                assertEquals(new BigDecimal(31580.00), results.get(2));                                
326        }
327        
328        private class TestSet {
329                
330                private BigDecimal minTransactionAmount;
331                private BigDecimal maxTransactionAmount;
332                
333                private BigDecimal minAccountBalance;
334                private BigDecimal maxAccountBalance; 
335                
336                private int numberOfTransactions;
337                
338                private Collection<Account> accounts = new LinkedList<Account>();
339                
340                public TestSet(int numberOfAccunts, int numberOfTransactionsPerAccount) {
341                        Random random = new Random(System.currentTimeMillis());
342                        for (int i=0; i<numberOfAccunts; ++i) {
343                                BigDecimal accountBalance = new BigDecimal(random.nextDouble()*1000000);
344                                Account account = new Account(HAMMURAPI_GROUP, random.nextInt(1000000), accountBalance);
345                                accounts.add(account);
346                                if (minAccountBalance==null || minAccountBalance.compareTo(accountBalance)>0) {
347                                        minAccountBalance = accountBalance;
348                                }
349                                if (maxAccountBalance==null || maxAccountBalance.compareTo(accountBalance)<0) {
350                                        maxAccountBalance = accountBalance;
351                                }
352                                for (int j=0, l=random.nextInt(numberOfTransactionsPerAccount*2); j<l; ++j) {
353                                        Transaction t = new Transaction(false);
354                                        BigDecimal transactionAmount = new BigDecimal(random.nextDouble()*1000);
355                                        t.setAmount(transactionAmount);
356                                        t.setDate(new Date(System.currentTimeMillis()+ random.nextInt(10000000)));
357                                        account.getTransactionsImmediately().add(t);
358                                        if (minTransactionAmount==null || minTransactionAmount.compareTo(transactionAmount)>0) {
359                                                minTransactionAmount = transactionAmount;
360                                        }
361                                        if (maxTransactionAmount==null || maxTransactionAmount.compareTo(transactionAmount)<0) {
362                                                maxTransactionAmount = transactionAmount;
363                                        }
364                                        
365                                        ++numberOfTransactions;
366                                }
367                        }
368                }
369 
370                Collection<Account> getAccounts() {
371                        return accounts;
372                }
373 
374                public BigDecimal getMinTransactionAmount() {
375                        return minTransactionAmount;
376                }
377 
378                public BigDecimal getMaxTransactionAmount() {
379                        return maxTransactionAmount;
380                }
381 
382                public BigDecimal getMinAccountBalance() {
383                        return minAccountBalance;
384                }
385 
386                public BigDecimal getMaxAccountBalance() {
387                        return maxAccountBalance;
388                }
389 
390                public int getNumberOfTransactions() {
391                        return numberOfTransactions;
392                }
393                
394                
395        }
396        
397        @Test
398        public void testGetMulti() {
399                Config<Account, Integer, LocalStore<Account, Integer>> config = new Config<Account, Integer, LocalStore<Account, Integer>>();
400                config.setPrimaryKeyExtractor(new AccountNumberExtractor());
401                config.setExecutorService(executorService);                
402                LocalStore<Account, Integer> store = new LocalStoreImpl<Account,Integer>(config);
403                
404                TestSet testSet = new TestSet(20, 100);
405                for (Account a: testSet.getAccounts()) {
406                        store.put(a);                        
407                }
408                
409                // Select transactions from accounts with more than average balance ordered transaction amount.
410                final BigDecimal averageBalance = testSet.getMinAccountBalance().add(testSet.getMaxAccountBalance()).divide(new BigDecimal(2));
411                
412                Predicate<Account, LocalStore<Account, Integer>> selector = new AbstractPredicate<Account, LocalStore<Account, Integer>>(0, null, false, 0) {
413 
414                        @Override
415                        protected Boolean extractInternal(
416                                        LocalStore<Account, Integer> context,
417                                        Map<LocalStore<Account, Integer>, Map<Extractor<Account, ? super Boolean, LocalStore<Account, Integer>>, ? super Boolean>> cache,
418                                        Account... obj) {
419                                return obj[0].getBalance().compareTo(averageBalance)>0;
420                        }
421                };
422                                                
423                Extractor<Account, Iterable<Transaction>, LocalStore<Account, Integer>>  extractor = new AbstractExtractor<Account, Iterable<Transaction>, LocalStore<Account, Integer>>(0, null, false, 0) {
424 
425                        @Override
426                        protected Iterable<Transaction> extractInternal(
427                                        LocalStore<Account, Integer> context,
428                                        Map<LocalStore<Account, Integer>, Map<Extractor<Account, ? super Iterable<Transaction>, LocalStore<Account, Integer>>, ? super Iterable<Transaction>>> cache,
429                                        Account... obj) {
430                                return obj[0].getTransactions();
431                        }
432                };
433                
434                Comparator<Transaction> comparator = new Comparator<Transaction>() {
435                        
436                        @Override
437                        public int compare(Transaction o1, Transaction o2) {
438                                return o1.getAmount().compareTo(o2.getAmount());
439                        }
440                        
441                };
442                
443                long start = System.currentTimeMillis();
444                
445                // Verify that transactions are ordered and that the total number of transactions
446                // is more than 0 and less than total.
447                BigDecimal lastAmount = null;
448                int totalTransactions = 0;
449                for (Transaction t: store.getMultiple(selector, extractor, null, true, comparator)) {
450                        if (lastAmount!=null) {
451                                assertTrue("Transaction amounts are not ordered", lastAmount.compareTo(t.getAmount())<=0);
452                        }
453                        lastAmount = t.getAmount();
454                        ++totalTransactions;
455                }
456                assertTrue("All transactions included", totalTransactions<testSet.getNumberOfTransactions());
457                assertTrue("No transactions are included", totalTransactions>0);
458                
459                long period = System.currentTimeMillis() - start;
460                
461                // Verify parallelism
462                // We invoke getBalance() - 100 ms, getTransactions() - 150 ms.
463                long singleThreadedTime = testSet.getAccounts().size()*250;
464                // We have 10 threads, so total time should be at least 5 times less than single threaded time.
465                assertTrue("Execution took too long, single-threaded?", period<singleThreadedTime/5);                
466        }
467        
468        @Test
469        public void testQuery() {
470                Config<Account, Integer, LocalStore<Account, Integer>> config = new Config<Account, Integer, LocalStore<Account, Integer>>();
471                config.setPrimaryKeyExtractor(new AccountNumberExtractor());
472                config.setExecutorService(executorService);                
473                LocalStore<Account, Integer> store = new LocalStoreImpl<Account,Integer>(config);
474                
475                TestSet testSet = new TestSet(20, 100);
476                for (Account a: testSet.getAccounts()) {
477                        store.put(a);                        
478                }
479                
480                // Select transactions from accounts with more than average balance ordered transaction amount.
481                final BigDecimal averageBalance = testSet.getMinAccountBalance().add(testSet.getMaxAccountBalance()).divide(new BigDecimal(2));
482                
483                Predicate<Account, LocalStore<Account, Integer>> selector = new AbstractPredicate<Account, LocalStore<Account, Integer>>(0, null, false, 0) {
484 
485                        @Override
486                        protected Boolean extractInternal(
487                                        LocalStore<Account, Integer> context,
488                                        Map<LocalStore<Account, Integer>, Map<Extractor<Account, ? super Boolean, LocalStore<Account, Integer>>, ? super Boolean>> cache,
489                                        Account... obj) {
490                                return obj[0].getBalance().compareTo(averageBalance)>0;
491                        }
492                };
493                                                
494                long start = System.currentTimeMillis();
495                
496                final AtomicInteger totalTransactions = new AtomicInteger();
497                final AtomicInteger totalAccounts = new AtomicInteger();
498                
499                Store.QueryTask<Account, Integer, LocalStore<Account, Integer>> qTask = new Store.QueryTask<Account, Integer, LocalStore<Account, Integer>>() {
500                        
501                        @Override
502                        public void execute(LocalStore<Account, Integer> store, Account obj, Integer primaryKey) {
503                                totalTransactions.addAndGet(obj.getTransactions().size());
504                                totalAccounts.incrementAndGet();
505                        }
506                };
507                
508                store.query(selector, qTask);
509                assertTrue("All transactions included", totalTransactions.get()<testSet.getNumberOfTransactions());
510                assertTrue("No transactions are included", totalTransactions.get()>0);
511                
512                long period = System.currentTimeMillis() - start;
513                
514                // Verify parallelism
515                // We invoke getBalance() - 100 ms, getTransactions() - 150 ms and for each account query.execute()/account.getTransactions() - 150 ms.
516                long singleThreadedTime = testSet.getAccounts().size()*250+totalAccounts.get()*150;
517                // We have 10 threads, so total time should be at least 5 times less than single threaded time.
518                assertTrue("Execution took too long, single-threaded?", period<singleThreadedTime/5);                
519        }
520        
521        @Test
522        public void testMultiQuery() {
523                Config<Account, Integer, LocalStore<Account, Integer>> config = new Config<Account, Integer, LocalStore<Account, Integer>>();
524                config.setPrimaryKeyExtractor(new AccountNumberExtractor());
525                config.setExecutorService(executorService);                
526                LocalStore<Account, Integer> store = new LocalStoreImpl<Account,Integer>(config);
527                
528                TestSet testSet = new TestSet(20, 100);
529                for (Account a: testSet.getAccounts()) {
530                        store.put(a);                        
531                }
532                
533                // Select transactions from accounts with more than average balance ordered transaction amount.
534                final BigDecimal averageBalance = testSet.getMinAccountBalance().add(testSet.getMaxAccountBalance()).divide(new BigDecimal(2));
535                
536                Predicate<Account, LocalStore<Account, Integer>> selector = new AbstractPredicate<Account, LocalStore<Account, Integer>>(0, null, false, 0) {
537 
538                        @Override
539                        protected Boolean extractInternal(
540                                        LocalStore<Account, Integer> context,
541                                        Map<LocalStore<Account, Integer>, Map<Extractor<Account, ? super Boolean, LocalStore<Account, Integer>>, ? super Boolean>> cache,
542                                        Account... obj) {
543                                return obj[0].getBalance().compareTo(averageBalance)>0;
544                        }
545                };
546                                                
547                Extractor<Account, Iterable<Transaction>, LocalStore<Account, Integer>>  extractor = new AbstractExtractor<Account, Iterable<Transaction>, LocalStore<Account, Integer>>(0, null, false, 0) {
548 
549                        @Override
550                        protected Iterable<Transaction> extractInternal(
551                                        LocalStore<Account, Integer> context,
552                                        Map<LocalStore<Account, Integer>, Map<Extractor<Account, ? super Iterable<Transaction>, LocalStore<Account, Integer>>, ? super Iterable<Transaction>>> cache,
553                                        Account... obj) {
554                                return obj[0].getTransactions();
555                        }
556                };
557                
558                long start = System.currentTimeMillis();
559                
560                final AtomicInteger totalTransactions = new AtomicInteger();
561                
562                Store.QueryTask<Transaction, Integer, LocalStore<Account, Integer>> qTask = new Store.QueryTask<Transaction, Integer, LocalStore<Account, Integer>>() {
563                        
564                        @Override
565                        public void execute(LocalStore<Account, Integer> store, Transaction obj, Integer primaryKey) {
566                                try {
567                                        Thread.sleep(150);
568                                } catch (InterruptedException e) {
569                                        throw new StoreException(e);
570                                }
571                                totalTransactions.incrementAndGet();                                
572                        }
573                };
574 
575                store.queryMultiple(selector, extractor, null, qTask);
576                
577                assertTrue("All transactions included", totalTransactions.get()<testSet.getNumberOfTransactions());
578                assertTrue("No transactions are included", totalTransactions.get()>0);
579                
580                long period = System.currentTimeMillis() - start;
581                
582                // Verify parallelism
583                // We invoke getBalance() - 100 ms, getTransactions() - 150 ms and for each transaction query.execute() - 100 ms.
584                long singleThreadedTime = testSet.getAccounts().size()*250+totalTransactions.get()*150;
585                // We have 10 threads, so total time should be at least 5 times less than single threaded time.
586                assertTrue("Execution took too long, single-threaded?", period<singleThreadedTime/5);                
587        }
588        
589        // Test update 
590        
591        @Test
592        public void testUpdate() {
593                Config<Account, Integer, LocalStore<Account, Integer>> config = new Config<Account, Integer, LocalStore<Account, Integer>>();
594                config.setPrimaryKeyExtractor(new AccountNumberExtractor());
595                config.setExecutorService(executorService);                
596                LocalStore<Account, Integer> store = new LocalStoreImpl<Account,Integer>(config);
597                
598                TestSet testSet = new TestSet(20, 100);
599                for (Account a: testSet.getAccounts()) {
600                        store.put(a);                        
601                }
602                
603                // Select transactions from accounts with more than average balance ordered transaction amount.
604                final BigDecimal averageBalance = testSet.getMinAccountBalance().add(testSet.getMaxAccountBalance()).divide(new BigDecimal(2));
605                
606                Predicate<Account, LocalStore<Account, Integer>> selector = new AbstractPredicate<Account, LocalStore<Account, Integer>>(0, null, false, 0) {
607 
608                        @Override
609                        protected Boolean extractInternal(
610                                        LocalStore<Account, Integer> context,
611                                        Map<LocalStore<Account, Integer>, Map<Extractor<Account, ? super Boolean, LocalStore<Account, Integer>>, ? super Boolean>> cache,
612                                        Account... obj) {
613                                return obj[0].getBalance().compareTo(averageBalance)>0;
614                        }
615                };
616                                                
617                long start = System.currentTimeMillis();
618                
619                final AtomicInteger totalTransactions = new AtomicInteger();
620                final AtomicInteger totalAccounts = new AtomicInteger();
621                
622                Store.UpdateTask<Account, Integer, LocalStore<Account, Integer>> qTask = new Store.UpdateTask<Account, Integer, LocalStore<Account, Integer>>() {
623                        
624                        @Override
625                        public Runnable execute(LocalStore<Account, Integer> store, Handle<Account, Integer, LocalStore<Account, Integer>> handle) {
626                                Account account = handle.get();
627                                totalTransactions.addAndGet(account.getTransactions().size());
628                                totalAccounts.incrementAndGet();
629                                
630                                // We create a new account with the same number, no transactions and increased balance.
631                                Account newAccount = new Account(HAMMURAPI_GROUP, account.getNumber(), account.getBalance().add(new BigDecimal(333)));
632                                handle.update(newAccount);
633                                return null;
634                        }
635                };
636                
637                store.update(selector, qTask);
638                assertTrue("All transactions included", totalTransactions.get()<testSet.getNumberOfTransactions());
639                assertTrue("No transactions are included", totalTransactions.get()>0);
640                
641                long period = System.currentTimeMillis() - start;
642                
643                // Verify parallelism
644                // We invoke getBalance() - 100 ms, getTransactions() - 150 ms and for each account query.execute()/account.getTransactions() - 150 ms.
645                long singleThreadedTime = testSet.getAccounts().size()*250+totalAccounts.get()*150;
646                // We have 10 threads, so total time should be at least 5 times less than single threaded time.
647                assertTrue("Execution took too long, single-threaded?", period<singleThreadedTime/5);                
648        }
649        
650        
651        @Test
652        public void testView() {
653                Config<Account, Integer, LocalStore<Account, Integer>> config = new Config<Account, Integer, LocalStore<Account, Integer>>();
654                config.setPrimaryKeyExtractor(new AccountNumberExtractor());
655                config.setExecutorService(executorService);                
656                LocalStore<Account, Integer> store = new LocalStoreImpl<Account,Integer>(config);
657                
658                store.put(new Account(HAMMURAPI_GROUP, 123, null));                
659                store.put(new Account(HAMMURAPI_GROUP, 456, null));
660                store.put(new Account("Pavel Vlasov", 789, null));
661                
662                Predicate<Account, LocalStore<Account, Integer>> viewPredicate = new AbstractPredicate<Account, LocalStore<Account, Integer>>(0, null, false, 0) {
663 
664                        @Override
665                        protected Boolean extractInternal(
666                                        LocalStore<Account, Integer> context,
667                                        Map<LocalStore<Account, Integer>, Map<Extractor<Account, ? super Boolean, LocalStore<Account, Integer>>, ? super Boolean>> cache,
668                                        Account... obj) {
669                                return HAMMURAPI_GROUP.equals(obj[0].getCustomer());
670                        }
671                         
672                };
673                
674                LocalStore<Account, Integer> view = store.createView(viewPredicate, ViewType.LIVE);
675 
676                int cnt = 0;
677                for (Account a: view) {
678                        ++cnt;
679                        assertEquals(a.getCustomer(), HAMMURAPI_GROUP);
680                }
681                
682                assertEquals(cnt, 2);                
683        }
684        
685        @Test(expected=StoreException.class)
686        public void testViewPut() {
687                Config<Account, Integer, LocalStore<Account, Integer>> config = new Config<Account, Integer, LocalStore<Account, Integer>>();
688                config.setPrimaryKeyExtractor(new AccountNumberExtractor());
689                config.setExecutorService(executorService);                
690                LocalStore<Account, Integer> store = new LocalStoreImpl<Account,Integer>(config);
691                
692                Predicate<Account, LocalStore<Account, Integer>> viewPredicate = new AbstractPredicate<Account, LocalStore<Account, Integer>>(0, null, false, 0) {
693 
694                        @Override
695                        protected Boolean extractInternal(
696                                        LocalStore<Account, Integer> context,
697                                        Map<LocalStore<Account, Integer>, Map<Extractor<Account, ? super Boolean, LocalStore<Account, Integer>>, ? super Boolean>> cache,
698                                        Account... obj) {
699                                return HAMMURAPI_GROUP.equals(obj[0].getCustomer());
700                        }
701                         
702                };
703                
704                LocalStore<Account, Integer> view = store.createView(viewPredicate, ViewType.LIVE);
705                view.put(new Account("Pavel Vlasov", 789, null));
706        }
707        
708        @Test(expected=StoreException.class)
709        public void testUniqueIndex() {
710                Config<Account, Integer, LocalStore<Account, Integer>> config = new Config<Account, Integer, LocalStore<Account, Integer>>();
711                config.setPrimaryKeyExtractor(new AccountNumberExtractor());
712                config.setExecutorService(executorService);                
713                LocalStore<Account, Integer> store = new LocalStoreImpl<Account,Integer>(config);
714                
715                store.put(new Account(HAMMURAPI_GROUP, 123, null));
716                
717                Extractor<Account, String, LocalStore<Account, Integer>> customerExtractor = new AbstractExtractor<Account, String, LocalStore<Account, Integer>>(0, null, false, 0) {
718 
719                        @Override
720                        protected String extractInternal(
721                                        LocalStore<Account, Integer> context,
722                                        Map<LocalStore<Account, Integer>, Map<Extractor<Account, ? super String, LocalStore<Account, Integer>>, ? super String>> cache,
723                                        Account... obj) {
724                                return obj[0].getCustomer();
725                        }
726                        
727                };
728                
729                store.addIndex(null, customerExtractor, Index.Type.UNIQUE, false, null);
730                
731                store.put(new Account(HAMMURAPI_GROUP, 456, null));
732        }
733        
734        @Test
735        public void testIndex() {
736                Config<Account, Integer, LocalStore<Account, Integer>> config = new Config<Account, Integer, LocalStore<Account, Integer>>();
737                config.setPrimaryKeyExtractor(new AccountNumberExtractor());
738                config.setExecutorService(executorService);                
739                LocalStore<Account, Integer> store = new LocalStoreImpl<Account,Integer>(config);
740                
741                store.put(new Account(HAMMURAPI_GROUP, 123, new BigDecimal(100)));                
742                store.put(new Account(HAMMURAPI_GROUP, 456, new BigDecimal(10)));
743                store.put(new Account("Pavel Vlasov", 789, new BigDecimal(1)));
744                
745                Predicate<Account, LocalStore<Account, Integer>> indexPredicate = new AbstractPredicate<Account, LocalStore<Account, Integer>>(0, null, false, 0) {
746 
747                        @Override
748                        protected Boolean extractInternal(
749                                        LocalStore<Account, Integer> context,
750                                        Map<LocalStore<Account, Integer>, Map<Extractor<Account, ? super Boolean, LocalStore<Account, Integer>>, ? super Boolean>> cache,
751                                        Account... obj) {
752                                return HAMMURAPI_GROUP.equals(obj[0].getCustomer());
753                        }
754                         
755                };
756                                
757                MultiIndex<Account, Integer, BigDecimal, LocalStore<Account, Integer>> index = (MultiIndex<Account, Integer, BigDecimal, LocalStore<Account, Integer>>) store.addIndex(indexPredicate, balanceExtractor, Index.Type.ASYNCHRONOUS, true, null);
758                                
759                // Using index to access data
760                int cnt = 0;
761                BigDecimal prevBal = null;
762                for (Account a: index) {
763                        ++cnt;
764                        assertEquals(a.getCustomer(), HAMMURAPI_GROUP);
765                        if (prevBal!=null) {
766                                assertTrue(a.getBalance().compareTo(prevBal)>0);
767                        }
768                        prevBal = a.getBalance();
769                }
770                                                
771                assertEquals(cnt, 2);
772                
773                cnt = 0;
774                for (Account a: index.find(new BigDecimal(10))) {
775                        assertEquals(new BigDecimal(10), a.getBalance());
776                        ++cnt;
777                }
778                
779                assertEquals(1, cnt);
780                
781                cnt = 0;
782                for (Account a: index.find(new BigDecimal(12345))) {
783                        assertEquals(new BigDecimal(12345), a.getBalance());
784                        ++cnt;
785                }
786                
787                assertEquals(0, cnt);
788                
789                // Doing get, use of index is verified by checking that results are ordered.
790                cnt = 0;
791                prevBal = null;
792                for (Account a: store.get(indexPredicate)) {
793                        ++cnt;
794                        assertEquals(a.getCustomer(), HAMMURAPI_GROUP);
795                        if (prevBal!=null) {
796                                assertTrue(a.getBalance().compareTo(prevBal)>0);
797                        }
798                        prevBal = a.getBalance();
799                }
800                
801                assertEquals(cnt, 2);        
802                
803        }
804        
805        /**
806         * Tests that no tasks are executed after join() returns.
807         * @throws InterruptedException
808         */
809        @Test
810        public void testLocalTrackingServiceJoin() throws InterruptedException {
811                
812                final AtomicBoolean afterJoin = new AtomicBoolean(false);
813                final AtomicInteger failures = new AtomicInteger();                
814                final AtomicInteger completed = new AtomicInteger();
815                final Random random = new Random(System.currentTimeMillis());
816                final AtomicInteger createdTasks = new AtomicInteger();
817                
818                final LocalTrackingExecutorService ltes = new LocalTrackingExecutorService(executorService, false, null);
819                final int numberOfTasks = 5;
820                
821                class TestTask implements Runnable {
822                        
823                        private int depth;
824 
825                        public TestTask(long delay, int depth) {
826                                createdTasks.incrementAndGet();
827                                this.delay = delay;
828                                this.depth = depth;
829                        }
830                        
831                        long delay;
832                        
833                        @Override
834                        public void run() {
835                                try {
836                                        if (depth>0) {
837                                                for (int i=0; i<numberOfTasks; ++i) {
838                                                        ltes.submit(new TestTask(random.nextInt(100), depth-1));
839                                                }
840                                        }
841                                        Thread.sleep(delay);
842                                        if (afterJoin.get()) {
843                                                failures.incrementAndGet();
844                                        }
845                                } catch (Exception e) {
846                                        e.printStackTrace();
847                                } finally {
848                                        completed.incrementAndGet();
849                                }
850                        }
851                };
852                
853                
854                int depth = 3;
855                for (int i=0; i<numberOfTasks; ++i) {
856                        ltes.submit(new TestTask(random.nextInt(100), depth));
857                }
858                
859                ltes.join();
860                
861                assertEquals(createdTasks.get(), completed.get());
862                assertEquals(0, failures.get());                                
863 
864        }
865}

[all classes][com.hammurapi.common.store.tests]
EMMA 2.0.5312 EclEmma Fix 2 (C) Vladimir Roubtsov