postjevsql.git / tests / gate_layout_parity.rs
1//! Release gate "layout parity", replayed (`tests/fixtures/layout_parity.json`,
2//! from `tools/record-gates --send`). The row-as-state requests are sent
3//! by the extension and must match the recording byte for byte. Row in
4//! instructions is unreachable from the extension until this gate passes
5//! (`LayoutParity` has no values), so its recorded exchange is checked
6//! for an answer per row rather than replayed.
7
8use support::gates::{QUESTION, ROWS, fixture, setup_people};
9use support::mock_jev::MockJev;
10use support::mock_jev::replay::Replay;
11
12#[tokio::test(flavor = "multi_thread")]
13async fn row_as_state_replays_and_row_in_instructions_answers_every_row() {
14    let fixture = fixture("layout_parity");
15    let replay = Replay::new(&fixture);
16    let mock = MockJev::start(replay.responder()).await;
17    let (_pg, client) = support::jev_instance(&mock).await;
18    setup_people(&client).await.expect("setup");
19
20    let rows = client
21        .query("SELECT name, jev_prob(p, $1) FROM people p", &[&QUESTION])
22        .await
23        .expect("replayed");
24    assert_eq!(rows.len(), ROWS.len());
25    assert_eq!(mock.requests().len(), ROWS.len(), "one request per row, as state");
26    replay.assert_complete();
27
28    // The one exchange the extension did not send: every row a question.
29    let sent: Vec<String> = mock.requests().iter().map(|r| String::from_utf8(r.body.to_vec()).unwrap()).collect();
30    let unsent: Vec<_> = fixture.exchanges.iter().filter(|(request, _)| !sent.contains(request)).collect();
31    assert_eq!(unsent.len(), 1, "row in instructions is one request");
32    let (request, responses) = unsent[0];
33    let request: serde_json::Value = serde_json::from_str(request).unwrap();
34    assert_eq!(request["state"], serde_json::json!({}));
35    let body: serde_json::Value = serde_json::from_str(&responses[0].body).unwrap();
36    for (i, row) in ROWS.iter().enumerate() {
37        let row: serde_json::Value = serde_json::from_str(row).unwrap();
38        assert_eq!(request["questions"][format!("r{i}")]["instructions"]["row"], row);
39        let p = body["answers"][format!("r{i}")]["noul"].as_f64();
40        assert!(p.is_some_and(|p| (0.0..=1.0).contains(&p)), "r{i} answered: {body}");
41    }
42}