@yuneta/gobj-ui 7.25.13 → 7.25.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -15
- package/dist/gobj-ui.cjs.js +25 -21
- package/dist/gobj-ui.es.js +25 -21
- package/package.json +1 -1
- package/src/c_yui_treedb_topics.js +30 -25
- package/src/treedb_topics_transport.wiring.test.js +79 -11
package/README.md
CHANGED
|
@@ -819,24 +819,29 @@ A write is known by its topic AND its serial (`<topic>^<form_write>`): each
|
|
|
819
819
|
topic's form counts its serials from 1, and keyed by the serial alone two
|
|
820
820
|
forms saving at once shared one entry.
|
|
821
821
|
|
|
822
|
-
**A
|
|
823
|
-
reads its topic again at once, so a cell edited in place goes
|
|
824
|
-
store has. A write that fails while the transport is NOT in
|
|
825
|
-
drop: a routing adapter (gui_agent's
|
|
826
|
-
had in flight when its session closes.
|
|
827
|
-
transport refuses the read (*"cannot route
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
822
|
+
**A drop is followed by a read of every open table** (7.25.13, 7.25.14). A
|
|
823
|
+
refused write reads its topic again at once, so a cell edited in place goes
|
|
824
|
+
back to what the store has. A write that fails while the transport is NOT in
|
|
825
|
+
session is the drop, not a refusal: a routing adapter (gui_agent's
|
|
826
|
+
`C_AGENT_TREEDB_LINK`) settles what it had in flight when its session closes.
|
|
827
|
+
The topic cannot be read then — the transport refuses the read (*"cannot route
|
|
828
|
+
'nodes' -- not in session"*) — so the view logs a warning and waits.
|
|
829
|
+
|
|
830
|
+
A drop also hides the node events published while it lasts: another writer's
|
|
831
|
+
create, update or delete reaches no table. So the disconnect edge marks the
|
|
832
|
+
view, and the first edge that finds the transport in session again reads
|
|
833
|
+
EVERY open table once — as the schema editor reloads its model on the
|
|
834
|
+
reconnect. An `EV_CONNECTION_STATE` "up" that comes before the view's own
|
|
835
|
+
transport is in session does not read; the read waits for an edge that finds
|
|
836
|
+
the transport in session. An "up" with no drop before it reads nothing. A form
|
|
837
|
+
is answered once, also when the edge answered it before the failure arrived.
|
|
834
838
|
|
|
835
839
|
```js
|
|
836
|
-
// Session up
|
|
837
|
-
// Session drops
|
|
840
|
+
// Session up, tables `users` and `roles` open.
|
|
841
|
+
// Session drops -> writes in flight answered refused
|
|
842
|
+
// (another writer creates a user; its EV_TREEDB_NODE_CREATED is lost)
|
|
838
843
|
// EV_TRANSPORT_STATE {connected: true}, transport in session
|
|
839
|
-
//
|
|
844
|
+
// -> `nodes` of users and of roles, once each
|
|
840
845
|
```
|
|
841
846
|
|
|
842
847
|
**The pkey2 of an update goes back as the record had it** (7.25.5). It names
|
package/dist/gobj-ui.cjs.js
CHANGED
|
@@ -23757,7 +23757,7 @@ var __gclass__$6 = null;
|
|
|
23757
23757
|
***************************************************************/
|
|
23758
23758
|
function mt_create$6(gobj) {
|
|
23759
23759
|
gobj.priv.form_writes = {};
|
|
23760
|
-
gobj.priv.
|
|
23760
|
+
gobj.priv.reread_on_session = false;
|
|
23761
23761
|
gobj.priv.conn_shell = null;
|
|
23762
23762
|
build_ui$6(gobj);
|
|
23763
23763
|
let subscriber = (0, _yuneta_gobj_js.gobj_read_pointer_attr)(gobj, "subscriber");
|
|
@@ -25193,7 +25193,7 @@ function ac_mt_command_answer$2(gobj, event, kw, src) {
|
|
|
25193
25193
|
if (is_connected$1(gobj)) (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_REFRESH_TOPIC", { topic_name: failed_topic }, gobj);
|
|
25194
25194
|
else {
|
|
25195
25195
|
(0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: the write of '${failed_topic}' was cut by the drop: the topic is read again when the session is back`);
|
|
25196
|
-
gobj.priv.
|
|
25196
|
+
gobj.priv.reread_on_session = true;
|
|
25197
25197
|
}
|
|
25198
25198
|
}
|
|
25199
25199
|
if (settle_form_write(gobj.priv.form_writes, form_write, failed_topic)) answer_form_write(gobj, get_gobj_formtable(gobj, failed_topic), form_write, false);
|
|
@@ -25394,30 +25394,34 @@ function ac_back_to_topics(gobj, event, kw, src) {
|
|
|
25394
25394
|
function ac_transport_state$2(gobj, event, kw, src) {
|
|
25395
25395
|
let connected = !!(kw && kw.connected);
|
|
25396
25396
|
refresh_toolbar_buttons(gobj, connected);
|
|
25397
|
-
if (!connected)
|
|
25398
|
-
|
|
25399
|
-
|
|
25400
|
-
|
|
25401
|
-
|
|
25402
|
-
|
|
25397
|
+
if (!connected) {
|
|
25398
|
+
gobj.priv.reread_on_session = true;
|
|
25399
|
+
abandon_form_writes(gobj.priv.form_writes).forEach((w) => {
|
|
25400
|
+
(0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: transport closed, the write ${w.form_write} of '${w.topic_name}' is lost`);
|
|
25401
|
+
answer_form_write(gobj, get_gobj_formtable(gobj, w.topic_name), w.form_write, false);
|
|
25402
|
+
});
|
|
25403
|
+
} else reread_open_topics(gobj);
|
|
25403
25404
|
return 0;
|
|
25404
25405
|
}
|
|
25405
25406
|
/************************************************************
|
|
25406
|
-
* The session is back: read
|
|
25407
|
-
*
|
|
25408
|
-
*
|
|
25409
|
-
*
|
|
25410
|
-
*
|
|
25411
|
-
*
|
|
25407
|
+
* The session is back after a drop: read every open table again,
|
|
25408
|
+
* as the schema editor reloads its model. A drop cuts the writes
|
|
25409
|
+
* in flight AND the node events published meanwhile, so any
|
|
25410
|
+
* table may be stale, not only the one a cut write left.
|
|
25411
|
+
*
|
|
25412
|
+
* Only when the TRANSPORT says so too -- the app's connection
|
|
25413
|
+
* (EV_CONNECTION_STATE) can report "up" before the transport of
|
|
25414
|
+
* this view is in session, and a read asked then is refused. The
|
|
25415
|
+
* read waits for an edge that finds the transport in session, and
|
|
25416
|
+
* is done once, though both edges report the same "up".
|
|
25412
25417
|
************************************************************/
|
|
25413
|
-
function
|
|
25418
|
+
function reread_open_topics(gobj) {
|
|
25414
25419
|
let priv = gobj.priv;
|
|
25415
|
-
if (!is_connected$1(gobj)) return;
|
|
25416
|
-
|
|
25417
|
-
|
|
25418
|
-
|
|
25419
|
-
if (
|
|
25420
|
-
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_REFRESH_TOPIC", { topic_name }, gobj);
|
|
25420
|
+
if (!priv.reread_on_session || !is_connected$1(gobj)) return;
|
|
25421
|
+
priv.reread_on_session = false;
|
|
25422
|
+
(0, _yuneta_gobj_js.gobj_match_children)(gobj, { __gclass_name__: "C_YUI_TREEDB_TOPIC_WITH_FORM" }).forEach((form) => {
|
|
25423
|
+
let topic_name = (0, _yuneta_gobj_js.gobj_read_attr)(form, "topic_name");
|
|
25424
|
+
if (topic_name) (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_REFRESH_TOPIC", { topic_name }, gobj);
|
|
25421
25425
|
});
|
|
25422
25426
|
}
|
|
25423
25427
|
/************************************************************
|
package/dist/gobj-ui.es.js
CHANGED
|
@@ -23752,7 +23752,7 @@ var __gclass__$6 = null;
|
|
|
23752
23752
|
***************************************************************/
|
|
23753
23753
|
function mt_create$6(gobj) {
|
|
23754
23754
|
gobj.priv.form_writes = {};
|
|
23755
|
-
gobj.priv.
|
|
23755
|
+
gobj.priv.reread_on_session = false;
|
|
23756
23756
|
gobj.priv.conn_shell = null;
|
|
23757
23757
|
build_ui$6(gobj);
|
|
23758
23758
|
let subscriber = gobj_read_pointer_attr(gobj, "subscriber");
|
|
@@ -25188,7 +25188,7 @@ function ac_mt_command_answer$2(gobj, event, kw, src) {
|
|
|
25188
25188
|
if (is_connected$1(gobj)) gobj_send_event(gobj, "EV_REFRESH_TOPIC", { topic_name: failed_topic }, gobj);
|
|
25189
25189
|
else {
|
|
25190
25190
|
log_warning(`${gobj_short_name(gobj)}: the write of '${failed_topic}' was cut by the drop: the topic is read again when the session is back`);
|
|
25191
|
-
gobj.priv.
|
|
25191
|
+
gobj.priv.reread_on_session = true;
|
|
25192
25192
|
}
|
|
25193
25193
|
}
|
|
25194
25194
|
if (settle_form_write(gobj.priv.form_writes, form_write, failed_topic)) answer_form_write(gobj, get_gobj_formtable(gobj, failed_topic), form_write, false);
|
|
@@ -25389,30 +25389,34 @@ function ac_back_to_topics(gobj, event, kw, src) {
|
|
|
25389
25389
|
function ac_transport_state$2(gobj, event, kw, src) {
|
|
25390
25390
|
let connected = !!(kw && kw.connected);
|
|
25391
25391
|
refresh_toolbar_buttons(gobj, connected);
|
|
25392
|
-
if (!connected)
|
|
25393
|
-
|
|
25394
|
-
|
|
25395
|
-
|
|
25396
|
-
|
|
25397
|
-
|
|
25392
|
+
if (!connected) {
|
|
25393
|
+
gobj.priv.reread_on_session = true;
|
|
25394
|
+
abandon_form_writes(gobj.priv.form_writes).forEach((w) => {
|
|
25395
|
+
log_warning(`${gobj_short_name(gobj)}: transport closed, the write ${w.form_write} of '${w.topic_name}' is lost`);
|
|
25396
|
+
answer_form_write(gobj, get_gobj_formtable(gobj, w.topic_name), w.form_write, false);
|
|
25397
|
+
});
|
|
25398
|
+
} else reread_open_topics(gobj);
|
|
25398
25399
|
return 0;
|
|
25399
25400
|
}
|
|
25400
25401
|
/************************************************************
|
|
25401
|
-
* The session is back: read
|
|
25402
|
-
*
|
|
25403
|
-
*
|
|
25404
|
-
*
|
|
25405
|
-
*
|
|
25406
|
-
*
|
|
25402
|
+
* The session is back after a drop: read every open table again,
|
|
25403
|
+
* as the schema editor reloads its model. A drop cuts the writes
|
|
25404
|
+
* in flight AND the node events published meanwhile, so any
|
|
25405
|
+
* table may be stale, not only the one a cut write left.
|
|
25406
|
+
*
|
|
25407
|
+
* Only when the TRANSPORT says so too -- the app's connection
|
|
25408
|
+
* (EV_CONNECTION_STATE) can report "up" before the transport of
|
|
25409
|
+
* this view is in session, and a read asked then is refused. The
|
|
25410
|
+
* read waits for an edge that finds the transport in session, and
|
|
25411
|
+
* is done once, though both edges report the same "up".
|
|
25407
25412
|
************************************************************/
|
|
25408
|
-
function
|
|
25413
|
+
function reread_open_topics(gobj) {
|
|
25409
25414
|
let priv = gobj.priv;
|
|
25410
|
-
if (!is_connected$1(gobj)) return;
|
|
25411
|
-
|
|
25412
|
-
|
|
25413
|
-
|
|
25414
|
-
if (
|
|
25415
|
-
gobj_send_event(gobj, "EV_REFRESH_TOPIC", { topic_name }, gobj);
|
|
25415
|
+
if (!priv.reread_on_session || !is_connected$1(gobj)) return;
|
|
25416
|
+
priv.reread_on_session = false;
|
|
25417
|
+
gobj_match_children(gobj, { __gclass_name__: "C_YUI_TREEDB_TOPIC_WITH_FORM" }).forEach((form) => {
|
|
25418
|
+
let topic_name = gobj_read_attr(form, "topic_name");
|
|
25419
|
+
if (topic_name) gobj_send_event(gobj, "EV_REFRESH_TOPIC", { topic_name }, gobj);
|
|
25416
25420
|
});
|
|
25417
25421
|
}
|
|
25418
25422
|
/************************************************************
|
package/package.json
CHANGED
|
@@ -160,10 +160,11 @@ function mt_create(gobj)
|
|
|
160
160
|
* and serial (form_writes_in_flight): answered refused when the
|
|
161
161
|
* transport closes under them. */
|
|
162
162
|
gobj.priv.form_writes = {};
|
|
163
|
-
/* The
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
|
|
163
|
+
/* The session dropped since the tables were read: every open table
|
|
164
|
+
* may be stale (a write the drop cut, node events published while
|
|
165
|
+
* nobody heard them). Read again when the session is back
|
|
166
|
+
* (reread_open_topics), never out of session. */
|
|
167
|
+
gobj.priv.reread_on_session = false;
|
|
167
168
|
gobj.priv.conn_shell = null; /* the shell whose EV_CONNECTION_STATE we hear */
|
|
168
169
|
|
|
169
170
|
build_ui(gobj);
|
|
@@ -2111,7 +2112,7 @@ function ac_mt_command_answer(gobj, event, kw, src)
|
|
|
2111
2112
|
log_warning(`${gobj_short_name(gobj)}: the write of ` +
|
|
2112
2113
|
`'${failed_topic}' was cut by the drop: the topic is ` +
|
|
2113
2114
|
`read again when the session is back`);
|
|
2114
|
-
gobj.priv.
|
|
2115
|
+
gobj.priv.reread_on_session = true;
|
|
2115
2116
|
}
|
|
2116
2117
|
}
|
|
2117
2118
|
/* Answered once: the transport closing may have answered
|
|
@@ -2480,13 +2481,12 @@ function ac_transport_state(gobj, event, kw, src)
|
|
|
2480
2481
|
* was typed, and the person saves again when the session is back.
|
|
2481
2482
|
*/
|
|
2482
2483
|
if(!connected) {
|
|
2484
|
+
/* What happens in the store while the session is down reaches
|
|
2485
|
+
* no table: its node events are published to nobody. Every open
|
|
2486
|
+
* table is read again when the session is back. */
|
|
2487
|
+
gobj.priv.reread_on_session = true;
|
|
2483
2488
|
abandon_form_writes(gobj.priv.form_writes).forEach((w) => {
|
|
2484
2489
|
log_warning(`${gobj_short_name(gobj)}: transport closed, the write ${w.form_write} of '${w.topic_name}' is lost`);
|
|
2485
|
-
/* Whether it reached the store is unknown: read it again
|
|
2486
|
-
* when the session is back. */
|
|
2487
|
-
if(w.topic_name) {
|
|
2488
|
-
gobj.priv.reload_on_session[w.topic_name] = true;
|
|
2489
|
-
}
|
|
2490
2490
|
answer_form_write(
|
|
2491
2491
|
gobj,
|
|
2492
2492
|
get_gobj_formtable(gobj, w.topic_name),
|
|
@@ -2495,32 +2495,37 @@ function ac_transport_state(gobj, event, kw, src)
|
|
|
2495
2495
|
);
|
|
2496
2496
|
});
|
|
2497
2497
|
} else {
|
|
2498
|
-
|
|
2498
|
+
reread_open_topics(gobj);
|
|
2499
2499
|
}
|
|
2500
2500
|
return 0;
|
|
2501
2501
|
}
|
|
2502
2502
|
|
|
2503
2503
|
/************************************************************
|
|
2504
|
-
* The session is back: read
|
|
2505
|
-
*
|
|
2506
|
-
*
|
|
2507
|
-
*
|
|
2508
|
-
*
|
|
2509
|
-
*
|
|
2504
|
+
* The session is back after a drop: read every open table again,
|
|
2505
|
+
* as the schema editor reloads its model. A drop cuts the writes
|
|
2506
|
+
* in flight AND the node events published meanwhile, so any
|
|
2507
|
+
* table may be stale, not only the one a cut write left.
|
|
2508
|
+
*
|
|
2509
|
+
* Only when the TRANSPORT says so too -- the app's connection
|
|
2510
|
+
* (EV_CONNECTION_STATE) can report "up" before the transport of
|
|
2511
|
+
* this view is in session, and a read asked then is refused. The
|
|
2512
|
+
* read waits for an edge that finds the transport in session, and
|
|
2513
|
+
* is done once, though both edges report the same "up".
|
|
2510
2514
|
************************************************************/
|
|
2511
|
-
function
|
|
2515
|
+
function reread_open_topics(gobj)
|
|
2512
2516
|
{
|
|
2513
2517
|
let priv = gobj.priv;
|
|
2514
|
-
if(!is_connected(gobj)) {
|
|
2518
|
+
if(!priv.reread_on_session || !is_connected(gobj)) {
|
|
2515
2519
|
return;
|
|
2516
2520
|
}
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2521
|
+
priv.reread_on_session = false;
|
|
2522
|
+
gobj_match_children(gobj, {
|
|
2523
|
+
__gclass_name__: "C_YUI_TREEDB_TOPIC_WITH_FORM"
|
|
2524
|
+
}).forEach((form) => {
|
|
2525
|
+
let topic_name = gobj_read_attr(form, "topic_name");
|
|
2526
|
+
if(topic_name) {
|
|
2527
|
+
gobj_send_event(gobj, "EV_REFRESH_TOPIC", {topic_name: topic_name}, gobj);
|
|
2522
2528
|
}
|
|
2523
|
-
gobj_send_event(gobj, "EV_REFRESH_TOPIC", {topic_name: topic_name}, gobj);
|
|
2524
2529
|
});
|
|
2525
2530
|
}
|
|
2526
2531
|
|
|
@@ -30,6 +30,7 @@ const {register_c_yui_treedb_topics} = await import("./c_yui_treedb_topics.js");
|
|
|
30
30
|
|
|
31
31
|
const logged = [];
|
|
32
32
|
const answers = []; /* what the fake forms were told */
|
|
33
|
+
const loaded = []; /* the rows each fake form was loaded with */
|
|
33
34
|
const commands = []; /* what the fake transport was asked */
|
|
34
35
|
|
|
35
36
|
/*
|
|
@@ -57,6 +58,12 @@ function ac_form_answer(gobj, event, kw, src)
|
|
|
57
58
|
return 0;
|
|
58
59
|
}
|
|
59
60
|
|
|
61
|
+
function ac_form_load(gobj, event, kw, src)
|
|
62
|
+
{
|
|
63
|
+
loaded.push({topic: gobj.priv_topic, rows: kw});
|
|
64
|
+
return 0;
|
|
65
|
+
}
|
|
66
|
+
|
|
60
67
|
let yuno = null;
|
|
61
68
|
let remote = null;
|
|
62
69
|
|
|
@@ -76,10 +83,11 @@ beforeAll(() => {
|
|
|
76
83
|
);
|
|
77
84
|
gclass_create(
|
|
78
85
|
"C_YUI_TREEDB_TOPIC_WITH_FORM",
|
|
79
|
-
[["EV_WRITE_DONE", 0], ["EV_WRITE_REFUSED", 0]],
|
|
86
|
+
[["EV_WRITE_DONE", 0], ["EV_WRITE_REFUSED", 0], ["EV_LOAD_NODES", 0]],
|
|
80
87
|
[["ST_IDLE", [
|
|
81
88
|
["EV_WRITE_DONE", ac_form_answer, null],
|
|
82
|
-
["EV_WRITE_REFUSED", ac_form_answer, null]
|
|
89
|
+
["EV_WRITE_REFUSED", ac_form_answer, null],
|
|
90
|
+
["EV_LOAD_NODES", ac_form_load, null]
|
|
83
91
|
]]],
|
|
84
92
|
{},
|
|
85
93
|
0,
|
|
@@ -115,6 +123,7 @@ beforeEach(() => {
|
|
|
115
123
|
logged.length = 0;
|
|
116
124
|
answers.length = 0;
|
|
117
125
|
commands.length = 0;
|
|
126
|
+
loaded.length = 0;
|
|
118
127
|
});
|
|
119
128
|
|
|
120
129
|
function build(name)
|
|
@@ -136,7 +145,9 @@ function build(name)
|
|
|
136
145
|
|
|
137
146
|
const forms = {};
|
|
138
147
|
for(const topic of ["users", "roles"]) {
|
|
139
|
-
forms
|
|
148
|
+
/* Named as the view names its forms: the answer of a `nodes`
|
|
149
|
+
* finds its table by that name. */
|
|
150
|
+
forms[topic] = gobj_create(`${name}_topics?${topic}`, "C_YUI_TREEDB_TOPIC_WITH_FORM",
|
|
140
151
|
{topic_name: topic}, topics);
|
|
141
152
|
forms[topic].priv_topic = topic;
|
|
142
153
|
}
|
|
@@ -277,13 +288,12 @@ describe("a write cut by the drop does not reload out of session", () => {
|
|
|
277
288
|
gobj_send_event(topics, "EV_TRANSPORT_STATE", {connected: false}, topics);
|
|
278
289
|
expect(nodes_asked()).toEqual([]);
|
|
279
290
|
|
|
280
|
-
/* The reconnect
|
|
281
|
-
*
|
|
291
|
+
/* The reconnect reads every open table -- once, though two edges
|
|
292
|
+
* report it. */
|
|
282
293
|
gobj_change_state(remote, "ST_SESSION");
|
|
283
294
|
gobj_send_event(topics, "EV_TRANSPORT_STATE", {connected: true}, topics);
|
|
284
|
-
yui_shell_set_connection_state(shell, false);
|
|
285
295
|
yui_shell_set_connection_state(shell, true);
|
|
286
|
-
expect(nodes_asked()).toEqual(["users"]);
|
|
296
|
+
expect(nodes_asked().sort()).toEqual(["roles", "users"]);
|
|
287
297
|
expect(errors()).toEqual([]);
|
|
288
298
|
});
|
|
289
299
|
|
|
@@ -303,7 +313,7 @@ describe("a write cut by the drop does not reload out of session", () => {
|
|
|
303
313
|
|
|
304
314
|
gobj_change_state(remote, "ST_SESSION");
|
|
305
315
|
yui_shell_set_connection_state(shell, true);
|
|
306
|
-
expect(nodes_asked()).toEqual(["users"]);
|
|
316
|
+
expect(nodes_asked().sort()).toEqual(["roles", "users"]);
|
|
307
317
|
expect(errors()).toEqual([]);
|
|
308
318
|
});
|
|
309
319
|
|
|
@@ -322,20 +332,78 @@ describe("a write cut by the drop does not reload out of session", () => {
|
|
|
322
332
|
|
|
323
333
|
gobj_change_state(remote, "ST_SESSION");
|
|
324
334
|
gobj_send_event(topics, "EV_TRANSPORT_STATE", {connected: true}, topics);
|
|
325
|
-
expect(nodes_asked()).toEqual(["roles"]);
|
|
335
|
+
expect(nodes_asked().sort()).toEqual(["roles", "users"]);
|
|
326
336
|
expect(errors().filter((m) => m.includes("not in session"))).toEqual([]);
|
|
327
337
|
});
|
|
328
338
|
|
|
329
|
-
test("a write refused IN session reloads its topic at once
|
|
339
|
+
test("a write refused IN session reloads its topic at once", () => {
|
|
330
340
|
const {shell, topics} = build("t9");
|
|
331
341
|
yui_shell_set_connection_state(shell, true);
|
|
332
342
|
gobj_send_event(topics, "EV_UPDATE_FIELD",
|
|
333
343
|
{topic_name: "users", id: "x", field: "name", value: "typed"}, topics);
|
|
334
344
|
gobj_send_event(topics, "EV_MT_COMMAND_ANSWER", failed_write("users", 0), remote);
|
|
335
345
|
expect(nodes_asked()).toEqual(["users"]);
|
|
346
|
+
});
|
|
347
|
+
});
|
|
336
348
|
|
|
349
|
+
/*
|
|
350
|
+
* The answer of a `nodes`, the way C_IEVENT_CLI delivers it.
|
|
351
|
+
*/
|
|
352
|
+
function nodes_answer_of(topic_name, rows)
|
|
353
|
+
{
|
|
354
|
+
return {result: 0, comment: "", data: rows, __md_iev__: {
|
|
355
|
+
command_stack: [{command: "nodes", kw: {topic_name: topic_name}}]
|
|
356
|
+
}};
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
describe("what the drop hid is read again on the reconnect", () => {
|
|
360
|
+
|
|
361
|
+
test("a node created during the drop is in its table after the reconnect", () => {
|
|
362
|
+
const {shell, topics} = build("t10");
|
|
363
|
+
yui_shell_set_connection_state(shell, true);
|
|
364
|
+
|
|
365
|
+
/* No write in flight: the session just drops. While it is down,
|
|
366
|
+
* another writer creates a user; its EV_TREEDB_NODE_CREATED is
|
|
367
|
+
* published to nobody. */
|
|
368
|
+
gobj_change_state(remote, "ST_DISCONNECTED");
|
|
337
369
|
gobj_send_event(topics, "EV_TRANSPORT_STATE", {connected: false}, topics);
|
|
370
|
+
yui_shell_set_connection_state(shell, false);
|
|
371
|
+
expect(nodes_asked()).toEqual([]);
|
|
372
|
+
|
|
373
|
+
gobj_change_state(remote, "ST_SESSION");
|
|
338
374
|
gobj_send_event(topics, "EV_TRANSPORT_STATE", {connected: true}, topics);
|
|
339
|
-
|
|
375
|
+
yui_shell_set_connection_state(shell, true);
|
|
376
|
+
|
|
377
|
+
/* Every open table is read once, though two edges said "up". */
|
|
378
|
+
expect(nodes_asked().sort()).toEqual(["roles", "users"]);
|
|
379
|
+
|
|
380
|
+
gobj_send_event(topics, "EV_MT_COMMAND_ANSWER",
|
|
381
|
+
nodes_answer_of("users", [{id: "x"}, {id: "created_during_the_drop"}]), remote);
|
|
382
|
+
expect(loaded).toEqual([
|
|
383
|
+
{topic: "users", rows: [{id: "x"}, {id: "created_during_the_drop"}]}
|
|
384
|
+
]);
|
|
385
|
+
expect(errors()).toEqual([]);
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
test("an 'up' with no drop before it reads nothing", () => {
|
|
389
|
+
const {shell, topics} = build("t11");
|
|
390
|
+
yui_shell_set_connection_state(shell, true);
|
|
391
|
+
gobj_send_event(topics, "EV_TRANSPORT_STATE", {connected: true}, topics);
|
|
392
|
+
expect(nodes_asked()).toEqual([]);
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
test("an edge that says 'up' before the transport is in session waits", () => {
|
|
396
|
+
const {shell, topics} = build("t12");
|
|
397
|
+
yui_shell_set_connection_state(shell, true);
|
|
398
|
+
gobj_change_state(remote, "ST_DISCONNECTED");
|
|
399
|
+
yui_shell_set_connection_state(shell, false);
|
|
400
|
+
|
|
401
|
+
yui_shell_set_connection_state(shell, true);
|
|
402
|
+
expect(nodes_asked()).toEqual([]);
|
|
403
|
+
expect(errors().filter((m) => m.includes("not in session"))).toEqual([]);
|
|
404
|
+
|
|
405
|
+
gobj_change_state(remote, "ST_SESSION");
|
|
406
|
+
gobj_send_event(topics, "EV_TRANSPORT_STATE", {connected: true}, topics);
|
|
407
|
+
expect(nodes_asked().sort()).toEqual(["roles", "users"]);
|
|
340
408
|
});
|
|
341
409
|
});
|