mirror of
https://github.com/bod09/frame-autopass.git
synced 2026-10-06 00:00:05 +02:00
140 lines
5.4 KiB
C++
140 lines
5.4 KiB
C++
// Host-side test for XrServiceLog against a fake Steam logs directory:
|
|
// initial state from an existing log, appended lines (including one split
|
|
// across two writes), unrelated noise, and an XRService restart that
|
|
// replaces the xrservice.txt symlink.
|
|
|
|
#include "xrservice_log.hpp"
|
|
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <fstream>
|
|
#include <ctime>
|
|
#include <string>
|
|
#include <unistd.h>
|
|
|
|
using autopass::XrServiceLog;
|
|
|
|
namespace {
|
|
|
|
int failures = 0;
|
|
#define CHECK(expr) do { if (!(expr)) { std::printf("FAIL line %d: %s\n", __LINE__, #expr); ++failures; } } while (0)
|
|
|
|
const char* kAuto = "Wed Sep 30 2026 22:39:15.067651 INFO: SLAMConsole: [IREmitters] IR emitters mode changed to Auto\n";
|
|
const char* kOn = "Wed Sep 30 2026 22:40:49.267834 INFO: SLAMConsole: [IREmitters] IR Emitters Turned On\n";
|
|
const char* kOff = "Wed Sep 30 2026 22:41:24.230440 INFO: SLAMConsole: [IREmitters] IR Emitters Turned Off\n";
|
|
const char* kNoise = "Wed Sep 30 2026 22:39:23.152963 WARNING: [DeckardCaptureSource] Max number of iteration reached\n";
|
|
|
|
void append(const std::string& path, const std::string& text) {
|
|
std::ofstream f(path, std::ios::app | std::ios::binary);
|
|
f << text;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
int main() {
|
|
char tmpl[] = "/tmp/autopass_emitter_XXXXXX";
|
|
const std::string dir = ::mkdtemp(tmpl);
|
|
const std::string log1 = dir + "/XRService-1.log", log2 = dir + "/XRService-2.log", link = dir + "/xrservice.txt";
|
|
const std::string log3 = dir + "/XRService-3.log";
|
|
|
|
append(log1, std::string(kAuto) + kNoise + kOn + kNoise);
|
|
CHECK(::symlink(log1.c_str(), link.c_str()) == 0);
|
|
|
|
XrServiceLog w(dir);
|
|
CHECK(w.start());
|
|
CHECK(w.state().emitters == std::optional<bool>(true)); // last line in the existing log
|
|
CHECK(!w.update()); // nothing new
|
|
CHECK(!w.take_restarted());
|
|
|
|
append(log1, kNoise);
|
|
CHECK(!w.update());
|
|
CHECK(w.state().emitters == std::optional<bool>(true));
|
|
|
|
// A line written in two parts is only parsed once complete.
|
|
const std::string off = kOff;
|
|
append(log1, off.substr(0, 40));
|
|
w.update();
|
|
CHECK(w.state().emitters == std::optional<bool>(true));
|
|
append(log1, off.substr(40));
|
|
CHECK(w.update());
|
|
CHECK(w.state().emitters == std::optional<bool>(false));
|
|
|
|
// XRService restarts: a new session log, symlink replaced atomically.
|
|
append(log2, std::string(kAuto) + kNoise);
|
|
const std::string tmp_link = dir + "/xrservice.txt.new";
|
|
CHECK(::symlink(log2.c_str(), tmp_link.c_str()) == 0);
|
|
CHECK(std::rename(tmp_link.c_str(), link.c_str()) == 0);
|
|
w.update();
|
|
CHECK(w.state().emitters == std::optional<bool>(false)); // "mode changed to Auto" with no On: off
|
|
CHECK(w.take_restarted());
|
|
CHECK(!w.take_restarted());
|
|
append(log2, kOn);
|
|
CHECK(w.update());
|
|
CHECK(w.state().emitters == std::optional<bool>(true));
|
|
// The old log is no longer followed.
|
|
append(log1, kOff);
|
|
w.update();
|
|
CHECK(w.state().emitters == std::optional<bool>(true));
|
|
|
|
// A restart while the watcher is stopped (passthrough off) is still
|
|
// noticed on the next start.
|
|
w.stop();
|
|
CHECK(!w.running());
|
|
append(log3, kAuto);
|
|
const std::string tmp3 = dir + "/xrservice.txt.3";
|
|
CHECK(::symlink(log3.c_str(), tmp3.c_str()) == 0);
|
|
CHECK(std::rename(tmp3.c_str(), link.c_str()) == 0);
|
|
CHECK(w.start());
|
|
CHECK(w.take_restarted());
|
|
// ...but not when it is the same session.
|
|
w.stop();
|
|
CHECK(w.start());
|
|
CHECK(!w.take_restarted());
|
|
w.stop();
|
|
std::remove(log3.c_str());
|
|
std::remove(link.c_str());
|
|
std::remove(log1.c_str());
|
|
std::remove(log2.c_str());
|
|
::rmdir(dir.c_str());
|
|
|
|
// Session start from the real path layout.
|
|
const long long t0 = XrServiceLog::parse_session_start(
|
|
"/home/steamos/.local/share/Steam/logs/XRService-2026.09.30/XRService-23-49-58.log");
|
|
CHECK(t0 > 0);
|
|
{
|
|
const std::time_t tt = static_cast<std::time_t>(t0);
|
|
const std::tm* lt = std::localtime(&tt);
|
|
CHECK(lt->tm_year == 126 && lt->tm_mon == 8 && lt->tm_mday == 30 && lt->tm_hour == 23 && lt->tm_min == 49 &&
|
|
lt->tm_sec == 58);
|
|
}
|
|
CHECK(XrServiceLog::parse_session_start("/tmp/whatever.log") == 0);
|
|
|
|
// Passthrough and standby lines in the same stream.
|
|
{
|
|
char tmpl2[] = "/tmp/autopass_xrlog_XXXXXX";
|
|
const std::string d2 = ::mkdtemp(tmpl2);
|
|
const std::string lg = d2 + "/XRService-1.log", lk = d2 + "/xrservice.txt";
|
|
append(lg, "x INFO: [DeckardCaptureSource] Passthrough cameras resumed\n");
|
|
CHECK(::symlink(lg.c_str(), lk.c_str()) == 0);
|
|
XrServiceLog x(d2);
|
|
CHECK(x.start());
|
|
CHECK(x.state().passthrough == std::optional<bool>(true));
|
|
append(lg, "x INFO: [UserPresence] Received onEnterStandby from SteamVR.\nx INFO: [DeckardCaptureSource] Passthrough cameras paused\n");
|
|
CHECK(x.update());
|
|
CHECK(x.state().passthrough == std::optional<bool>(false) && x.state().standby == std::optional<bool>(true));
|
|
x.stop();
|
|
std::remove(lk.c_str());
|
|
std::remove(lg.c_str());
|
|
::rmdir(d2.c_str());
|
|
}
|
|
|
|
// No log at all: start() fails cleanly.
|
|
XrServiceLog missing("/nonexistent/autopass/logs");
|
|
CHECK(!missing.start());
|
|
CHECK(!missing.error().empty());
|
|
|
|
if (failures) { std::printf("%d check(s) failed\n", failures); return 1; }
|
|
std::printf("all XRService log tests passed\n");
|
|
return 0;
|
|
}
|