/rugnux/status kept answering with the previous collection's rugnux run after POST /initialize, and also after a /start whose collection does not run rugnux - the latter under the new run's tokens. RugnuxLiveStatus gets a Clear(), called from JFJochReceiverService::ClearResults(), which /start already uses to drop the previous run's status, plots and buffered images before the tokens change. Initialize now calls ClearResults() instead of ClearImageBuffer(), so a fresh start also drops the previous run's receiver status and plots. Authentication: every rugnux endpoint (GET/PUT /config/rugnux, PUT/DELETE /config/rugnux/model, GET /rugnux/status) was already in the broker's bearer-protected set and carries bearerAuth in jfjoch_api.yaml; the HTTP auth test now checks all five. The yaml descriptions of /initialize and rugnux_live_status say so; the C++ model and frontend client are regenerated (comments only). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PXc1zD1yxHqaR1DGdCTHL4
89 lines
3.0 KiB
C++
89 lines
3.0 KiB
C++
// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
#include <catch2/catch_all.hpp>
|
|
|
|
#include "../receiver/RugnuxLiveStatus.h"
|
|
#include "../image_puller/TestImagePuller.h"
|
|
|
|
using namespace std::chrono_literals;
|
|
|
|
TEST_CASE("RugnuxLiveStatus_TimesFromFirstImage", "[RugnuxLive]") {
|
|
// 11 images at 100 Hz, the first 3 s after START, reported out of order as several forward threads do
|
|
const auto start = std::chrono::steady_clock::now() - 10s;
|
|
const auto first = start + 3s;
|
|
|
|
RugnuxLiveStatus status;
|
|
status.Start(11, 0.11, start);
|
|
for (int i: {1, 0, 2, 3, 4, 5, 6, 7, 8, 10, 9})
|
|
status.ImageReceived(first + i * 10ms);
|
|
|
|
auto s = status.Get();
|
|
CHECK(s.expected_collection_s.value() == Catch::Approx(0.11));
|
|
REQUIRE(s.images_received == 11);
|
|
REQUIRE(s.start_to_first_image_s.value() == Catch::Approx(3.0));
|
|
CHECK(!s.last_image_s);
|
|
// "now" is 10 s after START, 7 s after the first image
|
|
CHECK(s.elapsed_s == Catch::Approx(7.0).margin(0.5));
|
|
|
|
REQUIRE(status.LastImage() == first + 100ms);
|
|
s = status.Get();
|
|
REQUIRE(s.last_image_s.value() == Catch::Approx(0.1));
|
|
CHECK((s.images_received - 1) / s.last_image_s.value() == Catch::Approx(100.0));
|
|
}
|
|
|
|
TEST_CASE("RugnuxLiveStatus_BeforeFirstImage", "[RugnuxLive]") {
|
|
RugnuxLiveStatus status;
|
|
status.Start(10, std::nullopt, std::chrono::steady_clock::now() - 2s);
|
|
status.Step("waiting");
|
|
|
|
const auto s = status.Get();
|
|
CHECK(!s.start_to_first_image_s);
|
|
CHECK(!s.expected_collection_s);
|
|
CHECK(s.elapsed_s == 0.0);
|
|
REQUIRE(s.steps.size() == 1);
|
|
CHECK(s.steps[0].started_s <= 0.0);
|
|
CHECK(!status.LastImage());
|
|
}
|
|
|
|
TEST_CASE("RugnuxLiveStatus_Clear", "[RugnuxLive]") {
|
|
RugnuxLiveStatus status;
|
|
status.Start(10, 1.0, std::chrono::steady_clock::now() - 2s);
|
|
status.ImageReceived(std::chrono::steady_clock::now() - 1s);
|
|
status.Step("indexing");
|
|
status.Probe("lattice found");
|
|
status.Result("OK", "fine", {{"Space group", "P 1"}}, {"a warning"});
|
|
status.Finish(RugnuxLiveState::Done);
|
|
REQUIRE(status.LastImage());
|
|
|
|
status.Clear();
|
|
const auto s = status.Get();
|
|
CHECK(s.state == RugnuxLiveState::Idle);
|
|
CHECK(s.images_expected == 0);
|
|
CHECK(s.images_received == 0);
|
|
CHECK(s.steps.empty());
|
|
CHECK(s.probe.empty());
|
|
CHECK(s.verdict.empty());
|
|
CHECK(s.summary.empty());
|
|
CHECK(s.warnings.empty());
|
|
CHECK(!s.start_to_first_image_s);
|
|
CHECK(!s.last_image_s);
|
|
CHECK(s.elapsed_s == 0.0);
|
|
CHECK(!status.LastImage());
|
|
}
|
|
|
|
TEST_CASE("TestImagePuller_SetsReceiveTime", "[RugnuxLive]") {
|
|
TestImagePuller puller;
|
|
const auto before = std::chrono::steady_clock::now();
|
|
puller.Put(ImagePullerOutput{});
|
|
const auto given = before - 5s;
|
|
puller.Put(ImagePullerOutput{.received = given});
|
|
|
|
auto out = puller.PollImage();
|
|
REQUIRE(out);
|
|
CHECK(out->received >= before);
|
|
out = puller.PollImage();
|
|
REQUIRE(out);
|
|
CHECK(out->received == given);
|
|
}
|