@Test(dataProvider = "owningModeAndWriteMethod") public void testExceptionPropagation(boolean isOwner, WriteMethod method) { Object key = getKey(isOwner, DIST); try { method.eval(key, wo, rw, view -> null, (view, nil) -> { throw new TestException(); }, getClass()); fail("Should throw CompletionException:CacheException:[RemoteException:]*TestException"); } catch (CacheException | CompletionException e) { // catches RemoteExceptions, too Throwable t = e; if (Boolean.TRUE.equals(transactional) && t.getCause() instanceof RollbackException) { Throwable[] suppressed = t.getCause().getSuppressed(); if (suppressed != null && suppressed.length > 0) { t = suppressed[0]; assertEquals(XAException.class, t.getClass()); t = t.getCause(); } } assertException(CompletionException.class, t); t = t.getCause(); assertExceptionNonStrict(CacheException.class, t); while (t.getCause() instanceof RemoteException && t != t.getCause()) { t = t.getCause(); } assertException(TestException.class, t.getCause()); } }
@DataProvider(name = "writeMethods") public static Object[][] writeMethods() { return Stream.of(WriteMethod.values()).map(m -> new Object[]{m}).toArray(Object[][]::new); }
@Test(dataProvider = "owningModeAndWriteMethod") public void testEntryInvalidated(boolean isOwner, WriteMethod method) { Cache<Object, String> primary = cache(isOwner ? 0 : 2, DIST); Cache<Object, String> backup = cache(1, DIST); Cache<Object, String> reader = cache(3, DIST); Cache<Object, String> nonOwner = cache(isOwner ? 2 : 0, DIST); Object KEY = getKeyForCache(primary, backup); primary.put(KEY, "value"); assertNoEntry(reader, KEY); assertEquals("value", reader.get(KEY)); assertEntry(primary, KEY, "value", false); assertEntry(backup, KEY, "value", false); assertEntry(reader, KEY, "value", true); assertNoEntry(nonOwner, KEY); FunctionalMapImpl<Object, String> functionalMap = FunctionalMapImpl.create(this.<Object, String>cache(0, DIST).getAdvancedCache()); FunctionalMap.WriteOnlyMap<Object, String> wo = WriteOnlyMapImpl.create(functionalMap); FunctionalMap.ReadWriteMap<Object, String> rw = ReadWriteMapImpl.create(functionalMap); Function<ReadEntryView<Object, String>, String> readFunc = MarshallableFunctions.returnReadOnlyFindOrNull(); method.eval(KEY, wo, rw, readFunc, (view, nil) -> view.set("value2"), FunctionalL1Test.class); assertEntry(primary, KEY, "value2", false); assertEntry(backup, KEY, "value2", false); assertNoEntry(reader, KEY); assertNoEntry(nonOwner, KEY); }
@Test(dataProvider = "writeMethods") public void testWriteLoadLocal(WriteMethod method) { Integer key = 1; method.eval(key, lwo, lrw, view -> { assertFalse(view.find().isPresent()); return null; }, (view, nil) -> view.set("value"), getClass()); assertInvocations(1); Cache<Integer, String> cache = cacheManagers.get(0).getCache(); assertEquals(cache.get(key), "value"); cache.evict(key); assertFalse(cache.getAdvancedCache().getDataContainer().containsKey(key)); DummyInMemoryStore store = getStore(cache); assertTrue(store.contains(key)); method.eval(key, lwo, lrw, view -> { assertTrue(view.find().isPresent()); assertEquals(view.get(), "value"); return null; }, (view, nil) -> {}, getClass()); assertInvocations(2); }
@Test(dataProvider = "owningModeAndWriteMethod") public void testExceptionPropagation(boolean isOwner, WriteMethod method) { Object key = getKey(isOwner, SCATTERED); try { method.eval(key, swo, srw, view -> null, (view, nil) -> { throw new TestException(); }, getClass()); fail("Should throw CompletionException:CacheException:[RemoteException:]*TestException"); } catch (CacheException | CompletionException e) { // catches RemoteExceptions, too Throwable t = e; assertException(CompletionException.class, t); t = t.getCause(); assertExceptionNonStrict(CacheException.class, t); while (t.getCause() instanceof RemoteException && t != t.getCause()) { t = t.getCause(); } assertException(TestException.class, t.getCause()); } }
@Test(dataProvider = "owningModeAndReadWrites") public void testWriteOnMissingValue(boolean isOwner, WriteMethod method) { Object key = getKey(isOwner, DIST); try { method.eval(key, null, rw, view -> view.get(), (view, nil) -> {}, getClass()); fail("Should throw CompletionException:CacheException:[RemoteException:]*NoSuchElementException"); } catch (CompletionException e) { // catches RemoteExceptions, too Throwable t = e; assertException(CompletionException.class, t); t = t.getCause(); assertExceptionNonStrict(CacheException.class, t); while (t.getCause() instanceof RemoteException && t != t.getCause()) { t = t.getCause(); } assertException(NoSuchElementException.class, t.getCause()); } }
@Test(dataProvider = "writeMethods") public void testWriteLoadLocal(WriteMethod method) { Integer key = 1; method.eval(key, lwo, lrw, view -> { assertFalse(view.find().isPresent()); return null; }, (view, nil) -> view.set("value"), getClass()); assertInvocations(1); assertEquals(cacheManagers.get(0).getCache().get(key), "value"); method.eval(key, lwo, lrw, view -> { assertTrue(view.find().isPresent()); assertEquals(view.get(), "value"); return null; }, (view, nil) -> {}, getClass()); assertInvocations(2); }
@Test(dataProvider = "owningModeAndWriteMethod") public void testWrite(boolean isOwner, WriteMethod method) { Object key = getKey(isOwner, SCATTERED); method.eval(key, swo, srw, view -> { assertFalse(view.find().isPresent()); return null; }, (view, nil) -> view.set("value"), getClass()); assertInvocations(1); caches(SCATTERED).forEach(cache -> assertEquals(cache.get(key), "value", getAddress(cache).toString())); Utils.assertOwnershipAndNonOwnership(caches(SCATTERED), key); method.eval(key, swo, srw, view -> { assertTrue(view.find().isPresent()); assertEquals(view.get(), "value"); return null; }, (view, nil) -> {}, getClass()); assertInvocations(2); }
@Test(dataProvider = "owningModeAndReadWrites") public void testWriteOnMissingValue(boolean isOwner, WriteMethod method) { Object key = getKey(isOwner, SCATTERED); try { method.eval(key, null, srw, view -> view.get(), (view, nil) -> {}, getClass()); fail("Should throw CompletionException:CacheException:[RemoteException:]*NoSuchElementException"); } catch (CompletionException e) { // catches RemoteExceptions, too Throwable t = e; assertException(CompletionException.class, t); t = t.getCause(); assertExceptionNonStrict(CacheException.class, t); while (t.getCause() instanceof RemoteException && t != t.getCause()) { t = t.getCause(); } assertException(NoSuchElementException.class, t.getCause()); } }
@Test(dataProvider = "owningModeAndReadWrites") public void testReadWriteAfterMods(boolean isOwner, WriteMethod method) throws Exception { Object KEY = getKey(isOwner, DIST); cache(0, DIST).put(KEY, "a"); tm.begin(); assertEquals("a", rw.eval(KEY, append("b")).join()); assertEquals("ab", rw.evalMany(Collections.singleton(KEY), append("c")).findAny().get()); assertEquals(null, rw.eval("otherKey", append("d")).join()); assertEquals("abc", method.eval(KEY, wo, rw, MarshallableFunctions.returnReadOnlyFindOrNull(), (e, prev) -> {}, getClass())); tm.commit(); }
@Test(dataProvider = "owningModeAndReadWrites") public void testWriteModsInTxContext(boolean isOwner, WriteMethod method) throws Exception { Object KEY = getKey(isOwner, DIST); cache(0, DIST).put(KEY, "a"); tm.begin(); assertEquals("a", cache(0, DIST).put(KEY, "b")); // read-write operation should execute locally instead assertEquals("b", method.eval(KEY, null, rw, EntryView.ReadEntryView::get, (e, prev) -> e.set(prev + "c"), getClass())); // make sure that the operation was executed in context assertEquals("bc", ro.eval(KEY, MarshallableFunctions.returnReadOnlyFindOrNull()).join()); tm.commit(); }
@DataProvider(name = "owningModeAndReadWrites") public static Object[][] owningModeAndReadWrites() { return Stream.of(Boolean.TRUE, Boolean.FALSE) .flatMap(isSourceOwner -> Stream.of(WriteMethod.values()).filter(m -> m.doesRead) .map(method -> new Object[]{isSourceOwner, method})) .toArray(Object[][]::new); }
@DataProvider(name = "owningModeAndWriteMethod") public static Object[][] owningModeAndWriteMethod() { return Stream.of(Boolean.TRUE, Boolean.FALSE) .flatMap(isSourceOwner -> Stream.of(WriteMethod.values()) .map(method -> new Object[]{isSourceOwner, method})) .toArray(Object[][]::new); }