Files
lix/tests/unit/libstore/machines_toml.cc
T
Commentator2.0 8f5bf1e905 libstore/machines: add enable flag for toml machines
Provide a way to statically disable a machine.
This is fully static and not dynamic.

Change-Id: I394433ad533bca5dbf6a2f7fea22b8aa0f5aad3f
2025-12-04 12:11:23 +01:00

317 lines
11 KiB
C++

#include "lix/libutil/file-system.hh"
#include "lix/libstore/machines.hh"
#include "lix/libstore/globals.hh"
#include "lix/libutil/logging.hh"
#include "lix/libutil/strings.hh"
#include <gmock/gmock-matchers.h>
using testing::Contains;
using testing::ElementsAre;
using testing::EndsWith;
using testing::Eq;
using testing::Field;
using testing::HasSubstr;
using testing::SizeIs;
using nix::absPath;
using nix::FormatError;
using nix::getMachines;
using nix::Machine;
using nix::Machines;
using nix::pathExists;
using nix::settings;
using nix::UsageError;
TEST(machines, getMachinesTOMLWithEmptyBuilders)
{
settings.builders.override("");
Machines actual = getMachines();
ASSERT_THAT(actual, SizeIs(0));
}
TEST(machines, getMachinesTOMLUriOnly)
{
settings.builders.override(
"[machines.scratchy]\n"
"uri = \"ssh://nix@scratchy.labs.cs.uu.nl\""
);
Machines actual = getMachines();
ASSERT_THAT(actual, SizeIs(1));
EXPECT_THAT(actual[0], Field(&Machine::storeUri, Eq("ssh://nix@scratchy.labs.cs.uu.nl")));
EXPECT_THAT(actual[0], Field(&Machine::systemTypes, ElementsAre("TEST_ARCH-TEST_OS")));
EXPECT_THAT(actual[0], Field(&Machine::sshKey, SizeIs(0)));
EXPECT_THAT(actual[0], Field(&Machine::maxJobs, Eq(1)));
EXPECT_THAT(actual[0], Field(&Machine::speedFactor, Eq(1)));
EXPECT_THAT(actual[0], Field(&Machine::supportedFeatures, SizeIs(0)));
EXPECT_THAT(actual[0], Field(&Machine::mandatoryFeatures, SizeIs(0)));
EXPECT_THAT(actual[0], Field(&Machine::sshPublicHostKey, SizeIs(0)));
}
TEST(machines, getMachinesTOMLMultipleMachines)
{
settings.builders.override(
"[machines.scratchy]\n"
"uri = \"nix@scratchy.labs.cs.uu.nl\"\n"
"[machines.itchy]\n"
"uri = \"nix@itchy.labs.cs.uu.nl\"\n"
);
Machines actual = getMachines();
ASSERT_THAT(actual, SizeIs(2));
EXPECT_THAT(
actual, Contains(Field(&Machine::storeUri, EndsWith("nix@scratchy.labs.cs.uu.nl")))
);
EXPECT_THAT(actual, Contains(Field(&Machine::storeUri, EndsWith("nix@itchy.labs.cs.uu.nl"))));
}
TEST(machines, getMachinesTOMLWithCorrectCompleteSingleBuilder)
{
settings.builders.override(
"[machines.scratchy]\n"
"uri = \"nix@scratchy.labs.cs.uu.nl\"\n"
"system-types = [\"i686-linux\"]\n"
"ssh-key = \"/home/nix/.ssh/id_scratchy_auto\"\n"
"jobs = 8\n"
"speed-factor = 3.0\n"
"supported-features = [\"kvm\"]\n"
"mandatory-features = [\"benchmark\"]\n"
"ssh-public-host-key = \"ssh-ed25519 "
"AAAAC3NzaC1lZDI1NTE5AAAAIJYfqESaiQlOrL3Wm1Q9s9q8b4mjj2nIuyqCZub5aGPi nix@scratchy\"\n"
);
Machines actual = getMachines();
ASSERT_THAT(actual, SizeIs(1));
EXPECT_THAT(actual[0], Field(&Machine::storeUri, EndsWith("nix@scratchy.labs.cs.uu.nl")));
EXPECT_THAT(actual[0], Field(&Machine::systemTypes, ElementsAre("i686-linux")));
EXPECT_THAT(actual[0], Field(&Machine::sshKey, Eq("/home/nix/.ssh/id_scratchy_auto")));
EXPECT_THAT(actual[0], Field(&Machine::maxJobs, Eq(8)));
EXPECT_THAT(actual[0], Field(&Machine::speedFactor, Eq(3)));
EXPECT_THAT(actual[0], Field(&Machine::supportedFeatures, ElementsAre("kvm")));
EXPECT_THAT(actual[0], Field(&Machine::mandatoryFeatures, ElementsAre("benchmark")));
EXPECT_THAT(
actual[0],
Field(
&Machine::sshPublicHostKey,
Eq("c3NoLWVkMjU1MTkgQUFBQUMzTnphQzFsWkRJMU5URTVBQUFBSUpZZnFFU2FpUWxPckwzV20xUTlzOXE4YjR"
"tamoybkl1eXFDWnViNWFHUGkgbml4QHNjcmF0Y2h5")
)
);
}
TEST(machines, getMachinesTOMLBothFloatFormats)
{
settings.builders.override(
"[machines.andesite]\n"
"uri = \"ssh://lix@andesite.lix.systems\"\n"
"speed-factor = 3\n"
);
auto actual = getMachines();
ASSERT_THAT(actual, SizeIs(1));
EXPECT_THAT(actual[0], Field(&Machine::speedFactor, Eq(3)));
settings.builders.override(
"[machines.diorite]\n"
"uri = \"ssh://lix@diorite.lix.systems\"\n"
"speed-factor = 3.1\n"
);
actual = getMachines();
ASSERT_THAT(actual, SizeIs(1));
EXPECT_THAT(actual[0], Field(&Machine::speedFactor, Eq(3.1f)));
}
TEST(machines, getMachinesTOMLWithMultiOptions)
{
settings.builders.override(
"[machines.scratchy]\n"
"uri = \"nix@scratchy.labs.cs.uu.nl\"\n"
"system-types = [\"Arch1\", \"Arch2\"]\n"
"supported-features = [\"SupportedFeature1\", \"SupportedFeature2\"]\n"
"mandatory-features = [\"MandatoryFeature1\", \"MandatoryFeature2\"]\n"
);
Machines actual = getMachines();
ASSERT_THAT(actual, SizeIs(1));
EXPECT_THAT(actual[0], Field(&Machine::storeUri, EndsWith("nix@scratchy.labs.cs.uu.nl")));
EXPECT_THAT(actual[0], Field(&Machine::systemTypes, ElementsAre("Arch1", "Arch2")));
EXPECT_THAT(
actual[0],
Field(&Machine::supportedFeatures, ElementsAre("SupportedFeature1", "SupportedFeature2"))
);
EXPECT_THAT(
actual[0],
Field(&Machine::mandatoryFeatures, ElementsAre("MandatoryFeature1", "MandatoryFeature2"))
);
}
#define EXPECT_MESSAGE_THROW(EXPR, EXC, MSG) \
EXPECT_THROW( \
{ \
try { \
EXPR; \
} catch (const EXC & e) { \
EXPECT_THAT(e.what(), HasSubstr(MSG)); \
throw; \
} \
}, \
EXC \
);
TEST(machines, getMachinesTOMLExtraKeys)
{
settings.builders.override(
"[machines.andesite]\n"
"uri = \"ssh://lix@andesite.lix.systems\"\n"
"extra-key = 3\n"
);
EXPECT_MESSAGE_THROW(getMachines(), UsageError, "unexpected key `extra-key`");
settings.builders.override(
"[machines.andesite]\n"
"uri = \"ssh://lix@andesite.lix.systems\"\n"
"another-key = 3\n"
);
EXPECT_MESSAGE_THROW(getMachines(), UsageError, "unexpected key `another-key`");
}
/*
This should throw a syntax error, but actually parses successfully and puts weird shit in the uri
field instead Other parsers (e.g. pythons tomllib) do successfully throw a syntax error here, but
toml11 doesn't AAAAAAAAAAAAAAAAAAAAAA An upstream issue was created for this on 2025-12-01
(https://github.com/ToruNiina/toml11/issues/303)
Note: this somehow worked once or twice, but now its broken again (and CI agrees that it's broken)
*/
TEST(machines, getMachinesTOMLNoQuotationOnUri)
{
GTEST_SKIP() << "See upstream issue https://github.com/ToruNiina/toml11/issues/303";
settings.builders.override(
"[machines.invalid_syntax]\n"
"uri = ssh://lix@andesite.lix.systems\n"
"maxJobs = -3\n"
);
EXPECT_MESSAGE_THROW(getMachines(), UsageError, "bad format: unknown value appeared");
}
TEST(machines, getMachinesTOMLWithIncorrectTyping)
{
settings.builders.override("[machines.a]");
EXPECT_MESSAGE_THROW(getMachines(), UsageError, "uri must be present");
settings.builders.override(
"[machines.scratchy]\n"
"uri = \"nix@scratchy.labs.cs.uu.nl\"\n"
"jobs = -3\n"
);
EXPECT_MESSAGE_THROW(getMachines(), UsageError, "jobs must be >= 0");
settings.builders.override(
"[machines.scratchy]\n"
"uri = \"nix@scratchy.labs.cs.uu.nl\"\n"
"jobs = \"three\"\n"
);
EXPECT_MESSAGE_THROW(getMachines(), UsageError, "bad_cast to integer");
settings.builders.override(
"[machines.scratchy]\n"
"uri = \"nix@scratchy.labs.cs.uu.nl\"\n"
"jobs = 8\n"
"speed-factor = -3.0\n"
);
EXPECT_MESSAGE_THROW(getMachines(), UsageError, "speed factor must be >= 0");
settings.builders.override(
"[machines.scratchy]\n"
"uri = \"nix@scratchy.labs.cs.uu.nl\"\n"
"jobs = 8\n"
"speed-factor = \"three\"\n"
);
EXPECT_MESSAGE_THROW(getMachines(), UsageError, "bad_cast to floating");
settings.builders.override(
"[[machines]]\n"
"uri = \"lix@andesite.lix.systems\"\n"
"[[machines]]\n"
"uri = \"lix@diorite.lix.systems\"\n"
);
EXPECT_MESSAGE_THROW(
getMachines(),
UsageError,
"Expected key `machines` to be a table of name -> machine configurations"
);
settings.builders.override("machines.a = \"lix@andesite.lix.sytems\"\n");
EXPECT_MESSAGE_THROW(getMachines(), UsageError, "Each machine must be a table");
settings.builders.override(
"version = \"1\"\n"
"[machines.scratchy]\n"
"uri = \"nix@scratchy.labs.cs.uu.nl\"\n"
);
EXPECT_MESSAGE_THROW(getMachines(), UsageError, "bad_cast to integer");
settings.builders.override(
"version = 1\n"
"[machines.legacy]\n"
"uri = \"ssh://nix@nix-15-11.nixos.org\"\n"
"enable = 0\n"
);
EXPECT_MESSAGE_THROW(getMachines(), UsageError, "bad_cast to boolean");
}
TEST(machines, getMachinesTOMLBadVersion)
{
settings.builders.override(
"version = \"hello\"\n"
"machines = {}\n"
);
EXPECT_MESSAGE_THROW(getMachines(), UsageError, "bad_cast to integer");
}
TEST(machines, getMachinesTOMLTooHighVersion)
{
settings.builders.override(
"version = 42\n"
"machines = {}\n"
);
EXPECT_MESSAGE_THROW(
getMachines(),
UsageError,
"Unable to parse Machines of version 42, only versions between 1 and 1 are supported."
);
}
TEST(machines, getMachinesTOMLTooLowVersion)
{
settings.builders.override(
"version = -1\n"
"machines = {}\n"
);
EXPECT_MESSAGE_THROW(
getMachines(),
UsageError,
"Unable to parse Machines of version -1, only versions between 1 and 1 are supported."
);
}
TEST(machines, getMachinesTOMLInvalidSyntaxButClearlyTOML)
{
settings.builders.override(
"version = 1\n"
"[machines]\n"
"[machines.hello]\n"
"uri = \"ssh://hello\"\n"
" = 5\n"
);
EXPECT_MESSAGE_THROW(getMachines(), UsageError, "invalid Machines TOML syntax:");
}
TEST(machines, getMachinesTOMLOneDisabled)
{
settings.builders.override(
"version = 1\n"
"[machines.a]\n"
"uri = \"ssh://test\"\n"
"enable = false\n"
"\n"
"[machines.b]\n"
"uri = \"ssh://test2\"\n"
);
auto actual = getMachines();
ASSERT_THAT(actual, SizeIs(1));
EXPECT_THAT(actual[0], Field(&Machine::storeUri, EndsWith("test2")));
}
#undef EXPECT_MESSAGE_THROW