Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4957)

Unified Diff: chrome/browser/policy/remote_commands/remote_commands_browsertest.cc

Issue 879233003: Initial RemoteCommandService (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@remote-commands
Patch Set: fixes addressing #10 #11 and #12 Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/policy/remote_commands/remote_commands_browsertest.cc
diff --git a/chrome/browser/policy/remote_commands/remote_commands_browsertest.cc b/chrome/browser/policy/remote_commands/remote_commands_browsertest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..d44d3a14f8517bffef8b46107f71b0baf6d1f8ba
--- /dev/null
+++ b/chrome/browser/policy/remote_commands/remote_commands_browsertest.cc
@@ -0,0 +1,400 @@
+// 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 <string>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/command_line.h"
+#include "base/logging.h"
bartfab (slow) 2015/02/23 13:13:57 Nit: Not used.
binjin 2015/02/24 05:29:49 Done.
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/run_loop.h"
+#include "base/time/time.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/policy/cloud/test_request_interceptor.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "components/policy/core/browser/browser_policy_connector.h"
+#include "components/policy/core/common/policy_switches.h"
+#include "components/policy/core/common/remote_commands/remote_command_job.h"
+#include "components/policy/core/common/remote_commands/remote_commands_factory.h"
+#include "components/policy/core/common/remote_commands/remote_commands_service.h"
+#include "components/policy/core/common/remote_commands/test_remote_command_job.h"
+#include "components/policy/core/common/remote_commands/testing_remote_commands_server.h"
+#include "content/public/browser/browser_thread.h"
+#include "net/base/net_errors.h"
+#include "net/url_request/url_request_context_getter.h"
+#include "policy/proto/device_management_backend.pb.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.h"
+#include "chrome/browser/chromeos/policy/user_cloud_policy_manager_factory_chromeos.h"
+#else
+#include "chrome/browser/policy/cloud/user_cloud_policy_manager_factory.h"
+#include "components/policy/core/common/cloud/user_cloud_policy_manager.h"
+#endif
+
+using testing::AnyNumber;
+using testing::InvokeWithoutArgs;
+using testing::ReturnNew;
+using testing::_;
+
+namespace policy {
+
+namespace {
+const char kTestToken[] = "secret_token";
+const char kTestClientID[] = "testing_client_id";
+const char kTestPayload[] = "_testing_payload_";
+
+const int kTestCommandExecutionTimeInSeconds = 1;
+} // namespace
+
+namespace em = enterprise_management;
+
+// Mocked RemoteCommand factory to allow us to build test commands.
+class MockTestRemoteCommandFactory : public RemoteCommandsFactory {
+ public:
+ MockTestRemoteCommandFactory() {
+ ON_CALL(*this, BuildTestCommand())
+ .WillByDefault(ReturnNew<TestRemoteCommandJob>(
+ true,
+ base::TimeDelta::FromSeconds(kTestCommandExecutionTimeInSeconds)));
+ }
+ ~MockTestRemoteCommandFactory() override {}
+
+ MOCK_METHOD0(BuildTestCommand, TestRemoteCommandJob*());
+
+ private:
+ // RemoteCommandJobsFactory:
+ scoped_ptr<RemoteCommandJob> BuildJobForType(
+ em::RemoteCommand_Type type) override {
+ if (type != em::RemoteCommand_Type_COMMAND_ECHO_TEST) {
+ ADD_FAILURE();
+ return nullptr;
+ }
+ return make_scoped_ptr<RemoteCommandJob>(BuildTestCommand());
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(MockTestRemoteCommandFactory);
+};
+
+// Mocked TestingRemoteCommandsServer for verifying commands results.
+class MockRemoteCommandsServer : public TestingRemoteCommandsServer {
+ public:
+ MockRemoteCommandsServer() {}
+ ~MockRemoteCommandsServer() override {}
+
+ MOCK_CONST_METHOD2(SucceededJobReported,
+ void(const std::string&, base::Time));
+ MOCK_CONST_METHOD1(FailedJobReported, void(base::Time));
+ MOCK_CONST_METHOD1(IgnoredJobReported, void(base::Time));
+
+ private:
+ // TestingRemoteCommandsServer:
+ void OnJobResultReported(const enterprise_management::RemoteCommandResult&
+ job_result) const override {
+ const base::Time timestamp =
+ base::TimeDelta::FromMilliseconds(job_result.timestamp()) +
+ base::Time::UnixEpoch();
+ switch (job_result.result()) {
+ case em::RemoteCommandResult_ResultType_RESULT_SUCCESS:
+ SucceededJobReported(job_result.payload(), timestamp);
+ break;
+ case em::RemoteCommandResult_ResultType_RESULT_FAILURE:
+ FailedJobReported(timestamp);
+ break;
+ case em::RemoteCommandResult_ResultType_RESULT_IGNORED:
+ IgnoredJobReported(timestamp);
+ break;
+ default:
+ ADD_FAILURE();
+ }
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(MockRemoteCommandsServer);
+};
+
+// Base class for all browser tests regarding remote commands service.
+class RemoteCommandsBrowserTest : public InProcessBrowserTest {
+ protected:
+ RemoteCommandsBrowserTest() {}
+ ~RemoteCommandsBrowserTest() override {}
+
+ // Register on DMServer with faked token and client id.
+ void Register() {
+ ASSERT_TRUE(policy_manager());
+ ASSERT_TRUE(policy_manager()->core()->client());
+
+ EXPECT_FALSE(policy_manager()->core()->client()->is_registered());
+ policy_manager()->core()->client()->SetupRegistration(kTestToken,
+ kTestClientID);
+ EXPECT_TRUE(policy_manager()->core()->client()->is_registered());
+ }
+
+ // Start the service, must be called after Register(). Note that remote
+ // commands service will immediately start fetching commands.
+ void StartService(scoped_ptr<MockTestRemoteCommandFactory> factory) {
+ EXPECT_FALSE(service_started_);
+ service_started_ = true;
+
+ policy_manager()->core()->StartRemoteCommandsService(factory.Pass());
+ }
+
+ // Start the service, but will wait until the initial remote commands
+ // fetch completes (with no command fetched).
+ void StartServiceWithoutCommandsFetched(
+ scoped_ptr<MockTestRemoteCommandFactory> factory) {
+ PrepareRunLoopForNextFetch();
+ ExpectFetchCommands(0u, 0u);
+ StartService(factory.Pass());
+ run_loop_->Run();
+ }
+
+ void ExpectFetchCommands(size_t expected_command_results,
+ size_t expected_fetched_commands) {
+ interceptor_->PushJobCallback(
+ TestRequestInterceptor::FetchRemoteCommandsJob(
+ server_.get(), expected_command_results,
+ expected_fetched_commands));
+ }
+
+ void PrepareRunLoop() {
+ run_loop_.reset(new base::RunLoop);
+ }
+
+ void PrepareRunLoopForNextFetch() {
+ PrepareRunLoop();
+ interceptor_->AddRequestServicedCallback(run_loop_->QuitClosure());
+ }
+
+ void SetUpInProcessBrowserTestFixture() override {
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ command_line->AppendSwitchASCII(switches::kDeviceManagementUrl,
+ "http://localhost");
+ }
+
+ void SetUpOnMainThread() override {
+ // Set up interceptor and ignore 'register' and 'policy' requests.
+ interceptor_.reset(new TestRequestInterceptor(
+ "localhost", content::BrowserThread::GetMessageLoopProxyForThread(
+ content::BrowserThread::IO)));
+ interceptor_->AddIgnoredRequestType("register");
+ interceptor_->AddIgnoredRequestType("policy");
+
+ server_.reset(new MockRemoteCommandsServer());
+
+ BrowserPolicyConnector* const connector =
+ g_browser_process->browser_policy_connector();
+ connector->ScheduleServiceInitialization(0);
+
+ ASSERT_TRUE(policy_manager());
+
+#if !defined(OS_CHROMEOS)
+ policy_manager()->Connect(
+ g_browser_process->local_state(),
+ g_browser_process->system_request_context(),
+ UserCloudPolicyManager::CreateCloudPolicyClient(
+ connector->device_management_service(),
+ g_browser_process->system_request_context()).Pass());
+#endif
+ }
+
+ void TearDownOnMainThread() override {
+ EXPECT_EQ(0u, interceptor_->GetPendingSize());
+ interceptor_.reset();
+ server_.reset();
+ }
+
+#if defined(OS_CHROMEOS)
+ UserCloudPolicyManagerChromeOS* policy_manager() {
+ return UserCloudPolicyManagerFactoryChromeOS::GetForProfile(
+ browser()->profile());
+ }
+#else
+ UserCloudPolicyManager* policy_manager() {
+ return UserCloudPolicyManagerFactory::GetForBrowserContext(
+ browser()->profile());
+ }
+#endif // defined(OS_CHROMEOS)
+
+ RemoteCommandsService* remote_commands_service() {
+ return policy_manager()->core()->remote_commands_service();
+ }
+
+ scoped_ptr<base::RunLoop> run_loop_;
+
+ scoped_ptr<TestRequestInterceptor> interceptor_;
+ scoped_ptr<MockRemoteCommandsServer> server_;
+
+ private:
+ bool service_started_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(RemoteCommandsBrowserTest);
+};
+
+// Tests that no command will be fetched if no commands is issued.
+IN_PROC_BROWSER_TEST_F(RemoteCommandsBrowserTest, NoCommands) {
+ scoped_ptr<MockTestRemoteCommandFactory> factory(
+ new MockTestRemoteCommandFactory());
+ EXPECT_CALL(*factory, BuildTestCommand()).Times(0);
+
+ Register();
+ StartServiceWithoutCommandsFetched(factory.Pass());
+
+ // A follow up fetch requst should also get nothing from server.
+ ExpectFetchCommands(0u, 0u);
+ PrepareRunLoopForNextFetch();
+ EXPECT_TRUE(remote_commands_service()->FetchRemoteCommands());
+ run_loop_->Run();
+}
+
+// Tests that existing commands issued before service started will be fetched.
+IN_PROC_BROWSER_TEST_F(RemoteCommandsBrowserTest, ExistingCommand) {
+ scoped_ptr<MockTestRemoteCommandFactory> factory(
+ new MockTestRemoteCommandFactory());
+ EXPECT_CALL(*factory, BuildTestCommand()).Times(1);
+
+ Register();
+
+ // Issue a command before service started.
+ server_->IssueCommand(em::RemoteCommand_Type_COMMAND_ECHO_TEST, kTestPayload,
+ false);
+
+ // Start the service, run until the command is fetched.
+ ExpectFetchCommands(0u, 1u);
+ PrepareRunLoopForNextFetch();
+ StartService(factory.Pass());
+ run_loop_->Run();
+
+ // And run until the command result is reported.
+ PrepareRunLoop();
+ ExpectFetchCommands(1u, 0u);
+ EXPECT_CALL(*server_, SucceededJobReported(kTestPayload, _))
+ .Times(1)
+ .WillOnce(InvokeWithoutArgs(run_loop_.get(), &base::RunLoop::Quit));
+ run_loop_->Run();
+
+ EXPECT_EQ(0u, server_->NumberOfCommandsPendingResult());
+}
+
+// Tests that commands issued after service started will be fetched.
+IN_PROC_BROWSER_TEST_F(RemoteCommandsBrowserTest, NewCommand) {
+ scoped_ptr<MockTestRemoteCommandFactory> factory(
+ new MockTestRemoteCommandFactory());
+ EXPECT_CALL(*factory, BuildTestCommand()).Times(1);
+
+ Register();
+ StartServiceWithoutCommandsFetched(factory.Pass());
+
+ // The first request will fetch one command, and the second will fetch none
+ // but provide result for the previous command instead.
+ ExpectFetchCommands(0u, 1u);
+ ExpectFetchCommands(1u, 0u);
+
+ PrepareRunLoop();
+ EXPECT_CALL(*server_, SucceededJobReported(kTestPayload, _))
+ .Times(1)
+ .WillOnce(InvokeWithoutArgs(run_loop_.get(), &base::RunLoop::Quit));
+ server_->IssueCommand(em::RemoteCommand_Type_COMMAND_ECHO_TEST, kTestPayload,
+ false);
+
+ // Manually trigger a command fetch immediately, it's supposed to be
+ // triggered by invalidation service though.
+ EXPECT_TRUE(remote_commands_service()->FetchRemoteCommands());
+
+ // Run until the result of commands is reported.
+ run_loop_->Run();
+
+ EXPECT_EQ(0u, server_->NumberOfCommandsPendingResult());
+}
+
+// Tests that commands issued after service will be fetched even if the
+// network is unstable.
+IN_PROC_BROWSER_TEST_F(RemoteCommandsBrowserTest, NewCommandWithBadConnection) {
+ scoped_ptr<MockTestRemoteCommandFactory> factory(
+ new MockTestRemoteCommandFactory());
+ EXPECT_CALL(*factory, BuildTestCommand()).Times(1);
+
+ Register();
+ StartServiceWithoutCommandsFetched(factory.Pass());
+
+ // Inserts some bad request resposne due to network here.
+ interceptor_->PushJobCallback(
+ TestRequestInterceptor::ErrorJob(net::ERR_NETWORK_CHANGED));
+ ExpectFetchCommands(0u, 1u);
+ interceptor_->PushJobCallback(
+ TestRequestInterceptor::ErrorJob(net::ERR_NETWORK_CHANGED));
+ ExpectFetchCommands(1u, 0u);
+
+ PrepareRunLoop();
+ EXPECT_CALL(*server_, SucceededJobReported(kTestPayload, _))
+ .Times(1)
+ .WillOnce(InvokeWithoutArgs(run_loop_.get(), &base::RunLoop::Quit));
+ server_->IssueCommand(em::RemoteCommand_Type_COMMAND_ECHO_TEST, kTestPayload,
+ false);
+
+ EXPECT_TRUE(remote_commands_service()->FetchRemoteCommands());
+
+ // Run until the result of command is reported.
+ run_loop_->Run();
+
+ EXPECT_EQ(0u, server_->NumberOfCommandsPendingResult());
+}
+
+// Tests that commands issued after service started will be fetched, even if
+// the command is issued when a fetch request is ongoing.
+IN_PROC_BROWSER_TEST_F(RemoteCommandsBrowserTest, NewCommandFollwingFetch) {
+ scoped_ptr<MockTestRemoteCommandFactory> factory(
+ new MockTestRemoteCommandFactory());
+ EXPECT_CALL(*factory, BuildTestCommand()).Times(1);
+
+ Register();
+ StartServiceWithoutCommandsFetched(factory.Pass());
+
+ // Add a command which will be issued after first fetch.
+ server_->IssueCommand(em::RemoteCommand_Type_COMMAND_ECHO_TEST, kTestPayload,
+ true);
+
+ PrepareRunLoopForNextFetch();
+ ExpectFetchCommands(0u, 0u);
+
+ // Attempts to fetch commands.
+ EXPECT_TRUE(remote_commands_service()->FetchRemoteCommands());
+
+ // There should be not issued command at this point.
+ EXPECT_EQ(0u, server_->NumberOfCommandsPendingResult());
+
+ // The command fetch should be in progress.
+ EXPECT_TRUE(remote_commands_service()->IsCommandFetchInProgressForTesting());
+
+ // And second a following up fetch request should be enqueued.
+ EXPECT_FALSE(remote_commands_service()->FetchRemoteCommands());
+
+ // Run until first fetch request is completed.
+ run_loop_->Run();
+
+ // The command should be issued now. Note that this command was actually
+ // issued before the first fetch request completes in previous run loop.
+ EXPECT_EQ(1u, server_->NumberOfCommandsPendingResult());
+
+ ExpectFetchCommands(0u, 1u);
+ ExpectFetchCommands(1u, 0u);
+
+ // No further fetch request is made, but the new issued command should be
+ // fetched and executed.
+ PrepareRunLoop();
+ EXPECT_CALL(*server_, SucceededJobReported(kTestPayload, _))
+ .Times(1)
+ .WillOnce(InvokeWithoutArgs(run_loop_.get(), &base::RunLoop::Quit));
bartfab (slow) 2015/02/23 13:13:57 Nit: This EXPECT_CALL() appears in at least four p
binjin 2015/02/24 05:29:49 Code removed, N/A now.
+
+ run_loop_->Run();
+
+ EXPECT_EQ(0u, server_->NumberOfCommandsPendingResult());
+}
+
+} // namespace policy

Powered by Google App Engine
This is Rietveld 408576698