reiern70 opened a new issue, #1616:
URL: https://github.com/apache/wicket/issues/1616

   ### Summary
   
   `AsynchronousPageStoreTest.storeAsynchronousContextClosed` passes without 
ever
   running the assertions it exists to make, and fails intermittently in CI for 
an
   unrelated reason. It has been hiding a wrong expectation about
   `AsynchronousPageStore.PendingAdd#getSessionAttribute`.
   
   ### What the test intends
   
   It checks what an `IPageStore` may do with the `IPageContext` it is handed 
once
   the add has moved to the page saving thread: the session id is still 
readable,
   request data is not, session data and attributes read back but cannot be
   changed.
   
   ### Why it does not
   
   ```java
   asyncPageStore.addPage(context, page);
   
   store.destroy();          // the delegate, not the AsynchronousPageStore
   
   if (asyncFail.get() != null) {
       throw asyncFail.get();
   }
   ```
   
   `addPage` queues a `PendingAdd` and returns. `destroy()` is called on the
   delegate store, so `AsynchronousPageStore#destroy()` — the method that
   interrupts and joins the page saving thread — never runs. The test reads
   `asyncFail` and returns while the saving thread has usually not started, so 
the
   overridden `addPage` holding every assertion is typically never executed.
   
   ### Consequence 1: intermittent CI failure
   
   Assertion failures raised on the saving thread are `Error`s, so
   `PageAddingRunnable`'s `catch (Exception x)` does not hold them. They escape
   onto a daemon thread that outlives the test and is writing into a store the
   test already destroyed. Surfaced at whatever point the runner notices, this
   appears as:
   
   ```
   [ERROR] Errors:
   [ERROR]   AsynchronousPageStoreTest.storeAsynchronousContextClosed »
   ```
   
   The same test passes on a rerun, which is what makes it read as flaky.
   
   ### Consequence 2: a wrong expectation went unnoticed
   
   Once the test actually waits for the add, it fails:
   
   ```
   Expected org.apache.wicket.WicketRuntimeException to be thrown, but nothing 
was thrown.
        at 
AsynchronousPageStoreTest$6.addPage(AsynchronousPageStoreTest.java:414)
   ```
   
   The test required this to throw:
   
   ```java
   context.getSessionAttribute("key2", () -> null);
   ```
   
   It does not, and should not. `PendingAdd#getSessionAttribute` throws only 
where
   a value would be *changed*:
   
   ```java
   value = (T)attributeCache.get(key);
   if (value == null && defaultValue.get() != null)
   {
       throw new WicketRuntimeException("session attribute can not be changed 
asynchronuously");
   }
   ```
   
   A read of a missing key with a `null` default changes nothing and returns
   `null`. The `getSessionData` block three lines above in the same test already
   expects exactly that. The attribute expectation is simply wrong.
   
   **No production behaviour is at fault here** — this is a test defect only.
   
   ### Proposed fix
   
   - Count down a `CountDownLatch` in a `finally` around the asynchronous body 
and
     `assertTrue(added.await(...))`, so an add that never happens fails the test
     rather than passing it.
   - Record any `Throwable` from that body for the test thread to rethrow. With
     failures able to propagate, the sentinel idiom
     (`asyncFail.set(new Exception().fillInStackTrace())` followed by swallowing
     the expected exception) gives way to `assertThrows`.
   - Call `destroy()` on the `AsynchronousPageStore`, which interrupts and joins
     the saving thread and still reaches the delegate via `DelegatingPageStore`.
   - Correct the attribute expectations to mirror the session-data ones: a 
cached
     key reads back, a missing key reads `null`, only an attempted set throws.
   
   Verified with `mvn clean verify -Pjs-test` green and 8/8 on repeated runs of 
the
   class. Branch: `fix-async-pagestore-test`.
   
   ### Related
   
   `runTest` in the same class has the same leak — it destroys the delegate 
rather
   than the `AsynchronousPageStore`, so the other four tests each leak a saving
   thread. Not addressed here.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to