// Copyright 2015 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "remoting/test/app_remoting_latency_test_fixture.h" #include #include "base/logging.h" #include "base/run_loop.h" #include "base/thread_task_runner_handle.h" #include "base/timer/timer.h" #include "remoting/proto/event.pb.h" #include "remoting/protocol/input_stub.h" #include "remoting/test/app_remoting_connection_helper.h" #include "remoting/test/app_remoting_test_driver_environment.h" #include "remoting/test/rgb_value.h" #include "remoting/test/test_chromoting_client.h" #include "remoting/test/test_video_renderer.h" namespace remoting { namespace test { AppRemotingLatencyTestFixture::AppRemotingLatencyTestFixture() : timer_(new base::Timer(true, false)) { // NOTE: Derived fixture must initialize application details in constructor. } AppRemotingLatencyTestFixture::~AppRemotingLatencyTestFixture() {} void AppRemotingLatencyTestFixture::SetUp() { scoped_ptr test_video_renderer(new TestVideoRenderer()); test_video_renderer_ = test_video_renderer->GetWeakPtr(); scoped_ptr test_chromoting_client( new TestChromotingClient(std::move(test_video_renderer))); test_chromoting_client->AddRemoteConnectionObserver(this); connection_helper_.reset( new AppRemotingConnectionHelper(GetApplicationDetails())); connection_helper_->Initialize(std::move(test_chromoting_client)); if (!connection_helper_->StartConnection()) { LOG(ERROR) << "Remote host connection could not be established."; FAIL(); } if (!PrepareApplicationForTesting()) { LOG(ERROR) << "Unable to prepare application for testing."; FAIL(); } } void AppRemotingLatencyTestFixture::TearDown() { // Only reset application state when remote host connection is established. if (connection_helper_->ConnectionIsReadyForTest()) { ResetApplicationState(); } connection_helper_->test_chromoting_client()->RemoveRemoteConnectionObserver( this); connection_helper_.reset(); } WaitForImagePatternMatchCallback AppRemotingLatencyTestFixture::SetExpectedImagePattern( const webrtc::DesktopRect& expected_rect, const RGBValue& expected_color) { scoped_ptr run_loop(new base::RunLoop()); test_video_renderer_->ExpectAverageColorInRect(expected_rect, expected_color, run_loop->QuitClosure()); return base::Bind(&AppRemotingLatencyTestFixture::WaitForImagePatternMatch, base::Unretained(this), base::Passed(&run_loop)); } void AppRemotingLatencyTestFixture::SaveFrameDataToDisk( bool save_frame_data_to_disk) { test_video_renderer_->SaveFrameDataToDisk(save_frame_data_to_disk); } bool AppRemotingLatencyTestFixture::WaitForImagePatternMatch( scoped_ptr run_loop, const base::TimeDelta& max_wait_time) { DCHECK(run_loop); DCHECK(!timer_->IsRunning()); timer_->Start(FROM_HERE, max_wait_time, run_loop->QuitClosure()); run_loop->Run(); // Image pattern is matched if we stopped because of the reply not the timer. bool image_pattern_is_matched = (timer_->IsRunning()); timer_->Stop(); run_loop.reset(); return image_pattern_is_matched; } void AppRemotingLatencyTestFixture::HostMessageReceived( const protocol::ExtensionMessage& message) { if (!host_message_received_callback_.is_null()) { host_message_received_callback_.Run(message); } } void AppRemotingLatencyTestFixture::PressKey(ui::DomCode dom_code, bool pressed) { remoting::protocol::KeyEvent event; event.set_usb_keycode(static_cast(dom_code)); event.set_pressed(pressed); connection_helper_->input_stub()->InjectKeyEvent(event); } void AppRemotingLatencyTestFixture::PressAndReleaseKey(ui::DomCode dom_code) { PressKey(dom_code, true); PressKey(dom_code, false); } void AppRemotingLatencyTestFixture::PressAndReleaseKeyCombination( const std::vector& dom_codes) { for (auto iter = dom_codes.begin(); iter != dom_codes.end(); ++iter) { PressKey(*iter, true); } for (auto iter = dom_codes.rbegin(); iter != dom_codes.rend(); ++iter) { PressKey(*iter, false); } } void AppRemotingLatencyTestFixture::SetHostMessageReceivedCallback( const HostMessageReceivedCallback& host_message_received_callback) { host_message_received_callback_ = host_message_received_callback; } void AppRemotingLatencyTestFixture::ResetHostMessageReceivedCallback() { host_message_received_callback_.Reset(); } void AppRemotingLatencyTestFixture::ResetApplicationState() { DCHECK(!timer_->IsRunning()); DCHECK(!run_loop_ || !run_loop_->running()); // Give the app some time to settle before reseting to initial state. run_loop_.reset(new base::RunLoop()); base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE, run_loop_->QuitClosure(), base::TimeDelta::FromSeconds(1)); run_loop_->Run(); // Press Alt + F4 and wait for amount of time for the input to be delivered // and processed. std::vector dom_codes; dom_codes.push_back(ui::DomCode::ALT_LEFT); dom_codes.push_back(ui::DomCode::F4); PressAndReleaseKeyCombination(dom_codes); run_loop_.reset(new base::RunLoop()); base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE, run_loop_->QuitClosure(), base::TimeDelta::FromSeconds(2)); run_loop_->Run(); // Press 'N' to choose not save and wait for 1 second for the input to be // delivered and processed. PressAndReleaseKey(ui::DomCode::US_N); run_loop_.reset(new base::RunLoop()); base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE, run_loop_->QuitClosure(), base::TimeDelta::FromSeconds(2)); run_loop_->Run(); run_loop_.reset(); } } // namespace test } // namespace remoting