< prev index next >
tests/system/src/test/java/test/memoryleak/JSCallbackMemoryTest.java
Print this page
*** 85,94 ****
--- 85,96 ----
private final int[] primitiveArray = { 1, 2, 3, 4, 5 };
private final Object[] objectArray = { new Object(), new Object(), new Object(), new Object() };
+ private AssertionError encounteredException = null;
+
public final class MyObject {
// called from JavaScript
public void jsobjcallback() {
if (VERBOSE) {
*** 218,231 ****
--- 220,260 ----
stages = null;
}
});
}
+ private boolean isAllStagesNull() {
+ Set<WeakReference<Object>> collected = new HashSet<>();
+
+ for (WeakReference<Object> ref : refs) {
+ if (ref.get() != null) {
+ return false;
+ }
+ collected.add(ref);
+ }
+
+ refs.removeAll(collected);
+
+ return true;
+ }
+
+ private boolean isAllCallbackStatusTrue() {
+
+ for (int i = 0; i < NUM_STAGES; i++) {
+ if (callbackStatus[i] == false) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
// ========================== TEST CASES ==========================
@Test
public void testJsCallbackLeak() throws Exception {
+ final CountDownLatch latch = new CountDownLatch(1);
Util.runAndWait(() -> {
int stagePosition = 40;
for (int i = 0; i < NUM_STAGES; i++) {
*** 242,301 ****
stage.setHeight(180);
stage.setScene(scene);
webview.getEngine().getLoadWorker().stateProperty().addListener((ov, o, n) -> {
if (n == Worker.State.SUCCEEDED) {
final JSObject window = (JSObject) webview.getEngine().executeScript("window");
assertNotNull(window);
window.setMember("callback1", stage);
}
});
webview.getEngine().loadContent(html);
stage.show();
refs.add( new WeakReference<Object>(stage));
}
});
! Util.sleep(SLEEP_TIME);
Util.runAndWait(() -> {
for (int i = 0; i < NUM_STAGES; i++) {
stages[i].hide();
}
stages = null;
});
! for (int j = 0; j < 2; j++) {
System.gc();
! Util.sleep(SLEEP_TIME);
! Set<WeakReference<Object>> collected = new HashSet<>();
! for (WeakReference<Object> ref : refs) {
! if (ref.get() == null) {
! collected.add(ref);
}
- }
- refs.removeAll(collected);
! if (j == 0) {
! // First time GC -> Collected will be equal to NUM_STAGES and refs size (remaining) will be 0
! assertEquals(NUM_STAGES, collected.size());
! assertEquals(0, refs.size());
}
- else {
- // Second time GC -> Collected will be 0 and refs size (remaining) will be 0
- assertEquals(0, collected.size());
assertEquals(0, refs.size());
}
- }
- }
@Test
public void testJsCallbackFunction() throws Exception {
Util.runAndWait(() -> {
int stagePosition = 40;
for (int i = 0; i < NUM_STAGES; i++) {
--- 271,333 ----
stage.setHeight(180);
stage.setScene(scene);
webview.getEngine().getLoadWorker().stateProperty().addListener((ov, o, n) -> {
if (n == Worker.State.SUCCEEDED) {
+ try {
final JSObject window = (JSObject) webview.getEngine().executeScript("window");
assertNotNull(window);
window.setMember("callback1", stage);
+ } catch(AssertionError ex) {
+ encounteredException = ex;
+ } finally {
+ latch.countDown();
+ }
}
});
webview.getEngine().loadContent(html);
stage.show();
refs.add( new WeakReference<Object>(stage));
}
});
! if (encounteredException != null) {
! throw encounteredException;
! }
!
! try {
! latch.await();
! } catch (InterruptedException ex) {
! throw new AssertionError(ex);
! }
Util.runAndWait(() -> {
for (int i = 0; i < NUM_STAGES; i++) {
stages[i].hide();
}
stages = null;
});
! for (int j = 0; j < 5; j++) {
System.gc();
! System.runFinalization();
! if (isAllStagesNull()) {
! break;
}
! Util.sleep(SLEEP_TIME);
}
assertEquals(0, refs.size());
}
@Test
public void testJsCallbackFunction() throws Exception {
+ final CountDownLatch latch = new CountDownLatch(1);
Util.runAndWait(() -> {
int stagePosition = 40;
for (int i = 0; i < NUM_STAGES; i++) {
*** 312,342 ****
stage.setHeight(180);
stage.setScene(scene);
webview.getEngine().getLoadWorker().stateProperty().addListener((ov, o, n) -> {
if (n == Worker.State.SUCCEEDED) {
final JSObject window = (JSObject) webview.getEngine().executeScript("window");
assertNotNull(window);
window.setMember("callback1", stage);
webview.getEngine().executeScript("document.getElementById(\"mybtn1\").click()");
}
});
webview.getEngine().loadContent(html);
stage.show();
}
});
! Util.sleep(SLEEP_TIME);
System.gc();
! for (int i = 0; i < NUM_STAGES; i++) {
! assertTrue(callbackStatus[i]);
}
}
@Test
public void testJsCallbackReleaseFunction() throws Exception {
Util.runAndWait(() -> {
int stagePosition = 40;
for (int i = 0; i < NUM_STAGES; i++) {
--- 344,398 ----
stage.setHeight(180);
stage.setScene(scene);
webview.getEngine().getLoadWorker().stateProperty().addListener((ov, o, n) -> {
if (n == Worker.State.SUCCEEDED) {
+ try {
final JSObject window = (JSObject) webview.getEngine().executeScript("window");
assertNotNull(window);
window.setMember("callback1", stage);
webview.getEngine().executeScript("document.getElementById(\"mybtn1\").click()");
+ } catch(AssertionError ex) {
+ encounteredException = ex;
+ } finally {
+ latch.countDown();
+ }
}
});
webview.getEngine().loadContent(html);
stage.show();
}
});
! if (encounteredException != null) {
! throw encounteredException;
! }
!
! try {
! latch.await();
! } catch (InterruptedException ex) {
! throw new AssertionError(ex);
! }
!
! for (int j = 0; j < 5; j++) {
System.gc();
! System.runFinalization();
!
! if (isAllCallbackStatusTrue()) {
! break;
}
+
+ Util.sleep(SLEEP_TIME);
+ }
+
+ assertTrue("All Button Callback return true", isAllCallbackStatusTrue());
}
@Test
public void testJsCallbackReleaseFunction() throws Exception {
+ final CountDownLatch latch = new CountDownLatch(1);
Util.runAndWait(() -> {
int stagePosition = 40;
for (int i = 0; i < NUM_STAGES; i++) {
*** 353,362 ****
--- 409,419 ----
stage.setHeight(180);
stage.setScene(scene);
webview.getEngine().getLoadWorker().stateProperty().addListener((ov, o, n) -> {
if (n == Worker.State.SUCCEEDED) {
+ try {
final JSObject window = (JSObject) webview.getEngine().executeScript("window");
assertNotNull(window);
window.setMember("callback1", stage);
window.setMember("callback4", myObj);
*** 365,390 ****
// Below executeScript call will make myObj=null and GC'ed
webview.getEngine().executeScript("document.getElementById(\"mybtn3\").click()");
// Below executeScript call should not execute the JS callback (jsobjcallback) and should not cause crash as above executeScript just made myObj=null;
webview.getEngine().executeScript("document.getElementById(\"mybtn4\").click()");
}
});
webview.getEngine().loadContent(html);
stage.show();
}
});
! Util.sleep(SLEEP_TIME);
System.gc();
assertFalse(unexpectedCallback);
}
@Test
public void testJsCallbackConsoleFunction() throws Exception {
Util.runAndWait(() -> {
int stagePosition = 40;
for (int i = 0; i < NUM_STAGES; i++) {
--- 422,471 ----
// Below executeScript call will make myObj=null and GC'ed
webview.getEngine().executeScript("document.getElementById(\"mybtn3\").click()");
// Below executeScript call should not execute the JS callback (jsobjcallback) and should not cause crash as above executeScript just made myObj=null;
webview.getEngine().executeScript("document.getElementById(\"mybtn4\").click()");
+ } catch(AssertionError ex) {
+ encounteredException = ex;
+ } finally {
+ latch.countDown();
+ }
}
});
webview.getEngine().loadContent(html);
stage.show();
}
});
! if (encounteredException != null) {
! throw encounteredException;
! }
!
! try {
! latch.await();
! } catch (InterruptedException ex) {
! throw new AssertionError(ex);
! }
!
! for (int j = 0; j < 5; j++) {
System.gc();
+ System.runFinalization();
+
+ if (unexpectedCallback) {
+ break;
+ }
+
+ Util.sleep(SLEEP_TIME);
+ }
assertFalse(unexpectedCallback);
}
@Test
public void testJsCallbackConsoleFunction() throws Exception {
+ final CountDownLatch latch = new CountDownLatch(1);
Util.runAndWait(() -> {
int stagePosition = 40;
for (int i = 0; i < NUM_STAGES; i++) {
*** 401,430 ****
stage.setHeight(180);
stage.setScene(scene);
webview.getEngine().getLoadWorker().stateProperty().addListener((ov, o, n) -> {
if (n == Worker.State.SUCCEEDED) {
final JSObject window = (JSObject) webview.getEngine().executeScript("window");
assertNotNull(window);
window.setMember("console", new Object());
System.gc(); System.gc();
webview.getEngine().executeScript("window.console.debug = function() {}");
}
});
webview.getEngine().loadContent(html);
stage.show();
}
});
! Util.sleep(SLEEP_TIME);
System.gc();
}
@Test
public void testJsCallbackStrongRefPrimitiveArrayFunction() throws Exception {
Util.runAndWait(() -> {
int stagePosition = 40;
for (int i = 0; i < NUM_STAGES; i++) {
--- 482,529 ----
stage.setHeight(180);
stage.setScene(scene);
webview.getEngine().getLoadWorker().stateProperty().addListener((ov, o, n) -> {
if (n == Worker.State.SUCCEEDED) {
+ try {
final JSObject window = (JSObject) webview.getEngine().executeScript("window");
assertNotNull(window);
window.setMember("console", new Object());
System.gc(); System.gc();
+ System.runFinalization();
webview.getEngine().executeScript("window.console.debug = function() {}");
+ } catch(AssertionError ex) {
+ encounteredException = ex;
+ } finally {
+ latch.countDown();
+ }
}
});
webview.getEngine().loadContent(html);
stage.show();
}
});
! if (encounteredException != null) {
! throw encounteredException;
! }
!
! try {
! latch.await();
! } catch (InterruptedException ex) {
! throw new AssertionError(ex);
! }
!
System.gc();
+ System.runFinalization();
}
@Test
public void testJsCallbackStrongRefPrimitiveArrayFunction() throws Exception {
+ final CountDownLatch latch = new CountDownLatch(1);
Util.runAndWait(() -> {
int stagePosition = 40;
for (int i = 0; i < NUM_STAGES; i++) {
*** 441,473 ****
stage.setHeight(180);
stage.setScene(scene);
webview.getEngine().getLoadWorker().stateProperty().addListener((ov, o, n) -> {
if (n == Worker.State.SUCCEEDED) {
final JSObject window = (JSObject) webview.getEngine().executeScript("window");
assertNotNull(window);
window.setMember("callback2", stage);
window.setMember("primitiveArray", primitiveArray);
webview.getEngine().executeScript("document.getElementById(\"mybtn2\").onclick = function() {callback2.jscallback2(primitiveArray);}");
webview.getEngine().executeScript("document.getElementById(\"mybtn2\").click()");
}
});
webview.getEngine().loadContent(html);
stage.show();
}
});
! Util.sleep(SLEEP_TIME);
System.gc();
! for (int i = 0; i < NUM_STAGES; i++) {
! assertTrue(callbackStatus[i]);
}
}
@Test
public void testJsCallbackLocalPrimitiveArrayFunctionWithGC() throws Exception {
Util.runAndWait(() -> {
int[] localPrimitiveArray = {1, 2, 3, 4, 5};
int stagePosition = 40;
--- 540,597 ----
stage.setHeight(180);
stage.setScene(scene);
webview.getEngine().getLoadWorker().stateProperty().addListener((ov, o, n) -> {
if (n == Worker.State.SUCCEEDED) {
+ try {
final JSObject window = (JSObject) webview.getEngine().executeScript("window");
assertNotNull(window);
window.setMember("callback2", stage);
window.setMember("primitiveArray", primitiveArray);
webview.getEngine().executeScript("document.getElementById(\"mybtn2\").onclick = function() {callback2.jscallback2(primitiveArray);}");
webview.getEngine().executeScript("document.getElementById(\"mybtn2\").click()");
+ } catch(AssertionError ex) {
+ encounteredException = ex;
+ } finally {
+ latch.countDown();
+ }
}
});
webview.getEngine().loadContent(html);
stage.show();
}
});
! if (encounteredException != null) {
! throw encounteredException;
! }
!
! try {
! latch.await();
! } catch (InterruptedException ex) {
! throw new AssertionError(ex);
! }
!
! for (int j = 0; j < 5; j++) {
System.gc();
! System.runFinalization();
!
! if (isAllCallbackStatusTrue()) {
! break;
}
+
+ Util.sleep(SLEEP_TIME);
+ }
+
+ assertTrue("All Button Callback return true", isAllCallbackStatusTrue());
}
@Test
public void testJsCallbackLocalPrimitiveArrayFunctionWithGC() throws Exception {
+ final CountDownLatch latch1 = new CountDownLatch(1);
+ final CountDownLatch latch2 = new CountDownLatch(1);
Util.runAndWait(() -> {
int[] localPrimitiveArray = {1, 2, 3, 4, 5};
int stagePosition = 40;
*** 486,525 ****
stage.setHeight(180);
stage.setScene(scene);
webview.getEngine().getLoadWorker().stateProperty().addListener((ov, o, n) -> {
if (n == Worker.State.SUCCEEDED) {
final JSObject window = (JSObject) webview.getEngine().executeScript("window");
assertNotNull(window);
window.setMember("callback2", stage);
window.setMember("localPrimitiveArray", new int[] { 1, 2, 3, 4, 5 });
System.gc(); System.gc();
}
});
webview.getEngine().loadContent(html);
stage.show();
}
});
Util.sleep(SLEEP_TIME);
- System.gc();
Util.runAndWait(() -> {
for (int i = 0; i < NUM_STAGES; i++) {
System.gc();
webviewArray[i].getEngine().executeScript("document.getElementById(\"mybtn2\").onclick = function() {callback2.jscallback3(localPrimitiveArray);}");
webviewArray[i].getEngine().executeScript("document.getElementById(\"mybtn2\").click()");
}
});
assertFalse(unexpectedCallback);
}
@Test
public void testJsCallbackStrongRefObjectArrayFunction() throws Exception {
Util.runAndWait(() -> {
int stagePosition = 40;
for (int i = 0; i < NUM_STAGES; i++) {
--- 610,674 ----
stage.setHeight(180);
stage.setScene(scene);
webview.getEngine().getLoadWorker().stateProperty().addListener((ov, o, n) -> {
if (n == Worker.State.SUCCEEDED) {
+ try {
final JSObject window = (JSObject) webview.getEngine().executeScript("window");
assertNotNull(window);
window.setMember("callback2", stage);
window.setMember("localPrimitiveArray", new int[] { 1, 2, 3, 4, 5 });
System.gc(); System.gc();
+ System.runFinalization();
+ } catch(AssertionError ex) {
+ encounteredException = ex;
+ } finally {
+ latch1.countDown();
+ }
}
});
webview.getEngine().loadContent(html);
stage.show();
}
});
+ if (encounteredException != null) {
+ throw encounteredException;
+ }
+
+ try {
+ latch1.await();
+ } catch (InterruptedException ex) {
+ throw new AssertionError(ex);
+ }
+
Util.sleep(SLEEP_TIME);
Util.runAndWait(() -> {
for (int i = 0; i < NUM_STAGES; i++) {
System.gc();
+ System.runFinalization();
webviewArray[i].getEngine().executeScript("document.getElementById(\"mybtn2\").onclick = function() {callback2.jscallback3(localPrimitiveArray);}");
webviewArray[i].getEngine().executeScript("document.getElementById(\"mybtn2\").click()");
}
+ latch2.countDown();
});
+ try {
+ latch2.await();
+ } catch (InterruptedException ex) {
+ throw new AssertionError(ex);
+ }
+
assertFalse(unexpectedCallback);
}
@Test
public void testJsCallbackStrongRefObjectArrayFunction() throws Exception {
+ final CountDownLatch latch = new CountDownLatch(1);
Util.runAndWait(() -> {
int stagePosition = 40;
for (int i = 0; i < NUM_STAGES; i++) {
*** 536,568 ****
stage.setHeight(180);
stage.setScene(scene);
webview.getEngine().getLoadWorker().stateProperty().addListener((ov, o, n) -> {
if (n == Worker.State.SUCCEEDED) {
final JSObject window = (JSObject) webview.getEngine().executeScript("window");
assertNotNull(window);
window.setMember("callback2", stage);
window.setMember("objectArray", objectArray);
webview.getEngine().executeScript("document.getElementById(\"mybtn2\").onclick = function() {callback2.jscallback4(objectArray);}");
webview.getEngine().executeScript("document.getElementById(\"mybtn2\").click()");
}
});
webview.getEngine().loadContent(html);
stage.show();
}
});
! Util.sleep(SLEEP_TIME);
System.gc();
! for (int i = 0; i < NUM_STAGES; i++) {
! assertTrue(callbackStatus[i]);
}
}
@Test
public void testJsCallbackLocalObjectArrayFunctionWithGC() throws Exception {
Util.runAndWait(() -> {
int stagePosition = 40;
for (int i = 0; i < NUM_STAGES; i++) {
--- 685,743 ----
stage.setHeight(180);
stage.setScene(scene);
webview.getEngine().getLoadWorker().stateProperty().addListener((ov, o, n) -> {
if (n == Worker.State.SUCCEEDED) {
+ try {
final JSObject window = (JSObject) webview.getEngine().executeScript("window");
assertNotNull(window);
window.setMember("callback2", stage);
window.setMember("objectArray", objectArray);
webview.getEngine().executeScript("document.getElementById(\"mybtn2\").onclick = function() {callback2.jscallback4(objectArray);}");
webview.getEngine().executeScript("document.getElementById(\"mybtn2\").click()");
+ } catch(AssertionError ex) {
+ encounteredException = ex;
+ } finally {
+ latch.countDown();
+ }
}
});
webview.getEngine().loadContent(html);
stage.show();
}
});
! if (encounteredException != null) {
! throw encounteredException;
! }
!
! try {
! latch.await();
! } catch (InterruptedException ex) {
! throw new AssertionError(ex);
! }
!
! for (int j = 0; j < 5; j++) {
System.gc();
! System.runFinalization();
!
! if (isAllCallbackStatusTrue()) {
! break;
}
+
+ Util.sleep(SLEEP_TIME);
+ }
+
+ assertTrue("All Button Callback return true", isAllCallbackStatusTrue());
+
}
@Test
public void testJsCallbackLocalObjectArrayFunctionWithGC() throws Exception {
+ final CountDownLatch latch1 = new CountDownLatch(1);
+ final CountDownLatch latch2 = new CountDownLatch(1);
Util.runAndWait(() -> {
int stagePosition = 40;
for (int i = 0; i < NUM_STAGES; i++) {
*** 580,612 ****
stage.setHeight(180);
stage.setScene(scene);
webview.getEngine().getLoadWorker().stateProperty().addListener((ov, o, n) -> {
if (n == Worker.State.SUCCEEDED) {
final JSObject window = (JSObject) webview.getEngine().executeScript("window");
assertNotNull(window);
window.setMember("callback2", stage);
window.setMember("localObjectArray", new Object[] { new Object(), new Object(), new Object(), new Object() });
System.gc(); System.gc();
}
});
webview.getEngine().loadContent(html);
stage.show();
}
});
Util.sleep(SLEEP_TIME);
- System.gc();
Util.runAndWait(() -> {
for (int i = 0; i < NUM_STAGES; i++) {
System.gc();
webviewArray[i].getEngine().executeScript("document.getElementById(\"mybtn2\").onclick = function() {callback2.jscallback5(localObjectArray);}");
webviewArray[i].getEngine().executeScript("document.getElementById(\"mybtn2\").click()");
}
});
assertFalse(unexpectedCallback);
}
}
--- 755,811 ----
stage.setHeight(180);
stage.setScene(scene);
webview.getEngine().getLoadWorker().stateProperty().addListener((ov, o, n) -> {
if (n == Worker.State.SUCCEEDED) {
+ try {
final JSObject window = (JSObject) webview.getEngine().executeScript("window");
assertNotNull(window);
window.setMember("callback2", stage);
window.setMember("localObjectArray", new Object[] { new Object(), new Object(), new Object(), new Object() });
System.gc(); System.gc();
+ System.runFinalization();
+ } catch(AssertionError ex) {
+ encounteredException = ex;
+ } finally {
+ latch1.countDown();
+ }
}
});
webview.getEngine().loadContent(html);
stage.show();
}
});
+ if (encounteredException != null) {
+ throw encounteredException;
+ }
+
+ try {
+ latch1.await();
+ } catch (InterruptedException ex) {
+ throw new AssertionError(ex);
+ }
+
Util.sleep(SLEEP_TIME);
Util.runAndWait(() -> {
for (int i = 0; i < NUM_STAGES; i++) {
System.gc();
+ System.runFinalization();
webviewArray[i].getEngine().executeScript("document.getElementById(\"mybtn2\").onclick = function() {callback2.jscallback5(localObjectArray);}");
webviewArray[i].getEngine().executeScript("document.getElementById(\"mybtn2\").click()");
}
+ latch2.countDown();
});
+ try {
+ latch2.await();
+ } catch (InterruptedException ex) {
+ throw new AssertionError(ex);
+ }
+
assertFalse(unexpectedCallback);
}
}
< prev index next >