Commit b4f505bc authored by Jeroen Dhollander's avatar Jeroen Dhollander Committed by Commit Bot

Detect out-of-order Assistant responses

This will help us detect failures caused by LibAssistant sending the
|OnInteractionFinished| event before all the responses (like
|OnOpenAndroidApp|) are received.

This will help us detect if the current test failures are caused by
this, or if there is some other cause we need to find.

The failure looks as follows (newlines added for commit message only):

assistant.OpenAndroidApp  [ FAIL ]
  Failed to send the Assistant text query:
  Error: OnOpenAppResponse was called after the interaction was closed


Bug: b/157144814
Change-Id: I22b29f1d7bcdebd3844cf996ffe1fbfece42754d
Tests: Tast tests with pattern "*ssistant*"
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2211049
Commit-Queue: Jeroen Dhollander <jeroendh@google.com>
Reviewed-by: default avatarTao Wu <wutao@chromium.org>
Reviewed-by: default avatarXiaohui Chen <xiaohuic@chromium.org>
Reviewed-by: default avatarAchuith Bhandarkar <achuith@chromium.org>
Cr-Commit-Position: refs/heads/master@{#771150}
parent 6a5c116f
...@@ -720,6 +720,13 @@ DisplaySmoothnessTrackers* GetDisplaySmoothnessTrackers() { ...@@ -720,6 +720,13 @@ DisplaySmoothnessTrackers* GetDisplaySmoothnessTrackers() {
return trackers.get(); return trackers.get();
} }
std::string ResolutionToString(
chromeos::assistant::mojom::AssistantInteractionResolution resolution) {
std::stringstream result;
result << resolution;
return result.str();
}
} // namespace } // namespace
class WindowStateChangeObserver : public aura::WindowObserver { class WindowStateChangeObserver : public aura::WindowObserver {
...@@ -2446,7 +2453,8 @@ void AutotestPrivateEnableAssistantAndWaitForReadyFunction:: ...@@ -2446,7 +2453,8 @@ void AutotestPrivateEnableAssistantAndWaitForReadyFunction::
class AssistantInteractionHelper class AssistantInteractionHelper
: public chromeos::assistant::DefaultAssistantInteractionSubscriber { : public chromeos::assistant::DefaultAssistantInteractionSubscriber {
public: public:
using OnInteractionFinishedCallback = base::OnceCallback<void(bool)>; using OnInteractionFinishedCallback =
base::OnceCallback<void(const base::Optional<std::string>& error)>;
AssistantInteractionHelper() AssistantInteractionHelper()
: query_status_(std::make_unique<base::DictionaryValue>()) {} : query_status_(std::make_unique<base::DictionaryValue>()) {}
...@@ -2492,10 +2500,13 @@ class AssistantInteractionHelper ...@@ -2492,10 +2500,13 @@ class AssistantInteractionHelper
chromeos::assistant::mojom::AssistantInteractionType::kVoice == chromeos::assistant::mojom::AssistantInteractionType::kVoice ==
metadata->type; metadata->type;
query_status_->SetKey("isMicOpen", base::Value(is_voice_interaction)); query_status_->SetKey("isMicOpen", base::Value(is_voice_interaction));
interaction_in_progress_ = true;
} }
void OnInteractionFinished( void OnInteractionFinished(
AssistantInteractionResolution resolution) override { AssistantInteractionResolution resolution) override {
interaction_in_progress_ = false;
// Only invoke the callback when |result_| is not empty to avoid an early // Only invoke the callback when |result_| is not empty to avoid an early
// return before the entire session is completed. This happens when // return before the entire session is completed. This happens when
// sending queries to modify device settings, e.g. "turn on bluetooth", // sending queries to modify device settings, e.g. "turn on bluetooth",
...@@ -2508,10 +2519,12 @@ class AssistantInteractionHelper ...@@ -2508,10 +2519,12 @@ class AssistantInteractionHelper
query_status_->SetKey("queryResponse", std::move(result_)); query_status_->SetKey("queryResponse", std::move(result_));
if (on_interaction_finished_callback_) { if (on_interaction_finished_callback_) {
const bool success = if (resolution == AssistantInteractionResolution::kNormal) {
(resolution == AssistantInteractionResolution::kNormal) ? true SendSuccessResponse();
: false; } else {
std::move(on_interaction_finished_callback_).Run(success); SendErrorResponse("Interaction closed with resolution " +
ResolutionToString(resolution));
}
} }
} }
...@@ -2519,10 +2532,12 @@ class AssistantInteractionHelper ...@@ -2519,10 +2532,12 @@ class AssistantInteractionHelper
const std::string& fallback) override { const std::string& fallback) override {
result_.SetKey("htmlResponse", base::Value(response)); result_.SetKey("htmlResponse", base::Value(response));
result_.SetKey("htmlFallback", base::Value(fallback)); result_.SetKey("htmlFallback", base::Value(fallback));
CheckResponseIsValid(__FUNCTION__);
} }
void OnTextResponse(const std::string& response) override { void OnTextResponse(const std::string& response) override {
result_.SetKey("text", base::Value(response)); result_.SetKey("text", base::Value(response));
CheckResponseIsValid(__FUNCTION__);
} }
void OnSpeechRecognitionFinalResult( void OnSpeechRecognitionFinalResult(
...@@ -2534,11 +2549,30 @@ class AssistantInteractionHelper ...@@ -2534,11 +2549,30 @@ class AssistantInteractionHelper
OnOpenAppResponseCallback callback) override { OnOpenAppResponseCallback callback) override {
result_.SetKey("openAppResponse", base::Value(app_info->package_name)); result_.SetKey("openAppResponse", base::Value(app_info->package_name));
std::move(callback).Run(true); std::move(callback).Run(true);
CheckResponseIsValid(__FUNCTION__);
}
void CheckResponseIsValid(const std::string& function_name) {
if (!interaction_in_progress_) {
// We should only get a response while the interaction is open
// (started and not finished).
SendErrorResponse(function_name +
" was called after the interaction was closed");
}
}
void SendSuccessResponse() {
std::move(on_interaction_finished_callback_).Run(base::nullopt);
}
void SendErrorResponse(const std::string& error) {
std::move(on_interaction_finished_callback_).Run(error);
} }
mojo::Remote<chromeos::assistant::mojom::Assistant> assistant_; mojo::Remote<chromeos::assistant::mojom::Assistant> assistant_;
std::unique_ptr<base::DictionaryValue> query_status_; std::unique_ptr<base::DictionaryValue> query_status_;
base::DictionaryValue result_; base::DictionaryValue result_;
bool interaction_in_progress_ = false;
// Callback triggered when interaction finished with non-empty response. // Callback triggered when interaction finished with non-empty response.
OnInteractionFinishedCallback on_interaction_finished_callback_; OnInteractionFinishedCallback on_interaction_finished_callback_;
...@@ -2593,16 +2627,14 @@ AutotestPrivateSendAssistantTextQueryFunction::Run() { ...@@ -2593,16 +2627,14 @@ AutotestPrivateSendAssistantTextQueryFunction::Run() {
} }
void AutotestPrivateSendAssistantTextQueryFunction:: void AutotestPrivateSendAssistantTextQueryFunction::
OnInteractionFinishedCallback(bool success) { OnInteractionFinishedCallback(const base::Optional<std::string>& error) {
if (error)
Respond(Error(error.value()));
else
Respond(OneArgument(interaction_helper_->GetQueryStatus()));
// |timeout_timer_| need to be hold until |Respond(.)| is called to avoid // |timeout_timer_| need to be hold until |Respond(.)| is called to avoid
// |this| being destructed. // |this| being destructed.
if (!success) {
Respond(Error("Interaction ends abnormally."));
timeout_timer_.AbandonAndStop();
return;
}
Respond(OneArgument(interaction_helper_->GetQueryStatus()));
timeout_timer_.AbandonAndStop(); timeout_timer_.AbandonAndStop();
} }
...@@ -2651,16 +2683,14 @@ AutotestPrivateWaitForAssistantQueryStatusFunction::Run() { ...@@ -2651,16 +2683,14 @@ AutotestPrivateWaitForAssistantQueryStatusFunction::Run() {
} }
void AutotestPrivateWaitForAssistantQueryStatusFunction:: void AutotestPrivateWaitForAssistantQueryStatusFunction::
OnInteractionFinishedCallback(bool success) { OnInteractionFinishedCallback(const base::Optional<std::string>& error) {
if (error)
Respond(Error(error.value()));
else
Respond(OneArgument(interaction_helper_->GetQueryStatus()));
// |timeout_timer_| need to be hold until |Respond(.)| is called to avoid // |timeout_timer_| need to be hold until |Respond(.)| is called to avoid
// |this| being destructed. // |this| being destructed.
if (!success) {
Respond(Error("Interaction ends abnormally."));
timeout_timer_.AbandonAndStop();
return;
}
Respond(OneArgument(interaction_helper_->GetQueryStatus()));
timeout_timer_.AbandonAndStop(); timeout_timer_.AbandonAndStop();
} }
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "ash/public/cpp/window_state_type.h" #include "ash/public/cpp/window_state_type.h"
#include "ash/rotator/screen_rotation_animator_observer.h" #include "ash/rotator/screen_rotation_animator_observer.h"
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/optional.h"
#include "base/scoped_observer.h" #include "base/scoped_observer.h"
#include "base/timer/timer.h" #include "base/timer/timer.h"
#include "chrome/browser/chromeos/printing/cups_printers_manager.h" #include "chrome/browser/chromeos/printing/cups_printers_manager.h"
...@@ -618,7 +619,7 @@ class AutotestPrivateSendAssistantTextQueryFunction : public ExtensionFunction { ...@@ -618,7 +619,7 @@ class AutotestPrivateSendAssistantTextQueryFunction : public ExtensionFunction {
ResponseAction Run() override; ResponseAction Run() override;
// Called when the interaction finished with non-empty response. // Called when the interaction finished with non-empty response.
void OnInteractionFinishedCallback(bool success); void OnInteractionFinishedCallback(const base::Optional<std::string>& error);
// Called when Assistant service fails to respond in a certain amount of // Called when Assistant service fails to respond in a certain amount of
// time. We will respond with an error. // time. We will respond with an error.
...@@ -642,7 +643,7 @@ class AutotestPrivateWaitForAssistantQueryStatusFunction ...@@ -642,7 +643,7 @@ class AutotestPrivateWaitForAssistantQueryStatusFunction
ResponseAction Run() override; ResponseAction Run() override;
// Called when the current interaction finished with non-empty response. // Called when the current interaction finished with non-empty response.
void OnInteractionFinishedCallback(bool success); void OnInteractionFinishedCallback(const base::Optional<std::string>& error);
// Called when Assistant service fails to respond in a certain amount of // Called when Assistant service fails to respond in a certain amount of
// time. We will respond with an error. // time. We will respond with an error.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment