From fb81751b9128ba5e3fa78a06def0c0d4cb9c2aba Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 12 Aug 2017 19:32:57 +0200 Subject: [PATCH] DiffMessage: draft multithreaded integration test of diff application (#1066) ...because it seems adequate really to cover the whole invocation pattern in a laboratory setup, including the twist to pass thread boundraries. --- tests/gui/bus-term-test.cpp | 144 +++++++++++++++++++++++++++++++++++- 1 file changed, 143 insertions(+), 1 deletion(-) diff --git a/tests/gui/bus-term-test.cpp b/tests/gui/bus-term-test.cpp index 49b209875..269755d14 100644 --- a/tests/gui/bus-term-test.cpp +++ b/tests/gui/bus-term-test.cpp @@ -27,6 +27,8 @@ #include "lib/test/run.hpp" #include "lib/test/test-helper.hpp" +#include "lib/sync.hpp" +#include "backend/thread-wrapper.hpp" #include "gui/ctrl/bus-term.hpp" #include "gui/ctrl/state-manager.hpp" #include "proc/control/command.hpp" @@ -34,6 +36,8 @@ #include "test/mock-elm.hpp" #include "lib/idi/entry-id.hpp" #include "lib/diff/gen-node.hpp" +#include "lib/iter-adapter-stl.hpp" +#include "lib/iter-stack.hpp" #include "lib/format-cout.hpp" #include "lib/time/timevalue.hpp" #include "lib/luid.h" @@ -41,6 +45,8 @@ +using lib::Sync; +using backend::ThreadJoinable; using lib::idi::EntryID; using lib::idi::BareEntryID; using gui::ctrl::StateManager; @@ -49,9 +55,13 @@ using gui::test::MockElm; using lib::diff::GenNode; using lib::diff::Rec; using lib::diff::Ref; +using lib::diff::DiffSource; +using lib::diff::DiffMessage; using lib::time::Time; using lib::time::TimeSpan; using lib::hash::LuidH; +using lib::iter_stl::snapshot; +using lib::IterStack; using lib::HashVal; using util::isnil; @@ -65,6 +75,15 @@ namespace test { using proc::control::Command; + namespace {// test data... + + // --------random-dispatch-test------ + uint const MAX_RAND_NUMBS = 200; + uint const MAX_RAND_BORGS = 500; + uint const MAX_RAND_DELAY = 1000; + // --------random-dispatch-test------ + } + @@ -501,10 +520,133 @@ namespace test { } + /** @test integration test of mutation by diff message + * Since this test focuses on the bus side of standard interactions, + * it seems indicated to emulate the complete invocation situation, + * which involves passing thread boundraries. The main thread running + * this test shall enact the role of the UI event thread (since the + * UI-Bus in the real application is confined to this UI thread). + * Thus we'll start another thread to enact the role of the Session, + * to produce a diff message and "cast" it towards the UI. + * @note a defining property of this whole interaction is the fact that + * the diff is _pulled asynchronously,_ which means the actual diff + * generation happens on callback from the UI. Access to any "session" + * data needs to be protected by lock in such a situation. + */ void pushDiff() { - UNIMPLEMENTED ("push a mutation diff towards an interface element"); + MARK_TEST_FUN + + struct SessionThread + : Sync<> + , ThreadJoinable + { + // shared data + IterStack sessionBorgs_; + + // access to shared session data + void + scheduleBorg (uint id) + { + Lock sync(this); + sessionBorgs_.feed(id); + } + + auto + dispatchBorgs() + { + Lock sync(this); + return snapshot(sessionBorgs_); + } + + /** + * Independent heap allocated diff generator. + * Implements the IterSource interface + * and will be pulled from the GUI-Thread for actually + * generating the diff. At this point, it needs to access + * the shared session data with proper locking, and derive + * a representation of the "changes" in diff format + */ + struct DiffGenerator + : boost::noncopyable + , DiffSource + { + using Iter = decltype(SessionThread::dispatchBorgs()); + using Pos = typename Iter::pointer; + + + SessionThread ctx_; + Iter src_; + + DiffGenerator (SessionThread& motherShip) + : ctx_{motherShip} + , src_{} + { } + + /* == Interface IterSource == */ + Pos + firstResult () + { + REQUIRE (not src_); + src_ = ctx_.dispatchBorgs(); + return & *src_; + } + + void + nextResult (Pos& pos) + { + if (!pos) return; + if (src_) ++src_; + if (src_) + pos = & *src_; + else + pos = 0; + } + }; + + + using UiBus = gui::ctrl::Nexus; + + /** + * The final part in the puzzle is to dispatch the diff messages into the UI + * In the real application, this operation is provided by the NotificationService. + * It has access to the UI-Bus, but has to ensure all bus operations are actually + * performed on the UI event thread. + */ + void + notifyGUI (UiBus& uiBus, DiffSource* diffGenerator) + { + ///TODO create diff message + ///TODO use a CallQueue + ///TODO dispatch application of the diff message via UiBus + } + + SessionThread(UiBus& uiBus) + : ThreadJoinable{"BusTerm_test: asynchronous diff mutation" + , [&, uiBus]() { + uint cnt = rand() % MAX_RAND_BORGS; + for (uint i=0; i