diff --git a/fdbserver/ConfigDatabaseUnitTests.actor.cpp b/fdbserver/ConfigDatabaseUnitTests.actor.cpp index 85ab4ea355..a3fab0d35c 100644 --- a/fdbserver/ConfigDatabaseUnitTests.actor.cpp +++ b/fdbserver/ConfigDatabaseUnitTests.actor.cpp @@ -54,7 +54,7 @@ Value longToValue(int64_t v) { return StringRef(reinterpret_cast(s.c_str()), s.size()); } -Future addTestClearMutations(SimpleConfigTransaction& tr) { +Future addTestClearMutations(SimpleConfigTransaction& tr, Version version /* TODO: shouldn't need this */) { tr.fullReset(); auto configKeyA = encodeConfigKey("class-A"_sr, "test_long"_sr); auto configKeyB = encodeConfigKey("class-B"_sr, "test_long"_sr); @@ -104,7 +104,9 @@ Future addTestSetMutations(WriteTo& writeTo, int64_t value) { return writeTo.addVersionedMutations(versionedMutations, version); } -ACTOR Future readConfigState(SimpleConfigTransaction* tr, Optional expected) { +ACTOR Future readConfigState(SimpleConfigTransaction* tr, + Optional expected, + bool immediate /* TODO : remove this */) { tr->fullReset(); state Key configKeyA = encodeConfigKey("class-A"_sr, "test_long"_sr); state Key configKeyB = encodeConfigKey("class-B"_sr, "test_long"_sr); @@ -120,14 +122,28 @@ ACTOR Future readConfigState(SimpleConfigTransaction* tr, Optional -Future readConfigState(LocalConfiguration const* localConfiguration, int64_t expected) { - if constexpr (immediate) { - ASSERT_EQ(localConfiguration->getTestKnobs().TEST_LONG, expected); +ACTOR template +Future waitUntil(F isReady) { + loop { + if (isReady()) { + return Void(); + } + wait(delayJittered(0.1)); + } +} + +Future readConfigState(LocalConfiguration const* localConfiguration, Optional expected, bool immediate) { + if (immediate) { + if (expected.present()) { + ASSERT_EQ(localConfiguration->getTestKnobs().TEST_LONG, expected.get()); + } else { + ASSERT_EQ(localConfiguration->getTestKnobs().TEST_LONG, 0); + } return Void(); } else { - return waitUntil( - [localConfiguration, expected] { return localConfiguration->getTestKnobs().TEST_LONG == expected; }); + return waitUntil([localConfiguration, expected] { + return localConfiguration->getTestKnobs().TEST_LONG == (expected.present() ? expected.get() : 0); + }); } } @@ -139,200 +155,243 @@ Future addTestGlobalSetMutation(ConfigStore& configStore, Version& lastWri return configStore.addVersionedMutations(versionedMutations, lastWrittenVersion); } -class DummyConfigSource { - ConfigFollowerInterface cfi; - ACTOR static Future serve(DummyConfigSource* self) { - loop { - choose { - when(ConfigFollowerGetVersionRequest req = waitNext(self->cfi.getVersion.getFuture())) { - req.reply.send(0); - } - when(ConfigFollowerGetSnapshotRequest req = waitNext(self->cfi.getSnapshot.getFuture())) { - req.reply.send(ConfigFollowerGetSnapshotReply{}); +class LocalConfigEnvironment { + LocalConfiguration localConfiguration; + +public: + LocalConfigEnvironment(std::string const& configPath, std::map const& manualKnobOverrides) + : localConfiguration(configPath, manualKnobOverrides) {} + + Future setup() { return localConfiguration.initialize("./", deterministicRandom()->randomUniqueID()); } + + template + Future run(Args&&... args) { + return TestType::run(localConfiguration, localConfiguration, std::forward(args)...); + } +}; + +class BroadcasterToLocalConfigEnvironment { + class DummyConfigSource { + ConfigFollowerInterface cfi; + ACTOR static Future serve(DummyConfigSource* self) { + loop { + choose { + when(ConfigFollowerGetVersionRequest req = waitNext(self->cfi.getVersion.getFuture())) { + req.reply.send(0); + } + when(ConfigFollowerGetSnapshotRequest req = waitNext(self->cfi.getSnapshot.getFuture())) { + req.reply.send(ConfigFollowerGetSnapshotReply{}); + } } } } + + public: + Future serve() { return serve(this); } + ConfigFollowerInterface const& getInterface() { return cfi; } + } dummyConfigSource; + ConfigBroadcaster broadcaster; + Reference> cfi; + LocalConfiguration localConfiguration; + ActorCollection actors{ false }; + + ACTOR static Future setup(BroadcasterToLocalConfigEnvironment* self) { + wait(self->localConfiguration.initialize("./", deterministicRandom()->randomUniqueID())); + self->actors.add(self->dummyConfigSource.serve()); + self->actors.add(self->broadcaster.serve(self->cfi->get())); + self->actors.add( + self->localConfiguration.consume(IDependentAsyncVar::create(self->cfi))); + return Void(); } public: - Future serve() { return serve(this); } - ConfigFollowerInterface const& getInterface() { return cfi; } + BroadcasterToLocalConfigEnvironment() + : broadcaster(dummyConfigSource.getInterface(), deterministicRandom()->randomUniqueID()), + cfi(makeReference>()), localConfiguration("class-A", {}) {} + + Future setup() { return setup(this); } + + template + Future run(Args&&... args) { + return waitOrError(TestType::run(broadcaster, localConfiguration, std::forward(args)...), + actors.getResult()); + } }; -ACTOR template -Future runLocalConfigEnvironment(std::string configPath, std::map manualKnobOverrides, F f) { - state LocalConfiguration localConfiguration(configPath, manualKnobOverrides); - state Version lastWrittenVersion = 0; - wait(localConfiguration.initialize("./", deterministicRandom()->randomUniqueID())); - wait(f(localConfiguration)); - return Void(); -} +class TransactionEnvironment { + ConfigTransactionInterface cti; + SimpleConfigTransaction tr; + SimpleConfigDatabaseNode node; + ActorCollection actors{ false }; -ACTOR template -Future runBroadcasterToLocalConfigEnvironment(F f) { - state DummyConfigSource dummyConfigSource; - state ConfigBroadcaster broadcaster(dummyConfigSource.getInterface(), deterministicRandom()->randomUniqueID()); - state Reference> cfi = makeReference>(); - state LocalConfiguration localConfigurationA("class-A", {}); - state LocalConfiguration localConfigurationB("class-B", {}); - state ActorCollection actors(false); - wait(localConfigurationA.initialize("./", deterministicRandom()->randomUniqueID())); - wait(localConfigurationB.initialize("./", deterministicRandom()->randomUniqueID())); - actors.add(dummyConfigSource.serve()); - actors.add(broadcaster.serve(cfi->get())); - actors.add(localConfigurationA.consume(IDependentAsyncVar::create(cfi))); - actors.add(localConfigurationB.consume(IDependentAsyncVar::create(cfi))); - wait(waitOrError(f(broadcaster, localConfigurationA, localConfigurationB), actors.getResult())); - return Void(); -} - -ACTOR template -Future runTransactionToLocalConfigEnvironment(F f) { - state ConfigTransactionInterface cti; - state Reference> cfi = makeReference>(); - state SimpleConfigTransaction tr(cti); - state SimpleConfigDatabaseNode node; - state ActorCollection actors(false); - state LocalConfiguration localConfigurationA("class-A", {}); - state LocalConfiguration localConfigurationB("class-B", {}); - wait(localConfigurationA.initialize("./", deterministicRandom()->randomUniqueID())); - wait(localConfigurationB.initialize("./", deterministicRandom()->randomUniqueID())); - wait(node.initialize("./", deterministicRandom()->randomUniqueID())); - actors.add(node.serve(cti)); - actors.add(node.serve(cfi->get())); - actors.add(localConfigurationA.consume(IDependentAsyncVar::create(cfi))); - actors.add(localConfigurationB.consume(IDependentAsyncVar::create(cfi))); - wait(waitOrError(f(tr, localConfigurationA, localConfigurationB), actors.getResult())); - return Void(); -} - -ACTOR template -Future runTransactionEnvironment(F f) { - state ConfigTransactionInterface cti; - state SimpleConfigTransaction tr(cti); - state SimpleConfigDatabaseNode node; - state ActorCollection actors(false); - wait(node.initialize("./", deterministicRandom()->randomUniqueID())); - actors.add(node.serve(cti)); - wait(waitOrError(f(tr), actors.getResult())); - return Void(); -} - -ACTOR template -Future waitUntil(F isReady) { - loop { - if (isReady()) { - return Void(); - } - wait(delayJittered(0.1)); + ACTOR static Future setup(TransactionEnvironment* self) { + wait(self->node.initialize("./", deterministicRandom()->randomUniqueID())); + self->actors.add(self->node.serve(self->cti)); + return Void(); } -} + +public: + TransactionEnvironment() : tr(cti) {} + + Future setup() { return setup(this); } + + template + Future run(Args&&... args) { + return waitOrError(TestType::run(tr, tr, std::forward(args)...), actors.getResult()); + } +}; + +class TransactionToLocalConfigEnvironment { + ConfigTransactionInterface cti; + Reference> cfi; + SimpleConfigTransaction tr; + SimpleConfigDatabaseNode node; + LocalConfiguration localConfiguration; + ActorCollection actors{ false }; + + ACTOR Future setup(TransactionToLocalConfigEnvironment* self) { + wait(self->localConfiguration.initialize("./", deterministicRandom()->randomUniqueID())); + wait(self->node.initialize("./", deterministicRandom()->randomUniqueID())); + self->actors.add(self->node.serve(self->cti)); + self->actors.add(self->node.serve(self->cfi->get())); + self->actors.add( + self->localConfiguration.consume(IDependentAsyncVar::create(self->cfi))); + return Void(); + } + +public: + TransactionToLocalConfigEnvironment() + : cfi(makeReference>()), tr(cti), localConfiguration("class-A", {}) {} + + Future setup() { return setup(this); } + + template + Future run(Args&&... args) { + return waitOrError(TestType::run(tr, localConfiguration, std::forward(args)...), actors.getResult()); + } +}; + +class TestSet { +public: + template + static Future run(WriteTo& writeTo, ReadFrom& readFrom, int64_t expected, bool immediate) { + std::function(Void const&)> check = [&readFrom, expected, immediate](Void const&) { + return readConfigState(&readFrom, expected, immediate); + }; + return addTestSetMutations(writeTo, 1) >>= check; + } +}; + +class TestClear { +public: + template + static Future run(WriteTo& writeTo, ReadFrom& readFrom, bool immediate) { + std::function(Void const&)> clear = [&writeTo](Void const&) { + return addTestClearMutations(writeTo, 2); + }; + std::function(Void const&)> check = [&readFrom, immediate](Void const&) { + return readConfigState(&readFrom, {}, immediate); + }; + return (addTestSetMutations(writeTo, 1) >>= clear) >>= check; + } +}; + +class TestGlobal { +public: + template + static Future run(WriteTo& writeTo, LocalConfiguration const& readFrom, bool immediate) { + std::function(Void const&)> globalWrite = [&writeTo](Void const&) { + return addTestGlobalSetMutation(writeTo, 2); + }; + std::function(Void const&)> check = [&readFrom, immediate](Void const&) { + return readConfigState(&readFrom, 2, immediate); + }; + return (addTestSetMutations(writeTo, 1) >>= globalWrite) >>= check; + } +}; } // namespace -TEST_CASE("/fdbserver/ConfigDB/LocalConfiguration/ManualOverride") { - wait(runLocalConfigEnvironment("class-A", { { "test_long"_sr, "1000"_sr } }, [](auto& conf) { - std::function(Void const&)> check = [&conf](Void const&) { - return readConfigState(&conf, 1000); - }; - return addTestSetMutations(conf, 1) >>= check; - })); - return Void(); -} - -TEST_CASE("/fdbserver/ConfigDB/LocalConfiguration/ConflictingOverride") { - wait(runLocalConfigEnvironment("class-A/class-B", {}, [](auto& conf) { - std::function(Void const&)> check = [&conf](Void const&) { - return readConfigState(&conf, 10); - }; - return addTestSetMutations(conf, 1) >>= check; - })); +TEST_CASE("/fdbserver/ConfigDB/LocalConfiguration/Set") { + state LocalConfigEnvironment environment("class-A", std::map{}); + wait(environment.setup()); + wait(environment.run(1, true)); return Void(); } TEST_CASE("/fdbserver/ConfigDB/LocalConfiguration/Clear") { - wait(runLocalConfigEnvironment("class-A/class-B", {}, [](auto& conf) { - std::function(Void const&)> clear = [&conf](Void const&) { - return addTestClearMutations(conf, 2); - }; - std::function(Void const&)> check = [&conf](Void const&) { - return readConfigState(&conf, 0); - }; - return (addTestSetMutations(conf, 1) >>= clear) >>= check; - })); + state LocalConfigEnvironment environment("class-A", std::map{}); + wait(environment.setup()); + wait(environment.run(true)); + return Void(); +} + +TEST_CASE("/fdbserver/ConfigDB/LocalConfiguration/ManualOverride") { + state LocalConfigEnvironment environment("class-A", std::map{ { "test_long"_sr, "1000"_sr } }); + wait(environment.setup()); + wait(environment.run(1000, true)); + return Void(); +} + +TEST_CASE("/fdbserver/ConfigDB/LocalConfiguration/ConflictingOverride") { + state LocalConfigEnvironment environment("class-A/class-B", std::map{}); + wait(environment.setup()); + wait(environment.run(10, true)); return Void(); } TEST_CASE("/fdbserver/ConfigDB/LocalConfiguration/Global") { - wait(runLocalConfigEnvironment("class-A", {}, [](auto& conf) { - std::function(Void const&)> setGlobal = [&conf](Void const&) { - return addTestGlobalSetMutation(conf, 2); - }; - std::function(Void const&)> check = [&conf](Void const&) { - return readConfigState(&conf, 2); - }; - return (addTestSetMutations(conf, 1) >>= setGlobal) >>= check; - })); + state LocalConfigEnvironment environment("class-A", std::map{}); + wait(environment.setup()); + wait(environment.run(true)); return Void(); } TEST_CASE("/fdbserver/ConfigDB/BroadcasterToLocalConfig/Set") { - wait(runBroadcasterToLocalConfigEnvironment([](auto& broadcaster, auto& confA, auto& confB) { - std::function(Void const&)> check = [&confA, &confB](Void const&) { - return readConfigState(&confA, 1) && readConfigState(&confB, 10); - }; - return addTestSetMutations(broadcaster, 1) >>= check; - })); + state BroadcasterToLocalConfigEnvironment environment; + wait(environment.setup()); + wait(environment.run(1, false)); return Void(); } TEST_CASE("/fdbserver/ConfigDB/BroadcasterToLocalConfig/Clear") { - wait(runBroadcasterToLocalConfigEnvironment([](auto& broadcaster, auto& confA, auto& confB) { - std::function(Void const&)> clear = [&broadcaster](Void const&) { - return addTestClearMutations(broadcaster, 2); - }; - std::function(Void const&)> check = [&confA, &confB](Void const&) { - return readConfigState(&confA, 0) && readConfigState(&confB, 0); - }; - return (addTestSetMutations(broadcaster, 1) >>= clear) >>= check; - })); + state BroadcasterToLocalConfigEnvironment environment; + wait(environment.setup()); + wait(environment.run(false)); + return Void(); +} + +TEST_CASE("/fdbserver/ConfigDB/BroadcasterToLocalConfig/Global") { + state BroadcasterToLocalConfigEnvironment environment; + wait(environment.setup()); + wait(environment.run(false)); return Void(); } TEST_CASE("/fdbserver/ConfigDB/Transaction/Set") { - wait(runTransactionEnvironment([](auto& tr) { - std::function(Void const&)> check = [&tr](Void const&) { return readConfigState(&tr, 1); }; - return addTestSetMutations(tr, 1) >>= check; - })); + state TransactionEnvironment environment; + wait(environment.setup()); + wait(environment.run(1, true)); return Void(); } TEST_CASE("/fdbserver/ConfigDB/Transaction/Clear") { - wait(runTransactionEnvironment([](auto& tr) { - std::function(Void const&)> clear = [&tr](Void const&) { return addTestClearMutations(tr); }; - std::function(Void const&)> check = [&tr](Void const&) { return readConfigState(&tr, {}); }; - return (addTestSetMutations(tr, 1) >>= clear) >>= check; - })); + state TransactionEnvironment environment; + wait(environment.setup()); + wait(environment.run(true)); return Void(); } TEST_CASE("/fdbserver/ConfigDB/TransactionToLocalConfig/Set") { - wait(runTransactionToLocalConfigEnvironment([](auto& tr, auto const& confA, auto const& confB) { - std::function(Void const&)> check = [&confA, &confB](Void const&) { - return readConfigState(&confA, 1) && readConfigState(&confB, 10); - }; - return addTestSetMutations(tr, 1) >>= check; - })); + state TransactionToLocalConfigEnvironment environment; + wait(environment.setup()); + wait(environment.run(1, false)); return Void(); } TEST_CASE("/fdbserver/ConfigDB/TransactionToLocalConfig/Clear") { - wait(runTransactionToLocalConfigEnvironment([](auto& tr, auto const& confA, auto const& confB) { - std::function(Void const&)> clear = [&tr](Void const&) { return addTestClearMutations(tr); }; - std::function(Void const&)> check = [&confA, &confB](Void const&) { - return readConfigState(&confA, 0) && readConfigState(&confB, 0); - }; - return (addTestSetMutations(tr, 1) >>= clear) >>= check; - })); + state TransactionToLocalConfigEnvironment environment; + wait(environment.setup()); + wait(environment.run(false)); return Void(); }