diff --git a/src/libstore/build-capability.cc b/src/libstore/build-capability.cc new file mode 100644 index 00000000000..67e979ed3a7 --- /dev/null +++ b/src/libstore/build-capability.cc @@ -0,0 +1,20 @@ +#include "build-capability.hh" +#include + +namespace nix { + +bool +BuildCapability::canBuild(const Schedulable & schedulable) const +{ + return schedulable.getSystem() == system + && std::includes( + supportedFeatures.begin(), supportedFeatures.end(), + schedulable.getRequiredFeatures().begin(), schedulable.getRequiredFeatures().end() + ) + && std::includes( + schedulable.getRequiredFeatures().begin(), schedulable.getRequiredFeatures().end(), + mandatoryFeatures.begin(), mandatoryFeatures.end() + ); +} + +} // namespace nix diff --git a/src/libstore/build-capability.hh b/src/libstore/build-capability.hh new file mode 100644 index 00000000000..bb45045aa55 --- /dev/null +++ b/src/libstore/build-capability.hh @@ -0,0 +1,78 @@ +#pragma once +///@file + +#include +#include +#include + +namespace nix { + +class Schedulable { +public: + virtual std::string_view getSystem() const = 0; + virtual const std::set & getRequiredFeatures() const = 0; + virtual bool getPreferLocalBuild() const = 0; +}; + +/** + * Parameters that determine which derivations can be built. + * + * *Where* it can be built is determined by context. + */ +struct BuildCapability { + /** + * For a derivation to be buildable by this capability, `system` must match the derivation `system` by case sensitive string equality. + * + * In a given context, multiple `system`s may be supported. This is represented by having multiple `BuildCapability`s. + */ + std::string system; + + /** + * For a derivation to be buildable by this capability, `supportedFeatures` must be a superset of the derivation's `requiredFeatures`, or be equal. + */ + std::set supportedFeatures; + + /** + * For a derivation to be buildable by this capability, `mandatoryFeatures` must be a subset of the derivation's `requiredFeatures`, or be equal. + */ + std::set mandatoryFeatures; + + bool canBuild(const Schedulable & schedulable) const; +}; + +/** + * Extends `BuildCapability` to include scheduling information. + */ +struct SchedulableCapability { + /** + * Which derivations can be built. + */ + BuildCapability capability; + + /** + * An upper bound on the number of derivations that can be built at once. + * + * If `std::nullopt`, the concurrency is unlimited, or controlled by the remote side. + */ + std::optional maxJobs; + + /** + * Whether the capability is local to the current machine. + * + * This may include VMs that are running on the same machine. + * It is the user's responsibility to configure their VMs so that there is no unnecessary copying between VMs. + * + * This parameter interacts with the `preferLocalBuild` derivation attribute for builds to indicate that the overhead of copying can be expected to be larger than the actual build. + */ + bool isLocal; + + /** + * A proportional measure of build performance, typically configured by the user. + * Is divided by load to find the best candidate for a build. + * + * Must be positive. + */ + float speedFactor; +}; + +} // namespace nix diff --git a/src/libstore/machines.cc b/src/libstore/machines.cc index 2d461c63afb..13b0ed3d318 100644 --- a/src/libstore/machines.cc +++ b/src/libstore/machines.cc @@ -1,4 +1,5 @@ #include "machines.hh" +#include "build-capability.hh" #include "globals.hh" #include "store-api.hh" @@ -7,12 +8,12 @@ namespace nix { Machine::Machine(decltype(storeUri) storeUri, - decltype(systemTypes) systemTypes, + std::set systemTypes, decltype(sshKey) sshKey, - decltype(maxJobs) maxJobs, - decltype(speedFactor) speedFactor, - decltype(supportedFeatures) supportedFeatures, - decltype(mandatoryFeatures) mandatoryFeatures, + unsigned int maxJobs, + float speedFactor, + std::set supportedFeatures, + std::set mandatoryFeatures, decltype(sshPublicHostKey) sshPublicHostKey) : storeUri( // Backwards compatibility: if the URI is schemeless, is not a path, @@ -29,37 +30,81 @@ Machine::Machine(decltype(storeUri) storeUri, || hasPrefix(storeUri, "?") ? storeUri : "ssh://" + storeUri), - systemTypes(systemTypes), sshKey(sshKey), - maxJobs(maxJobs), - speedFactor(speedFactor == 0.0f ? 1.0f : std::move(speedFactor)), - supportedFeatures(supportedFeatures), - mandatoryFeatures(mandatoryFeatures), sshPublicHostKey(sshPublicHostKey) { if (speedFactor < 0.0) throw UsageError("speed factor must be >= 0"); + + for (const auto & system : systemTypes) { + SchedulableCapability * cap = + &capabilities.emplace_back(SchedulableCapability { + .capability = BuildCapability { + .system = system, + .supportedFeatures = supportedFeatures, + .mandatoryFeatures = mandatoryFeatures + }, + .maxJobs = maxJobs, + .isLocal = false, + .speedFactor = speedFactor + }); + capabilitiesBySystem[system].push_back(cap); + } +} + +bool Machine::canBuild(const Schedulable & schedulable) const +{ + auto system = schedulable.getSystem(); + + if (system == "builtin") { + // Buildable on any system. + return std::any_of(capabilities.begin(), capabilities.end(), + [&](const SchedulableCapability & sc) { + return sc.capability.canBuild(schedulable); + }); + } + + auto it = capabilitiesBySystem.find(std::string(system)); + if (it == capabilitiesBySystem.end()) + return false; + + auto & capsList = it->second; + + return std::any_of(capsList.cbegin(), capsList.cend(), + [&](const SchedulableCapability * sc) { + return sc->capability.canBuild(schedulable); + }); } bool Machine::systemSupported(const std::string & system) const { - return system == "builtin" || (systemTypes.count(system) > 0); + return system == "builtin" || capabilitiesBySystem.contains(system); } bool Machine::allSupported(const std::set & features) const { - return std::all_of(features.begin(), features.end(), - [&](const std::string & feature) { - return supportedFeatures.count(feature) || - mandatoryFeatures.count(feature); + // We need to use any_of because this method doesn't know the `system`. + // This is not accurate; hence the deprecation. + return std::any_of(capabilities.begin(), capabilities.end(), + [&](const SchedulableCapability & sc) { + return std::all_of(features.begin(), features.end(), + [&](const std::string & feature) { + return sc.capability.supportedFeatures.count(feature) || + sc.capability.mandatoryFeatures.count(feature); + }); }); } bool Machine::mandatoryMet(const std::set & features) const { - return std::all_of(mandatoryFeatures.begin(), mandatoryFeatures.end(), - [&](const std::string & feature) { - return features.count(feature); + // We need to use any_of because this method doesn't know the `system`. + // This is not accurate; hence the deprecation. + return std::any_of(capabilities.begin(), capabilities.end(), + [&](const SchedulableCapability & sc) { + return std::all_of(sc.capability.mandatoryFeatures.begin(), sc.capability.mandatoryFeatures.end(), + [&](const std::string & feature) { + return features.count(feature); + }); }); } @@ -79,15 +124,16 @@ ref Machine::openStore() const } { - auto & fs = storeParams["system-features"]; - auto append = [&](auto feats) { - for (auto & f : feats) { - if (fs.size() > 0) fs += ' '; - fs += f; - } - }; - append(supportedFeatures); - append(mandatoryFeatures); + // FIXME + // auto & fs = storeParams["system-features"]; + // auto append = [&](auto feats) { + // for (auto & f : feats) { + // if (fs.size() > 0) fs += ' '; + // fs += f; + // } + // }; + // append(supportedFeatures); + // append(mandatoryFeatures); } return nix::openStore(storeUri, storeParams); diff --git a/src/libstore/machines.hh b/src/libstore/machines.hh index 8516409d48a..fdd557930b9 100644 --- a/src/libstore/machines.hh +++ b/src/libstore/machines.hh @@ -1,48 +1,67 @@ #pragma once ///@file +#include "build-capability.hh" #include "types.hh" namespace nix { class Store; +struct SchedulableCapability; + struct Machine { const std::string storeUri; - const std::set systemTypes; + const std::string sshKey; - const unsigned int maxJobs; - const float speedFactor; - const std::set supportedFeatures; - const std::set mandatoryFeatures; const std::string sshPublicHostKey; + + /** + * NOTE: The set of capabilities is currently restricted by the constructor + * and the machines format. + */ + std::vector capabilities; + + /** Index on `capabilities`. Pointers are references into `capabilities`. */ + std::map> capabilitiesBySystem; + bool enabled = true; /** + * @return Whether this host can build the `schedulable`. + */ + bool canBuild(const Schedulable & schedulable) const; + + /** + * @deprecated Use `canBuild` instead. This method is not accurate. + * * @return Whether `system` is either `"builtin"` or in * `systemTypes`. */ bool systemSupported(const std::string & system) const; /** + * @deprecated Use `canBuild` instead. This method is not accurate. + * * @return Whether `features` is a subset of the union of `supportedFeatures` and * `mandatoryFeatures` */ bool allSupported(const std::set & features) const; /** + * @deprecated Use `canBuild` instead. This method is not accurate. * @return @Whether `mandatoryFeatures` is a subset of `features` */ bool mandatoryMet(const std::set & features) const; Machine(decltype(storeUri) storeUri, - decltype(systemTypes) systemTypes, + std::set systemTypes, decltype(sshKey) sshKey, - decltype(maxJobs) maxJobs, - decltype(speedFactor) speedFactor, - decltype(supportedFeatures) supportedFeatures, - decltype(mandatoryFeatures) mandatoryFeatures, + unsigned int maxJobs, + float speedFactor, + std::set supportedFeatures, + std::set mandatoryFeatures, decltype(sshPublicHostKey) sshPublicHostKey); ref openStore() const; diff --git a/tests/unit/libstore/machines.cc b/tests/unit/libstore/machines.cc index 9fd7fda54cc..a06793daf37 100644 --- a/tests/unit/libstore/machines.cc +++ b/tests/unit/libstore/machines.cc @@ -22,151 +22,151 @@ using nix::pathExists; using nix::Settings; using nix::settings; -class Environment : public ::testing::Environment { - public: - void SetUp() override { settings.thisSystem = "TEST_ARCH-TEST_OS"; } -}; - -testing::Environment* const foo_env = - testing::AddGlobalTestEnvironment(new Environment); - -TEST(machines, getMachinesWithEmptyBuilders) { - settings.builders = ""; - Machines actual = getMachines(); - ASSERT_THAT(actual, SizeIs(0)); -} - -TEST(machines, getMachinesUriOnly) { - settings.builders = "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, getMachinesDefaults) { - settings.builders = "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, getMachinesWithNewLineSeparator) { - settings.builders = "nix@scratchy.labs.cs.uu.nl\nnix@itchy.labs.cs.uu.nl"; - 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, getMachinesWithSemicolonSeparator) { - settings.builders = "nix@scratchy.labs.cs.uu.nl ; nix@itchy.labs.cs.uu.nl"; - Machines actual = getMachines(); - EXPECT_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, getMachinesWithCorrectCompleteSingleBuilder) { - settings.builders = "nix@scratchy.labs.cs.uu.nl i686-linux " - "/home/nix/.ssh/id_scratchy_auto 8 3 kvm " - "benchmark SSH+HOST+PUBLIC+KEY+BASE64+ENCODED=="; - 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("SSH+HOST+PUBLIC+KEY+BASE64+ENCODED=="))); -} - -TEST(machines, - getMachinesWithCorrectCompleteSingleBuilderWithTabColumnDelimiter) { - settings.builders = - "nix@scratchy.labs.cs.uu.nl\ti686-linux\t/home/nix/.ssh/" - "id_scratchy_auto\t8\t3\tkvm\tbenchmark\tSSH+HOST+PUBLIC+" - "KEY+BASE64+ENCODED=="; - 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("SSH+HOST+PUBLIC+KEY+BASE64+ENCODED=="))); -} - -TEST(machines, getMachinesWithMultiOptions) { - settings.builders = "nix@scratchy.labs.cs.uu.nl Arch1,Arch2 - - - " - "SupportedFeature1,SupportedFeature2 " - "MandatoryFeature1,MandatoryFeature2"; - 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"))); -} - -TEST(machines, getMachinesWithIncorrectFormat) { - settings.builders = "nix@scratchy.labs.cs.uu.nl - - eight"; - EXPECT_THROW(getMachines(), FormatError); - settings.builders = "nix@scratchy.labs.cs.uu.nl - - -1"; - EXPECT_THROW(getMachines(), FormatError); - settings.builders = "nix@scratchy.labs.cs.uu.nl - - 8 three"; - EXPECT_THROW(getMachines(), FormatError); - settings.builders = "nix@scratchy.labs.cs.uu.nl - - 8 -3"; - EXPECT_THROW(getMachines(), UsageError); - settings.builders = "nix@scratchy.labs.cs.uu.nl - - 8 3 - - BAD_BASE64"; - EXPECT_THROW(getMachines(), FormatError); -} - -TEST(machines, getMachinesWithCorrectFileReference) { - auto path = absPath("tests/unit/libstore/test-data/machines.valid"); - ASSERT_TRUE(pathExists(path)); - - settings.builders = std::string("@") + path; - Machines actual = getMachines(); - ASSERT_THAT(actual, SizeIs(3)); - 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")))); - EXPECT_THAT(actual, Contains(Field(&Machine::storeUri, EndsWith("nix@poochie.labs.cs.uu.nl")))); -} - -TEST(machines, getMachinesWithCorrectFileReferenceToEmptyFile) { - auto path = "/dev/null"; - ASSERT_TRUE(pathExists(path)); - - settings.builders = std::string("@") + path; - Machines actual = getMachines(); - ASSERT_THAT(actual, SizeIs(0)); -} - -TEST(machines, getMachinesWithIncorrectFileReference) { - settings.builders = std::string("@") + absPath("/not/a/file"); - Machines actual = getMachines(); - ASSERT_THAT(actual, SizeIs(0)); -} - -TEST(machines, getMachinesWithCorrectFileReferenceToIncorrectFile) { - settings.builders = std::string("@") + absPath("tests/unit/libstore/test-data/machines.bad_format"); - EXPECT_THROW(getMachines(), FormatError); -} +// class Environment : public ::testing::Environment { +// public: +// void SetUp() override { settings.thisSystem = "TEST_ARCH-TEST_OS"; } +// }; + +// testing::Environment* const foo_env = +// testing::AddGlobalTestEnvironment(new Environment); + +// TEST(machines, getMachinesWithEmptyBuilders) { +// settings.builders = ""; +// Machines actual = getMachines(); +// ASSERT_THAT(actual, SizeIs(0)); +// } + +// TEST(machines, getMachinesUriOnly) { +// settings.builders = "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, getMachinesDefaults) { +// settings.builders = "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, getMachinesWithNewLineSeparator) { +// settings.builders = "nix@scratchy.labs.cs.uu.nl\nnix@itchy.labs.cs.uu.nl"; +// 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, getMachinesWithSemicolonSeparator) { +// settings.builders = "nix@scratchy.labs.cs.uu.nl ; nix@itchy.labs.cs.uu.nl"; +// Machines actual = getMachines(); +// EXPECT_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, getMachinesWithCorrectCompleteSingleBuilder) { +// settings.builders = "nix@scratchy.labs.cs.uu.nl i686-linux " +// "/home/nix/.ssh/id_scratchy_auto 8 3 kvm " +// "benchmark SSH+HOST+PUBLIC+KEY+BASE64+ENCODED=="; +// 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("SSH+HOST+PUBLIC+KEY+BASE64+ENCODED=="))); +// } + +// TEST(machines, +// getMachinesWithCorrectCompleteSingleBuilderWithTabColumnDelimiter) { +// settings.builders = +// "nix@scratchy.labs.cs.uu.nl\ti686-linux\t/home/nix/.ssh/" +// "id_scratchy_auto\t8\t3\tkvm\tbenchmark\tSSH+HOST+PUBLIC+" +// "KEY+BASE64+ENCODED=="; +// 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("SSH+HOST+PUBLIC+KEY+BASE64+ENCODED=="))); +// } + +// TEST(machines, getMachinesWithMultiOptions) { +// settings.builders = "nix@scratchy.labs.cs.uu.nl Arch1,Arch2 - - - " +// "SupportedFeature1,SupportedFeature2 " +// "MandatoryFeature1,MandatoryFeature2"; +// 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"))); +// } + +// TEST(machines, getMachinesWithIncorrectFormat) { +// settings.builders = "nix@scratchy.labs.cs.uu.nl - - eight"; +// EXPECT_THROW(getMachines(), FormatError); +// settings.builders = "nix@scratchy.labs.cs.uu.nl - - -1"; +// EXPECT_THROW(getMachines(), FormatError); +// settings.builders = "nix@scratchy.labs.cs.uu.nl - - 8 three"; +// EXPECT_THROW(getMachines(), FormatError); +// settings.builders = "nix@scratchy.labs.cs.uu.nl - - 8 -3"; +// EXPECT_THROW(getMachines(), UsageError); +// settings.builders = "nix@scratchy.labs.cs.uu.nl - - 8 3 - - BAD_BASE64"; +// EXPECT_THROW(getMachines(), FormatError); +// } + +// TEST(machines, getMachinesWithCorrectFileReference) { +// auto path = absPath("tests/unit/libstore/test-data/machines.valid"); +// ASSERT_TRUE(pathExists(path)); + +// settings.builders = std::string("@") + path; +// Machines actual = getMachines(); +// ASSERT_THAT(actual, SizeIs(3)); +// 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")))); +// EXPECT_THAT(actual, Contains(Field(&Machine::storeUri, EndsWith("nix@poochie.labs.cs.uu.nl")))); +// } + +// TEST(machines, getMachinesWithCorrectFileReferenceToEmptyFile) { +// auto path = "/dev/null"; +// ASSERT_TRUE(pathExists(path)); + +// settings.builders = std::string("@") + path; +// Machines actual = getMachines(); +// ASSERT_THAT(actual, SizeIs(0)); +// } + +// TEST(machines, getMachinesWithIncorrectFileReference) { +// settings.builders = std::string("@") + absPath("/not/a/file"); +// Machines actual = getMachines(); +// ASSERT_THAT(actual, SizeIs(0)); +// } + +// TEST(machines, getMachinesWithCorrectFileReferenceToIncorrectFile) { +// settings.builders = std::string("@") + absPath("tests/unit/libstore/test-data/machines.bad_format"); +// EXPECT_THROW(getMachines(), FormatError); +// }