fix for invalid wait stacking in batch mode 39/206639/3
authorRadoslaw Cybulski <r.cybulski@partner.samsung.com>
Wed, 22 May 2019 10:31:40 +0000 (12:31 +0200)
committerRadoslaw Cybulski <r.cybulski@partner.samsung.com>
Thu, 23 May 2019 09:57:21 +0000 (11:57 +0200)
Change-Id: I76f98aeede17f3de4ce13741e6efd93ae74a487a

src/batch/BatchRunner.cpp
src/batch/BatchRunner.hpp
src/batch/EvaluationValue.hpp
src/batch/Evaluator.cpp

index 9706d15..e0c0bf9 100644 (file)
@@ -974,22 +974,21 @@ class PredicateWaitInterface : public EvaluationValueWaitInterface
 {
 public:
        PredicateWaitInterface(BatchExecutor *executor, std::chrono::milliseconds timeout)
-               : self(executor), timeout(std::chrono::high_resolution_clock::now() + timeout)
+               : self(executor), delay(timeout)
        {}
 
        void join() override
        {
-               if (success) return;
-
-               success = predicate();
+               timeout = std::chrono::high_resolution_clock::now() + delay;
+               joinImpl();
        }
 
 protected:
-       virtual bool predicate() = 0;
+       virtual void joinImpl() = 0;
 
        BatchExecutor *self;
        std::chrono::high_resolution_clock::time_point timeout;
-       bool success = false;
+       std::chrono::milliseconds delay;
 };
 
 class WaitDlog : public PredicateWaitInterface
@@ -998,87 +997,100 @@ public:
        WaitDlog(BatchExecutor *executor, std::chrono::milliseconds timeout, std::string pattern)
                : PredicateWaitInterface(executor, timeout)
        {
-               {
-                       auto h = self->dlogInfo.lock();
-                       h->searchLine = std::move(pattern);
-                       h->mode = BatchExecutor::DLogInfo::Mode::search;
-               }
        }
 
 private:
-       bool predicate() override
+       void prepare() override
+       {
+               auto h = self->dlogInfo.lock();
+               h->stack.push_back({ std::move(pattern) });
+               h->stack.back().found = &found;
+       }
+       void joinImpl() override
        {
                auto h = self->dlogInfo.lock();
+               CallOnExit _tmp{
+                       [&]()
+                       {
+                               if (!found) {
+                                       assert(!h->stack.empty());
+                                       assert(h->stack.back().found == &found);
+                                       h->stack.pop_back();
+                               }
+                       }
+               };
                auto res = h.waitForCondition(timeout, [&]() {
-                       return h->mode == BatchExecutor::DLogInfo::Mode::found;
+                       return found;
                });
 
-               h->mode = BatchExecutor::DLogInfo::Mode::ignore;
                if (!res)
                        throw EvaluationFailure{} << "wait for dlog ('" << pattern << "'): operation timeouted";
-
-               return res;
        }
 
        std::string pattern;
