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

content / public / test / no_renderer_crashes_assertion.h [blame]

// 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.

#ifndef CONTENT_PUBLIC_TEST_NO_RENDERER_CRASHES_ASSERTION_H_
#define CONTENT_PUBLIC_TEST_NO_RENDERER_CRASHES_ASSERTION_H_

#include <map>

#include "base/gtest_prod_util.h"
#include "base/no_destructor.h"
#include "base/scoped_multi_source_observation.h"
#include "base/sequence_checker.h"
#include "content/public/browser/render_process_host_creation_observer.h"
#include "content/public/browser/render_process_host_observer.h"
#include "content/public/test/browser_test_utils.h"

namespace content {

class RenderProcessHost;

// Usually, a test should fail when BrowserTestBase detects a crash in a
// renderer process (see the NoRendererCrashesAssertion helper class below).
// The ScopedAllowRendererCrashes class can be used to temporarily suspend this
// behavior - this is useful in tests that explicitly expect renderer kills or
// crashes.
class ScopedAllowRendererCrashes {
 public:
  // Ignores *all* renderer crashes.
  ScopedAllowRendererCrashes();

  // Ignores crashes of |process|.
  explicit ScopedAllowRendererCrashes(RenderProcessHost* process);

  // Ignores crashes of the process associated with the given |frame|.
  explicit ScopedAllowRendererCrashes(const ToRenderFrameHost& frame);

  ScopedAllowRendererCrashes(const ScopedAllowRendererCrashes&) = delete;
  ScopedAllowRendererCrashes& operator=(const ScopedAllowRendererCrashes&) =
      delete;

  ~ScopedAllowRendererCrashes();

 private:
  // The id of the process that is allowed to crash while this
  // ScopedAllowRendererCrashes object is alive.
  //
  // The special |ChildProcessHost::kInvalidUniqueID| value means that crashes
  // of *any* process are allowed.
  int process_id_;
};

// Helper that BrowserTestBase can use to start monitoring for renderer crashes
// (triggering a test failure when a renderer crash happens).
class NoRendererCrashesAssertion : public RenderProcessHostCreationObserver,
                                   public RenderProcessHostObserver {
 public:
  NoRendererCrashesAssertion();

  NoRendererCrashesAssertion(const NoRendererCrashesAssertion&) = delete;
  NoRendererCrashesAssertion& operator=(const NoRendererCrashesAssertion&) =
      delete;

  ~NoRendererCrashesAssertion() override;

 private:
  // RenderProcessHostCreationObserver:
  void OnRenderProcessHostCreated(RenderProcessHost* host) override;

  // RenderProcessHostObserver:
  void RenderProcessExited(RenderProcessHost* host,
                           const ChildProcessTerminationInfo& info) override;
  void RenderProcessHostDestroyed(RenderProcessHost* host) override;

  base::ScopedMultiSourceObservation<RenderProcessHost,
                                     RenderProcessHostObserver>
      process_observations_{this};

  // Internal helper class for keeping track of suspensions that should cause
  // us to ignore crashes in a specific renderer process.
  class Suspensions {
   public:
    static Suspensions& GetInstance();
    Suspensions();

    Suspensions(const Suspensions&) = delete;
    Suspensions& operator=(const Suspensions&) = delete;

    ~Suspensions();

    // Methods for adding or removing a suspension.
    //
    // The special |ChildProcessHost::kInvalidUniqueID| value means that crashes
    // of *any* process are allowed.
    void AddSuspension(int process_id);
    void RemoveSuspension(int process_id);

    // Checks whether |process_id| has an active suspension.
    bool IsSuspended(int process_id);

   private:
    friend class base::NoDestructor<Suspensions>;

    std::map<int, int> process_id_to_suspension_count_;
    SEQUENCE_CHECKER(sequence_checker_);
  };
  friend ScopedAllowRendererCrashes;
  FRIEND_TEST_ALL_PREFIXES(NoRendererCrashesAssertionSuspensions,
                           SingleProcess);
  FRIEND_TEST_ALL_PREFIXES(NoRendererCrashesAssertionSuspensions, AllProcesses);
  FRIEND_TEST_ALL_PREFIXES(NoRendererCrashesAssertionSuspensions,
                           SingleProcessNesting);
  FRIEND_TEST_ALL_PREFIXES(NoRendererCrashesAssertionSuspensions,
                           AllProcessesNesting);
};

}  // namespace content

#endif  // CONTENT_PUBLIC_TEST_NO_RENDERER_CRASHES_ASSERTION_H_