File: incoming_native_messaging_apitest.cc

package info (click to toggle)
chromium 138.0.7204.183-1~deb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm-proposed-updates
  • size: 6,080,960 kB
  • sloc: cpp: 34,937,079; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,954; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,811; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (134 lines) | stat: -rw-r--r-- 5,158 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <memory>
#include <string>
#include <utility>

#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/run_loop.h"
#include "base/task/single_thread_task_runner.h"
#include "base/unguessable_token.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/profiles/profile.h"
#include "content/public/browser/child_process_host.h"
#include "content/public/test/browser_test.h"
#include "extensions/browser/api/messaging/channel_endpoint.h"
#include "extensions/browser/api/messaging/message_service.h"
#include "extensions/browser/api/messaging/native_message_host.h"
#include "extensions/browser/api/messaging/native_message_port.h"
#include "extensions/common/api/messaging/messaging_endpoint.h"
#include "extensions/common/api/messaging/port_id.h"
#include "extensions/common/mojom/message_port.mojom-shared.h"
#include "extensions/test/result_catcher.h"
#include "ipc/ipc_message.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"

using testing::_;
using testing::InvokeWithoutArgs;
using testing::Mock;
using testing::SaveArg;
using testing::StrictMock;

namespace {

const char kFakeNativeAppName[] = "com.google.chrome.test.initiator";

class MockNativeMessageHost : public extensions::NativeMessageHost {
 public:
  MOCK_METHOD1(OnMessage, void(const std::string& message));
  MOCK_METHOD1(Start, void(Client* client));

  scoped_refptr<base::SingleThreadTaskRunner> task_runner() const override {
    return task_runner_;
  }

 private:
  scoped_refptr<base::SingleThreadTaskRunner> task_runner_ =
      base::SingleThreadTaskRunner::GetCurrentDefault();
};

// Test fixture for testing native messaging API when the communication is
// initiated by the native application.
class ExtensionIncomingNativeMessagingTest
    : public extensions::ExtensionApiTest {
 public:
  ExtensionIncomingNativeMessagingTest(
      const ExtensionIncomingNativeMessagingTest&) = delete;
  ExtensionIncomingNativeMessagingTest& operator=(
      const ExtensionIncomingNativeMessagingTest&) = delete;

 protected:
  ExtensionIncomingNativeMessagingTest() = default;
  ~ExtensionIncomingNativeMessagingTest() override = default;

  bool LoadTestExtension() {
    extension_ =
        LoadExtension(test_data_dir_.AppendASCII("incoming_native_messaging"));
    return extension_ != nullptr;
  }

  void OpenMessageChannelToExtension(
      std::unique_ptr<extensions::NativeMessageHost> native_message_host) {
    auto* const message_service = extensions::MessageService::Get(profile());
    const extensions::PortId port_id(
        base::UnguessableToken::Create(), 1 /* port_number */,
        true /* is_opener */, extensions::mojom::SerializationFormat::kJson);
    auto native_message_port = std::make_unique<extensions::NativeMessagePort>(
        message_service->GetChannelDelegate(), port_id,
        std::move(native_message_host));
    message_service->OpenChannelToExtension(
        extensions::ChannelEndpoint(profile()), port_id,
        extensions::MessagingEndpoint::ForNativeApp(kFakeNativeAppName),
        std::move(native_message_port), extension_->id(), GURL(),
        extensions::mojom::ChannelType::kNative,
        std::string() /* channel_name */);
  }

 private:
  raw_ptr<const extensions::Extension, DanglingUntriaged> extension_ = nullptr;
};

// Tests that the extension receives the onConnectNative event when the native
// application opens a message channel to it, and that each of them can
// successfully send a message.
IN_PROC_BROWSER_TEST_F(ExtensionIncomingNativeMessagingTest,
                       SingleRequestResponse) {
  extensions::ResultCatcher catcher;

  ASSERT_TRUE(LoadTestExtension());

  auto owned_native_message_host =
      std::make_unique<StrictMock<MockNativeMessageHost>>();
  auto* const native_message_host = owned_native_message_host.get();

  extensions::NativeMessageHost::Client* native_message_host_client = nullptr;
  EXPECT_CALL(*native_message_host, Start(_))
      .WillOnce(SaveArg<0>(&native_message_host_client));

  const char kExpectedMessageFromExtension[] = R"({"request":"foo"})";
  base::RunLoop message_awaiting_run_loop;
  EXPECT_CALL(*native_message_host, OnMessage(kExpectedMessageFromExtension))
      .WillOnce(
          InvokeWithoutArgs(&message_awaiting_run_loop, &base::RunLoop::Quit));

  OpenMessageChannelToExtension(std::move(owned_native_message_host));

  // Wait until the extension sends a message to the native application.
  message_awaiting_run_loop.Run();
  Mock::VerifyAndClearExpectations(native_message_host);
  ASSERT_TRUE(native_message_host_client);

  // Post a reply to the extension.
  const char kResponseMessageToSend[] = R"({"response":"bar"})";
  native_message_host_client->PostMessageFromNativeHost(kResponseMessageToSend);

  // Wait till the extension receives and validates the reply.
  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}

}  // namespace