Bug #11631
fix issues with persistent UI triggers
100%
History
#2 Updated by Constantin Asofiei 3 months ago
- an
APPLY <event> TO <handle>can't find anON ANY-KEY [ANYWHERE]trigger - in batch mode,
ENTRYevent in 4GL is not fired viaAPPLY; in interactive mode, the widget must beSENSITIVE(and attached to frame) forAPPLYto find it - other issues found from testing
#3 Updated by Razvan-Nicolae Chichirau 3 months ago
- Assignee set to Razvan-Nicolae Chichirau
- Status changed from New to WIP
Constantin Asofiei wrote:
- an
APPLY <event> TO <handle>can't find anON ANY-KEY [ANYWHERE]trigger
Testcase:
def var fi as char view-as fill-in.
def button btn.
def frame f fi skip btn.
def var hFi as handle.
hFi = fi:handle.
on ANY-KEY of hFi do:
message "ANY-KEY".
end.
on choose of btn do:
apply "1" to hFi.
end.
enable all with frame f.
apply "entry" to btn.
wait-for window-close of current-window.
- in batch mode,
ENTRYevent in 4GL is not fired viaAPPLY; in interactive mode, the widget must beSENSITIVE(and attached to frame) forAPPLYto find it
Please post the relevant testcases here. I wasn't able to reproduce the issue.
- other issues found from testing
Can you describe them?
#4 Updated by Constantin Asofiei 3 months ago
The tests are in testcases rev 1854. They should be ran in both standalone and test-suite mode. They pass in OE, but needs to be double-checked. If ran individually, these are meant as 'batch programs'.
All checks I did until now were in batch mode (non-interactive).
About ENTRY, LEAVE, etc: the point is to have the widget not attached to a frame, not realized, etc. ENTRY from my experimenting is sent only if the widget is realized and SENSITIVE.
IMO, we will need to remove the EventList.lookup(long resourceId, boolean trigExit, TriggerMatch result) and use the main event lookup method. For this, we will need to be able to resolve easily the widget ID (if any) for a certain resource ID. I propose a maintained map in the WidgetRegistry, for (resourceID, widgetID) pairs. So that when we have a apply "x" to <resource>." we can resolve fast the widget ID and call the event lookup method. The problem: when destroying a widget, this widget needs to be removed from this map - so we need also (widgetID->resourceID) mapping.
Please thing about the above and lets find best way to do this. What I'm pretty sure we can't short-circuit the lookup when we have a resource ID as target.
Events in 4GL can be applied to any resource, but not all resources will execute them. For example, looks likeENTRY to a proc-handle will be a no-op, even if the proc-handle has a ON ENTRY OF proc-handle PERSISTENT RUN.
- user-defined events like
U1,U2, etc - key events like
a,b,c - widget-level events like
ENTRY,LEAVE,CHOOSE,VALUE-CHANGED, etc - anything else I'm missing
- widget state can be not-realized, realized, visible, sensitive.
Automation can be tested in batch mode. In interactive mode, is more complex.
#6 Updated by Razvan-Nicolae Chichirau 20 days ago
Can confirm the suite commited in testcases rev. 1854 passes fully in OE when executed in standalone or suite mode. Ran the same suite in FWD with trunk rev. 16765, this is the JUnit output:
Show
#7 Updated by Razvan-Nicolae Chichirau 20 days ago
First problem that I will analyze is in TestValidVersusInvalidResource.p:
/* (a) VALID resource: register + apply. hFill is not attached to a frame, so
ENTRY (a focus event) must not fire */
create fill-in hFill.
on 'ENTRY':U of hFill persistent run onEntry.
apply 'ENTRY':U to hFill.
Assert:Equals(0, iEntry). // FWD: 1, OE: 0
I checked in OpenEdge 12.8 (GUI + ChUI) whether PERSISTENT/NON-PERSISTENT triggers run when an event is sent with APPLY to a STATIC/DYNAMIC widget that has no frame (only for dynamic widgets), is not realized, is hidden, is not sensitive or is not enabled.
APPLY and records which triggers ran.
- Widget types: FILL-IN, BUTTON, TOGGLE-BOX, EDITOR, COMBO-BOX, SELECTION-LIST, RADIO-SET, SLIDER.
- States:
- CONTROL: visible and sensitive.
- NO-FRAME:
FRAMEnever set. - NOT-REALIZED:
FRAMEset, frame never viewed. - HIDDEN: realized, then
HIDDEN = TRUE. - NOT-SENSITIVE:
SENSITIVEset to TRUE, then FALSE. - NOT-ENABLED: visible,
SENSITIVEnever set. - FRAME-NOT-SENSITIVE: like CONTROL, but the frame's
SENSITIVE = FALSE.
- Events (39):
ENTRY,LEAVE,VALUE-CHANGED,CHOOSE,DEFAULT-ACTION,GO,RETURN,TAB,BACK-TAB,HELP,END-ERROR,ENDKEY,ERROR, the cursor keys,HOME,END,PAGE-UP,PAGE-DOWN,BACKSPACE,DELETE-CHARACTER,a,b(no own trigger, so it should reachANY-PRINTABLE),ANY-PRINTABLE, 10 mouse events andU1,U2,U10.
All 8 widget types were run to completion. 2107 cases produced a result and 77 crashed the session in OE.
Results¶
The same for PERSISTENT/NON-PERSISTENT triggers, STATIC/DYNAMIC widgets, GUI/ChUI:
| State | ENTRY trigger | Other 38 events |
|---|---|---|
| No frame | not run (0/8 types) | run |
| Frame set, not realized | not run (0/8) | run |
| Realized but hidden | FILL-IN: not run. Other 7 types: run, and the hidden widget gets focus | run |
| Not sensitive | not run (0/8) | run |
| Not enabled | not run (0/8) | run |
| frame not sensitive, widget sensitive | run (8/8), gets focus | run |
| CONTROL | run (8/8), gets focus | run |
Conclusion¶
Based on the provided results, the ENTRY trigger runs only when the widget can take focus:
- The widget must belong to a frame, and that frame must be realized.
APPLY "ENTRY"does not realize the widget. - The widget itself must have
SENSITIVE = TRUE. It makes no difference whether it was disabled after being enabled or never enabled. HIDDEN = TRUEblocks ENTRY only for FILL-IN. For the other 7 types a hidden (but realized and sensitive) widget still runs the ENTRY trigger and receives focus.SENSITIVE = FALSEon the parent frame does not block ENTRY; only the widget's ownSENSITIVEmatters.
Note: The crashes from OE were happening when calling APPLY with certain events. The crash reason was an ACCESS_VIOLATION from the .exe file, so it is a 4GL bug.
#8 Updated by Razvan-Nicolae Chichirau 20 days ago
P.S.: I've done the same testing for frames, and there is one single difference from the results posted in #11631-7. An APPLY "ENTRY" for a frame with SENSITIVE = false invokes the entry trigger on ChUI, but not in GUI.
#9 Updated by Razvan-Nicolae Chichirau 19 days ago
I was wondering whether APPLY "ENTRY" was only reduced to the trigger not being executed, while other side effects, such as a focus change, could still occur.
APPLY "ENTRY" did not execute the associated trigger:
- The
FOCUShandle didn't change at all. - The
VISIBLE,HIDDEN, andSENSITIVEattributes of the widget / frame didn't changed either - There are no other triggers that run on the widget, like a
LEAVEorVALUE-CHANGED - There are no errors or conditions raised.
With these in mind, I think it's safe to say that an APPLY "ENTRY" is basically just a NO-OP in these conditions and the call can be stopped before reaching the client.
#10 Updated by Razvan-Nicolae Chichirau 13 days ago
As Constantin pointed out in #11631-4, events in 4GL can be applied to any resource, but not all resources will execute them. I made an OE testcase which applies 56 events (focus, widget, window, procedure, socket/query, universal keys, navigation keys, printable keys, mouse, developer events U1..U10) to most of the non-widget resources, and also to windows, frames, menus in different states. This was executed in GUI and ChUI interactive + batch mode.
1. Non-widget resources (procedure, buffer, query, temp-table, dataset, data-source, socket, XML, call, etc...)¶
With a specific trigger (ON ev OF h), in GUI and ChUI, every event executes the trigger, except ENTRY:
ENTRYis a silent no-op: the trigger is not executed and no error is raised.LEAVEdoes execute the trigger, onTHIS-PROCEDUREand on any persistent procedure handle.SELFinside the trigger is the resource itself, procedure handles included.
2. Catch-all triggers (the same for all the resource types, windows, frames and menus included)¶
| Trigger | What it catches via APPLY |
|---|---|
ANY-KEY OF h |
only key labels (a, 1, b, F5) and U1..U10; never key functions (GO, RETURN, TAB, CURSOR-*, HELP, END-ERROR, ...) and never widget events |
ANY-PRINTABLE OF h |
only a, 1, b |
ON ev ANYWHERE |
the same as the specific trigger: everything except ENTRY, non-widget resources included |
ON ANY-KEY ANYWHERE, ON ANY-PRINTABLE ANYWHERE |
the same as ANY-KEY OF h / ANY-PRINTABLE OF h |
So APPLY <event> TO <handle> must find the ANY-KEY, ANY-PRINTABLE and ANYWHERE triggers for all the resource types, not only for widgets.
3. ChUI batch vs ChUI interactive¶
Regarding the trigger of the applied event itself, the only difference between ChUI batch and interactive is APPLY "ENTRY" to a widget:
| Case (APPLY "ENTRY") | ChUI interactive | ChUI batch |
|---|---|---|
| FILL-IN, sensitive, frame made visible | the FILL-IN is visible: executes the trigger, gets the focus | the FILL-IN is not visible: never executes the trigger (the same as a hidden FILL-IN in interactive ChUI) |
| other field-level widgets (button, toggle-box, combo-box, selection-list, radio-set, slider, browse), sensitive, frame made visible | executes the trigger, gets the focus | executes the trigger, gets the focus (the same as a hidden widget in interactive ChUI) |
widget in a frame which is not realized, with SENSITIVE = TRUE (button, toggle-box, combo-box, selection-list, radio-set, slider, browse) |
does not execute the trigger | executes the trigger and gets the focus |
| frame not realized | does not execute the trigger | executes the trigger |
4. APPLY "ENTRY", other cases¶
- a window executes the
ENTRYtrigger only when it isSENSITIVE(VISIBLEandHIDDENdo not matter). - a frame must be realized; in GUI it must also be
SENSITIVE, in ChUI a not sensitive frame still executes the trigger. - menus (menu-bar, sub-menu, menu-item, popup) and dynamic widgets which are not attached to a frame: silent no-op.
- IMAGE, RECTANGLE and TEXT never execute the
ENTRYtrigger, even whenSENSITIVE = TRUE. - OCXs such as
TreeView,PSTimeror an emptyCONTROL-FRAME: theAPPLYstatement can only be made for handles, not com-handles, so you can only apply events to theCONTROL-FRAME. Testing revealed that only the widgetSENSITIVEattribute matters.
Important note: The implemented code logic will not apply to third-party (pluggable) widgets. Thus, the server will not suppress the ENTRY event in this case.
testcases rev. 1854:
- trunk: 12 failed, 5 successful
- 11631a: 6 failed, 11 successful
I'll consider the APPLY investigation complete. Moving to the issues with ON ANY-KEY [ANYWHERE] triggers.
#11 Updated by Razvan-Nicolae Chichirau 6 days ago
- Status changed from WIP to Review
- % Done changed from 0 to 100
- reviewer Constantin Asofiei added
Constantin: Please review 11631a/rev. 16767.
I found out that an ENTRY event on widgets that can't process it directly can have side-effects, as opposed to the claims made in #11631-9. For example an entry on a non-sensitive widget can raise the entry for its frame, or even its window.
As such, I had to re-evaluate my research and implementation. Tested APPLY "ENTRY" on 15 widget and frame types in 20 states (sensitive, hidden, frame never realized, attributes changed right before the APPLY, etc.). The suite also covered nested frames, resources, menus and windows, implicit APPLY, APPLY from inside triggers and repeated APPLYs. Ran the suite in OE, FWD trunk and FWD 11631a, in GUI, ChUI and batch.
In addition, the suite tests the catch-all triggers, in GUI and ChUI: APPLY <ev> TO T with 22 trigger sets (ON ev OF T, ANY-KEY / ANY-PRINTABLE OF T, ON ev ANYWHERE, ANY-KEY / ANY-PRINTABLE ANYWHERE, ON ev / ANY-KEY of the frame and of the window, with and without ANYWHERE; all of them together, then without the winning trigger one at a time, to get the precedence order), 12 targets (query, buffer, procedure, X-document, popup menu-item, frameless button, button and fill-in in a frame, not sensitive button, button in a never realized frame, frame, window) and 17 events (a, 1, F5, CTRL-A, DEL, RETURN, TAB, U1, U10, GO, CHOOSE, ENTRY, INS, BACKSPACE, HOME, ,CURSOR-UP, DELETE-CHARACTER).
In OE, 3533 APPLY cases were run (mostly ENTRY); 3205 could be compared in all three runs, the rest use widgets the FWD ChUI client does not support (e.g. SLIDER).
| Class | Meaning |
|---|---|
| OK | branch = OE, trunk = OE |
| FIXED | branch = OE, trunk โ OE |
| REGRESSION | branch โ OE, trunk = OE |
| STILL-DIFF | branch = trunk โ OE (older FWD difference) |
| CHANGED | branch โ trunk, both โ OE |
APPLY "ENTRY"¶
| Mode | OK | FIXED | REGRESSION | CHANGED | STILL-DIFF |
|---|---|---|---|---|---|
| GUI | 309 | 204 | 0 | 13 | 853 |
| ChUI interactive | 10 | 0 | 0 | 131 | 847 |
| ChUI batch | 145 | 107 | 10 | 154 | 422 |
In batch, the regressions and most CHANGED cases run the same triggers as OE; they differ only in the frame's VISIBLE read before the APPLY: yes (the server value), OE: no. The suite's APPLY "ENTRY" to a SENSITIVE fill-in before each case is now dropped, so no client call refreshes it first (an older FWD difference). Comparing only the triggers which ran: 159 / 107 / 0 / 4 / 568.
ANY-KEY / ANY-PRINTABLE / ANYWHERE¶
For resources the lookup stopped at exact matches, and an applied key was not treated as a key event; both are fixed. In OE:
- precedence:
ON ev OF h>ANY-PRINTABLE/ANY-KEY OF h>ON ev ANYWHERE>ANY-PRINTABLE/ANY-KEY ANYWHERE, for every target; ANY-KEYcatches an applieda, 1, F5, CTRL-A, INS, U1, U10, notDEL, BACKSPACE, HOME, CURSOR-UP, DELETE-CHARACTER, RETURN, TAB, GO, CHOOSE, ENTRY;- ChUI: no window trigger runs for a widget in a never realized frame (GUI: it runs).
| Mode | Compared | OK | FIXED | REGRESSION | CHANGED | STILL-DIFF |
|---|---|---|---|---|---|---|
| GUI | 3419 | 1985 | 931 | 0 | 86 | 417 |
| ChUI interactive | 4366 | 2773 | 1487 | 0 | 2 | 104 |
No batch row: in batch, a trigger defined by an ON statement inside a DO ON ERROR UNDO, LEAVE block with a CATCH stays active after its procedure ends (trunk too; in OE it ends with the procedure), so leftover triggers fire in later cases.
With these 2 solutions in place, I ran the suite from rev. 1854: Show
I've also investigated the remaining 3 failed tests. When applying the event, getWidget() on client returns null because the widget is not in the registry, so the event ends up being rerouted to the default window. This is another, separate bug from 11631a. I will treat it in 11631b.
#12 Updated by Alexandru Lungu 1 day ago
- Priority changed from Normal to Urgent
Constantin: Please review 11631a/rev. 16767.
Constantin, please review with high priority. The related #11731 from the customer is meant to reach production soon and this fix is required.
Otherwise, do you think somebody from UI side is more fit to review?
#13 Updated by Constantin Asofiei 1 day ago
Razvan, please rebase. Also, please point me where the tests you've created are.
#14 Updated by Razvan-Nicolae Chichirau 1 day ago
- File regress_11631.p added
Rebased 11631a to trunk rev. 16796. Attached the tests. The results were gathered by comparing the log file of OE and FWD, GUI, ChUI + batch, with a script.
#15 Updated by Constantin Asofiei 1 day ago
- File deleted (
regress_11631.p)
#16 Updated by Constantin Asofiei 1 day ago
Razvan, please clean these up as unit-tests and commit them to testcases project.
#17 Updated by Razvan-Nicolae Chichirau 1 day ago
Unit tests are executed in batch mode, right? There are over 6k tests in this suite, and the behavior is different between gui/chui interactive and batch, so executing only in batch mode will tell half the story. Is any reliable way of testing the 3 modes with unit tests?
#18 Updated by Constantin Asofiei 1 day ago
Then this raises another question: what modes did you run the scenarios in the test? We need GUI, ChUI and batch.
The batch version of the tests can be re-written as unit-tests, at least.
#19 Updated by Razvan-Nicolae Chichirau 1 day ago
I ran the suite in all 3 modes. You can see the test results being listed for all modes.
#20 Updated by Greg Shah 1 day ago
Razvan-Nicolae Chichirau wrote:
Unit tests are executed in batch mode, right? There are over 6k tests in this suite, and the behavior is different between gui/chui interactive and batch, so executing only in batch mode will tell half the story. Is any reliable way of testing the 3 modes with unit tests?
Using Sikuli to Automate Interactive ABLUnit Tests
We are moving to Lyra which is even better for this but for which we need some work to implement/integrate the approach. See Testing.
#21 Updated by Razvan-Nicolae Chichirau 1 day ago
Greg, Sikuli is not needed here as the suite just applies some events like ENTRY or LEAVE and checks what triggers were executed and the current values of some attributes.
Constantin, I managed to run the unit tests as GUI and ChUI batch mode directly from Developer Studio. For ChUI, I had to run the unit tests from cmd:
"%DLC%\bin\_progres.exe" -p run_ablunit.p -param "CFG=ablunit.json"
All @Test methods will pass 3 expected results to one common endpoint which will execute the actual test and decide with what we should compare the result with, based on the current mode. In this way, we can have all 3 modes covered.