Корректное ожидание подтверждения Bridge
This commit is contained in:
@@ -67,6 +67,7 @@ let reconfigurationAllowsFreshDevice;
|
||||
let readOnlyObservationShowsNetworkUnavailable;
|
||||
let readOnlyFailureShowsNetworkUnavailable;
|
||||
let savedBridgeRequiresNetworkSetup;
|
||||
let isConnectionControlBootstrapSettling;
|
||||
let provisioningFailureRequiresFreshCandidate;
|
||||
let trustedConnectionBinding;
|
||||
let transportRefEquivalenceKey;
|
||||
@@ -189,6 +190,7 @@ before(async () => {
|
||||
readOnlyObservationShowsNetworkUnavailable,
|
||||
readOnlyFailureShowsNetworkUnavailable,
|
||||
savedBridgeRequiresNetworkSetup,
|
||||
isConnectionControlBootstrapSettling,
|
||||
provisioningFailureRequiresFreshCandidate,
|
||||
trustedConnectionBinding,
|
||||
transportRefEquivalenceKey,
|
||||
@@ -6228,6 +6230,92 @@ test("Apply presentation stays correlated through ACK, bootstrap, terminal and c
|
||||
);
|
||||
});
|
||||
|
||||
test("current Bridge bootstrap stays visible over an older unresolved STOP checkpoint", () => {
|
||||
const presentation = provisioningAttemptPresentation({
|
||||
localPhase: "settling",
|
||||
attemptId: "network-operation-current",
|
||||
});
|
||||
const state = durableTopologyState();
|
||||
state.snapshot_runtime_id = presentation.snapshotRuntimeId;
|
||||
state.connection_attempt = {
|
||||
schema_version: "missioncore.xgrids-k1-connection-attempt/v1",
|
||||
attempt_id: presentation.attemptId,
|
||||
connection_mode: "bridge",
|
||||
status: "running",
|
||||
phase: "network_applied",
|
||||
control_state: "unknown",
|
||||
stage: "mqtt-device-info",
|
||||
public_error_code: null,
|
||||
side_effect_status: "applied",
|
||||
safe_next_action: "wait-for-current-attempt",
|
||||
automatic_retry: false,
|
||||
accepted_at: OBSERVED_AT,
|
||||
completed_at: null,
|
||||
timeline: [],
|
||||
};
|
||||
state.operations = [{
|
||||
operation_id: presentation.attemptId,
|
||||
action: "network.provision",
|
||||
status: "succeeded",
|
||||
idempotency_key: presentation.idempotencyKey,
|
||||
}];
|
||||
state.physical_command = {
|
||||
status: "unresolved",
|
||||
reason_code: "physical-command-reconciliation-required",
|
||||
requires_reconciliation: true,
|
||||
resolved_active_recovery_required: false,
|
||||
automatic_replay_allowed: false,
|
||||
runtime_bound: true,
|
||||
reconciliation_ready: true,
|
||||
observed_session_state: "scan_stopping",
|
||||
active_operation_id: "older-stop-operation",
|
||||
record: {
|
||||
revision: 306,
|
||||
operation_id: "older-stop-operation",
|
||||
action: "stop",
|
||||
stage: "observing",
|
||||
resolution: null,
|
||||
connection: {
|
||||
transport_ref: presentation.deviceId,
|
||||
connection_mode: "quick-connect",
|
||||
target_ipv4: "192.168.56.1",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
assert.equal(isConnectionControlBootstrapSettling(state), true);
|
||||
const markup = renderProvisioningWithAttempt({
|
||||
controller: provisioningController(state),
|
||||
desiredMode: "bridge",
|
||||
}, presentation);
|
||||
|
||||
assert.match(markup, /Подтверждение подключения…/);
|
||||
assert.match(markup, /Настройки переданы один раз/);
|
||||
assert.match(markup, /<span>02<\/span>/);
|
||||
assert.match(markup, /nodedc-activity-indicator/);
|
||||
assert.doesNotMatch(markup, /Прежнее подключение не подтверждено/);
|
||||
assert.doesNotMatch(markup, />Переподключиться<\/button>/);
|
||||
assert.doesNotMatch(markup, />Подключить новый K1<\/button>/);
|
||||
|
||||
assert.equal(isConnectionControlBootstrapSettling({
|
||||
...state,
|
||||
connection_attempt: {
|
||||
...state.connection_attempt,
|
||||
status: "succeeded",
|
||||
safe_next_action: "verify-control-read-only",
|
||||
},
|
||||
}), true);
|
||||
assert.equal(isConnectionControlBootstrapSettling({
|
||||
...state,
|
||||
connection_attempt: {
|
||||
...state.connection_attempt,
|
||||
status: "failed",
|
||||
control_state: "control_not_ready",
|
||||
safe_next_action: "manual-recovery-required",
|
||||
},
|
||||
}), false);
|
||||
});
|
||||
|
||||
test("Apply spends secret state before I/O and never stores a password in its presentation latch", () => {
|
||||
const source = readFileSync(provisioningSourceUrl, "utf8");
|
||||
const presentationType = sourceSlice(
|
||||
|
||||
Reference in New Issue
Block a user