// Copyright Epic Games, Inc. All Rights Reserved. #if ZEN_WITH_TESTS # include "zenserver-test.h" # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include namespace zen::tests::hub { using namespace std::literals; TEST_SUITE_BEGIN("hub.lifecycle"); TEST_CASE("hub.lifecycle.basic") { { ZenServerInstance Instance(TestEnv, ZenServerInstance::ServerMode::kHubServer); const uint16_t PortNumber = Instance.SpawnServerAndWaitUntilReady(); CHECK(PortNumber != 0); HttpClient Client(Instance.GetBaseUri() + "/hub/"); HttpClient::Response Result = Client.Get("status"); CHECK(Result); } } TEST_CASE("hub.lifecycle.children") { ZenServerInstance Instance(TestEnv, ZenServerInstance::ServerMode::kHubServer); const uint16_t PortNumber = Instance.SpawnServerAndWaitUntilReady(); REQUIRE(PortNumber != 0); SUBCASE("spawn") { HttpClient Client(Instance.GetBaseUri() + "/hub/"); HttpClient::Response Result = Client.Get("status"); REQUIRE(Result); { Result = Client.Post("modules/abc/provision"); REQUIRE(Result); CbObject AbcResult = Result.AsObject(); CHECK(AbcResult["moduleId"].AsString() == "abc"sv); const uint16_t AbcPort = AbcResult["port"].AsUInt16(0); CHECK_NE(AbcPort, 0); // This should be a fresh instance with no contents HttpClient AbcClient(fmt::format("http://localhost:{}", AbcPort)); Result = AbcClient.Get("/z$/ns1/b/0123456789abcdef0123456789abcdef01234567"); CHECK_EQ(Result.StatusCode, HttpResponseCode::NotFound); Result = AbcClient.Put("/z$/ns1/b/0123456789abcdef0123456789abcdef01234567", IoBufferBuilder::MakeFromMemory(MakeMemoryView("abcdef"sv))); CHECK_EQ(Result.StatusCode, HttpResponseCode::Created); } { Result = Client.Post("modules/def/provision"); REQUIRE(Result); CbObject DefResult = Result.AsObject(); CHECK(DefResult["moduleId"].AsString() == "def"sv); const uint16_t DefPort = DefResult["port"].AsUInt16(0); REQUIRE_NE(DefPort, 0); // This should be a fresh instance with no contents HttpClient DefClient(fmt::format("http://localhost:{}", DefPort)); Result = DefClient.Get("/z$/ns1/b/0123456789abcdef0123456789abcdef01234567"); CHECK_EQ(Result.StatusCode, HttpResponseCode::NotFound); Result = DefClient.Put("/z$/ns1/b/0123456789abcdef0123456789abcdef01234567", IoBufferBuilder::MakeFromMemory(MakeMemoryView("AbcDef"sv))); CHECK_EQ(Result.StatusCode, HttpResponseCode::Created); } // this should be rejected because of the invalid module id Result = Client.Post("modules/!!!!!/provision"); CHECK(!Result); Result = Client.Post("modules/ghi/provision"); REQUIRE(Result); // Tear down instances Result = Client.Post("modules/abc/deprovision"); REQUIRE(Result); Result = Client.Post("modules/def/deprovision"); REQUIRE(Result); Result = Client.Post("modules/ghi/deprovision"); REQUIRE(Result); // re-provision to verify that (de)hydration preserved state { Result = Client.Post("modules/abc/provision"); REQUIRE(Result); CbObject AbcResult = Result.AsObject(); CHECK(AbcResult["moduleId"].AsString() == "abc"sv); const uint16_t AbcPort = AbcResult["port"].AsUInt16(0); REQUIRE_NE(AbcPort, 0); // This should contain the content from the previous run HttpClient AbcClient(fmt::format("http://localhost:{}", AbcPort)); Result = AbcClient.Get("/z$/ns1/b/0123456789abcdef0123456789abcdef01234567"); CHECK_EQ(Result.StatusCode, HttpResponseCode::OK); CHECK_EQ(Result.AsText(), "abcdef"sv); Result = AbcClient.Put("/z$/ns1/b/1123456789abcdef0123456789abcdef01234567", IoBufferBuilder::MakeFromMemory(MakeMemoryView("ghijklmnop"sv))); CHECK_EQ(Result.StatusCode, HttpResponseCode::Created); } { Result = Client.Post("modules/def/provision"); REQUIRE(Result); CbObject DefResult = Result.AsObject(); CHECK(DefResult["moduleId"].AsString() == "def"sv); const uint16_t DefPort = DefResult["port"].AsUInt16(0); REQUIRE_NE(DefPort, 0); // This should contain the content from the previous run HttpClient DefClient(fmt::format("http://localhost:{}", DefPort)); Result = DefClient.Get("/z$/ns1/b/0123456789abcdef0123456789abcdef01234567"); CHECK_EQ(Result.StatusCode, HttpResponseCode::OK); CHECK_EQ(Result.AsText(), "AbcDef"sv); Result = DefClient.Put("/z$/ns1/b/1123456789abcdef0123456789abcdef01234567", IoBufferBuilder::MakeFromMemory(MakeMemoryView("GhijklmNop"sv))); CHECK_EQ(Result.StatusCode, HttpResponseCode::Created); } Result = Client.Post("modules/abc/deprovision"); REQUIRE(Result); Result = Client.Post("modules/def/deprovision"); REQUIRE(Result); // re-provision to verify that (de)hydration preserved state, including // state which was generated after the very first dehydration { Result = Client.Post("modules/abc/provision"); REQUIRE(Result); CbObject AbcResult = Result.AsObject(); CHECK(AbcResult["moduleId"].AsString() == "abc"sv); const uint16_t AbcPort = AbcResult["port"].AsUInt16(0); REQUIRE_NE(AbcPort, 0); // This should contain the content from the previous two runs HttpClient AbcClient(fmt::format("http://localhost:{}", AbcPort)); Result = AbcClient.Get("/z$/ns1/b/0123456789abcdef0123456789abcdef01234567"); CHECK_EQ(Result.StatusCode, HttpResponseCode::OK); CHECK_EQ(Result.AsText(), "abcdef"sv); Result = AbcClient.Get("/z$/ns1/b/1123456789abcdef0123456789abcdef01234567"); CHECK_EQ(Result.StatusCode, HttpResponseCode::OK); CHECK_EQ(Result.AsText(), "ghijklmnop"sv); } { Result = Client.Post("modules/def/provision"); REQUIRE(Result); CbObject DefResult = Result.AsObject(); REQUIRE(DefResult["moduleId"].AsString() == "def"sv); const uint16_t DefPort = DefResult["port"].AsUInt16(0); REQUIRE_NE(DefPort, 0); // This should contain the content from the previous two runs HttpClient DefClient(fmt::format("http://localhost:{}", DefPort)); Result = DefClient.Get("/z$/ns1/b/0123456789abcdef0123456789abcdef01234567"); CHECK_EQ(Result.StatusCode, HttpResponseCode::OK); CHECK_EQ(Result.AsText(), "AbcDef"sv); Result = DefClient.Get("/z$/ns1/b/1123456789abcdef0123456789abcdef01234567"); CHECK_EQ(Result.StatusCode, HttpResponseCode::OK); CHECK_EQ(Result.AsText(), "GhijklmNop"sv); } Result = Client.Post("modules/abc/deprovision"); REQUIRE(Result); Result = Client.Post("modules/def/deprovision"); REQUIRE(Result); // final sanity check that the hub is still responsive Result = Client.Get("status"); CHECK(Result); } } TEST_SUITE_END(); TEST_CASE("hub.consul.lifecycle") { zen::consul::ConsulProcess ConsulProc; ConsulProc.SpawnConsulAgent(); zen::consul::ConsulClient Client("http://localhost:8500/"); Client.SetKeyValue("zen/hub/testkey", "testvalue"); std::string RetrievedValue = Client.GetKeyValue("zen/hub/testkey"); CHECK_EQ(RetrievedValue, "testvalue"); Client.DeleteKey("zen/hub/testkey"); ConsulProc.StopConsulAgent(); } } // namespace zen::tests::hub #endif