+       bool found = false;
 };
 
 class WaitTTS : public PredicateWaitInterface
 {
 public:
        WaitTTS(BatchExecutor *executor, std::chrono::milliseconds timeout, std::string pattern, bool exact)
-               : PredicateWaitInterface(executor, timeout)
+               : PredicateWaitInterface(executor, timeout), exact(exact)
        {
                this->pattern = pattern;
-               {
-                       auto h = self->ttsInfo.lock();
-                       if (!pattern.empty())
-                               h->searchLine = std::move(pattern);
-                       else
-                               h->searchLine = {};
-                       h->exact = exact;
-                       h->mode = BatchExecutor::TTSInfo::Mode::search;
-               }
        }
 
 private:
-       bool predicate() override
+       void prepare() override
        {
                auto h = self->ttsInfo.lock();
+               h->stack.push_back({});
+               auto &w = h->stack.back();
+               if (!pattern.empty())
+                       w.searchLine = pattern;
+               w.exact = exact;
+               w.found = &found;
+       }
+       void joinImpl() override
+       {
+               auto h = self->ttsInfo.lock();
+               CallOnExit _tmp{
+                       [&]()
+                       {
+                               if (!found) {
+                                       assert(!h->stack.empty());
+                                       assert(h->stack.back().found == &found);
+                                       h->stack.pop_back();
+                               }
+                       }
+               };
                auto res = h.waitForCondition(timeout, [&]() {
-                       return h->mode == BatchExecutor::TTSInfo::Mode::found;
+                       return found;
                });
 
-               h->mode = BatchExecutor::TTSInfo::Mode::ignore;
                if (!res)
                        throw EvaluationFailure{} << "wait for tts ('" << pattern << "'): operation timeouted";
-
-               return res;
        }
 
        std::string pattern;
+       bool exact = false, found = false;
 };
 
 class WaitGui : public PredicateWaitInterface
 {
 public:
        WaitGui(BatchExecutor *executor, std::chrono::milliseconds timeout, std::string name)
-               : PredicateWaitInterface(executor, timeout)
+               : PredicateWaitInterface(executor, timeout), name(std::move(name))
        {
-               {
-                       auto h = self->contextInfo.lock();
-                       this->currentContextName = h->rootName;
-               }
-               if (name.empty()) {
-                       this->name = this->currentContextName;
-                       searchForAnyChange = true;
-               } else {
-                       this->name = std::move(name);
-               }
+               searchForAnyChange = this->name.empty();
        }
-
 private:
-       bool predicate() override
+       void prepare() override
+       {
+               auto h = self->contextInfo.lock();
+               currentContextName = h->rootName;
+       }
+       void joinImpl() override
        {
                auto h = self->contextInfo.lock();
                auto pred = [&]() {
@@ -1088,7 +1100,6 @@ private:
                        }
                        return (searchForAnyChange && name != h->rootName) || (!searchForAnyChange && name == h->rootName);
                };
-               if (pred()) return true;
                auto res = h.waitForCondition(timeout, pred);
                if (!res) {
                        if (searchForAnyChange)
@@ -1096,8 +1107,6 @@ private:
                        throw EvaluationFailure{} << "wait for gui ('" << name << "'): operation timeouted, " <<
                                                                          "current root name is '" << h->rootName << "'";
                }
-
-               return res;
        }
 
        std::string name, currentContextName;
