diff options
author | Kyle Edwards <kyle.edwards@kitware.com> | 2019-07-03 19:00:38 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2019-10-02 13:33:54 (GMT) |
commit | c8f48069430cb286ca593a967e0c3b8e5ea842c4 (patch) | |
tree | f120fded0d29cd5e1a3caf48990897ad748f5f75 | |
parent | bb4a1410592342a824b1dd755b7ca8897deac65c (diff) | |
download | CMake-c8f48069430cb286ca593a967e0c3b8e5ea842c4.zip CMake-c8f48069430cb286ca593a967e0c3b8e5ea842c4.tar.gz CMake-c8f48069430cb286ca593a967e0c3b8e5ea842c4.tar.bz2 |
CTest: Add parser for hardware spec file
23 files changed, 404 insertions, 0 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 9750d0b..8e38590 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -918,6 +918,7 @@ set(CTEST_SRCS cmCTest.cxx CTest/cmCTestEmptyBinaryDirectoryCommand.cxx CTest/cmCTestGenericHandler.cxx CTest/cmCTestHandlerCommand.cxx + CTest/cmCTestHardwareSpec.cxx CTest/cmCTestLaunch.cxx CTest/cmCTestMemCheckCommand.cxx CTest/cmCTestMemCheckHandler.cxx diff --git a/Source/CTest/cmCTestHardwareSpec.cxx b/Source/CTest/cmCTestHardwareSpec.cxx new file mode 100644 index 0000000..137398a --- /dev/null +++ b/Source/CTest/cmCTestHardwareSpec.cxx @@ -0,0 +1,133 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmCTestHardwareSpec.h" + +#include <map> +#include <string> +#include <utility> +#include <vector> + +#include "cmsys/FStream.hxx" +#include "cmsys/RegularExpression.hxx" + +#include "cm_jsoncpp_reader.h" +#include "cm_jsoncpp_value.h" + +static const cmsys::RegularExpression IdentifierRegex{ "^[a-z_][a-z0-9_]*$" }; +static const cmsys::RegularExpression IdRegex{ "^[a-z0-9_]+$" }; + +bool cmCTestHardwareSpec::ReadFromJSONFile(const std::string& filename) +{ + cmsys::ifstream fin(filename.c_str()); + if (!fin) { + return false; + } + + Json::Value root; + Json::CharReaderBuilder builder; + if (!Json::parseFromStream(builder, fin, &root, nullptr)) { + return false; + } + + if (!root.isObject()) { + return false; + } + + auto const& local = root["local"]; + if (!local.isArray()) { + return false; + } + if (local.size() > 1) { + return false; + } + + if (local.empty()) { + this->LocalSocket.Resources.clear(); + return true; + } + + auto const& localSocket = local[0]; + if (!localSocket.isObject()) { + return false; + } + std::map<std::string, std::vector<cmCTestHardwareSpec::Resource>> resources; + cmsys::RegularExpressionMatch match; + for (auto const& key : localSocket.getMemberNames()) { + if (IdentifierRegex.find(key.c_str(), match)) { + auto const& value = localSocket[key]; + auto& r = resources[key]; + if (value.isArray()) { + for (auto const& item : value) { + if (item.isObject()) { + cmCTestHardwareSpec::Resource resource; + + if (!item.isMember("id")) { + return false; + } + auto const& id = item["id"]; + if (!id.isString()) { + return false; + } + resource.Id = id.asString(); + if (!IdRegex.find(resource.Id.c_str(), match)) { + return false; + } + + if (item.isMember("slots")) { + auto const& capacity = item["slots"]; + if (!capacity.isConvertibleTo(Json::uintValue)) { + return false; + } + resource.Capacity = capacity.asUInt(); + } else { + resource.Capacity = 1; + } + + r.push_back(resource); + } else { + return false; + } + } + } else { + return false; + } + } + } + + this->LocalSocket.Resources = std::move(resources); + return true; +} + +bool cmCTestHardwareSpec::operator==(const cmCTestHardwareSpec& other) const +{ + return this->LocalSocket == other.LocalSocket; +} + +bool cmCTestHardwareSpec::operator!=(const cmCTestHardwareSpec& other) const +{ + return !(*this == other); +} + +bool cmCTestHardwareSpec::Socket::operator==( + const cmCTestHardwareSpec::Socket& other) const +{ + return this->Resources == other.Resources; +} + +bool cmCTestHardwareSpec::Socket::operator!=( + const cmCTestHardwareSpec::Socket& other) const +{ + return !(*this == other); +} + +bool cmCTestHardwareSpec::Resource::operator==( + const cmCTestHardwareSpec::Resource& other) const +{ + return this->Id == other.Id && this->Capacity == other.Capacity; +} + +bool cmCTestHardwareSpec::Resource::operator!=( + const cmCTestHardwareSpec::Resource& other) const +{ + return !(*this == other); +} diff --git a/Source/CTest/cmCTestHardwareSpec.h b/Source/CTest/cmCTestHardwareSpec.h new file mode 100644 index 0000000..a0b4cae --- /dev/null +++ b/Source/CTest/cmCTestHardwareSpec.h @@ -0,0 +1,40 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmCTestHardwareSpec_h +#define cmCTestHardwareSpec_h + +#include <map> +#include <string> +#include <vector> + +class cmCTestHardwareSpec +{ +public: + class Resource + { + public: + std::string Id; + unsigned int Capacity; + + bool operator==(const Resource& other) const; + bool operator!=(const Resource& other) const; + }; + + class Socket + { + public: + std::map<std::string, std::vector<Resource>> Resources; + + bool operator==(const Socket& other) const; + bool operator!=(const Socket& other) const; + }; + + Socket LocalSocket; + + bool ReadFromJSONFile(const std::string& filename); + + bool operator==(const cmCTestHardwareSpec& other) const; + bool operator!=(const cmCTestHardwareSpec& other) const; +}; + +#endif diff --git a/Tests/CMakeLib/CMakeLists.txt b/Tests/CMakeLib/CMakeLists.txt index abb258b..901f097 100644 --- a/Tests/CMakeLib/CMakeLists.txt +++ b/Tests/CMakeLib/CMakeLists.txt @@ -8,6 +8,7 @@ include_directories( set(CMakeLib_TESTS testArgumentParser.cxx testCTestProcesses.cxx + testCTestHardwareSpec.cxx testGeneratedFileStream.cxx testRST.cxx testRange.cxx @@ -29,6 +30,7 @@ add_executable(testUVProcessChainHelper testUVProcessChainHelper.cxx) set(testRST_ARGS ${CMAKE_CURRENT_SOURCE_DIR}) set(testUVProcessChain_ARGS $<TARGET_FILE:testUVProcessChainHelper>) set(testUVStreambuf_ARGS $<TARGET_FILE:cmake>) +set(testCTestHardwareSpec_ARGS ${CMAKE_CURRENT_SOURCE_DIR}) if(WIN32) list(APPEND CMakeLib_TESTS diff --git a/Tests/CMakeLib/testCTestHardwareSpec.cxx b/Tests/CMakeLib/testCTestHardwareSpec.cxx new file mode 100644 index 0000000..3e3eccc --- /dev/null +++ b/Tests/CMakeLib/testCTestHardwareSpec.cxx @@ -0,0 +1,84 @@ +#include <iostream> +#include <string> +#include <vector> + +#include "cmCTestHardwareSpec.h" + +struct ExpectedSpec +{ + std::string Path; + bool ParseResult; + cmCTestHardwareSpec Expected; +}; + +static const std::vector<ExpectedSpec> expectedHardwareSpecs = { + /* clang-format off */ + {"spec1.json", true, {{{ + {"gpus", { + {"2", 4}, + {"e", 1}, + }}, + {"threads", { + }}, + }}}}, + {"spec2.json", true, {{{ + }}}}, + {"spec3.json", false, {{{}}}}, + {"spec4.json", false, {{{}}}}, + {"spec5.json", false, {{{}}}}, + {"spec6.json", false, {{{}}}}, + {"spec7.json", false, {{{}}}}, + {"spec8.json", false, {{{}}}}, + {"spec9.json", false, {{{}}}}, + {"spec10.json", false, {{{}}}}, + {"spec11.json", false, {{{}}}}, + {"spec12.json", false, {{{}}}}, + {"spec13.json", false, {{{}}}}, + {"spec14.json", true, {{{}}}}, + {"spec15.json", true, {{{}}}}, + {"spec16.json", true, {{{}}}}, + {"spec17.json", false, {{{}}}}, + {"spec18.json", false, {{{}}}}, + {"noexist.json", false, {{{}}}}, + /* clang-format on */ +}; + +static bool testSpec(const std::string& path, bool expectedResult, + const cmCTestHardwareSpec& expected) +{ + cmCTestHardwareSpec actual; + bool result = actual.ReadFromJSONFile(path); + if (result != expectedResult) { + std::cout << "ReadFromJSONFile(\"" << path << "\") returned " << result + << ", should be " << expectedResult << std::endl; + return false; + } + + if (result && actual != expected) { + std::cout << "ReadFromJSONFile(\"" << path + << "\") did not give expected spec" << std::endl; + return false; + } + + return true; +} + +int testCTestHardwareSpec(int argc, char** const argv) +{ + if (argc < 2) { + std::cout << "Invalid arguments.\n"; + return -1; + } + + int retval = 0; + for (auto const& spec : expectedHardwareSpecs) { + std::string path = argv[1]; + path += "/testCTestHardwareSpec_data/"; + path += spec.Path; + if (!testSpec(path, spec.ParseResult, spec.Expected)) { + retval = -1; + } + } + + return retval; +} diff --git a/Tests/CMakeLib/testCTestHardwareSpec_data/spec1.json b/Tests/CMakeLib/testCTestHardwareSpec_data/spec1.json new file mode 100644 index 0000000..ee3d0ce --- /dev/null +++ b/Tests/CMakeLib/testCTestHardwareSpec_data/spec1.json @@ -0,0 +1,23 @@ +{ + "local": [ + { + "gpus": [ + { + "id": "2", + "slots": 4 + }, + { + "id": "e" + } + ], + ".reserved": [ + { + "id": "a", + "slots": 3 + } + ], + "threads": [ + ] + } + ] +} diff --git a/Tests/CMakeLib/testCTestHardwareSpec_data/spec10.json b/Tests/CMakeLib/testCTestHardwareSpec_data/spec10.json new file mode 100644 index 0000000..22105d7 --- /dev/null +++ b/Tests/CMakeLib/testCTestHardwareSpec_data/spec10.json @@ -0,0 +1,11 @@ +{ + "local": [ + { + "gpus": [ + { + "id": 4 + } + ] + } + ] +} diff --git a/Tests/CMakeLib/testCTestHardwareSpec_data/spec11.json b/Tests/CMakeLib/testCTestHardwareSpec_data/spec11.json new file mode 100644 index 0000000..1e37ef5 --- /dev/null +++ b/Tests/CMakeLib/testCTestHardwareSpec_data/spec11.json @@ -0,0 +1,12 @@ +{ + "local": [ + { + "gpus": [ + { + "id": "4", + "slots": "giraffe" + } + ] + } + ] +} diff --git a/Tests/CMakeLib/testCTestHardwareSpec_data/spec12.json b/Tests/CMakeLib/testCTestHardwareSpec_data/spec12.json new file mode 100644 index 0000000..fe51488 --- /dev/null +++ b/Tests/CMakeLib/testCTestHardwareSpec_data/spec12.json @@ -0,0 +1 @@ +[] diff --git a/Tests/CMakeLib/testCTestHardwareSpec_data/spec13.json b/Tests/CMakeLib/testCTestHardwareSpec_data/spec13.json new file mode 100644 index 0000000..6b7a9f4 --- /dev/null +++ b/Tests/CMakeLib/testCTestHardwareSpec_data/spec13.json @@ -0,0 +1 @@ +not json diff --git a/Tests/CMakeLib/testCTestHardwareSpec_data/spec14.json b/Tests/CMakeLib/testCTestHardwareSpec_data/spec14.json new file mode 100644 index 0000000..ce708c7 --- /dev/null +++ b/Tests/CMakeLib/testCTestHardwareSpec_data/spec14.json @@ -0,0 +1,8 @@ +{ + "local": [ + { + "0": [ + ] + } + ] +} diff --git a/Tests/CMakeLib/testCTestHardwareSpec_data/spec15.json b/Tests/CMakeLib/testCTestHardwareSpec_data/spec15.json new file mode 100644 index 0000000..78b6990 --- /dev/null +++ b/Tests/CMakeLib/testCTestHardwareSpec_data/spec15.json @@ -0,0 +1,8 @@ +{ + "local": [ + { + "-": [ + ] + } + ] +} diff --git a/Tests/CMakeLib/testCTestHardwareSpec_data/spec16.json b/Tests/CMakeLib/testCTestHardwareSpec_data/spec16.json new file mode 100644 index 0000000..95c7d26 --- /dev/null +++ b/Tests/CMakeLib/testCTestHardwareSpec_data/spec16.json @@ -0,0 +1,8 @@ +{ + "local": [ + { + "A": [ + ] + } + ] +} diff --git a/Tests/CMakeLib/testCTestHardwareSpec_data/spec17.json b/Tests/CMakeLib/testCTestHardwareSpec_data/spec17.json new file mode 100644 index 0000000..1b6ab4b --- /dev/null +++ b/Tests/CMakeLib/testCTestHardwareSpec_data/spec17.json @@ -0,0 +1,11 @@ +{ + "local": [ + { + "gpus": [ + { + "id": "A" + } + ] + } + ] +} diff --git a/Tests/CMakeLib/testCTestHardwareSpec_data/spec18.json b/Tests/CMakeLib/testCTestHardwareSpec_data/spec18.json new file mode 100644 index 0000000..1a17df7 --- /dev/null +++ b/Tests/CMakeLib/testCTestHardwareSpec_data/spec18.json @@ -0,0 +1,11 @@ +{ + "local": [ + { + "gpus": [ + { + "id": "-" + } + ] + } + ] +} diff --git a/Tests/CMakeLib/testCTestHardwareSpec_data/spec2.json b/Tests/CMakeLib/testCTestHardwareSpec_data/spec2.json new file mode 100644 index 0000000..6175b1a --- /dev/null +++ b/Tests/CMakeLib/testCTestHardwareSpec_data/spec2.json @@ -0,0 +1,4 @@ +{ + "local": [ + ] +} diff --git a/Tests/CMakeLib/testCTestHardwareSpec_data/spec3.json b/Tests/CMakeLib/testCTestHardwareSpec_data/spec3.json new file mode 100644 index 0000000..82453ec --- /dev/null +++ b/Tests/CMakeLib/testCTestHardwareSpec_data/spec3.json @@ -0,0 +1,8 @@ +{ + "local": [ + { + }, + { + } + ] +} diff --git a/Tests/CMakeLib/testCTestHardwareSpec_data/spec4.json b/Tests/CMakeLib/testCTestHardwareSpec_data/spec4.json new file mode 100644 index 0000000..05e73d7 --- /dev/null +++ b/Tests/CMakeLib/testCTestHardwareSpec_data/spec4.json @@ -0,0 +1,4 @@ +{ + "local": { + } +} diff --git a/Tests/CMakeLib/testCTestHardwareSpec_data/spec5.json b/Tests/CMakeLib/testCTestHardwareSpec_data/spec5.json new file mode 100644 index 0000000..2c63c08 --- /dev/null +++ b/Tests/CMakeLib/testCTestHardwareSpec_data/spec5.json @@ -0,0 +1,2 @@ +{ +} diff --git a/Tests/CMakeLib/testCTestHardwareSpec_data/spec6.json b/Tests/CMakeLib/testCTestHardwareSpec_data/spec6.json new file mode 100644 index 0000000..93c790d --- /dev/null +++ b/Tests/CMakeLib/testCTestHardwareSpec_data/spec6.json @@ -0,0 +1,5 @@ +{ + "local": [ + [] + ] +} diff --git a/Tests/CMakeLib/testCTestHardwareSpec_data/spec7.json b/Tests/CMakeLib/testCTestHardwareSpec_data/spec7.json new file mode 100644 index 0000000..28b6a4f --- /dev/null +++ b/Tests/CMakeLib/testCTestHardwareSpec_data/spec7.json @@ -0,0 +1,8 @@ +{ + "local": [ + { + "gpus": { + } + } + ] +} diff --git a/Tests/CMakeLib/testCTestHardwareSpec_data/spec8.json b/Tests/CMakeLib/testCTestHardwareSpec_data/spec8.json new file mode 100644 index 0000000..79bd224 --- /dev/null +++ b/Tests/CMakeLib/testCTestHardwareSpec_data/spec8.json @@ -0,0 +1,9 @@ +{ + "local": [ + { + "gpus": [ + [] + ] + } + ] +} diff --git a/Tests/CMakeLib/testCTestHardwareSpec_data/spec9.json b/Tests/CMakeLib/testCTestHardwareSpec_data/spec9.json new file mode 100644 index 0000000..6bb1def --- /dev/null +++ b/Tests/CMakeLib/testCTestHardwareSpec_data/spec9.json @@ -0,0 +1,10 @@ +{ + "local": [ + { + "gpus": [ + { + } + ] + } + ] +} |