aboutsummaryrefslogtreecommitdiff
path: root/src/zenserver-test/objectstore-tests.cpp
diff options
context:
space:
mode:
authorDan Engelbrecht <[email protected]>2026-04-10 16:59:16 +0200
committerGitHub Enterprise <[email protected]>2026-04-10 16:59:16 +0200
commit9e6999f53c91ec44d04ef6685dd97800e1a66306 (patch)
treea40f48e1867c586319350fb2b0982379cd80d604 /src/zenserver-test/objectstore-tests.cpp
parentUpdate CHANGELOG.md (diff)
downloadzen-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.cpp281
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);
+ }
}
}