aboutsummaryrefslogtreecommitdiff
path: root/src/zenserver-test/nomad-tests.cpp
blob: f8f5a9a30f2062fde2dcf3933464278c53308b1f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// Copyright Epic Games, Inc. All Rights Reserved.

#if ZEN_WITH_TESTS && ZEN_WITH_NOMAD
#	include "zenserver-test.h"
#	include <zencore/filesystem.h>
#	include <zencore/logging.h>
#	include <zencore/testing.h>
#	include <zencore/timer.h>
#	include <zenhttp/httpclient.h>
#	include <zennomad/nomadclient.h>
#	include <zennomad/nomadprocess.h>
#	include <zenutil/zenserverprocess.h>

#	include <fmt/format.h>

namespace zen::tests::nomad_tests {

using namespace std::literals;

TEST_SUITE_BEGIN("server.nomad");

TEST_CASE("nomad.client.lifecycle" * doctest::skip())
{
	zen::nomad::NomadProcess NomadProc;
	NomadProc.SpawnNomadAgent();

	zen::nomad::NomadTestClient Client("http://localhost:4646/");

	// Submit a simple batch job that sleeps briefly
#	if ZEN_PLATFORM_WINDOWS
	auto Job = Client.SubmitJob("zen-test-job", "cmd.exe", {"/C", "timeout /t 10 /nobreak"});
#	else
	auto Job = Client.SubmitJob("zen-test-job", "/bin/sleep", {"10"});
#	endif
	REQUIRE(!Job.Id.empty());
	CHECK_EQ(Job.Status, "pending");

	// Poll until the job is running (or dead)
	{
		Stopwatch Timer;
		bool	  FoundRunning = false;
		while (Timer.GetElapsedTimeMs() < 15000)
		{
			auto Status = Client.GetJobStatus("zen-test-job");
			if (Status.Status == "running")
			{
				FoundRunning = true;
				break;
			}
			if (Status.Status == "dead")
			{
				break;
			}
			Sleep(500);
		}
		CHECK(FoundRunning);
	}

	// Verify allocations exist
	auto Allocs = Client.GetAllocations("zen-test-job");
	CHECK(!Allocs.empty());

	// Stop the job
	Client.StopJob("zen-test-job");

	// Verify it reaches dead state
	{
		Stopwatch Timer;
		bool	  FoundDead = false;
		while (Timer.GetElapsedTimeMs() < 10000)
		{
			auto Status = Client.GetJobStatus("zen-test-job");
			if (Status.Status == "dead")
			{
				FoundDead = true;
				break;
			}
			Sleep(500);
		}
		CHECK(FoundDead);
	}

	NomadProc.StopNomadAgent();
}

TEST_CASE("nomad.provisioner.integration" * doctest::skip())
{
	zen::nomad::NomadProcess NomadProc;
	NomadProc.SpawnNomadAgent();

	// Spawn zenserver in compute mode with Nomad provisioning enabled
	ZenServerInstance Instance(TestEnv, ZenServerInstance::ServerMode::kComputeServer);

	Instance.SetDataDir(TestEnv.CreateNewTestDir());

	std::filesystem::path ZenServerPath = TestEnv.ProgramBaseDir() / "zenserver" ZEN_EXE_SUFFIX_LITERAL;

	std::string NomadArgs = fmt::format(
		"--nomad-enabled=true"
		" --nomad-server=http://localhost:4646"
		" --nomad-driver=raw_exec"
		" --nomad-binary-path={}"
		" --nomad-max-cores=32"
		" --nomad-cores-per-job=32",
		ZenServerPath.string());

	const uint16_t Port = Instance.SpawnServerAndWaitUntilReady(NomadArgs);
	REQUIRE(Port != 0);

	// Give the provisioner time to submit jobs.
	// The management thread has a 5s wait between cycles, and the HTTP client has
	// a 10s connect timeout, so we need to allow enough time for at least one full cycle.
	Sleep(15000);

	// Verify jobs were submitted to Nomad
	zen::nomad::NomadTestClient NomadClient("http://localhost:4646/");

	auto Jobs = NomadClient.ListJobs("zenserver-worker");

	ZEN_INFO("nomad.provisioner.integration: found {} jobs with prefix 'zenserver-worker'", Jobs.size());
	CHECK_MESSAGE(!Jobs.empty(), Instance.GetLogOutput());

	Instance.Shutdown();
	NomadProc.StopNomadAgent();
}

TEST_SUITE_END();

}  // namespace zen::tests::nomad_tests
#endif