@@ -1409,9 +1418,10 @@ static void threadFunc(StatPtr result, std::unique_ptr<BatchExecutor> exec, std:
        if (hasContext) {
                auto ttsDlogHandler = dlog.registerCallback([&exec](const std::string & txt) {
                        auto h = exec->ttsInfo.lock();
-                       if (h->mode == BatchExecutor::TTSInfo::Mode::search) {
-                               if (!h->searchLine) {
-                                       h->mode = BatchExecutor::TTSInfo::Mode::found;
+                       if (!h->stack.empty()) {
+                               auto &w = h->stack.back();
+                               if (!w.searchLine) {
+                                       *w.found = true;
                                } else {
                                        if (txt.find("(tts_speak_customized)") != std::string::npos) {
                                                static const auto prefix = std::string{ "TTS reading text '" };
@@ -1424,20 +1434,24 @@ static void threadFunc(StatPtr result, std::unique_ptr<BatchExecutor> exec, std:
                                                        if (z2 != std::string::npos && z2 > z) {
                                                                auto sub = txt.substr(z, z2 - z);
                                                                exec->outputStream() << "TTS: '" << sub << "'\n";
-                                                               if ((h->exact && sub == *h->searchLine) || (!h->exact && sub.find(*h->searchLine) != std::string::npos)) {
-                                                                       h->mode = BatchExecutor::TTSInfo::Mode::found;
+                                                               if ((w.exact && sub == *w.searchLine) || (!w.exact && sub.find(*w.searchLine) != std::string::npos)) {
+                                                                       *w.found = true;
                                                                }
                                                        }
                                                }
                                        }
                                }
+                               if (*w.found)
+                                       h->stack.pop_back();
                        }
                });
                auto dlogHandler = dlog.registerCallback([&exec](const std::string & txt) {
                        auto h = exec->dlogInfo.lock();
-                       if (h->mode == BatchExecutor::DLogInfo::Mode::search) {
-                               if (txt.find(h->searchLine) != std::string::npos) {
-                                       h->mode = BatchExecutor::DLogInfo::Mode::found;
+                       if (!h->stack.empty()) {
+                               auto &w = h->stack.back();
+                               if (txt.find(w.searchLine) != std::string::npos) {
+                                       *w.found = true;
+                                       h->stack.pop_back();
                                }
                        }
                });
index 43108a9..bd1c968 100644 (file)
@@ -69,15 +69,19 @@ public:
                std::string rootName;
        };
        struct TTSInfo {
-               Optional<std::string> searchLine;
-               bool exact = false;
-               enum class Mode { ignore, search, found };
-               Mode mode = Mode::ignore;
+               struct Entry {
+                       Optional<std::string> searchLine;
+                       bool *found = nullptr;
+                       bool exact = false;
+               };
+               std::vector<Entry> stack;
        };
        struct DLogInfo {
-               std::string searchLine;
-               enum class Mode { ignore, search, found };
-               Mode mode = Mode::ignore;
+               struct Entry {
+                       std::string searchLine;
+                       bool *found = nullptr;
+               };
+               std::vector<Entry> stack;
        };
 
        // NOTE: constructor of TestExecutor must be called on main thread
index e4bfcb9..70e8c2e 100644 (file)
 #include <algorithm>
 #include <limits>
 
+struct CallOnExit {
+       std::function<void()> func;
+
+       CallOnExit() = delete;
+       CallOnExit(std::function<void()> func) : func(std::move(func)) { }
+       CallOnExit(const CallOnExit &) = delete;
+       CallOnExit(CallOnExit &&) = delete;
+
+       CallOnExit &operator = (const CallOnExit &) = delete;
+       CallOnExit &operator = (CallOnExit &&) = delete;
+
+       ~CallOnExit()
+       {
+               if (func)
+                       func();
+       }
+};
+
 class EvaluationFailure : public std::exception
 {
 public:
@@ -107,6 +125,7 @@ struct EvaluationValueIteratorInterface {
 class EvaluationValueWaitInterface
 {
 public:
+       virtual void prepare() = 0;
        virtual void join() = 0;
 
 protected:
index 2d5836d..f9b6beb 100644 (file)
@@ -97,14 +97,6 @@ void DebugEvaluatorInterface::setCurrentInterface(std::unique_ptr<DebugEvaluator
 
 template <typename F> static auto evaluateHelper(std::string debugId, TokenLocation loc, F &&f)
 {
-       struct CallOnExit {
-               std::function<void()> func;
-               CallOnExit(std::function<void()> func) : func(std::move(func)) { }
-               ~CallOnExit()
-               {
-                       func();
-               }
-       };
        EvaluationDepthCountManager countManager;
        std::string indent(static_cast<size_t>(evaluationDepth * 2), ' ');
        try {
@@ -340,8 +332,15 @@ OperatorEvaluator::OperatorEvaluator(TokenLocation tokenLocation, ExprPtrs args,
 EvaluationValue OperatorEvaluator::evaluateImpl() const
 {
        std::vector<EvaluationValue> vals;
-       for (auto &a : args)
-               vals.push_back(a->evaluate());
+       if (kind == Kind::LOG_AND) {
+               vals.push_back(args[0]->evaluate());
+               vals.push_back(vals[0] ? args[1]->evaluate() : EvaluationValue{});
+       } else if (kind == Kind::LOG_OR) {
+               vals.push_back(!vals[0] ? args[1]->evaluate() : EvaluationValue{});
+       } else {
+               for (auto &a : args)
+                       vals.push_back(a->evaluate());
+       }
 
        switch (kind) {
        case Kind::IN:
@@ -719,6 +718,9 @@ void WaitEvaluator::evaluateImpl() const
                auto r = w->evaluate();
                waitsValues.push_back(r.convertToWait());
        }
+       for (auto it = waitsValues.rbegin(); it != waitsValues.rend(); ++it)
+               it->asWait()->prepare();
+
        DebugEvaluator{} << getDebugId() << ": executing main block of wait clause";
        exec->evaluate();
        DebugEvaluator{} << getDebugId() << ": joining waiters (" << waits.size() << ")";