blob: 29cc15b706bbffef92e0388324596dbe8cb9b394 [file] [log] [blame]
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001/**
2* Copyright 2011, Big Switch Networks, Inc.
3* Originally created by David Erickson, Stanford University
4*
5* Licensed under the Apache License, Version 2.0 (the "License"); you may
6* not use this file except in compliance with the License. You may obtain
7* a copy of the License at
8*
9* http://www.apache.org/licenses/LICENSE-2.0
10*
11* Unless required by applicable law or agreed to in writing, software
12* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14* License for the specific language governing permissions and limitations
15* under the License.
16**/
17
18package net.floodlightcontroller.storage.tests;
19
20import static org.easymock.EasyMock.*;
21
22import java.util.concurrent.ExecutionException;
23import java.util.concurrent.Future;
24import java.util.concurrent.TimeoutException;
25import java.util.concurrent.TimeUnit;
26
27import java.util.Arrays;
28import java.util.HashMap;
29import java.util.HashSet;
30import java.util.Map;
31import java.util.Set;
32
33import net.floodlightcontroller.restserver.RestApiServer;
34import net.floodlightcontroller.storage.CompoundPredicate;
35import net.floodlightcontroller.storage.IStorageExceptionHandler;
36import net.floodlightcontroller.storage.IPredicate;
37import net.floodlightcontroller.storage.IQuery;
38import net.floodlightcontroller.storage.IResultSet;
39import net.floodlightcontroller.storage.IRowMapper;
40import net.floodlightcontroller.storage.IStorageSourceListener;
41import net.floodlightcontroller.storage.NullValueStorageException;
42import net.floodlightcontroller.storage.OperatorPredicate;
43import net.floodlightcontroller.storage.RowOrdering;
44import net.floodlightcontroller.storage.nosql.NoSqlStorageSource;
45import net.floodlightcontroller.test.FloodlightTestCase;
46
47import org.junit.Test;
48
49public abstract class StorageTest extends FloodlightTestCase {
50
51 protected NoSqlStorageSource storageSource;
52 protected RestApiServer restApi;
53
54 protected String PERSON_TABLE_NAME = "Person";
55
56 protected String PERSON_SSN = "SSN";
57 protected String PERSON_FIRST_NAME = "FirstName";
58 protected String PERSON_LAST_NAME = "LastName";
59 protected String PERSON_AGE = "Age";
60 protected String PERSON_REGISTERED = "Registered";
61
62 protected String[] PERSON_COLUMN_LIST = {PERSON_SSN, PERSON_FIRST_NAME, PERSON_LAST_NAME, PERSON_AGE, PERSON_REGISTERED};
63
64 class Person {
65 private String ssn;
66 private String firstName;
67 private String lastName;
68 int age;
69 boolean registered;
70
71 public Person(String ssn, String firstName, String lastName, int age, boolean registered) {
72 this.ssn = ssn;
73 this.firstName = firstName;
74 this.lastName = lastName;
75 this.age = age;
76 this.registered = registered;
77 }
78
79 public String getSSN() {
80 return ssn;
81 }
82
83 public String getFirstName() {
84 return firstName;
85 }
86
87 public String getLastName() {
88 return lastName;
89
90 }
91
92 public int getAge() {
93 return age;
94 }
95
96 public boolean isRegistered() {
97 return registered;
98 }
99 }
100
101 class PersonRowMapper implements IRowMapper {
102 public Object mapRow(IResultSet resultSet) {
103 String ssn = resultSet.getString(PERSON_SSN);
104 String firstName = resultSet.getString(PERSON_FIRST_NAME);
105 String lastName = resultSet.getString(PERSON_LAST_NAME);
106 int age = resultSet.getInt(PERSON_AGE);
107 boolean registered = resultSet.getBoolean(PERSON_REGISTERED);
108 return new Person(ssn, firstName, lastName, age, registered);
109 }
110 }
111
112 Object[][] PERSON_INIT_DATA = {
113 {"111-11-1111", "John", "Smith", 40, true},
114 {"222-22-2222", "Jim", "White", 24, false},
115 {"333-33-3333", "Lisa", "Jones", 27, true},
116 {"444-44-4444", "Susan", "Jones", 14, false},
117 {"555-55-5555", "Jose", "Garcia", 31, true},
118 {"666-66-6666", "Abigail", "Johnson", 35, false},
119 {"777-77-7777", "Bjorn", "Borg", 55, true},
120 {"888-88-8888", "John", "McEnroe", 53, false}
121 };
122
123 Map<String,Object> createPersonRowValues(Object[] personData) {
124 Map<String,Object> rowValues = new HashMap<String,Object>();
125 for (int i = 0; i < PERSON_COLUMN_LIST.length; i++) {
126 rowValues.put(PERSON_COLUMN_LIST[i], personData[i]);
127 }
128 return rowValues;
129 }
130
131 public void insertPerson(Object[] personData) {
132 Map<String,Object> rowValues = createPersonRowValues(personData);
133 storageSource.insertRow(PERSON_TABLE_NAME, rowValues);
134 }
135
136 public void initPersons() {
137 for (Object[] row: PERSON_INIT_DATA) {
138 insertPerson(row);
139 }
140 }
141
142 public void setUp() throws Exception {
143 super.setUp();
144 Set<String> indexedColumnNames = new HashSet<String>();
145 indexedColumnNames.add(PERSON_LAST_NAME);
146 storageSource.setExceptionHandler(null);
147 storageSource.createTable(PERSON_TABLE_NAME, indexedColumnNames);
148 storageSource.setTablePrimaryKeyName(PERSON_TABLE_NAME, PERSON_SSN);
149 initPersons();
150 }
151
152 public void checkExpectedResults(IResultSet resultSet, String[] columnNameList, Object[][] expectedRowList) {
153 boolean nextResult;
154 for (Object[] expectedRow: expectedRowList) {
155 nextResult = resultSet.next();
156 assertEquals(nextResult,true);
157 assertEquals(expectedRow.length, columnNameList.length);
158 for (int i = 0; i < expectedRow.length; i++) {
159 Object expectedObject = expectedRow[i];
160 String columnName = columnNameList[i];
161 if (expectedObject instanceof Boolean)
162 assertEquals(((Boolean)expectedObject).booleanValue(), resultSet.getBoolean(columnName));
163 else if (expectedObject instanceof Byte)
164 assertEquals(((Byte)expectedObject).byteValue(), resultSet.getByte(columnName));
165 else if (expectedObject instanceof Short)
166 assertEquals(((Short)expectedObject).shortValue(), resultSet.getShort(columnName));
167 else if (expectedObject instanceof Integer)
168 assertEquals(((Integer)expectedObject).intValue(), resultSet.getInt(columnName));
169 else if (expectedObject instanceof Long)
170 assertEquals(((Long)expectedObject).longValue(), resultSet.getLong(columnName));
171 else if (expectedObject instanceof Float)
172 assertEquals(((Float)expectedObject).floatValue(), resultSet.getFloat(columnName), 0.00001);
173 else if (expectedObject instanceof Double)
174 assertEquals(((Double)expectedObject).doubleValue(), resultSet.getDouble(columnName), 0.00001);
175 else if (expectedObject instanceof byte[])
176 assertEquals((byte[])expectedObject, resultSet.getByteArray(columnName));
177 else if (expectedObject instanceof String)
178 assertEquals((String)expectedObject, resultSet.getString(columnName));
179 else
180 assertTrue("Unexpected column value type", false);
181 }
182 }
183 nextResult = resultSet.next();
184 assertEquals(nextResult,false);
185 resultSet.close();
186 }
187
188 @Test
189 public void testInsertRows() {
190 IResultSet resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, null, null, new RowOrdering(PERSON_SSN));
191 checkExpectedResults(resultSet, PERSON_COLUMN_LIST, PERSON_INIT_DATA);
192 }
193
194 @Test
195 public void testOperatorQuery() {
196 Object[][] expectedResults = {
197 {"John", "Smith", 40},
198 {"Jim", "White", 24},
199 };
200 String[] columnList = {PERSON_FIRST_NAME,PERSON_LAST_NAME,PERSON_AGE};
201 IResultSet resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, columnList,
202 new OperatorPredicate(PERSON_LAST_NAME, OperatorPredicate.Operator.GTE, "Sm"),
203 new RowOrdering(PERSON_SSN));
204 checkExpectedResults(resultSet, columnList, expectedResults);
205 }
206
207 @Test
208 public void testAndQuery() {
209 String[] columnList = {PERSON_FIRST_NAME,PERSON_LAST_NAME};
210 Object[][] expectedResults = {
211 {"Lisa", "Jones"},
212 {"Susan", "Jones"},
213 {"Jose", "Garcia"},
214 {"Abigail", "Johnson"},
215 {"John", "McEnroe"}
216 };
217 IResultSet resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, columnList,
218 new CompoundPredicate(CompoundPredicate.Operator.AND, false,
219 new OperatorPredicate(PERSON_LAST_NAME, OperatorPredicate.Operator.GTE, "G"),
220 new OperatorPredicate(PERSON_LAST_NAME, OperatorPredicate.Operator.LT, "N")
221 ),
222 new RowOrdering(PERSON_SSN));
223 checkExpectedResults(resultSet, columnList, expectedResults);
224 }
225
226 @Test
227 public void testOrQuery() {
228 String[] columnList = {PERSON_FIRST_NAME,PERSON_LAST_NAME, PERSON_AGE};
229 Object[][] expectedResults = {
230 {"John", "Smith", 40},
231 {"Lisa", "Jones", 27},
232 {"Abigail", "Johnson", 35},
233 {"Bjorn", "Borg", 55},
234 {"John", "McEnroe", 53}
235 };
236 IResultSet resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, columnList,
237 new CompoundPredicate(CompoundPredicate.Operator.OR, false,
238 new OperatorPredicate(PERSON_AGE, OperatorPredicate.Operator.GTE, 35),
239 new OperatorPredicate(PERSON_FIRST_NAME, OperatorPredicate.Operator.EQ, "Lisa")
240 ),
241 new RowOrdering(PERSON_SSN));
242 checkExpectedResults(resultSet, columnList, expectedResults);
243}
244
245 @Test
246 public void testCreateQuery() {
247 String[] columnList = {PERSON_FIRST_NAME,PERSON_LAST_NAME};
248 Object[][] expectedResults = {
249 {"Lisa", "Jones"},
250 {"Susan", "Jones"}
251 };
252 IPredicate predicate = new OperatorPredicate(PERSON_LAST_NAME, OperatorPredicate.Operator.EQ, "Jones");
253 IQuery query = storageSource.createQuery(PERSON_TABLE_NAME, columnList, predicate, new RowOrdering(PERSON_SSN));
254 IResultSet resultSet = storageSource.executeQuery(query);
255 checkExpectedResults(resultSet, columnList, expectedResults);
256 }
257
258 @Test
259 public void testQueryParameters() {
260 String[] columnList = {PERSON_FIRST_NAME,PERSON_LAST_NAME, PERSON_AGE};
261 Object[][] expectedResults = {
262 {"John", "Smith", 40},
263 {"Bjorn", "Borg", 55},
264 {"John", "McEnroe", 53}
265 };
266 IPredicate predicate = new OperatorPredicate(PERSON_AGE, OperatorPredicate.Operator.GTE, "?MinimumAge?");
267 IQuery query = storageSource.createQuery(PERSON_TABLE_NAME, columnList, predicate, new RowOrdering(PERSON_SSN));
268 query.setParameter("MinimumAge", 40);
269 IResultSet resultSet = storageSource.executeQuery(query);
270 checkExpectedResults(resultSet, columnList, expectedResults);
271 }
272
273 private void checkPerson(Person person, Object[] expectedValues) {
274 assertEquals(person.getSSN(), expectedValues[0]);
275 assertEquals(person.getFirstName(), expectedValues[1]);
276 assertEquals(person.getLastName(), expectedValues[2]);
277 assertEquals(person.getAge(), expectedValues[3]);
278 assertEquals(person.isRegistered(), expectedValues[4]);
279 }
280
281 @Test
282 public void testRowMapper() {
283 Object[][] expectedResults = {
284 PERSON_INIT_DATA[2],
285 PERSON_INIT_DATA[3]
286 };
287 IPredicate predicate = new OperatorPredicate(PERSON_LAST_NAME, OperatorPredicate.Operator.EQ, "Jones");
288 IRowMapper rowMapper = new PersonRowMapper();
289 Object[] personList = storageSource.executeQuery(PERSON_TABLE_NAME, null, predicate, new RowOrdering(PERSON_SSN), rowMapper);
290 assertEquals(personList.length, 2);
291 for (int i = 0; i < personList.length; i++)
292 checkPerson((Person)personList[i], expectedResults[i]);
293 }
294
295 @Test
296 public void testDeleteRowsDirect() {
297
298 storageSource.deleteRow(PERSON_TABLE_NAME, "111-11-1111");
299 storageSource.deleteRow(PERSON_TABLE_NAME, "222-22-2222");
300 storageSource.deleteRow(PERSON_TABLE_NAME, "333-33-3333");
301 storageSource.deleteRow(PERSON_TABLE_NAME, "444-44-4444");
302
303 Object[][] expectedResults = {
304 {"555-55-5555", "Jose", "Garcia", 31, true},
305 {"666-66-6666", "Abigail", "Johnson", 35, false},
306 {"777-77-7777", "Bjorn", "Borg", 55, true},
307 {"888-88-8888", "John", "McEnroe", 53, false}
308 };
309 IResultSet resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, PERSON_COLUMN_LIST, null, new RowOrdering(PERSON_SSN));
310 checkExpectedResults(resultSet, PERSON_COLUMN_LIST, expectedResults);
311 }
312
313 @Test
314 public void testDeleteRowsFromResultSet() {
315 Object[][] expectedResults = {
316 {"555-55-5555", "Jose", "Garcia", 31, true},
317 {"666-66-6666", "Abigail", "Johnson", 35, false},
318 {"777-77-7777", "Bjorn", "Borg", 55, true},
319 {"888-88-8888", "John", "McEnroe", 53, false}
320 };
321
322 // Query once to delete the rows
323 IResultSet resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, PERSON_COLUMN_LIST, null, new RowOrdering(PERSON_SSN));
324 for (int i = 0; i < 4; i++) {
325 resultSet.next();
326 resultSet.deleteRow();
327 }
328 resultSet.save();
329 resultSet.close();
330
331 // Now query again to verify that the rows were deleted
332 resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, PERSON_COLUMN_LIST, null, new RowOrdering(PERSON_SSN));
333 checkExpectedResults(resultSet, PERSON_COLUMN_LIST, expectedResults);
334 }
335
336 @Test
337 public void testDeleteMatchingRows() {
338 Object[][] expectedResults = {
339 {"111-11-1111", "John", "Smith", 40, true},
340 {"777-77-7777", "Bjorn", "Borg", 55, true},
341 {"888-88-8888", "John", "McEnroe", 53, false}
342 };
343 storageSource.deleteMatchingRows(PERSON_TABLE_NAME, new OperatorPredicate(PERSON_AGE, OperatorPredicate.Operator.LT, 40));
344
345 // Now query again to verify that the rows were deleted
346 IResultSet resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, PERSON_COLUMN_LIST, null, new RowOrdering(PERSON_SSN));
347 checkExpectedResults(resultSet, PERSON_COLUMN_LIST, expectedResults);
348
349 storageSource.deleteMatchingRows(PERSON_TABLE_NAME, null);
350
351 // Now query again to verify that all rows were deleted
352 resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, PERSON_COLUMN_LIST, null, new RowOrdering(PERSON_SSN));
353 checkExpectedResults(resultSet, PERSON_COLUMN_LIST, new Object[0][]);
354 }
355
356 @Test
357 public void testUpdateRowsDirect() {
358
359 Object[][] expectedResults = {
360 {"777-77-7777", "Tennis", "Borg", 60, true},
361 {"888-88-8888", "Tennis", "McEnroe", 60, false}
362 };
363 Map<String,Object> updateValues = new HashMap<String,Object>();
364 updateValues.put(PERSON_FIRST_NAME, "Tennis");
365 updateValues.put(PERSON_AGE, 60);
366
367 IPredicate predicate = new OperatorPredicate(PERSON_AGE, OperatorPredicate.Operator.GT, 50);
368 IResultSet resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, null, predicate, new RowOrdering(PERSON_SSN));
369 while (resultSet.next()) {
370 String key = resultSet.getString(PERSON_SSN);
371 storageSource.updateRow(PERSON_TABLE_NAME, key, updateValues);
372 }
373 resultSet.close();
374
375 resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, PERSON_COLUMN_LIST, predicate, new RowOrdering(PERSON_SSN));
376 checkExpectedResults(resultSet, PERSON_COLUMN_LIST, expectedResults);
377 }
378
379 @Test
380 public void testUpdateRowsFromResultSet() {
381
382 Object[][] expectedResults = {
383 {"777-77-7777", "Tennis", "Borg", 60, true},
384 {"888-88-8888", "Tennis", "McEnroe", 60, false}
385 };
386
387 IPredicate predicate = new OperatorPredicate(PERSON_AGE, OperatorPredicate.Operator.GT, 50);
388 IResultSet resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, null, predicate, null);
389 while (resultSet.next()) {
390 resultSet.setString(PERSON_FIRST_NAME, "Tennis");
391 resultSet.setInt(PERSON_AGE, 60);
392 }
393 resultSet.save();
394 resultSet.close();
395
396 resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, PERSON_COLUMN_LIST, predicate, new RowOrdering(PERSON_SSN));
397 checkExpectedResults(resultSet, PERSON_COLUMN_LIST, expectedResults);
398 }
399
400 @Test
401 public void testNullValues() {
402
403 IPredicate predicate = new OperatorPredicate(PERSON_LAST_NAME, OperatorPredicate.Operator.EQ, "Jones");
404 IResultSet resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, null, predicate, new RowOrdering(PERSON_SSN));
405 while (resultSet.next()) {
406 resultSet.setNull(PERSON_FIRST_NAME);
407 resultSet.setIntegerObject(PERSON_AGE, null);
408 }
409 resultSet.save();
410 resultSet.close();
411
412 resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, null, predicate, new RowOrdering(PERSON_SSN));
413 int count = 0;
414 while (resultSet.next()) {
415 boolean checkNull = resultSet.isNull(PERSON_FIRST_NAME);
416 assertTrue(checkNull);
417 String s = resultSet.getString(PERSON_FIRST_NAME);
418 assertEquals(s, null);
419 checkNull = resultSet.isNull(PERSON_AGE);
420 assertTrue(checkNull);
421 Integer intObj = resultSet.getIntegerObject(PERSON_AGE);
422 assertEquals(intObj, null);
423 Short shortObj = resultSet.getShortObject(PERSON_AGE);
424 assertEquals(shortObj, null);
425 boolean excThrown = false;
426 try {
427 resultSet.getInt(PERSON_AGE);
428 }
429 catch (NullValueStorageException exc) {
430 excThrown = true;
431 }
432 assertTrue(excThrown);
433 count++;
434 }
435 resultSet.close();
436 assertEquals(count, 2);
437
438 predicate = new OperatorPredicate(PERSON_FIRST_NAME, OperatorPredicate.Operator.EQ, null);
439 resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, null, predicate, new RowOrdering(PERSON_SSN));
440 count = 0;
441 while (resultSet.next()) {
442 boolean checkNull = resultSet.isNull(PERSON_FIRST_NAME);
443 assertTrue(checkNull);
444 count++;
445 checkNull = resultSet.isNull(PERSON_AGE);
446 assertTrue(checkNull);
447 }
448 resultSet.close();
449 assertEquals(count, 2);
450 }
451
452 @Test
453 public void testInsertNotification() {
454 // Set up the listener and record the expected notification
455 IStorageSourceListener mockListener = createNiceMock(IStorageSourceListener.class);
456 Set<Object> expectedKeys = new HashSet<Object>();
457 expectedKeys.add("999-99-9999");
458 mockListener.rowsModified(PERSON_TABLE_NAME, expectedKeys);
459
460 replay(mockListener);
461
462 // Now try it for real
463 storageSource.addListener(PERSON_TABLE_NAME, mockListener);
464
465 // Create a new person, which should trigger the listener
466 Object[] newPerson = {"999-99-9999", "Serena", "Williams", 22, true};
467 insertPerson(newPerson);
468
469 verify(mockListener);
470 }
471
472 @Test
473 public void testUpdateNotification() {
474 // Set up the listener and record the expected notification
475 IStorageSourceListener mockListener = createNiceMock(IStorageSourceListener.class);
476 Set<Object> expectedKeys = new HashSet<Object>();
477 expectedKeys.add("111-11-1111");
478 mockListener.rowsModified(PERSON_TABLE_NAME, expectedKeys);
479
480 replay(mockListener);
481
482 // Now try it for real
483 storageSource.addListener(PERSON_TABLE_NAME, mockListener);
484
485 // Create a new person, which should trigger the listener
486 Map<String,Object> updateValues = new HashMap<String,Object>();
487 updateValues.put(PERSON_FIRST_NAME, "Tennis");
488 storageSource.updateRow(PERSON_TABLE_NAME, "111-11-1111", updateValues);
489
490 verify(mockListener);
491 }
492
493 @Test
494 public void testDeleteNotification() {
495 IStorageSourceListener mockListener = createNiceMock(IStorageSourceListener.class);
496 Set<Object> expectedKeys = new HashSet<Object>();
497 expectedKeys.add("111-11-1111");
498 mockListener.rowsDeleted(PERSON_TABLE_NAME, expectedKeys);
499
500 replay(mockListener);
501
502 // Now try it for real
503 storageSource.addListener(PERSON_TABLE_NAME, mockListener);
504
505 // Create a new person, which should trigger the listener
506 storageSource.deleteRow(PERSON_TABLE_NAME, "111-11-1111");
507
508 verify(mockListener);
509 }
510
511 public void waitForFuture(Future<?> future) {
512 try
513 {
514 future.get(10, TimeUnit.SECONDS);
515 }
516 catch (InterruptedException exc)
517 {
518 fail("Async storage operation interrupted");
519 }
520 catch (ExecutionException exc) {
521 fail("Async storage operation failed");
522 }
523 catch (TimeoutException exc) {
524 fail("Async storage operation timed out");
525 }
526 }
527
528 @Test
529 public void testAsyncQuery1() {
530 Object[][] expectedResults = {
531 {"John", "Smith", 40},
532 {"Jim", "White", 24},
533 };
534 String[] columnList = {PERSON_FIRST_NAME,PERSON_LAST_NAME,PERSON_AGE};
535 IPredicate predicate = new OperatorPredicate(PERSON_LAST_NAME, OperatorPredicate.Operator.GTE, "Sm");
536 IQuery query = storageSource.createQuery(PERSON_TABLE_NAME, columnList, predicate, new RowOrdering(PERSON_SSN));
537 Future<IResultSet> future = storageSource.executeQueryAsync(query);
538 waitForFuture(future);
539 try {
540 IResultSet resultSet = future.get();
541 checkExpectedResults(resultSet, columnList, expectedResults);
542 }
543 catch (Exception e) {
544 fail("Exception thrown in async storage operation: " + e.toString());
545 }
546 }
547
548 @Test
549 public void testAsyncQuery2() {
550 Object[][] expectedResults = {
551 {"John", "Smith", 40},
552 {"Jim", "White", 24},
553 };
554 String[] columnList = {PERSON_FIRST_NAME,PERSON_LAST_NAME,PERSON_AGE};
555 IPredicate predicate = new OperatorPredicate(PERSON_LAST_NAME, OperatorPredicate.Operator.GTE, "Sm");
556 Future<IResultSet> future = storageSource.executeQueryAsync(PERSON_TABLE_NAME,
557 columnList, predicate, new RowOrdering(PERSON_SSN));
558 waitForFuture(future);
559 try {
560 IResultSet resultSet = future.get();
561 checkExpectedResults(resultSet, columnList, expectedResults);
562 }
563 catch (Exception e) {
564 fail("Exception thrown in async storage operation: " + e.toString());
565 }
566 }
567
568 @Test
569 public void testAsyncQuery3() {
570 Object[][] expectedResults = {
571 PERSON_INIT_DATA[2],
572 PERSON_INIT_DATA[3]
573 };
574 IPredicate predicate = new OperatorPredicate(PERSON_LAST_NAME, OperatorPredicate.Operator.EQ, "Jones");
575 IRowMapper rowMapper = new PersonRowMapper();
576 Future<Object[]> future = storageSource.executeQueryAsync(PERSON_TABLE_NAME,
577 null, predicate, new RowOrdering(PERSON_SSN), rowMapper);
578 waitForFuture(future);
579 try {
580 Object[] personList = future.get();
581 assertEquals(personList.length, 2);
582 for (int i = 0; i < personList.length; i++)
583 checkPerson((Person)personList[i], expectedResults[i]);
584 }
585 catch (Exception e) {
586 fail("Exception thrown in async storage operation: " + e.toString());
587 }
588 }
589
590 @Test
591 public void testAsyncException() {
592 class TestExceptionHandler implements IStorageExceptionHandler {
593 public int exceptionCount = 0;
594 @Override
595 public void handleException(Exception exception) {
596 exceptionCount++;
597 }
598 }
599 TestExceptionHandler exceptionHandler = new TestExceptionHandler();
600 storageSource.setExceptionHandler(exceptionHandler);
601
602 // Use an invalid table name, which should cause the storage API call to throw
603 // an exception, which should then be converted to an ExecutionException.
604 Future<IResultSet> future = storageSource.executeQueryAsync("InvalidTableName",
605 null, null, null);
606 try {
607 future.get(10, TimeUnit.SECONDS);
608 fail("Expected ExecutionException was not thrown");
609 }
610 catch (ExecutionException e) {
611 assertTrue(true);
612 }
613 catch (Exception e) {
614 fail("Exception thrown in async storage operation: " + e.toString());
615 }
616 assertEquals(exceptionHandler.exceptionCount, 1);
617 }
618
619 @Test
620 public void testAsyncInsertRow() {
621 Object[][] newPersonInfo = {{"999-99-9999", "Ellen", "Wilson", 40, true}};
622 Map<String,Object> rowValues = createPersonRowValues(newPersonInfo[0]);
623 Future<?> future = storageSource.insertRowAsync(PERSON_TABLE_NAME, rowValues);
624 waitForFuture(future);
625 try {
626 IResultSet resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, null, null, new RowOrdering(PERSON_SSN));
627 Object[][] expectedPersons = Arrays.copyOf(PERSON_INIT_DATA, PERSON_INIT_DATA.length + newPersonInfo.length);
628 System.arraycopy(newPersonInfo, 0, expectedPersons, PERSON_INIT_DATA.length, newPersonInfo.length);
629 checkExpectedResults(resultSet, PERSON_COLUMN_LIST, expectedPersons);
630 }
631 catch (Exception e) {
632 fail("Exception thrown in async storage operation: " + e.toString());
633 }
634 }
635
636 @Test
637 public void testAsyncUpdateRow() {
638 Map<String,Object> updateValues = new HashMap<String,Object>();
639 updateValues.put(PERSON_SSN, "777-77-7777");
640 updateValues.put(PERSON_FIRST_NAME, "Tennis");
641 updateValues.put(PERSON_AGE, 60);
642
643 Future<?> future = storageSource.updateRowAsync(PERSON_TABLE_NAME, updateValues);
644 waitForFuture(future);
645
646 try {
647 IResultSet resultSet = storageSource.getRow(PERSON_TABLE_NAME, "777-77-7777");
648 Object[][] expectedPersons = {{"777-77-7777", "Tennis", "Borg", 60, true}};
649 checkExpectedResults(resultSet, PERSON_COLUMN_LIST, expectedPersons);
650 }
651 catch (Exception e) {
652 fail("Exception thrown in async storage operation: " + e.toString());
653 }
654 }
655
656 @Test
657 public void testAsyncUpdateRow2() {
658 Map<String,Object> updateValues = new HashMap<String,Object>();
659 updateValues.put(PERSON_FIRST_NAME, "Tennis");
660 updateValues.put(PERSON_AGE, 60);
661
662 Future<?> future = storageSource.updateRowAsync(PERSON_TABLE_NAME, "777-77-7777", updateValues);
663 waitForFuture(future);
664
665 try {
666 IResultSet resultSet = storageSource.getRow(PERSON_TABLE_NAME, "777-77-7777");
667 Object[][] expectedPersons = {{"777-77-7777", "Tennis", "Borg", 60, true}};
668 checkExpectedResults(resultSet, PERSON_COLUMN_LIST, expectedPersons);
669 }
670 catch (Exception e) {
671 fail("Exception thrown in async storage operation: " + e.toString());
672 }
673 }
674
675 @Test
676 public void testAsyncUpdateMatchingRows() {
677 Map<String,Object> updateValues = new HashMap<String,Object>();
678 updateValues.put(PERSON_FIRST_NAME, "Tennis");
679 updateValues.put(PERSON_AGE, 60);
680
681 IPredicate predicate = new OperatorPredicate(PERSON_SSN, OperatorPredicate.Operator.EQ, "777-77-7777");
682 Future<?> future = storageSource.updateMatchingRowsAsync(PERSON_TABLE_NAME, predicate, updateValues);
683 waitForFuture(future);
684 try {
685 IResultSet resultSet = storageSource.getRow(PERSON_TABLE_NAME, "777-77-7777");
686 Object[][] expectedPersons = {{"777-77-7777", "Tennis", "Borg", 60, true}};
687 checkExpectedResults(resultSet, PERSON_COLUMN_LIST, expectedPersons);
688 }
689 catch (Exception e) {
690 fail("Exception thrown in async storage operation: " + e.toString());
691 }
692 }
693
694 @Test
695 public void testAsyncDeleteRow() {
696 Future<?> future = storageSource.deleteRowAsync(PERSON_TABLE_NAME, "111-11-1111");
697 waitForFuture(future);
698 try {
699 IResultSet resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, null, null, new RowOrdering(PERSON_SSN));
700 Object[][] expectedPersons = Arrays.copyOfRange(PERSON_INIT_DATA, 1, PERSON_INIT_DATA.length);
701 checkExpectedResults(resultSet, PERSON_COLUMN_LIST, expectedPersons);
702 }
703 catch (Exception e) {
704 fail("Exception thrown in async storage operation: " + e.toString());
705 }
706 }
707
708 @Test
709 public void testAsyncDeleteMatchingRows() {
710 Future<?> future = storageSource.deleteMatchingRowsAsync(PERSON_TABLE_NAME, null);
711 waitForFuture(future);
712 try {
713 IResultSet resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, null, null, new RowOrdering(PERSON_SSN));
714 checkExpectedResults(resultSet, PERSON_COLUMN_LIST, new Object[0][]);
715 }
716 catch (Exception e) {
717 fail("Exception thrown in async storage operation: " + e.toString());
718 }
719 }
720
721 @Test
722 public void testAsyncSave() {
723 // Get a result set and make some changes to it
724 IResultSet resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, null, null, new RowOrdering(PERSON_SSN));
725 resultSet.next();
726 resultSet.deleteRow();
727 resultSet.next();
728 resultSet.setString(PERSON_FIRST_NAME, "John");
729
730 Future<?> future = storageSource.saveAsync(resultSet);
731 waitForFuture(future);
732 try {
733 resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, null, null, new RowOrdering(PERSON_SSN));
734 Object[][] expectedPersons = Arrays.copyOfRange(PERSON_INIT_DATA, 1, PERSON_INIT_DATA.length);
735 expectedPersons[0][1] = "John";
736 checkExpectedResults(resultSet, PERSON_COLUMN_LIST, expectedPersons);
737 }
738 catch (Exception e) {
739 fail("Exception thrown in async storage operation: " + e.toString());
740 }
741
742 }
743}