File: extension_host_test_helper.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (146 lines) | stat: -rw-r--r-- 6,019 bytes parent folder | download | duplicates (6)
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
135
136
137
138
139
140
141
142
143
144
145
146
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef EXTENSIONS_BROWSER_EXTENSION_HOST_TEST_HELPER_H_
#define EXTENSIONS_BROWSER_EXTENSION_HOST_TEST_HELPER_H_

#include <map>
#include <optional>

#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/scoped_observation.h"
#include "extensions/browser/extension_host_registry.h"
#include "extensions/common/extension_id.h"
#include "extensions/common/mojom/view_type.mojom.h"

namespace content {
class BrowserContext;
}

namespace extensions {

// A helper class to wait for particular events associated with ExtensionHosts.
// TODO(devlin): Add enough bits and bobs to use this class within (or to
// replace) our background page-specific test helpers.
class ExtensionHostTestHelper : public ExtensionHostRegistry::Observer {
 public:
  // Constructs an ExtensionHostTestHelper restricted to a given
  // `extension_id`. Only hosts associated with the given `browser_context`
  // (or its off/on-the-record counterpart) are considered.
  ExtensionHostTestHelper(content::BrowserContext* browser_context,
                          ExtensionId extension_id);

  // As above, but observes *all* extension hosts for the given
  // `browser_context`. Prefer the above constructor when possible to eliminate
  // possibilities of observing an unrelated event.
  explicit ExtensionHostTestHelper(content::BrowserContext* browser_context);

  ExtensionHostTestHelper(const ExtensionHostTestHelper&) = delete;
  ExtensionHostTestHelper& operator=(const ExtensionHostTestHelper&) = delete;
  ~ExtensionHostTestHelper() override;

  // Restricts this class to only observing ExtensionHosts of the specified
  // `view_type`. Other extension hosts matching the event (even from the same
  // extension and browser context) will be ignored. This allows tests to wait
  // for, e.g., a background page or popup host event to happen.
  void RestrictToType(mojom::ViewType view_type);

  // Restricts this class to only observing the specified `host`.
  void RestrictToHost(const ExtensionHost* host);

  // Waits for an ExtensionHost matching the restrictions (if any) to fire the
  // corresponding notification.
  // NOTE: These WaitFor() methods can return null if the host has already been
  // destroyed (which can happen if the host was closed before this method was
  // called or if the host is destroyed synchronously from creation), before
  // the run loop is quit.
  ExtensionHost* WaitForRenderProcessReady() {
    return WaitFor(HostEvent::kRenderProcessReady);
  }
  ExtensionHost* WaitForDocumentElementAvailable() {
    return WaitFor(HostEvent::kDocumentElementAvailable);
  }
  ExtensionHost* WaitForHostCompletedFirstLoad() {
    return WaitFor(HostEvent::kCompletedFirstLoad);
  }
  // NOTE: No return because the ExtensionHost is *always* (obviously)
  // destroyed by the time this returns.
  void WaitForHostDestroyed() { WaitFor(HostEvent::kDestroyed); }
  // Technically, the host can outlive the render process, but it's unlikely to
  // be for long. Similar to above, avoid returning the host object.
  void WaitForRenderProcessGone() { WaitFor(HostEvent::kRenderProcessGone); }

 private:
  // The different types of events this class can wait for.
  enum class HostEvent {
    kRenderProcessReady,
    kDocumentElementAvailable,
    kCompletedFirstLoad,
    kDestroyed,
    kRenderProcessGone,
  };

  // ExtensionHostRegistry::Observer:
  void OnExtensionHostRenderProcessReady(
      content::BrowserContext* browser_context,
      ExtensionHost* host) override;
  void OnExtensionHostDocumentElementAvailable(
      content::BrowserContext* browser_context,
      ExtensionHost* host) override;
  void OnExtensionHostCompletedFirstLoad(
      content::BrowserContext* browser_context,
      ExtensionHost* host) override;
  void OnExtensionHostDestroyed(content::BrowserContext* browser_context,
                                ExtensionHost* host) override;
  void OnExtensionHostRenderProcessGone(
      content::BrowserContext* browser_context,
      ExtensionHost* host) override;

  // Waits for the given `event` to happen. This may return immediately if the
  // event was already observed. Returns the ExtensionHost corresponding to the
  // event if the host is still valid (it may not be, if it has already been
  // destroyed).
  ExtensionHost* WaitFor(HostEvent event);

  // Called when an `event` has been seen, and quits an active run loop if
  // we're currently waiting on the event.
  void EventSeen(ExtensionHost* host, HostEvent event);

  // The event we're currently waiting for, if any.
  std::optional<HostEvent> waiting_for_;

  // A closure to quit an active run loop, if we're waiting on a given event.
  base::OnceClosure quit_loop_;

  // The associated browser context.
  const raw_ptr<content::BrowserContext, AcrossTasksDanglingUntriaged>
      browser_context_;

  // The ID of the extension whose hosts this helper is watching, if it is
  // restricted to a given ID.
  const ExtensionId extension_id_;

  // The specific type of host this helper is waiting on, if any (nullopt
  // implies waiting on any kind of ExtensionHost).
  std::optional<mojom::ViewType> restrict_to_type_;

  // The specific host this helper is waiting on, if any (null implies
  // waiting on any host).
  raw_ptr<const ExtensionHost, AcrossTasksDanglingUntriaged> restrict_to_host_ =
      nullptr;

  // The set of all events this helper has seen and their corresponding
  // ExtensionHosts. ExtensionHosts are nulled out when they are destroyed, but
  // the events stay in the map.
  std::map<HostEvent, raw_ptr<ExtensionHost, CtnExperimental>> observed_events_;

  base::ScopedObservation<ExtensionHostRegistry,
                          ExtensionHostRegistry::Observer>
      host_registry_observation_{this};
};

}  // namespace extensions

#endif  // EXTENSIONS_BROWSER_EXTENSION_HOST_TEST_HELPER_H_