diff options
| author | Dan Engelbrecht <[email protected]> | 2026-04-10 16:59:16 +0200 |
|---|---|---|
| committer | GitHub Enterprise <[email protected]> | 2026-04-10 16:59:16 +0200 |
| commit | 9e6999f53c91ec44d04ef6685dd97800e1a66306 (patch) | |
| tree | a40f48e1867c586319350fb2b0982379cd80d604 /src/zenserver-test/objectstore-tests.cpp | |
| parent | Update CHANGELOG.md (diff) | |
| download | zen-9e6999f53c91ec44d04ef6685dd97800e1a66306.tar.xz zen-9e6999f53c91ec44d04ef6685dd97800e1a66306.zip | |
reduce test runtime (#933)
* reduce zenserver spawns in tests
* fix filesystemutils wrong test suite name
* tweak tests for faster runtime
* reduce more test runtime
* more wall time improvements
* fast http and processmanager tests
Diffstat (limited to 'src/zenserver-test/objectstore-tests.cpp')
| -rw-r--r-- | src/zenserver-test/objectstore-tests.cpp | 281 |
1 files changed, 139 insertions, 142 deletions
diff --git a/src/zenserver-test/objectstore-tests.cpp b/src/zenserver-test/objectstore-tests.cpp index ff2314089..2139d4d3a 100644 --- a/src/zenserver-test/objectstore-tests.cpp +++ b/src/zenserver-test/objectstore-tests.cpp @@ -19,18 +19,22 @@ using namespace std::literals; TEST_SUITE_BEGIN("server.objectstore"); -TEST_CASE("objectstore.blobs") +TEST_CASE("objectstore") { - std::string_view Bucket = "bkt"sv; + ZenServerInstance Instance(TestEnv); + + const uint16_t Port = Instance.SpawnServerAndWaitUntilReady("--objectstore-enabled"); + CHECK(Port != 0); - std::vector<IoHash> CompressedBlobsHashes; - std::vector<uint64_t> BlobsSizes; - std::vector<uint64_t> CompressedBlobsSizes; + // --- objectstore.blobs --- { - ZenServerInstance Instance(TestEnv); + INFO("objectstore.blobs"); + + std::string_view Bucket = "bkt"sv; - const uint16_t PortNumber = Instance.SpawnServerAndWaitUntilReady(fmt::format("--objectstore-enabled")); - CHECK(PortNumber != 0); + std::vector<IoHash> CompressedBlobsHashes; + std::vector<uint64_t> BlobsSizes; + std::vector<uint64_t> CompressedBlobsSizes; HttpClient Client(Instance.GetBaseUri() + "/obj/"); @@ -68,155 +72,148 @@ TEST_CASE("objectstore.blobs") CHECK_EQ(RawSize, BlobsSizes[I]); } } -} -TEST_CASE("objectstore.s3client") -{ - ZenServerInstance Instance(TestEnv); - const uint16_t Port = Instance.SpawnServerAndWaitUntilReady("--objectstore-enabled"); - CHECK_MESSAGE(Port != 0, Instance.GetLogOutput()); - - // S3Client in path-style builds paths as /{bucket}/{key}. - // The objectstore routes objects at bucket/{bucket}/{key} relative to its base. - // Point the S3Client endpoint at {server}/obj/bucket so the paths line up. - S3ClientOptions Opts; - Opts.BucketName = "s3test"; - Opts.Region = "us-east-1"; - Opts.Endpoint = fmt::format("http://localhost:{}/obj/bucket", Port); - Opts.PathStyle = true; - Opts.Credentials.AccessKeyId = "testkey"; - Opts.Credentials.SecretAccessKey = "testsecret"; - - S3Client Client(Opts); - - // -- PUT + GET roundtrip -- - std::string_view TestData = "hello from s3client via objectstore"sv; - IoBuffer Content = IoBufferBuilder::MakeFromMemory(MakeMemoryView(TestData)); - S3Result PutRes = Client.PutObject("test/hello.txt", std::move(Content)); - REQUIRE_MESSAGE(PutRes.IsSuccess(), PutRes.Error); - - S3GetObjectResult GetRes = Client.GetObject("test/hello.txt"); - REQUIRE_MESSAGE(GetRes.IsSuccess(), GetRes.Error); - CHECK(GetRes.AsText() == TestData); - - // -- PUT overwrites -- - IoBuffer Original = IoBufferBuilder::MakeFromMemory(MakeMemoryView("original"sv)); - IoBuffer Overwrite = IoBufferBuilder::MakeFromMemory(MakeMemoryView("overwritten"sv)); - REQUIRE(Client.PutObject("overwrite/file.txt", std::move(Original)).IsSuccess()); - REQUIRE(Client.PutObject("overwrite/file.txt", std::move(Overwrite)).IsSuccess()); - - S3GetObjectResult OverwriteGet = Client.GetObject("overwrite/file.txt"); - REQUIRE(OverwriteGet.IsSuccess()); - CHECK(OverwriteGet.AsText() == "overwritten"sv); - - // -- GET not found -- - S3GetObjectResult NotFoundGet = Client.GetObject("nonexistent/file.dat"); - CHECK_FALSE(NotFoundGet.IsSuccess()); - - // -- HEAD found -- - std::string_view HeadData = "head test data"sv; - IoBuffer HeadContent = IoBufferBuilder::MakeFromMemory(MakeMemoryView(HeadData)); - REQUIRE(Client.PutObject("head/meta.txt", std::move(HeadContent)).IsSuccess()); - - S3HeadObjectResult HeadRes = Client.HeadObject("head/meta.txt"); - REQUIRE_MESSAGE(HeadRes.IsSuccess(), HeadRes.Error); - CHECK(HeadRes.Status == HeadObjectResult::Found); - CHECK(HeadRes.Info.Size == HeadData.size()); - - // -- HEAD not found -- - S3HeadObjectResult HeadNotFound = Client.HeadObject("nonexistent/file.dat"); - CHECK(HeadNotFound.IsSuccess()); - CHECK(HeadNotFound.Status == HeadObjectResult::NotFound); - - // -- LIST objects -- - for (int i = 0; i < 3; ++i) + // --- objectstore.s3client --- { - std::string Key = fmt::format("listing/item-{}.txt", i); - std::string Payload = fmt::format("content-{}", i); - IoBuffer Buf = IoBufferBuilder::MakeFromMemory(MakeMemoryView(Payload)); - REQUIRE(Client.PutObject(Key, std::move(Buf)).IsSuccess()); - } + INFO("objectstore.s3client"); + + S3ClientOptions Opts; + Opts.BucketName = "s3test"; + Opts.Region = "us-east-1"; + Opts.Endpoint = fmt::format("http://localhost:{}/obj/bucket", Port); + Opts.PathStyle = true; + Opts.Credentials.AccessKeyId = "testkey"; + Opts.Credentials.SecretAccessKey = "testsecret"; + + S3Client Client(Opts); + + // -- PUT + GET roundtrip -- + std::string_view TestData = "hello from s3client via objectstore"sv; + IoBuffer Content = IoBufferBuilder::MakeFromMemory(MakeMemoryView(TestData)); + S3Result PutRes = Client.PutObject("test/hello.txt", std::move(Content)); + REQUIRE_MESSAGE(PutRes.IsSuccess(), PutRes.Error); + + S3GetObjectResult GetRes = Client.GetObject("test/hello.txt"); + REQUIRE_MESSAGE(GetRes.IsSuccess(), GetRes.Error); + CHECK(GetRes.AsText() == TestData); + + // -- PUT overwrites -- + IoBuffer Original = IoBufferBuilder::MakeFromMemory(MakeMemoryView("original"sv)); + IoBuffer Overwrite = IoBufferBuilder::MakeFromMemory(MakeMemoryView("overwritten"sv)); + REQUIRE(Client.PutObject("overwrite/file.txt", std::move(Original)).IsSuccess()); + REQUIRE(Client.PutObject("overwrite/file.txt", std::move(Overwrite)).IsSuccess()); + + S3GetObjectResult OverwriteGet = Client.GetObject("overwrite/file.txt"); + REQUIRE(OverwriteGet.IsSuccess()); + CHECK(OverwriteGet.AsText() == "overwritten"sv); + + // -- GET not found -- + S3GetObjectResult NotFoundGet = Client.GetObject("nonexistent/file.dat"); + CHECK_FALSE(NotFoundGet.IsSuccess()); + + // -- HEAD found -- + std::string_view HeadData = "head test data"sv; + IoBuffer HeadContent = IoBufferBuilder::MakeFromMemory(MakeMemoryView(HeadData)); + REQUIRE(Client.PutObject("head/meta.txt", std::move(HeadContent)).IsSuccess()); + + S3HeadObjectResult HeadRes = Client.HeadObject("head/meta.txt"); + REQUIRE_MESSAGE(HeadRes.IsSuccess(), HeadRes.Error); + CHECK(HeadRes.Status == HeadObjectResult::Found); + CHECK(HeadRes.Info.Size == HeadData.size()); + + // -- HEAD not found -- + S3HeadObjectResult HeadNotFound = Client.HeadObject("nonexistent/file.dat"); + CHECK(HeadNotFound.IsSuccess()); + CHECK(HeadNotFound.Status == HeadObjectResult::NotFound); + + // -- LIST objects -- + for (int i = 0; i < 3; ++i) + { + std::string Key = fmt::format("listing/item-{}.txt", i); + std::string Payload = fmt::format("content-{}", i); + IoBuffer Buf = IoBufferBuilder::MakeFromMemory(MakeMemoryView(Payload)); + REQUIRE(Client.PutObject(Key, std::move(Buf)).IsSuccess()); + } - S3ListObjectsResult ListRes = Client.ListObjects("listing/"); - REQUIRE_MESSAGE(ListRes.IsSuccess(), ListRes.Error); - REQUIRE(ListRes.Objects.size() == 3); + S3ListObjectsResult ListRes = Client.ListObjects("listing/"); + REQUIRE_MESSAGE(ListRes.IsSuccess(), ListRes.Error); + REQUIRE(ListRes.Objects.size() == 3); - std::vector<std::string> Keys; - for (const S3ObjectInfo& Obj : ListRes.Objects) - { - Keys.push_back(Obj.Key); - CHECK(Obj.Size > 0); + std::vector<std::string> Keys; + for (const S3ObjectInfo& Obj : ListRes.Objects) + { + Keys.push_back(Obj.Key); + CHECK(Obj.Size > 0); + } + std::sort(Keys.begin(), Keys.end()); + CHECK(Keys[0] == "listing/item-0.txt"); + CHECK(Keys[1] == "listing/item-1.txt"); + CHECK(Keys[2] == "listing/item-2.txt"); + + // -- LIST empty prefix -- + S3ListObjectsResult EmptyList = Client.ListObjects("no-such-prefix/"); + REQUIRE(EmptyList.IsSuccess()); + CHECK(EmptyList.Objects.empty()); } - std::sort(Keys.begin(), Keys.end()); - CHECK(Keys[0] == "listing/item-0.txt"); - CHECK(Keys[1] == "listing/item-1.txt"); - CHECK(Keys[2] == "listing/item-2.txt"); - - // -- LIST empty prefix -- - S3ListObjectsResult EmptyList = Client.ListObjects("no-such-prefix/"); - REQUIRE(EmptyList.IsSuccess()); - CHECK(EmptyList.Objects.empty()); -} -TEST_CASE("objectstore.range-requests") -{ - ZenServerInstance Instance(TestEnv); - const uint16_t Port = Instance.SpawnServerAndWaitUntilReady("--objectstore-enabled"); - REQUIRE(Port != 0); + // --- objectstore.range-requests --- + { + INFO("objectstore.range-requests"); - HttpClient Client(Instance.GetBaseUri() + "/obj/"); + HttpClient Client(Instance.GetBaseUri() + "/obj/"); - IoBuffer Blob = CreateRandomBlob(1024); - MemoryView BlobView = Blob.GetView(); - std::string ObjectPath = "bucket/bkt/range-test/data.bin"; + IoBuffer Blob = CreateRandomBlob(1024); + MemoryView BlobView = Blob.GetView(); + std::string ObjectPath = "bucket/bkt/range-test/data.bin"; - HttpClient::Response PutResult = Client.Put(ObjectPath, IoBuffer(Blob)); - REQUIRE(PutResult); + HttpClient::Response PutResult = Client.Put(ObjectPath, IoBuffer(Blob)); + REQUIRE(PutResult); - // Full GET without Range header - { - HttpClient::Response Result = Client.Get(ObjectPath); - CHECK(Result.StatusCode == HttpResponseCode::OK); - CHECK_EQ(Result.ResponsePayload.GetSize(), 1024u); - CHECK(Result.ResponsePayload.GetView().EqualBytes(BlobView)); - } + // Full GET without Range header + { + HttpClient::Response Result = Client.Get(ObjectPath); + CHECK(Result.StatusCode == HttpResponseCode::OK); + CHECK_EQ(Result.ResponsePayload.GetSize(), 1024u); + CHECK(Result.ResponsePayload.GetView().EqualBytes(BlobView)); + } - // Single range: bytes 100-199 - { - HttpClient::Response Result = Client.Get(ObjectPath, {{"Range", "bytes=100-199"}}); - CHECK(Result.StatusCode == HttpResponseCode::PartialContent); - CHECK_EQ(Result.ResponsePayload.GetSize(), 100u); - CHECK(Result.ResponsePayload.GetView().EqualBytes(BlobView.Mid(100, 100))); - } + // Single range: bytes 100-199 + { + HttpClient::Response Result = Client.Get(ObjectPath, {{"Range", "bytes=100-199"}}); + CHECK(Result.StatusCode == HttpResponseCode::PartialContent); + CHECK_EQ(Result.ResponsePayload.GetSize(), 100u); + CHECK(Result.ResponsePayload.GetView().EqualBytes(BlobView.Mid(100, 100))); + } - // Range starting at zero: bytes 0-49 - { - HttpClient::Response Result = Client.Get(ObjectPath, {{"Range", "bytes=0-49"}}); - CHECK(Result.StatusCode == HttpResponseCode::PartialContent); - CHECK_EQ(Result.ResponsePayload.GetSize(), 50u); - CHECK(Result.ResponsePayload.GetView().EqualBytes(BlobView.Mid(0, 50))); - } + // Range starting at zero: bytes 0-49 + { + HttpClient::Response Result = Client.Get(ObjectPath, {{"Range", "bytes=0-49"}}); + CHECK(Result.StatusCode == HttpResponseCode::PartialContent); + CHECK_EQ(Result.ResponsePayload.GetSize(), 50u); + CHECK(Result.ResponsePayload.GetView().EqualBytes(BlobView.Mid(0, 50))); + } - // Range at end of file: bytes 1000-1023 - { - HttpClient::Response Result = Client.Get(ObjectPath, {{"Range", "bytes=1000-1023"}}); - CHECK(Result.StatusCode == HttpResponseCode::PartialContent); - CHECK_EQ(Result.ResponsePayload.GetSize(), 24u); - CHECK(Result.ResponsePayload.GetView().EqualBytes(BlobView.Mid(1000, 24))); - } + // Range at end of file: bytes 1000-1023 + { + HttpClient::Response Result = Client.Get(ObjectPath, {{"Range", "bytes=1000-1023"}}); + CHECK(Result.StatusCode == HttpResponseCode::PartialContent); + CHECK_EQ(Result.ResponsePayload.GetSize(), 24u); + CHECK(Result.ResponsePayload.GetView().EqualBytes(BlobView.Mid(1000, 24))); + } - // Multiple ranges: not supported, falls back to 200 with full body per RFC 7233 - { - HttpClient::Response Result = Client.Get(ObjectPath, {{"Range", "bytes=0-49,100-149"}}); - CHECK(Result.StatusCode == HttpResponseCode::OK); - CHECK_EQ(Result.ResponsePayload.GetSize(), 1024u); - CHECK(Result.ResponsePayload.GetView().EqualBytes(BlobView)); - } + // Multiple ranges: not supported, falls back to 200 with full body per RFC 7233 + { + HttpClient::Response Result = Client.Get(ObjectPath, {{"Range", "bytes=0-49,100-149"}}); + CHECK(Result.StatusCode == HttpResponseCode::OK); + CHECK_EQ(Result.ResponsePayload.GetSize(), 1024u); + CHECK(Result.ResponsePayload.GetView().EqualBytes(BlobView)); + } - // Out-of-bounds range: should return 400 - { - HttpClient::Response Result = Client.Get(ObjectPath, {{"Range", "bytes=2000-2099"}}); - CHECK(Result.StatusCode == HttpResponseCode::BadRequest); + // Out-of-bounds range: should return 400 + { + HttpClient::Response Result = Client.Get(ObjectPath, {{"Range", "bytes=2000-2099"}}); + CHECK(Result.StatusCode == HttpResponseCode::BadRequest); + } } } |