diff options
Diffstat (limited to 'searchcore/src/tests/proton/server/move_operation_limiter_test.cpp')
-rw-r--r-- | searchcore/src/tests/proton/server/move_operation_limiter_test.cpp | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/searchcore/src/tests/proton/server/move_operation_limiter_test.cpp b/searchcore/src/tests/proton/server/move_operation_limiter_test.cpp new file mode 100644 index 00000000000..dee5fd2fd2c --- /dev/null +++ b/searchcore/src/tests/proton/server/move_operation_limiter_test.cpp @@ -0,0 +1,109 @@ +// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include <vespa/searchcore/proton/server/i_blockable_maintenance_job.h> +#include <vespa/searchcore/proton/server/move_operation_limiter.h> +#include <vespa/vespalib/testkit/test_kit.h> +#include <queue> + +using namespace proton; + +struct MyBlockableMaintenanceJob : public IBlockableMaintenanceJob { + bool blocked; + MyBlockableMaintenanceJob() + : IBlockableMaintenanceJob("my_job", 1s, 1s), + blocked(false) + {} + void setBlocked(BlockedReason reason) override { + ASSERT_TRUE(reason == BlockedReason::OUTSTANDING_OPS); + EXPECT_FALSE(blocked); + blocked = true; + } + void unBlock(BlockedReason reason) override { + ASSERT_TRUE(reason == BlockedReason::OUTSTANDING_OPS); + EXPECT_TRUE(blocked); + blocked = false; + } + bool run() override { return true; } + void onStop() override { } +}; + +struct Fixture { + using OpsQueue = std::queue<std::shared_ptr<vespalib::IDestructorCallback>>; + using MoveOperationLimiterSP = std::shared_ptr<MoveOperationLimiter>; + + MyBlockableMaintenanceJob job; + MoveOperationLimiterSP limiter; + OpsQueue ops; + Fixture(uint32_t maxOutstandingOps = 2) + : job(), + limiter(std::make_shared<MoveOperationLimiter>(&job, maxOutstandingOps)), + ops() + {} + void beginOp() { ops.push(limiter->beginOperation()); } + void endOp() { ops.pop(); } + void clearJob() { limiter->clearJob(); } + void clearLimiter() { limiter = MoveOperationLimiterSP(); } + void assertAboveLimit() const { + EXPECT_TRUE(limiter->isAboveLimit()); + EXPECT_TRUE(job.blocked); + } + void assertBelowLimit() const { + EXPECT_FALSE(limiter->isAboveLimit()); + EXPECT_FALSE(job.blocked); + } +}; + +TEST_F("require that hasPending reflects if any jobs are outstanding", Fixture) +{ + EXPECT_FALSE(f.limiter->hasPending()); + f.beginOp(); + EXPECT_TRUE(f.limiter->hasPending()); + f.endOp(); + EXPECT_FALSE(f.limiter->hasPending()); +} + +TEST_F("require that job is blocked / unblocked when crossing max outstanding ops boundaries", Fixture) +{ + f.beginOp(); + TEST_DO(f.assertBelowLimit()); + f.beginOp(); + TEST_DO(f.assertAboveLimit()); + f.beginOp(); + TEST_DO(f.assertAboveLimit()); + f.endOp(); + TEST_DO(f.assertAboveLimit()); + f.endOp(); + TEST_DO(f.assertBelowLimit()); + f.endOp(); + TEST_DO(f.assertBelowLimit()); +} + +TEST_F("require that cleared job is not blocked when crossing max ops boundary", Fixture) +{ + f.beginOp(); + f.clearJob(); + f.beginOp(); + EXPECT_FALSE(f.job.blocked); + EXPECT_TRUE(f.limiter->isAboveLimit()); +} + +TEST_F("require that cleared job is not unblocked when crossing max ops boundary", Fixture) +{ + f.beginOp(); + f.beginOp(); + TEST_DO(f.assertAboveLimit()); + f.clearJob(); + f.endOp(); + EXPECT_TRUE(f.job.blocked); + EXPECT_FALSE(f.limiter->isAboveLimit()); +} + +TEST_F("require that destructor callback has reference to limiter via shared ptr", Fixture) +{ + f.beginOp(); + f.beginOp(); + TEST_DO(f.assertAboveLimit()); + f.clearLimiter(); + f.endOp(); + EXPECT_FALSE(f.job.blocked); +} |