aboutsummaryrefslogtreecommitdiff
path: root/zenserver-test/zenserver-test.cpp
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2021-06-18 15:43:58 +0200
committerStefan Boberg <[email protected]>2021-06-18 15:43:58 +0200
commit8d4e57692725dd76c82137577eedfc459cb959f4 (patch)
tree749c6863edfe60ed72af7fc07e626f659fdac4d6 /zenserver-test/zenserver-test.cpp
parentAdded ZenTestEnvironment::RootDir to construct a path to a subdirectory in th... (diff)
downloadzen-8d4e57692725dd76c82137577eedfc459cb959f4.tar.xz
zen-8d4e57692725dd76c82137577eedfc459cb959f4.zip
Improved some logging in test harness, added launcher test
Diffstat (limited to 'zenserver-test/zenserver-test.cpp')
-rw-r--r--zenserver-test/zenserver-test.cpp175
1 files changed, 174 insertions, 1 deletions
diff --git a/zenserver-test/zenserver-test.cpp b/zenserver-test/zenserver-test.cpp
index 114c3e86b..187566d44 100644
--- a/zenserver-test/zenserver-test.cpp
+++ b/zenserver-test/zenserver-test.cpp
@@ -660,7 +660,7 @@ main(int argc, char** argv)
TestEnv.Initialize(ProgramBaseDir, TestBaseDir);
- spdlog::info("Running tests...");
+ spdlog::info("Running tests...(base dir: '{}')", TestBaseDir);
return doctest::Context(argc, argv).run();
}
@@ -1177,4 +1177,177 @@ TEST_CASE("z$.basic")
}
}
+struct RemoteExecutionRequest
+{
+ RemoteExecutionRequest(std::string_view Host, int Port, std::filesystem::path& TreePath)
+ : m_HostName(Host)
+ , m_PortNumber(Port)
+ , m_TreePath(TreePath)
+ {
+ }
+
+ void Build(std::string_view Command, std::string_view Arguments)
+ {
+ zen::FileSystemTraversal Traversal;
+ Traversal.TraverseFileSystem(m_TreePath, m_Visit);
+
+ zen::CbObjectWriter PrepReq;
+
+ PrepReq << "cmd"
+ << Command;
+ PrepReq << "args"
+ << Arguments;
+
+ PrepReq.BeginArray("files");
+
+ for (const auto& Kv : m_Visit.m_Files)
+ {
+ PrepReq.BeginObject();
+ PrepReq << "file" << zen::WideToUtf8(Kv.first) << "size" << Kv.second.Size << "hash" << Kv.second.Hash;
+ PrepReq.EndObject();
+ }
+ PrepReq.EndArray();
+
+ zen::BinaryWriter MemWriter(m_MemOut);
+ PrepReq.Save(MemWriter);
+ }
+
+ void Prep()
+ {
+ cpr::Response Response = cpr::Post(cpr::Url("{}/prep"_format(m_BaseUri)), cpr::Body((const char*)m_MemOut.Data(), m_MemOut.Size()));
+
+ if (Response.status_code < 300)
+ {
+ zen::IoBuffer Payload(zen::IoBuffer::Clone, Response.text.data(), Response.text.size());
+ zen::CbObject Result = zen::LoadCompactBinaryObject(Payload);
+
+ for (auto& Need : Result["need"])
+ {
+ zen::IoHash NeedHash = Need.AsHash();
+
+ if (auto It = m_Visit.m_HashToFile.find(NeedHash); It != m_Visit.m_HashToFile.end())
+ {
+ zen::IoBuffer FileData = zen::IoBufferBuilder::MakeFromFile(It->second.c_str());
+
+ cpr::Response CasResponse = cpr::Post(cpr::Url(m_CasUri), cpr::Body((const char*)FileData.Data(), FileData.Size()));
+
+ if (CasResponse.status_code >= 300)
+ {
+ spdlog::error("CAS put failed with {}", CasResponse.status_code);
+ }
+ }
+ else
+ {
+ spdlog::error("unknown hash in 'need' list: {}", NeedHash);
+ }
+ }
+ }
+ }
+
+ zen::CbObject Exec()
+ {
+ cpr::Response JobResponse = cpr::Post(cpr::Url(m_BaseUri), cpr::Body((const char*)m_MemOut.Data(), m_MemOut.Size()));
+
+ if (JobResponse.status_code < 300)
+ {
+ zen::IoBuffer Payload(zen::IoBuffer::Clone, JobResponse.text.data(), JobResponse.text.size());
+ return zen::LoadCompactBinaryObject(std::move(Payload));
+ }
+
+ spdlog::info("job exec: {}", JobResponse.status_code);
+ return {};
+ }
+
+private:
+ struct Visitor : public zen::FileSystemTraversal::TreeVisitor
+ {
+ const std::filesystem::path& m_RootPath;
+
+ Visitor(const std::filesystem::path& RootPath) : m_RootPath(RootPath) {}
+
+ virtual void VisitFile(const std::filesystem::path& Parent, const std::wstring_view& FileName, uint64_t FileSize) override
+ {
+ std::filesystem::path FullPath = Parent / FileName;
+
+ zen::IoHashStream Ios;
+ zen::ScanFile(FullPath, 64 * 1024, [&](const void* Data, size_t Size) { Ios.Append(Data, Size); });
+ zen::IoHash Hash = Ios.GetHash();
+
+ std::wstring RelativePath = FullPath.lexically_relative(m_RootPath).native();
+ // spdlog::info("File: {:32} => {} ({})", zen::WideToUtf8(RelativePath), Hash, FileSize);
+
+ FileEntry& Entry = m_Files[RelativePath];
+ Entry.Hash = Hash;
+ Entry.Size = FileSize;
+
+ m_HashToFile[Hash] = FullPath;
+ }
+
+ virtual bool VisitDirectory(const std::filesystem::path& Parent, const std::wstring_view& DirectoryName) override
+ {
+ std::filesystem::path FullPath = Parent / DirectoryName;
+
+ if (DirectoryName.starts_with(L"."))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ struct FileEntry
+ {
+ uint64_t Size;
+ zen::IoHash Hash;
+ };
+
+ std::map<std::wstring, FileEntry> m_Files;
+ std::unordered_map<zen::IoHash, std::filesystem::path, zen::IoHash::Hasher> m_HashToFile;
+ };
+
+ std::string m_HostName;
+ int m_PortNumber;
+ std::filesystem::path m_TreePath;
+ const std::string m_BaseUri = "http://{}:{}/exec/jobs"_format(m_HostName, m_PortNumber);
+ const std::string m_CasUri = "http://{}:{}/cas"_format(m_HostName, m_PortNumber);
+ Visitor m_Visit{m_TreePath};
+ zen::MemoryOutStream m_MemOut;
+};
+
+TEST_CASE("exec.basic")
+{
+ using namespace std::literals;
+
+ std::filesystem::path TestDir = TestEnv.CreateNewTestDir();
+
+ const uint16_t PortNumber = 13337;
+
+ const int kIterationCount = 100;
+
+ ZenServerInstance Zen1(TestEnv);
+ Zen1.SetTestDir(TestDir);
+ Zen1.SpawnServer(PortNumber);
+ Zen1.WaitUntilReady();
+
+ std::filesystem::path TreePath = TestEnv.RootDir("test/remote1");
+
+ {
+ RemoteExecutionRequest RemoteRequest("localhost", PortNumber, TreePath);
+ RemoteRequest.Build("zentest-appstub.exe", "");
+ RemoteRequest.Prep();
+ zen::CbObject Result = RemoteRequest.Exec();
+
+ CHECK(Result["exitcode"].AsInt32(-1) == 0);
+ }
+
+ {
+ RemoteExecutionRequest RemoteRequest("localhost", PortNumber, TreePath);
+ RemoteRequest.Build("zentest-appstub.exe", "-f=1");
+ RemoteRequest.Prep();
+ zen::CbObject Result = RemoteRequest.Exec();
+
+ CHECK(Result["exitcode"].AsInt32(-1) == 1);
+ }
+}
+
#endif