// Copyright 2017 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 "base/containers/flat_set.h"
#include "base/test/simple_test_tick_clock.h"
#include "components/viz/common/surfaces/surface_id.h"
#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h"
#include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
#include "components/viz/test/begin_frame_args_test.h"
#include "components/viz/test/compositor_frame_helpers.h"
#include "components/viz/test/fake_external_begin_frame_source.h"
#include "components/viz/test/fake_surface_observer.h"
#include "components/viz/test/mock_compositor_frame_sink_client.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

using testing::_;
using testing::Eq;
using testing::IsEmpty;
using testing::UnorderedElementsAre;

namespace viz {
namespace {

constexpr bool kIsRoot = true;
constexpr bool kIsChildRoot = false;
constexpr bool kNeedsSyncPoints = true;
constexpr FrameSinkId kDisplayFrameSink(2, 0);
constexpr FrameSinkId kParentFrameSink(3, 0);
constexpr FrameSinkId kChildFrameSink1(65563, 0);
constexpr FrameSinkId kChildFrameSink2(65564, 0);
constexpr FrameSinkId kArbitraryFrameSink(1337, 7331);

std::vector<SurfaceId> empty_surface_ids() {
  return std::vector<SurfaceId>();
}
std::vector<SurfaceRange> empty_surface_ranges() {
  return std::vector<SurfaceRange>();
}

SurfaceId MakeSurfaceId(const FrameSinkId& frame_sink_id,
                        uint32_t parent_sequence_number,
                        uint32_t child_sequence_number = 1u) {
  return SurfaceId(frame_sink_id,
                   LocalSurfaceId(parent_sequence_number, child_sequence_number,
                                  base::UnguessableToken::Deserialize(0, 1u)));
}

CompositorFrame MakeCompositorFrame(
    std::vector<SurfaceId> activation_dependencies,
    std::vector<SurfaceRange> referenced_surfaces,
    std::vector<TransferableResource> resource_list,
    const FrameDeadline& deadline = FrameDeadline()) {
  return CompositorFrameBuilder()
      .AddDefaultRenderPass()
      .SetActivationDependencies(std::move(activation_dependencies))
      .SetReferencedSurfaces(std::move(referenced_surfaces))
      .SetTransferableResources(std::move(resource_list))
      .SetDeadline(deadline)
      .Build();
}

}  // namespace

class SurfaceSynchronizationTest : public testing::Test {
 public:
  SurfaceSynchronizationTest()
      : frame_sink_manager_(&shared_bitmap_manager_),
        surface_observer_(false) {}
  ~SurfaceSynchronizationTest() override {}

  CompositorFrameSinkSupport& display_support() {
    return *supports_[kDisplayFrameSink];
  }
  Surface* display_surface() {
    return display_support().GetLastCreatedSurfaceForTesting();
  }

  CompositorFrameSinkSupport& parent_support() {
    return *supports_[kParentFrameSink];
  }
  Surface* parent_surface() {
    return parent_support().GetLastCreatedSurfaceForTesting();
  }

  CompositorFrameSinkSupport& child_support1() {
    return *supports_[kChildFrameSink1];
  }
  Surface* child_surface1() {
    return child_support1().GetLastCreatedSurfaceForTesting();
  }

  CompositorFrameSinkSupport& child_support2() {
    return *supports_[kChildFrameSink2];
  }
  Surface* child_surface2() {
    return child_support2().GetLastCreatedSurfaceForTesting();
  }

  void CreateFrameSink(const FrameSinkId& frame_sink_id, bool is_root) {
    supports_[frame_sink_id] = std::make_unique<CompositorFrameSinkSupport>(
        &support_client_, &frame_sink_manager_, frame_sink_id, is_root,
        kNeedsSyncPoints);
  }

  void DestroyFrameSink(const FrameSinkId& frame_sink_id) {
    auto it = supports_.find(frame_sink_id);
    if (it == supports_.end())
      return;
    supports_.erase(it);
  }

  void ExpireAllTemporaryReferencesAndGarbageCollect() {
    frame_sink_manager_.surface_manager()->ExpireOldTemporaryReferences();
    frame_sink_manager_.surface_manager()->ExpireOldTemporaryReferences();
    frame_sink_manager_.surface_manager()->GarbageCollectSurfaces();
  }

  // Returns all the references where |surface_id| is the parent.
  const base::flat_set<SurfaceId>& GetReferencesFrom(
      const SurfaceId& surface_id) {
    return frame_sink_manager()
        .surface_manager()
        ->GetSurfacesReferencedByParent(surface_id);
  }

  FrameSinkManagerImpl& frame_sink_manager() { return frame_sink_manager_; }

  // Returns all the references where |surface_id| is the parent.
  const base::flat_set<SurfaceId>& GetChildReferences(
      const SurfaceId& surface_id) {
    return frame_sink_manager()
        .surface_manager()
        ->GetSurfacesReferencedByParent(surface_id);
  }

  // Returns true if there is a temporary reference for |surface_id|.
  bool HasTemporaryReference(const SurfaceId& surface_id) {
    return frame_sink_manager().surface_manager()->HasTemporaryReference(
        surface_id);
  }

  // Returns true if there is a Persistent reference for |surface_id|.
  bool HasPersistentReference(const SurfaceId& surface_id) {
    return frame_sink_manager().surface_manager()->HasPersistentReference(
        surface_id);
  }

  Surface* GetLatestInFlightSurface(const SurfaceRange& surface_range) {
    return frame_sink_manager().surface_manager()->GetLatestInFlightSurface(
        surface_range);
  }

  FakeExternalBeginFrameSource* begin_frame_source() {
    return begin_frame_source_.get();
  }

  base::TimeTicks Now() { return now_src_->NowTicks(); }

  FrameDeadline MakeDefaultDeadline() {
    return FrameDeadline(Now(), 4u, BeginFrameArgs::DefaultInterval(), false);
  }

  FrameDeadline MakeDeadline(uint32_t deadline_in_frames) {
    return FrameDeadline(Now(), deadline_in_frames,
                         BeginFrameArgs::DefaultInterval(), false);
  }

  void SendNextBeginFrame() {
    // Creep the time forward so that any BeginFrameArgs is not equal to the
    // last one otherwise we violate the BeginFrameSource contract.
    now_src_->Advance(BeginFrameArgs::DefaultInterval());
    BeginFrameArgs args = begin_frame_source_->CreateBeginFrameArgs(
        BEGINFRAME_FROM_HERE, now_src_.get());
    begin_frame_source_->TestOnBeginFrame(args);
  }

  void SendLateBeginFrame() {
    // Creep the time forward so that any BeginFrameArgs is not equal to the
    // last one otherwise we violate the BeginFrameSource contract.
    now_src_->Advance(4u * BeginFrameArgs::DefaultInterval());
    BeginFrameArgs args = begin_frame_source_->CreateBeginFrameArgs(
        BEGINFRAME_FROM_HERE, now_src_.get());
    begin_frame_source_->TestOnBeginFrame(args);
  }

  FakeSurfaceObserver& surface_observer() { return surface_observer_; }

  // testing::Test:
  void SetUp() override {
    testing::Test::SetUp();

    begin_frame_source_ =
        std::make_unique<FakeExternalBeginFrameSource>(0.f, false);
    now_src_ = std::make_unique<base::SimpleTestTickClock>();
    frame_sink_manager_.surface_manager()->SetTickClockForTesting(
        now_src_.get());
    frame_sink_manager_.surface_manager()->AddObserver(&surface_observer_);
    supports_[kDisplayFrameSink] = std::make_unique<CompositorFrameSinkSupport>(
        &support_client_, &frame_sink_manager_, kDisplayFrameSink, kIsRoot,
        kNeedsSyncPoints);

    supports_[kParentFrameSink] = std::make_unique<CompositorFrameSinkSupport>(
        &support_client_, &frame_sink_manager_, kParentFrameSink, kIsChildRoot,
        kNeedsSyncPoints);

    supports_[kChildFrameSink1] = std::make_unique<CompositorFrameSinkSupport>(
        &support_client_, &frame_sink_manager_, kChildFrameSink1, kIsChildRoot,
        kNeedsSyncPoints);

    supports_[kChildFrameSink2] = std::make_unique<CompositorFrameSinkSupport>(
        &support_client_, &frame_sink_manager_, kChildFrameSink2, kIsChildRoot,
        kNeedsSyncPoints);

    // Normally, the BeginFrameSource would be registered by the Display. We
    // register it here so that BeginFrames are received by the display support,
    // for use in the PassesOnBeginFrameAcks test. Other supports do not receive
    // BeginFrames, since the frame sink hierarchy is not set up in this test.
    frame_sink_manager_.RegisterBeginFrameSource(begin_frame_source_.get(),
                                                 kDisplayFrameSink);
  }

  void TearDown() override {
    frame_sink_manager_.surface_manager()->RemoveObserver(&surface_observer_);
    frame_sink_manager_.UnregisterBeginFrameSource(begin_frame_source_.get());

    begin_frame_source_->SetClient(nullptr);
    begin_frame_source_.reset();

    supports_.clear();

    surface_observer_.Reset();
  }

  bool IsMarkedForDestruction(const SurfaceId& surface_id) {
    return frame_sink_manager_.surface_manager()->IsMarkedForDestruction(
        surface_id);
  }

  Surface* GetSurfaceForId(const SurfaceId& surface_id) {
    return frame_sink_manager_.surface_manager()->GetSurfaceForId(surface_id);
  }

 protected:
  testing::NiceMock<MockCompositorFrameSinkClient> support_client_;

 private:
  std::unique_ptr<base::SimpleTestTickClock> now_src_;
  ServerSharedBitmapManager shared_bitmap_manager_;
  FrameSinkManagerImpl frame_sink_manager_;
  FakeSurfaceObserver surface_observer_;
  std::unique_ptr<FakeExternalBeginFrameSource> begin_frame_source_;
  std::unordered_map<FrameSinkId,
                     std::unique_ptr<CompositorFrameSinkSupport>,
                     FrameSinkIdHash>
      supports_;

  DISALLOW_COPY_AND_ASSIGN(SurfaceSynchronizationTest);
};

// The display root surface should have a surface reference from the top-level
// root added/removed when a CompositorFrame is submitted with a new
// SurfaceId.
TEST_F(SurfaceSynchronizationTest, RootSurfaceReceivesReferences) {
  const SurfaceId display_id_first = MakeSurfaceId(kDisplayFrameSink, 1);
  const SurfaceId display_id_second = MakeSurfaceId(kDisplayFrameSink, 2);

  // Submit a CompositorFrame for the first display root surface.
  display_support().SubmitCompositorFrame(display_id_first.local_surface_id(),
                                          MakeDefaultCompositorFrame());

  // A surface reference from the top-level root is added and there shouldn't be
  // a temporary reference.
  EXPECT_FALSE(HasTemporaryReference(display_id_first));
  EXPECT_THAT(GetChildReferences(
                  frame_sink_manager().surface_manager()->GetRootSurfaceId()),
              UnorderedElementsAre(display_id_first));

  // Submit a CompositorFrame for the second display root surface.
  display_support().SubmitCompositorFrame(display_id_second.local_surface_id(),
                                          MakeDefaultCompositorFrame());

  // A surface reference from the top-level root to |display_id_second| should
  // be added and the reference to |display_root_first| removed.
  EXPECT_FALSE(HasTemporaryReference(display_id_second));
  EXPECT_THAT(GetChildReferences(
                  frame_sink_manager().surface_manager()->GetRootSurfaceId()),
              UnorderedElementsAre(display_id_second));

  frame_sink_manager().surface_manager()->GarbageCollectSurfaces();

  // Surface |display_id_first| is unreachable and should get deleted.
  EXPECT_EQ(nullptr, GetSurfaceForId(display_id_first));
}

// The parent Surface is blocked on |child_id1| and |child_id2|.
TEST_F(SurfaceSynchronizationTest, BlockedOnTwo) {
  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
  const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 1);

  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame({child_id1, child_id2}, empty_surface_ranges(),
                          std::vector<TransferableResource>()));

  // parent_support is blocked on |child_id1| and |child_id2|.
  EXPECT_TRUE(parent_surface()->has_deadline());
  EXPECT_FALSE(parent_surface()->HasActiveFrame());
  EXPECT_TRUE(parent_surface()->HasPendingFrame());
  EXPECT_THAT(parent_surface()->activation_dependencies(),
              UnorderedElementsAre(child_id1, child_id2));

  // Submit a CompositorFrame without any dependencies to |child_id1|.
  // parent_support should now only be blocked on |child_id2|.
  child_support1().SubmitCompositorFrame(child_id1.local_surface_id(),
                                         MakeDefaultCompositorFrame());

  EXPECT_TRUE(parent_surface()->has_deadline());
  EXPECT_FALSE(parent_surface()->HasActiveFrame());
  EXPECT_TRUE(parent_surface()->HasPendingFrame());
  EXPECT_THAT(parent_surface()->activation_dependencies(),
              UnorderedElementsAre(child_id2));

  // Submit a CompositorFrame without any dependencies to |child_id2|.
  // parent_support should be activated.
  child_support2().SubmitCompositorFrame(child_id2.local_surface_id(),
                                         MakeDefaultCompositorFrame());

  EXPECT_FALSE(child_surface2()->has_deadline());
  EXPECT_TRUE(parent_surface()->HasActiveFrame());
  EXPECT_FALSE(parent_surface()->HasPendingFrame());
  EXPECT_THAT(parent_surface()->activation_dependencies(), IsEmpty());
}

// The parent Surface is blocked on |child_id2| which is blocked on
// |child_id3|.
TEST_F(SurfaceSynchronizationTest, BlockedChain) {
  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
  const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 1);

  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame({child_id1}, empty_surface_ranges(),
                          std::vector<TransferableResource>()));

  // parent_support is blocked on |child_id1|.
  EXPECT_TRUE(parent_surface()->has_deadline());
  EXPECT_FALSE(parent_surface()->HasActiveFrame());
  EXPECT_TRUE(parent_surface()->HasPendingFrame());
  EXPECT_THAT(parent_surface()->activation_dependencies(),
              UnorderedElementsAre(child_id1));
  // The parent should not report damage until it activates.
  EXPECT_FALSE(surface_observer().IsSurfaceDamaged(parent_id));

  child_support1().SubmitCompositorFrame(
      child_id1.local_surface_id(),
      MakeCompositorFrame({child_id2}, empty_surface_ranges(),
                          std::vector<TransferableResource>()));

  // child_support1 should now be blocked on |child_id2|.
  EXPECT_TRUE(child_surface1()->has_deadline());
  EXPECT_FALSE(child_surface1()->HasActiveFrame());
  EXPECT_TRUE(child_surface1()->HasPendingFrame());
  EXPECT_THAT(child_surface1()->activation_dependencies(),
              UnorderedElementsAre(child_id2));
  // The parent and child should not report damage until they activate.
  EXPECT_FALSE(surface_observer().IsSurfaceDamaged(parent_id));
  EXPECT_FALSE(surface_observer().IsSurfaceDamaged(child_id1));

  // The parent should still be blocked on |child_id1| because it's pending.
  EXPECT_THAT(parent_surface()->activation_dependencies(),
              UnorderedElementsAre(child_id1));

  // Submit a CompositorFrame without any dependencies to |child_id2|.
  // parent_support should be activated.
  child_support2().SubmitCompositorFrame(
      child_id2.local_surface_id(),
      MakeCompositorFrame(empty_surface_ids(), empty_surface_ranges(),
                          std::vector<TransferableResource>()));

  EXPECT_FALSE(child_surface2()->has_deadline());

  // child_surface1 should now be active.
  EXPECT_TRUE(child_surface1()->HasActiveFrame());
  EXPECT_FALSE(child_surface1()->HasPendingFrame());
  EXPECT_THAT(child_surface1()->activation_dependencies(), IsEmpty());

  // parent_surface should now be active.
  EXPECT_TRUE(parent_surface()->HasActiveFrame());
  EXPECT_FALSE(parent_surface()->HasPendingFrame());
  EXPECT_THAT(parent_surface()->activation_dependencies(), IsEmpty());

  // All three surfaces |parent_id|, |child_id1|, and |child_id2| should
  // now report damage. This would trigger a new display frame.
  EXPECT_TRUE(surface_observer().IsSurfaceDamaged(parent_id));
  EXPECT_TRUE(surface_observer().IsSurfaceDamaged(child_id1));
  EXPECT_TRUE(surface_observer().IsSurfaceDamaged(child_id2));
}

// parent_surface and child_surface1 are blocked on |child_id2|.
TEST_F(SurfaceSynchronizationTest, TwoBlockedOnOne) {
  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
  const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 1);

  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame({child_id2}, empty_surface_ranges(),
                          std::vector<TransferableResource>()));

  // parent_support is blocked on |child_id2|.
  EXPECT_TRUE(parent_surface()->has_deadline());
  EXPECT_FALSE(parent_surface()->HasActiveFrame());
  EXPECT_TRUE(parent_surface()->HasPendingFrame());
  EXPECT_THAT(parent_surface()->activation_dependencies(),
              UnorderedElementsAre(child_id2));

  // child_support1 should now be blocked on |child_id2|.
  child_support1().SubmitCompositorFrame(
      child_id1.local_surface_id(),
      MakeCompositorFrame({child_id2}, empty_surface_ranges(),
                          std::vector<TransferableResource>()));

  EXPECT_TRUE(child_surface1()->has_deadline());
  EXPECT_FALSE(child_surface1()->HasActiveFrame());
  EXPECT_TRUE(child_surface1()->HasPendingFrame());
  EXPECT_THAT(child_surface1()->activation_dependencies(),
              UnorderedElementsAre(child_id2));

  // The parent should still be blocked on |child_id2|.
  EXPECT_THAT(parent_surface()->activation_dependencies(),
              UnorderedElementsAre(child_id2));

  // Submit a CompositorFrame without any dependencies to |child_id2|.
  // parent_support should be activated.
  child_support2().SubmitCompositorFrame(child_id2.local_surface_id(),
                                         MakeDefaultCompositorFrame());

  EXPECT_FALSE(child_surface2()->has_deadline());

  // child_surface1 should now be active.
  EXPECT_TRUE(child_surface1()->HasActiveFrame());
  EXPECT_FALSE(child_surface1()->HasPendingFrame());
  EXPECT_THAT(child_surface1()->activation_dependencies(), IsEmpty());

  // parent_surface should now be active.
  EXPECT_TRUE(parent_surface()->HasActiveFrame());
  EXPECT_FALSE(parent_surface()->HasPendingFrame());
  EXPECT_THAT(parent_surface()->activation_dependencies(), IsEmpty());
}

// parent_surface is blocked on |child_id1|, and child_surface2 is blocked on
// |child_id2| until the deadline hits.
TEST_F(SurfaceSynchronizationTest, DeadlineHits) {
  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
  const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 1);

  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame({child_id1}, empty_surface_ranges(),
                          std::vector<TransferableResource>(),
                          MakeDefaultDeadline()));

  // parent_support is blocked on |child_id1|.
  EXPECT_TRUE(parent_surface()->has_deadline());
  EXPECT_FALSE(parent_surface()->HasActiveFrame());
  EXPECT_TRUE(parent_surface()->HasPendingFrame());
  EXPECT_THAT(parent_surface()->activation_dependencies(),
              UnorderedElementsAre(child_id1));

  child_support1().SubmitCompositorFrame(
      child_id1.local_surface_id(),
      MakeCompositorFrame({child_id2}, empty_surface_ranges(),
                          std::vector<TransferableResource>(),
                          MakeDefaultDeadline()));

  // child_support1 should now be blocked on |child_id2|.
  EXPECT_TRUE(child_surface1()->has_deadline());
  EXPECT_FALSE(child_surface1()->HasActiveFrame());
  EXPECT_TRUE(child_surface1()->HasPendingFrame());
  EXPECT_THAT(child_surface1()->activation_dependencies(),
              UnorderedElementsAre(child_id2));

  // The parent should still be blocked on |child_id1| because it's pending.
  EXPECT_THAT(parent_surface()->activation_dependencies(),
              UnorderedElementsAre(child_id1));

  for (int i = 0; i < 3; ++i) {
    SendNextBeginFrame();
    // There is still a looming deadline! Eeek!
    EXPECT_TRUE(parent_surface()->has_deadline());

    // parent_support is still blocked on |child_id1|.
    EXPECT_FALSE(parent_surface()->HasActiveFrame());
    EXPECT_TRUE(parent_surface()->HasPendingFrame());
    EXPECT_THAT(parent_surface()->activation_dependencies(),
                UnorderedElementsAre(child_id1));

    // child_support1 is still blocked on |child_id2|.
    EXPECT_FALSE(child_surface1()->HasActiveFrame());
    EXPECT_TRUE(child_surface1()->HasPendingFrame());
    EXPECT_THAT(child_surface1()->activation_dependencies(),
                UnorderedElementsAre(child_id2));
  }

  SendNextBeginFrame();

  // The deadline has passed.
  EXPECT_FALSE(parent_surface()->has_deadline());

  // parent_surface has been activated.
  EXPECT_TRUE(parent_surface()->HasActiveFrame());
  EXPECT_FALSE(parent_surface()->HasPendingFrame());
  EXPECT_THAT(parent_surface()->activation_dependencies(), IsEmpty());

  // child_surface1 has been activated.
  EXPECT_TRUE(child_surface1()->HasActiveFrame());
  EXPECT_FALSE(child_surface1()->HasPendingFrame());
  EXPECT_THAT(child_surface1()->activation_dependencies(), IsEmpty());
}

// This test verifies that unlimited deadline mode works and that surfaces will
// not activate until dependencies are resolved.
TEST_F(SurfaceSynchronizationTest, UnlimitedDeadline) {
  // Turn on unlimited deadline mode.
  frame_sink_manager()
      .surface_manager()
      ->SetActivationDeadlineInFramesForTesting(base::nullopt);

  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);

  // The deadline specified by the parent is ignored in unlimited deadline
  // mode.
  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame({child_id1}, empty_surface_ranges(),
                          std::vector<TransferableResource>(),
                          MakeDefaultDeadline()));

  // parent_support is blocked on |child_id1|.
  EXPECT_FALSE(parent_surface()->HasActiveFrame());
  EXPECT_TRUE(parent_surface()->HasPendingFrame());
  EXPECT_THAT(parent_surface()->activation_dependencies(),
              UnorderedElementsAre(child_id1));

  for (int i = 0; i < 4; ++i) {
    SendNextBeginFrame();
    // parent_support is still blocked on |child_id1|.
    EXPECT_FALSE(parent_surface()->HasActiveFrame());
    EXPECT_TRUE(parent_surface()->HasPendingFrame());
    EXPECT_THAT(parent_surface()->activation_dependencies(),
                UnorderedElementsAre(child_id1));
  }

  // parent_support is STILL blocked on |child_id1|.
  EXPECT_FALSE(parent_surface()->HasActiveFrame());
  EXPECT_TRUE(parent_surface()->HasPendingFrame());
  EXPECT_THAT(parent_surface()->activation_dependencies(),
              UnorderedElementsAre(child_id1));

  child_support1().SubmitCompositorFrame(child_id1.local_surface_id(),
                                         MakeDefaultCompositorFrame());

  // parent_surface has been activated.
  EXPECT_TRUE(parent_surface()->HasActiveFrame());
  EXPECT_FALSE(parent_surface()->HasPendingFrame());
  EXPECT_THAT(parent_surface()->activation_dependencies(), IsEmpty());
}

// parent_surface is blocked on |child_id1| until a late BeginFrame arrives and
// triggers a deadline.
TEST_F(SurfaceSynchronizationTest, LateBeginFrameTriggersDeadline) {
  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);

  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame({child_id1}, empty_surface_ranges(),
                          std::vector<TransferableResource>()));

  // parent_support is blocked on |child_id1|.
  EXPECT_TRUE(parent_surface()->has_deadline());
  EXPECT_FALSE(parent_surface()->HasActiveFrame());
  EXPECT_TRUE(parent_surface()->HasPendingFrame());
  EXPECT_THAT(parent_surface()->activation_dependencies(),
              UnorderedElementsAre(child_id1));

  SendLateBeginFrame();

  // The deadline has passed.
  EXPECT_FALSE(parent_surface()->has_deadline());

  // parent_surface has been activated.
  EXPECT_TRUE(parent_surface()->HasActiveFrame());
  EXPECT_FALSE(parent_surface()->HasPendingFrame());
  EXPECT_THAT(parent_surface()->activation_dependencies(), IsEmpty());
}

// This test verifies at the Surface activates once a CompositorFrame is
// submitted that has no unresolved dependencies.
TEST_F(SurfaceSynchronizationTest, NewFrameOverridesOldDependencies) {
  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId arbitrary_id = MakeSurfaceId(kArbitraryFrameSink, 1);

  // Submit a CompositorFrame that depends on |arbitrary_id|.
  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame({arbitrary_id}, empty_surface_ranges(),
                          std::vector<TransferableResource>()));

  // Verify that the CompositorFrame is blocked on |arbitrary_id|.
  EXPECT_FALSE(parent_surface()->HasActiveFrame());
  EXPECT_TRUE(parent_surface()->HasPendingFrame());
  EXPECT_THAT(parent_surface()->activation_dependencies(),
              UnorderedElementsAre(arbitrary_id));

  // Submit a CompositorFrame that has no dependencies.
  parent_support().SubmitCompositorFrame(parent_id.local_surface_id(),
                                         MakeDefaultCompositorFrame());

  // Verify that the CompositorFrame has been activated.
  EXPECT_TRUE(parent_surface()->HasActiveFrame());
  EXPECT_FALSE(parent_surface()->HasPendingFrame());
  EXPECT_THAT(parent_surface()->activation_dependencies(), IsEmpty());
}

// This test verifies that a pending CompositorFrame does not affect surface
// references. A new surface from a child will continue to exist as a temporary
// reference until the parent's frame activates.
TEST_F(SurfaceSynchronizationTest, OnlyActiveFramesAffectSurfaceReferences) {
  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
  const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 1);

  // child_support1 submits a CompositorFrame without any dependencies.
  // DidReceiveCompositorFrameAck should call on immediate activation.
  EXPECT_CALL(support_client_, DidReceiveCompositorFrameAck(_)).Times(1);
  child_support1().SubmitCompositorFrame(child_id1.local_surface_id(),
                                         MakeDefaultCompositorFrame());
  testing::Mock::VerifyAndClearExpectations(&support_client_);

  // Verify that the child surface is not blocked.
  EXPECT_TRUE(child_surface1()->HasActiveFrame());
  EXPECT_FALSE(child_surface1()->HasPendingFrame());
  EXPECT_THAT(child_surface1()->activation_dependencies(), IsEmpty());

  // Verify that there's a temporary reference for |child_id1|.
  EXPECT_TRUE(HasTemporaryReference(child_id1));

  // parent_support submits a CompositorFrame that depends on |child_id1|
  // (which is already active) and |child_id2|. Thus, the parent should not
  // activate immediately. DidReceiveCompositorFrameAck should not be called
  // immediately because the parent CompositorFrame is also blocked on
  // |child_id2|.
  EXPECT_CALL(support_client_, DidReceiveCompositorFrameAck(_)).Times(0);
  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame({child_id2}, {SurfaceRange(child_id1)},
                          std::vector<TransferableResource>()));
  EXPECT_FALSE(parent_surface()->HasActiveFrame());
  EXPECT_TRUE(parent_surface()->HasPendingFrame());
  EXPECT_THAT(parent_surface()->activation_dependencies(),
              UnorderedElementsAre(child_id2));
  EXPECT_THAT(GetChildReferences(parent_id), IsEmpty());
  testing::Mock::VerifyAndClearExpectations(&support_client_);

  // Verify that there's a temporary reference for |child_id1| that still
  // exists.
  EXPECT_TRUE(HasTemporaryReference(child_id1));

  // child_support2 submits a CompositorFrame without any dependencies.
  // Both the child and the parent should immediately ACK CompositorFrames
  // on activation.
  EXPECT_CALL(support_client_, DidReceiveCompositorFrameAck(_)).Times(2);
  child_support2().SubmitCompositorFrame(child_id2.local_surface_id(),
                                         MakeDefaultCompositorFrame());
  testing::Mock::VerifyAndClearExpectations(&support_client_);

  // Verify that the child surface is not blocked.
  EXPECT_TRUE(child_surface1()->HasActiveFrame());
  EXPECT_FALSE(child_surface1()->HasPendingFrame());
  EXPECT_THAT(child_surface1()->activation_dependencies(), IsEmpty());

  // Verify that the parent surface's CompositorFrame has activated and that
  // the temporary reference has been replaced by a permanent one.
  EXPECT_TRUE(parent_surface()->HasActiveFrame());
  EXPECT_FALSE(parent_surface()->HasPendingFrame());
  EXPECT_THAT(parent_surface()->activation_dependencies(), IsEmpty());
  EXPECT_FALSE(HasTemporaryReference(child_id1));
  EXPECT_THAT(GetChildReferences(parent_id), UnorderedElementsAre(child_id1));
}

// This test verifies that we do not double count returned resources when a
// CompositorFrame starts out as pending, then becomes active, and then is
// replaced with another active CompositorFrame.
TEST_F(SurfaceSynchronizationTest, ResourcesOnlyReturnedOnce) {
  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 1);

  // The parent submits a CompositorFrame that depends on |child_id| before
  // the child submits a CompositorFrame. The CompositorFrame also has
  // resources in its resource list.
  TransferableResource resource;
  resource.id = 1337;
  resource.format = ALPHA_8;
  resource.filter = 1234;
  resource.size = gfx::Size(1234, 5678);
  std::vector<TransferableResource> resource_list = {resource};
  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame({child_id}, empty_surface_ranges(), resource_list));

  // Verify that the CompositorFrame is blocked on |child_id|.
  EXPECT_FALSE(parent_surface()->HasActiveFrame());
  EXPECT_TRUE(parent_surface()->HasPendingFrame());
  EXPECT_THAT(parent_surface()->activation_dependencies(),
              UnorderedElementsAre(child_id));

  child_support1().SubmitCompositorFrame(
      child_id.local_surface_id(),
      MakeCompositorFrame(empty_surface_ids(), empty_surface_ranges(),
                          std::vector<TransferableResource>()));

  // Verify that the child CompositorFrame activates immediately.
  EXPECT_TRUE(child_surface1()->HasActiveFrame());
  EXPECT_FALSE(child_surface1()->HasPendingFrame());
  EXPECT_THAT(child_surface1()->activation_dependencies(), IsEmpty());

  // Verify that the parent has activated.
  EXPECT_TRUE(parent_surface()->HasActiveFrame());
  EXPECT_FALSE(parent_surface()->HasPendingFrame());
  EXPECT_THAT(parent_surface()->activation_dependencies(), IsEmpty());

  std::vector<ReturnedResource> returned_resources = {
      resource.ToReturnedResource()};
  EXPECT_CALL(support_client_,
              DidReceiveCompositorFrameAck(returned_resources));

  // The parent submits a CompositorFrame without any dependencies. That
  // frame should activate immediately, replacing the earlier frame. The
  // resource from the earlier frame should be returned to the client.
  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame({empty_surface_ids()}, {empty_surface_ranges()},
                          std::vector<TransferableResource>()));
  EXPECT_TRUE(parent_surface()->HasActiveFrame());
  EXPECT_FALSE(parent_surface()->HasPendingFrame());
  EXPECT_THAT(parent_surface()->activation_dependencies(), IsEmpty());
}

// This test verifies that if a surface has both a pending and active
// CompositorFrame and the pending CompositorFrame activates, replacing
// the existing active CompositorFrame, then the surface reference hierarchy
// will be updated allowing garbage collection of surfaces that are no longer
// referenced.
TEST_F(SurfaceSynchronizationTest, DropStaleReferencesAfterActivation) {
  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
  const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 1);

  // The parent submits a CompositorFrame that depends on |child_id1| before
  // the child submits a CompositorFrame.
  EXPECT_CALL(support_client_, DidReceiveCompositorFrameAck(_)).Times(0);
  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame({child_id1}, empty_surface_ranges(),
                          std::vector<TransferableResource>()));

  // Verify that the CompositorFrame is blocked on |child_id|.
  EXPECT_FALSE(parent_surface()->HasActiveFrame());
  EXPECT_TRUE(parent_surface()->HasPendingFrame());
  EXPECT_THAT(parent_surface()->activation_dependencies(),
              UnorderedElementsAre(child_id1));
  testing::Mock::VerifyAndClearExpectations(&support_client_);

  // Verify that no references are added while the CompositorFrame is
  // pending.
  EXPECT_THAT(GetChildReferences(parent_id), IsEmpty());

  // DidReceiveCompositorFrameAck should get called twice: once for the child
  // and once for the now active parent CompositorFrame.
  EXPECT_CALL(support_client_, DidReceiveCompositorFrameAck(_)).Times(2);
  child_support1().SubmitCompositorFrame(child_id1.local_surface_id(),
                                         MakeDefaultCompositorFrame());
  testing::Mock::VerifyAndClearExpectations(&support_client_);

  // Verify that the child CompositorFrame activates immediately.
  EXPECT_TRUE(child_surface1()->HasActiveFrame());
  EXPECT_FALSE(child_surface1()->HasPendingFrame());
  EXPECT_THAT(child_surface1()->activation_dependencies(), IsEmpty());

  // Verify that the parent Surface has activated.
  EXPECT_TRUE(parent_surface()->HasActiveFrame());
  EXPECT_FALSE(parent_surface()->HasPendingFrame());
  EXPECT_THAT(parent_surface()->activation_dependencies(), IsEmpty());

  // Submit a new parent CompositorFrame to add a reference.
  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame(empty_surface_ids(), {SurfaceRange(child_id1)},
                          std::vector<TransferableResource>()));

  // Verify that the parent Surface has activated.
  EXPECT_TRUE(parent_surface()->HasActiveFrame());
  EXPECT_FALSE(parent_surface()->HasPendingFrame());
  EXPECT_THAT(parent_surface()->activation_dependencies(), IsEmpty());

  // Verify that there is no temporary reference for the child and that
  // the reference from the parent to the child still exists.
  EXPECT_FALSE(HasTemporaryReference(child_id1));
  EXPECT_THAT(GetChildReferences(parent_id), UnorderedElementsAre(child_id1));

  // The parent submits another CompositorFrame that depends on |child_id2|.
  // Submitting a pending CompositorFrame will not trigger a
  // CompositorFrameAck.
  EXPECT_CALL(support_client_, DidReceiveCompositorFrameAck(_)).Times(0);
  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame({child_id2}, empty_surface_ranges(),
                          std::vector<TransferableResource>()));
  testing::Mock::VerifyAndClearExpectations(&support_client_);

  // The parent surface should now have both a pending and activate
  // CompositorFrame. Verify that the set of child references from
  // |parent_id| are only from the active CompositorFrame.
  EXPECT_TRUE(parent_surface()->HasActiveFrame());
  EXPECT_TRUE(parent_surface()->HasPendingFrame());
  EXPECT_THAT(parent_surface()->activation_dependencies(),
              UnorderedElementsAre(child_id2));
  EXPECT_THAT(GetChildReferences(parent_id), UnorderedElementsAre(child_id1));

  child_support2().SubmitCompositorFrame(child_id2.local_surface_id(),
                                         MakeDefaultCompositorFrame());

  // Verify that the parent Surface has activated and no longer has a
  // pending CompositorFrame. Also verify that |child_id1| is no longer a
  // child reference of |parent_id|.
  EXPECT_TRUE(parent_surface()->HasActiveFrame());
  EXPECT_FALSE(parent_surface()->HasPendingFrame());
  EXPECT_THAT(parent_surface()->activation_dependencies(), IsEmpty());
  // The parent will not immediately refer to the child until it submits a new
  // CompositorFrame with the reference.
  EXPECT_THAT(GetChildReferences(parent_id), IsEmpty());
}

// Verifies that LatencyInfo does not get too large after multiple resizes.
TEST_F(SurfaceSynchronizationTest, LimitLatencyInfo) {
  const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId parent_id2 = MakeSurfaceId(kParentFrameSink, 2);
  const ui::LatencyComponentType latency_type1 =
      ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT;
  const ui::LatencyComponentType latency_type2 =
      ui::LATENCY_BEGIN_FRAME_UI_MAIN_COMPONENT;

  // Submit a frame with latency info
  ui::LatencyInfo info;
  info.AddLatencyNumber(latency_type1);

  CompositorFrameBuilder builder;
  builder.AddDefaultRenderPass();
  for (int i = 0; i < 60; ++i)
    builder.AddLatencyInfo(info);
  CompositorFrame frame = builder.Build();

  parent_support().SubmitCompositorFrame(parent_id1.local_surface_id(),
                                         std::move(frame));

  // Verify that the old surface has an active frame and no pending frame.
  Surface* old_surface = GetSurfaceForId(parent_id1);
  ASSERT_NE(nullptr, old_surface);
  EXPECT_TRUE(old_surface->HasActiveFrame());
  EXPECT_FALSE(old_surface->HasPendingFrame());

  // Submit another frame with some other latency info and a different
  // LocalSurfaceId.
  ui::LatencyInfo info2;
  info2.AddLatencyNumber(latency_type2);

  builder.AddDefaultRenderPass();
  for (int i = 0; i < 60; ++i)
    builder.AddLatencyInfo(info);
  CompositorFrame frame2 = builder.Build();

  parent_support().SubmitCompositorFrame(parent_id2.local_surface_id(),
                                         std::move(frame2));

  // Verify that the new surface has an active frame and no pending frames.
  Surface* surface = GetSurfaceForId(parent_id2);
  ASSERT_NE(nullptr, surface);
  EXPECT_TRUE(surface->HasActiveFrame());
  EXPECT_FALSE(surface->HasPendingFrame());

  // Verify that the new surface has no latency info objects because it grew
  // too large.
  std::vector<ui::LatencyInfo> info_list;
  surface->TakeLatencyInfo(&info_list);
  EXPECT_EQ(0u, info_list.size());
}

// Checks whether the latency info are moved to the new surface from the old
// one when LocalSurfaceId changes. No frame has unresolved dependencies.
TEST_F(SurfaceSynchronizationTest,
       LatencyInfoCarriedOverOnResize_NoUnresolvedDependencies) {
  const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId parent_id2 = MakeSurfaceId(kParentFrameSink, 2);
  const ui::LatencyComponentType latency_type1 =
      ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT;
  const ui::LatencyComponentType latency_type2 =
      ui::LATENCY_BEGIN_FRAME_UI_MAIN_COMPONENT;

  // Submit a frame with latency info
  ui::LatencyInfo info;
  info.AddLatencyNumber(latency_type1);

  CompositorFrame frame = CompositorFrameBuilder()
                              .AddDefaultRenderPass()
                              .AddLatencyInfo(info)
                              .Build();

  parent_support().SubmitCompositorFrame(parent_id1.local_surface_id(),
                                         std::move(frame));

  // Verify that the old surface has an active frame and no pending frame.
  Surface* old_surface = GetSurfaceForId(parent_id1);
  ASSERT_NE(nullptr, old_surface);
  EXPECT_TRUE(old_surface->HasActiveFrame());
  EXPECT_FALSE(old_surface->HasPendingFrame());

  // Submit another frame with some other latency info and a different
  // LocalSurfaceId.
  ui::LatencyInfo info2;
  info2.AddLatencyNumber(latency_type2);

  CompositorFrame frame2 = CompositorFrameBuilder()
                               .AddDefaultRenderPass()
                               .AddLatencyInfo(info2)
                               .Build();

  parent_support().SubmitCompositorFrame(parent_id2.local_surface_id(),
                                         std::move(frame2));

  // Verify that the new surface has an active frame and no pending frames.
  Surface* surface = GetSurfaceForId(parent_id2);
  ASSERT_NE(nullptr, surface);
  EXPECT_TRUE(surface->HasActiveFrame());
  EXPECT_FALSE(surface->HasPendingFrame());

  // Verify that the new surface has both latency info elements.
  std::vector<ui::LatencyInfo> info_list;
  surface->TakeLatencyInfo(&info_list);
  EXPECT_EQ(2u, info_list.size());

  ui::LatencyInfo aggregated_latency_info = info_list[0];
  aggregated_latency_info.AddNewLatencyFrom(info_list[1]);

  // Two components are the original ones, and the third one is
  // DISPLAY_COMPOSITOR_RECEIVED_FRAME_COMPONENT, logged on compositor frame
  // submit.
  EXPECT_EQ(3u, aggregated_latency_info.latency_components().size());

  EXPECT_TRUE(aggregated_latency_info.FindLatency(latency_type1, nullptr));
  EXPECT_TRUE(aggregated_latency_info.FindLatency(latency_type2, nullptr));
  EXPECT_TRUE(aggregated_latency_info.FindLatency(
      ui::DISPLAY_COMPOSITOR_RECEIVED_FRAME_COMPONENT, nullptr));
}

// Checks whether the latency info are moved to the new surface from the old
// one when LocalSurfaceId changes. Old surface has unresolved
// dependencies.
TEST_F(SurfaceSynchronizationTest,
       LatencyInfoCarriedOverOnResize_OldSurfaceHasPendingAndActiveFrame) {
  const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId parent_id2 = MakeSurfaceId(kParentFrameSink, 2);
  const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 1);

  const ui::LatencyComponentType latency_type1 =
      ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT;
  const ui::LatencyComponentType latency_type2 =
      ui::LATENCY_BEGIN_FRAME_UI_MAIN_COMPONENT;

  // Submit a frame with no unresolved dependecy.
  ui::LatencyInfo info;
  info.AddLatencyNumber(latency_type1);

  CompositorFrame frame = MakeDefaultCompositorFrame();
  frame.metadata.latency_info.push_back(info);

  parent_support().SubmitCompositorFrame(parent_id1.local_surface_id(),
                                         std::move(frame));

  // Submit a frame with unresolved dependencies.
  ui::LatencyInfo info2;
  info2.AddLatencyNumber(latency_type2);

  CompositorFrame frame2 = MakeCompositorFrame(
      {child_id}, empty_surface_ranges(), std::vector<TransferableResource>());
  frame2.metadata.latency_info.push_back(info2);

  parent_support().SubmitCompositorFrame(parent_id1.local_surface_id(),
                                         std::move(frame2));

  // Verify that the old surface has both an active and a pending frame.
  Surface* old_surface = GetSurfaceForId(parent_id1);
  ASSERT_NE(nullptr, old_surface);
  EXPECT_TRUE(old_surface->HasActiveFrame());
  EXPECT_TRUE(old_surface->HasPendingFrame());

  // Submit a frame with a new local surface id.
  parent_support().SubmitCompositorFrame(parent_id2.local_surface_id(),
                                         MakeDefaultCompositorFrame());

  // Verify that the new surface has an active frame only.
  Surface* surface = GetSurfaceForId(parent_id2);
  ASSERT_NE(nullptr, surface);
  EXPECT_TRUE(surface->HasActiveFrame());
  EXPECT_FALSE(surface->HasPendingFrame());

  // Verify that the new surface has latency info from both active and pending
  // frame of the old surface.
  std::vector<ui::LatencyInfo> info_list;
  surface->TakeLatencyInfo(&info_list);
  EXPECT_EQ(2u, info_list.size());

  ui::LatencyInfo aggregated_latency_info = info_list[0];
  aggregated_latency_info.AddNewLatencyFrom(info_list[1]);

  // Two components are the original ones, and the third one is
  // DISPLAY_COMPOSITOR_RECEIVED_FRAME_COMPONENT, logged on compositor frame
  // submit.
  EXPECT_EQ(3u, aggregated_latency_info.latency_components().size());

  EXPECT_TRUE(aggregated_latency_info.FindLatency(latency_type1, nullptr));
  EXPECT_TRUE(aggregated_latency_info.FindLatency(latency_type2, nullptr));
  EXPECT_TRUE(aggregated_latency_info.FindLatency(
      ui::DISPLAY_COMPOSITOR_RECEIVED_FRAME_COMPONENT, nullptr));
}

// Checks whether the latency info are moved to the new surface from the old
// one when LocalSurfaceId changes. The new surface has unresolved
// dependencies.
TEST_F(SurfaceSynchronizationTest,
       LatencyInfoCarriedOverOnResize_NewSurfaceHasPendingFrame) {
  const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId parent_id2 = MakeSurfaceId(kParentFrameSink, 2);
  const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 1);

  const ui::LatencyComponentType latency_type1 =
      ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT;
  const ui::LatencyComponentType latency_type2 =
      ui::LATENCY_BEGIN_FRAME_UI_MAIN_COMPONENT;

  // Submit a frame with no unresolved dependencies.
  ui::LatencyInfo info;
  info.AddLatencyNumber(latency_type1);

  CompositorFrame frame = MakeDefaultCompositorFrame();
  frame.metadata.latency_info.push_back(info);

  parent_support().SubmitCompositorFrame(parent_id1.local_surface_id(),
                                         std::move(frame));

  // Verify that the old surface has an active frame only.
  Surface* old_surface = GetSurfaceForId(parent_id1);
  ASSERT_NE(nullptr, old_surface);
  EXPECT_TRUE(old_surface->HasActiveFrame());
  EXPECT_FALSE(old_surface->HasPendingFrame());

  // Submit a frame with a new local surface id and with unresolved
  // dependencies.
  ui::LatencyInfo info2;
  info2.AddLatencyNumber(latency_type2);

  CompositorFrame frame2 = MakeCompositorFrame(
      {child_id}, empty_surface_ranges(), std::vector<TransferableResource>());
  frame2.metadata.latency_info.push_back(info2);

  parent_support().SubmitCompositorFrame(parent_id2.local_surface_id(),
                                         std::move(frame2));

  // Verify that the new surface has a pending frame and no active frame.
  Surface* surface = GetSurfaceForId(parent_id2);
  ASSERT_NE(nullptr, surface);
  EXPECT_TRUE(surface->HasPendingFrame());
  EXPECT_FALSE(surface->HasActiveFrame());

  // Resolve the dependencies. The frame in parent's surface must become active.
  child_support1().SubmitCompositorFrame(child_id.local_surface_id(),
                                         MakeDefaultCompositorFrame());
  EXPECT_FALSE(surface->HasPendingFrame());
  EXPECT_TRUE(surface->HasActiveFrame());

  // Both latency info elements must exist in the now-activated frame of the
  // new surface.
  std::vector<ui::LatencyInfo> info_list;
  surface->TakeLatencyInfo(&info_list);
  EXPECT_EQ(2u, info_list.size());

  ui::LatencyInfo aggregated_latency_info = info_list[0];
  aggregated_latency_info.AddNewLatencyFrom(info_list[1]);

  // Two components are the original ones, and the third one is
  // DISPLAY_COMPOSITOR_RECEIVED_FRAME_COMPONENT, logged on compositor frame
  // submit.
  EXPECT_EQ(3u, aggregated_latency_info.latency_components().size());

  EXPECT_TRUE(aggregated_latency_info.FindLatency(latency_type1, nullptr));
  EXPECT_TRUE(aggregated_latency_info.FindLatency(latency_type2, nullptr));
  EXPECT_TRUE(aggregated_latency_info.FindLatency(
      ui::DISPLAY_COMPOSITOR_RECEIVED_FRAME_COMPONENT, nullptr));
}

// Checks that resources and ack are sent together if possible.
TEST_F(SurfaceSynchronizationTest, ReturnResourcesWithAck) {
  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
  TransferableResource resource;
  resource.id = 1234;
  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame(empty_surface_ids(), empty_surface_ranges(),
                          {resource}));
  std::vector<ReturnedResource> returned_resources =
      TransferableResource::ReturnResources({resource});
  EXPECT_CALL(support_client_, ReclaimResources(_)).Times(0);
  EXPECT_CALL(support_client_,
              DidReceiveCompositorFrameAck(Eq(returned_resources)));
  parent_support().SubmitCompositorFrame(parent_id.local_surface_id(),
                                         MakeDefaultCompositorFrame());
}

// Verifies that arrival of a new CompositorFrame doesn't change the fact that a
// surface is marked for destruction.
TEST_F(SurfaceSynchronizationTest, SubmitToDestroyedSurface) {
  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 3);

  // Create the child surface by submitting a frame to it.
  EXPECT_EQ(nullptr, GetSurfaceForId(child_id));
  TransferableResource resource;
  resource.id = 1234;
  child_support1().SubmitCompositorFrame(
      child_id.local_surface_id(),
      MakeCompositorFrame(empty_surface_ids(), empty_surface_ranges(),
                          {resource}));
  // Verify that the child surface is created.
  Surface* surface = GetSurfaceForId(child_id);
  EXPECT_NE(nullptr, surface);

  // Add a reference from the parent to the child.
  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame({child_id}, {SurfaceRange(child_id)},
                          std::vector<TransferableResource>()));

  // Attempt to destroy the child surface. The surface must still exist since
  // the parent needs it but it will be marked as destroyed.
  child_support1().EvictSurface(child_id.local_surface_id());
  surface = GetSurfaceForId(child_id);
  EXPECT_NE(nullptr, surface);
  EXPECT_TRUE(IsMarkedForDestruction(child_id));

  // Child submits another frame to the same local surface id that is marked
  // destroyed. The frame is immediately rejected.
  {
    EXPECT_CALL(support_client_, ReclaimResources(_)).Times(0);
    EXPECT_CALL(support_client_, DidReceiveCompositorFrameAck(_));
    surface_observer().Reset();
    child_support1().SubmitCompositorFrame(child_id.local_surface_id(),
                                           MakeDefaultCompositorFrame());
    testing::Mock::VerifyAndClearExpectations(&support_client_);
  }

  // The parent stops referencing the child surface. This allows the child
  // surface to be garbage collected.
  parent_support().SubmitCompositorFrame(parent_id.local_surface_id(),
                                         MakeDefaultCompositorFrame());

  {
    std::vector<ReturnedResource> returned_resources =
        TransferableResource::ReturnResources({resource});
    EXPECT_CALL(support_client_, ReclaimResources(Eq(returned_resources)));
    frame_sink_manager().surface_manager()->GarbageCollectSurfaces();
    testing::Mock::VerifyAndClearExpectations(&support_client_);
  }

  // We shouldn't observe an OnFirstSurfaceActivation because we reject the
  // CompositorFrame to the evicted surface.
  EXPECT_EQ(SurfaceId(), surface_observer().last_created_surface_id());
}

// Verifies that if a LocalSurfaceId belonged to a surface that doesn't
// exist anymore, it can not be recreated.
TEST_F(SurfaceSynchronizationTest, LocalSurfaceIdIsNotReusable) {
  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 3);

  // Submit the first frame. Creates the surface.
  child_support1().SubmitCompositorFrame(child_id.local_surface_id(),
                                         MakeDefaultCompositorFrame());
  EXPECT_NE(nullptr, GetSurfaceForId(child_id));

  // Add a reference from parent.
  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame({child_id}, {SurfaceRange(child_id)},
                          std::vector<TransferableResource>()));

  // Remove the reference from parant. This allows us to destroy the surface.
  parent_support().SubmitCompositorFrame(parent_id.local_surface_id(),
                                         MakeDefaultCompositorFrame());

  // Destroy the surface.
  child_support1().EvictSurface(child_id.local_surface_id());
  frame_sink_manager().surface_manager()->GarbageCollectSurfaces();

  EXPECT_EQ(nullptr, GetSurfaceForId(child_id));

  // Submit another frame with the same local surface id. The surface should not
  // be recreated.
  child_support1().SubmitCompositorFrame(child_id.local_surface_id(),
                                         MakeDefaultCompositorFrame());
  EXPECT_EQ(nullptr, GetSurfaceForId(child_id));
}

// This test verifies that a crash does not occur if garbage collection is
// triggered during surface dependency resolution. This test triggers garbage
// collection during surface resolution, by causing an activation to remove
// a surface subtree from the root. Both the old subtree and the new
// activated subtree refer to the same dependency. The old subtree was activated
// by deadline, and the new subtree was activated by a dependency finally
// resolving.
TEST_F(SurfaceSynchronizationTest, DependencyTrackingGarbageCollection) {
  const SurfaceId display_id = MakeSurfaceId(kDisplayFrameSink, 1);
  const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId parent_id2 = MakeSurfaceId(kParentFrameSink, 2);
  const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 1);

  parent_support().SubmitCompositorFrame(
      parent_id1.local_surface_id(),
      MakeCompositorFrame({child_id}, empty_surface_ranges(),
                          std::vector<TransferableResource>(),
                          MakeDefaultDeadline()));
  display_support().SubmitCompositorFrame(
      display_id.local_surface_id(),
      MakeCompositorFrame({parent_id1}, empty_surface_ranges(),
                          std::vector<TransferableResource>(),
                          MakeDefaultDeadline()));

  EXPECT_TRUE(parent_surface()->has_deadline());

  // Advance BeginFrames to trigger a deadline.
  for (int i = 0; i < 3; ++i) {
    SendNextBeginFrame();
    EXPECT_TRUE(display_surface()->has_deadline());
    EXPECT_TRUE(parent_surface()->has_deadline());
  }
  SendNextBeginFrame();

  EXPECT_TRUE(display_surface()->HasActiveFrame());
  EXPECT_FALSE(display_surface()->HasPendingFrame());
  EXPECT_TRUE(parent_surface()->HasActiveFrame());
  EXPECT_FALSE(parent_surface()->HasPendingFrame());

  parent_support().SubmitCompositorFrame(
      parent_id2.local_surface_id(),
      MakeCompositorFrame({child_id}, empty_surface_ranges(),
                          std::vector<TransferableResource>(),
                          MakeDefaultDeadline()));
  display_support().SubmitCompositorFrame(
      display_id.local_surface_id(),
      MakeCompositorFrame({parent_id2}, empty_surface_ranges(),
                          std::vector<TransferableResource>(),
                          MakeDefaultDeadline()));

  // The display surface now has two CompositorFrames. One that is pending,
  // indirectly blocked on child_id and one that is active, also indirectly
  // referring to child_id, but activated due to the deadline above.
  EXPECT_TRUE(display_surface()->HasActiveFrame());
  EXPECT_TRUE(display_surface()->HasPendingFrame());

  // Submitting a CompositorFrame will trigger garbage collection of the
  // |parent_id1| subtree. This should not crash.
  child_support1().SubmitCompositorFrame(child_id.local_surface_id(),
                                         MakeDefaultCompositorFrame());
}

// This test verifies that a crash does not occur if garbage collection is
// triggered when a deadline forces frame activation. This test triggers garbage
// collection during deadline activation by causing the activation of a display
// frame to replace a previously activated display frame that was referring to
// a now-unreachable surface subtree. That subtree gets garbage collected during
// deadline activation. SurfaceDependencyTracker is also tracking a surface
// from that subtree due to an unresolved dependency. This test verifies that
// this dependency resolution does not crash.
TEST_F(SurfaceSynchronizationTest, GarbageCollectionOnDeadline) {
  const SurfaceId display_id = MakeSurfaceId(kDisplayFrameSink, 1);
  const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId parent_id2 = MakeSurfaceId(kParentFrameSink, 2);
  const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 1);

  // |parent_id1| is blocked on |child_id|.
  parent_support().SubmitCompositorFrame(
      parent_id1.local_surface_id(),
      MakeCompositorFrame({child_id}, empty_surface_ranges(),
                          std::vector<TransferableResource>(),
                          MakeDefaultDeadline()));

  display_support().SubmitCompositorFrame(
      display_id.local_surface_id(),
      MakeCompositorFrame({parent_id1}, {SurfaceRange(parent_id1)},
                          std::vector<TransferableResource>(),
                          MakeDefaultDeadline()));

  EXPECT_TRUE(display_surface()->has_deadline());
  EXPECT_TRUE(parent_surface()->has_deadline());
  EXPECT_TRUE(display_surface()->HasPendingFrame());
  EXPECT_FALSE(display_surface()->HasActiveFrame());

  // Advance BeginFrames to trigger a deadline. This activates the
  // CompositorFrame submitted above.
  for (int i = 0; i < 3; ++i) {
    SendNextBeginFrame();
    EXPECT_TRUE(display_surface()->has_deadline());
    EXPECT_TRUE(parent_surface()->has_deadline());
  }
  SendNextBeginFrame();
  EXPECT_FALSE(display_surface()->has_deadline());
  EXPECT_FALSE(parent_surface()->has_deadline());
  EXPECT_FALSE(display_surface()->HasPendingFrame());
  EXPECT_TRUE(display_surface()->HasActiveFrame());

  // By submitting a display CompositorFrame, and replacing the parent's
  // CompositorFrame with another surface ID, parent_id1 becomes unreachable
  // and a candidate for garbage collection.
  display_support().SubmitCompositorFrame(
      display_id.local_surface_id(),
      MakeCompositorFrame({parent_id2}, empty_surface_ranges(),
                          std::vector<TransferableResource>(),
                          MakeDefaultDeadline()));
  EXPECT_TRUE(display_surface()->has_deadline());

  // Now |parent_id1| is only kept alive by the active |display_id| frame.
  parent_support().SubmitCompositorFrame(
      parent_id2.local_surface_id(),
      MakeCompositorFrame({child_id}, empty_surface_ranges(),
                          std::vector<TransferableResource>(),
                          MakeDefaultDeadline()));
  EXPECT_TRUE(display_surface()->has_deadline());
  EXPECT_TRUE(parent_surface()->has_deadline());

  // SurfaceDependencyTracker should now be tracking |display_id|, |parent_id1|
  // and |parent_id2|. By activating the pending |display_id| frame by deadline,
  // |parent_id1| becomes unreachable and is garbage collected while
  // SurfaceDependencyTracker is in the process of activating surfaces. This
  // should not cause a crash or use-after-free.
  for (int i = 0; i < 3; ++i) {
    SendNextBeginFrame();
    EXPECT_TRUE(display_surface()->has_deadline());
  }
  SendNextBeginFrame();
  EXPECT_FALSE(display_surface()->has_deadline());
}

// This test verifies that a CompositorFrame will only blocked on embedded
// surfaces but not on other retained surface IDs in the CompositorFrame.
TEST_F(SurfaceSynchronizationTest, OnlyBlockOnEmbeddedSurfaces) {
  const SurfaceId display_id = MakeSurfaceId(kDisplayFrameSink, 1);
  const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId parent_id2 = MakeSurfaceId(kParentFrameSink, 2);

  // Submitting a CompositorFrame with |parent_id2| so that the display
  // CompositorFrame can hold a reference to it.
  parent_support().SubmitCompositorFrame(parent_id1.local_surface_id(),
                                         MakeDefaultCompositorFrame());

  display_support().SubmitCompositorFrame(
      display_id.local_surface_id(),
      MakeCompositorFrame({parent_id2}, {SurfaceRange(parent_id1)},
                          std::vector<TransferableResource>()));

  EXPECT_TRUE(display_surface()->HasPendingFrame());
  EXPECT_FALSE(display_surface()->HasActiveFrame());
  EXPECT_TRUE(display_surface()->has_deadline());

  // Verify that the display CompositorFrame will only block on |parent_id2|
  // but not |parent_id1|.
  EXPECT_THAT(display_surface()->activation_dependencies(),
              UnorderedElementsAre(parent_id2));
  // Verify that the display surface holds no references while its
  // CompositorFrame is pending.
  EXPECT_THAT(GetChildReferences(display_id), IsEmpty());

  // Submitting a CompositorFrame with |parent_id2| should unblock the
  // display CompositorFrame.
  parent_support().SubmitCompositorFrame(parent_id2.local_surface_id(),
                                         MakeDefaultCompositorFrame());

  EXPECT_FALSE(display_surface()->has_deadline());
  EXPECT_FALSE(display_surface()->HasPendingFrame());
  EXPECT_TRUE(display_surface()->HasActiveFrame());
  EXPECT_THAT(display_surface()->activation_dependencies(), IsEmpty());
}

// This test verifies that a late arriving CompositorFrame activates
// immediately and does not trigger a new deadline.
TEST_F(SurfaceSynchronizationTest, LateArrivingDependency) {
  const SurfaceId display_id = MakeSurfaceId(kDisplayFrameSink, 1);
  const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);

  display_support().SubmitCompositorFrame(
      display_id.local_surface_id(),
      MakeCompositorFrame({parent_id1}, empty_surface_ranges(),
                          std::vector<TransferableResource>(),
                          MakeDefaultDeadline()));

  EXPECT_TRUE(display_surface()->HasPendingFrame());
  EXPECT_FALSE(display_surface()->HasActiveFrame());
  EXPECT_TRUE(display_surface()->has_deadline());

  // Advance BeginFrames to trigger a deadline. This activates the
  // CompositorFrame submitted above.
  for (int i = 0; i < 3; ++i) {
    SendNextBeginFrame();
    EXPECT_TRUE(display_surface()->has_deadline());
  }
  SendNextBeginFrame();
  EXPECT_FALSE(display_surface()->has_deadline());
  EXPECT_FALSE(display_surface()->HasPendingFrame());
  EXPECT_TRUE(display_surface()->HasActiveFrame());

  // A late arriving CompositorFrame should activate immediately without
  // scheduling a deadline and without waiting for dependencies to resolve.
  parent_support().SubmitCompositorFrame(
      parent_id1.local_surface_id(),
      MakeCompositorFrame({child_id1}, empty_surface_ranges(),
                          std::vector<TransferableResource>(),
                          MakeDefaultDeadline()));
  EXPECT_FALSE(parent_surface()->has_deadline());
  EXPECT_FALSE(parent_surface()->HasPendingFrame());
  EXPECT_TRUE(parent_surface()->HasActiveFrame());
}

// This test verifies that a late arriving CompositorFrame activates
// immediately along with its subtree and does not trigger a new deadline.
TEST_F(SurfaceSynchronizationTest, MultiLevelLateArrivingDependency) {
  const SurfaceId display_id = MakeSurfaceId(kDisplayFrameSink, 1);
  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 1);
  const SurfaceId arbitrary_id = MakeSurfaceId(kArbitraryFrameSink, 1);

  display_support().SubmitCompositorFrame(
      display_id.local_surface_id(),
      MakeCompositorFrame({parent_id}, empty_surface_ranges(),
                          std::vector<TransferableResource>(),
                          MakeDefaultDeadline()));
  EXPECT_TRUE(display_surface()->HasPendingFrame());
  EXPECT_FALSE(display_surface()->HasActiveFrame());
  EXPECT_TRUE(display_surface()->has_deadline());

  // Issue some BeginFrames to trigger the deadline and activate the display's
  // surface. |parent_id| is now late. Advance BeginFrames to trigger a
  // deadline.
  for (int i = 0; i < 4; ++i) {
    EXPECT_TRUE(display_surface()->has_deadline());
    SendNextBeginFrame();
  }
  EXPECT_FALSE(display_surface()->HasPendingFrame());
  EXPECT_TRUE(display_surface()->HasActiveFrame());
  EXPECT_FALSE(display_surface()->has_deadline());

  // The child surface is not currently causally linked to the display's
  // surface and so it gets a separate deadline.
  child_support1().SubmitCompositorFrame(
      child_id.local_surface_id(),
      MakeCompositorFrame({arbitrary_id}, empty_surface_ranges(),
                          std::vector<TransferableResource>(),
                          MakeDefaultDeadline()));
  EXPECT_TRUE(child_surface1()->HasPendingFrame());
  EXPECT_FALSE(child_surface1()->HasActiveFrame());
  EXPECT_TRUE(child_surface1()->has_deadline());

  // Submitting a CompositorFrame to the parent surface creates a dependency
  // chain from the display to the parent to the child, allowing them all to
  // assume the same deadline. Both the parent and the child are determined to
  // be late and activate immediately.
  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame({child_id}, empty_surface_ranges(),
                          std::vector<TransferableResource>(),
                          MakeDefaultDeadline()));
  EXPECT_FALSE(parent_surface()->HasPendingFrame());
  EXPECT_TRUE(parent_surface()->HasActiveFrame());
  EXPECT_FALSE(parent_surface()->has_deadline());

  EXPECT_FALSE(child_surface1()->HasPendingFrame());
  EXPECT_TRUE(child_surface1()->HasActiveFrame());
  EXPECT_FALSE(child_surface1()->has_deadline());
}

// This test verifies that CompositorFrames submitted to a surface referenced
// by a parent CompositorFrame as a fallback will be rejected and ACK'ed
// immediately.
TEST_F(SurfaceSynchronizationTest, FallbackSurfacesClosed) {
  const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1);
  // This is the fallback child surface that the parent holds a reference to.
  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
  // This is the primary child surface that the parent wants to block on.
  const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink1, 2);

  // child_support1 submits a CompositorFrame without any dependencies.
  // DidReceiveCompositorFrameAck should call on immediate activation.
  // However, resources will not be returned because this frame is a candidate
  // for display.
  TransferableResource resource;
  resource.id = 1337;
  resource.format = ALPHA_8;
  resource.filter = 1234;
  resource.size = gfx::Size(1234, 5678);
  std::vector<ReturnedResource> returned_resources =
      TransferableResource::ReturnResources({resource});

  EXPECT_CALL(support_client_, DidReceiveCompositorFrameAck(
                                   Eq(std::vector<ReturnedResource>())));
  child_support1().SubmitCompositorFrame(
      child_id1.local_surface_id(),
      MakeCompositorFrame(empty_surface_ids(), empty_surface_ranges(),
                          {resource}, MakeDefaultDeadline()));
  EXPECT_FALSE(child_surface1()->has_deadline());
  testing::Mock::VerifyAndClearExpectations(&support_client_);

  // The parent is blocked on |child_id2| and references |child_id1|. The
  // surface corresponding to |child_id1| will not accept new CompositorFrames
  // while the parent CompositorFrame is blocked.
  parent_support().SubmitCompositorFrame(
      parent_id1.local_surface_id(),
      MakeCompositorFrame({child_id2}, {SurfaceRange(child_id1, child_id2)},
                          std::vector<TransferableResource>(),
                          MakeDefaultDeadline()));
  EXPECT_TRUE(parent_surface()->has_deadline());
  EXPECT_TRUE(parent_surface()->HasPendingFrame());
  EXPECT_FALSE(parent_surface()->HasActiveFrame());

  // Resources will be returned immediately because |child_id1|'s surface is
  // closed.
  TransferableResource resource2;
  resource2.id = 1246;
  resource2.format = ALPHA_8;
  resource2.filter = 1357;
  resource2.size = gfx::Size(8765, 4321);
  std::vector<ReturnedResource> returned_resources2 =
      TransferableResource::ReturnResources({resource2});
  EXPECT_CALL(support_client_,
              DidReceiveCompositorFrameAck(Eq(returned_resources2)));
  child_support1().SubmitCompositorFrame(
      child_id1.local_surface_id(),
      MakeCompositorFrame(empty_surface_ids(), empty_surface_ranges(),
                          {resource2}, MakeDefaultDeadline()));
  testing::Mock::VerifyAndClearExpectations(&support_client_);

  // Advance BeginFrames to trigger a deadline. This activates the
  // CompositorFrame submitted to the parent.
  for (int i = 0; i < 3; ++i) {
    SendNextBeginFrame();
    EXPECT_TRUE(parent_surface()->has_deadline());
  }
  SendNextBeginFrame();
  EXPECT_FALSE(parent_surface()->has_deadline());
  EXPECT_FALSE(parent_surface()->HasPendingFrame());
  EXPECT_TRUE(parent_surface()->HasActiveFrame());

  // Resources will be returned immediately because |child_id1|'s surface is
  // closed forever.
  EXPECT_CALL(support_client_,
              DidReceiveCompositorFrameAck(Eq(returned_resources2)));
  child_support1().SubmitCompositorFrame(
      child_id1.local_surface_id(),
      MakeCompositorFrame(empty_surface_ids(), empty_surface_ranges(),
                          {resource2}, MakeDefaultDeadline()));
  testing::Mock::VerifyAndClearExpectations(&support_client_);
}

// This test verifies that two surface subtrees have independent deadlines.
TEST_F(SurfaceSynchronizationTest, IndependentDeadlines) {
  const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
  const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 1);
  const SurfaceId arbitrary_id = MakeSurfaceId(kArbitraryFrameSink, 1);

  child_support1().SubmitCompositorFrame(child_id1.local_surface_id(),
                                         MakeDefaultCompositorFrame());
  EXPECT_FALSE(child_surface1()->HasPendingFrame());
  EXPECT_TRUE(child_surface1()->HasActiveFrame());

  child_support2().SubmitCompositorFrame(child_id2.local_surface_id(),
                                         MakeDefaultCompositorFrame());
  EXPECT_FALSE(child_surface2()->HasPendingFrame());
  EXPECT_TRUE(child_surface2()->HasActiveFrame());

  parent_support().SubmitCompositorFrame(
      parent_id1.local_surface_id(),
      MakeCompositorFrame({child_id1, child_id2}, empty_surface_ranges(),
                          std::vector<TransferableResource>(),
                          MakeDefaultDeadline()));

  EXPECT_FALSE(parent_surface()->HasPendingFrame());
  EXPECT_TRUE(parent_surface()->HasActiveFrame());
  EXPECT_FALSE(parent_surface()->has_deadline());

  // Submit another CompositorFrame to |child_id1| that blocks on
  // |arbitrary_id|.
  child_support1().SubmitCompositorFrame(
      child_id1.local_surface_id(),
      MakeCompositorFrame(
          {arbitrary_id}, empty_surface_ranges(),
          std::vector<TransferableResource>(),
          FrameDeadline(Now(), 3, BeginFrameArgs::DefaultInterval(), false)));
  EXPECT_TRUE(child_surface1()->HasPendingFrame());
  EXPECT_TRUE(child_surface1()->HasActiveFrame());
  EXPECT_TRUE(child_surface1()->has_deadline());

  // Advance to the next BeginFrame. |child_id1|'s pending Frame should activate
  // after 2 frames.
  SendNextBeginFrame();

  // Submit another CompositorFrame to |child_id2| that blocks on
  // |arbitrary_id|.
  child_support2().SubmitCompositorFrame(
      child_id2.local_surface_id(),
      MakeCompositorFrame({arbitrary_id}, empty_surface_ranges(),
                          std::vector<TransferableResource>(),
                          MakeDefaultDeadline()));
  EXPECT_TRUE(child_surface2()->HasPendingFrame());
  EXPECT_TRUE(child_surface2()->HasActiveFrame());
  EXPECT_TRUE(child_surface2()->has_deadline());

  // If we issue another two BeginFrames both children should remain blocked.
  SendNextBeginFrame();
  EXPECT_TRUE(child_surface1()->has_deadline());
  EXPECT_TRUE(child_surface2()->has_deadline());

  // Issuing another BeginFrame should activate the frame in |child_id1| but not
  // |child_id2|. This verifies that |child_id1| and |child_id2| have different
  // deadlines.
  SendNextBeginFrame();

  EXPECT_TRUE(child_surface2()->has_deadline());

  EXPECT_FALSE(child_surface1()->has_deadline());
  EXPECT_FALSE(child_surface1()->HasPendingFrame());
  EXPECT_TRUE(child_surface1()->HasActiveFrame());

  SendNextBeginFrame();

  EXPECT_TRUE(child_surface2()->has_deadline());
  EXPECT_TRUE(child_surface2()->HasPendingFrame());
  EXPECT_TRUE(child_surface2()->HasActiveFrame());

  // Issuing another BeginFrame should activate the frame in |child_id2|.
  SendNextBeginFrame();

  EXPECT_FALSE(child_surface2()->has_deadline());
  EXPECT_FALSE(child_surface2()->HasPendingFrame());
  EXPECT_TRUE(child_surface2()->HasActiveFrame());
}

// This test verifies that a child inherits its deadline from its dependent
// parent (embedder) surface.
TEST_F(SurfaceSynchronizationTest, DeadlineInheritance) {
  const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
  const SurfaceId arbitrary_id = MakeSurfaceId(kArbitraryFrameSink, 1);

  // Using the default lower bound deadline results in the deadline of 2 frames
  // effectively being ignored because the default lower bound is 4 frames.
  parent_support().SubmitCompositorFrame(
      parent_id1.local_surface_id(),
      MakeCompositorFrame(
          {child_id1}, empty_surface_ranges(),
          std::vector<TransferableResource>(),
          FrameDeadline(Now(), 2, BeginFrameArgs::DefaultInterval(), true)));

  EXPECT_TRUE(parent_surface()->HasPendingFrame());
  EXPECT_FALSE(parent_surface()->HasActiveFrame());
  EXPECT_TRUE(parent_surface()->has_deadline());

  // Advance to the next BeginFrame. The parent surface will activate in 3
  // frames.
  SendNextBeginFrame();

  child_support1().SubmitCompositorFrame(
      child_id1.local_surface_id(),
      MakeCompositorFrame({arbitrary_id}, empty_surface_ranges(),
                          std::vector<TransferableResource>(),
                          MakeDefaultDeadline()));
  EXPECT_TRUE(child_surface1()->HasPendingFrame());
  EXPECT_FALSE(child_surface1()->HasActiveFrame());
  EXPECT_TRUE(child_surface1()->has_deadline());

  // If we issue another three BeginFrames then both the parent and the child
  // should activate, verifying that the child's deadline is inherited from the
  // parent.
  for (int i = 0; i < 3; ++i) {
    EXPECT_TRUE(parent_surface()->has_deadline());
    EXPECT_TRUE(child_surface1()->has_deadline());
    SendNextBeginFrame();
  }

  // Verify that both the parent and child have activated.
  EXPECT_FALSE(parent_surface()->HasPendingFrame());
  EXPECT_TRUE(parent_surface()->HasActiveFrame());
  EXPECT_FALSE(parent_surface()->has_deadline());

  EXPECT_FALSE(child_surface1()->HasPendingFrame());
  EXPECT_TRUE(child_surface1()->HasActiveFrame());
  EXPECT_FALSE(child_surface1()->has_deadline());
}

// This test verifies that all surfaces within a dependency chain will
// ultimately inherit the same deadline even if the grandchild is available
// before the child.
TEST_F(SurfaceSynchronizationTest, MultiLevelDeadlineInheritance) {
  const SurfaceId display_id = MakeSurfaceId(kDisplayFrameSink, 1);
  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 1);
  const SurfaceId arbitrary_id = MakeSurfaceId(kArbitraryFrameSink, 1);

  display_support().SubmitCompositorFrame(
      display_id.local_surface_id(),
      MakeCompositorFrame({parent_id}, empty_surface_ranges(),
                          std::vector<TransferableResource>(),
                          MakeDefaultDeadline()));
  EXPECT_TRUE(display_surface()->HasPendingFrame());
  EXPECT_FALSE(display_surface()->HasActiveFrame());
  EXPECT_TRUE(display_surface()->has_deadline());

  // Issue a BeginFrame to move closer to the display's deadline.
  SendNextBeginFrame();

  // The child surface is not currently causally linked to the display's
  // surface and so it gets a separate deadline.
  child_support1().SubmitCompositorFrame(
      child_id.local_surface_id(),
      MakeCompositorFrame({arbitrary_id}, empty_surface_ranges(),
                          std::vector<TransferableResource>(),
                          MakeDefaultDeadline()));
  EXPECT_TRUE(child_surface1()->HasPendingFrame());
  EXPECT_FALSE(child_surface1()->HasActiveFrame());
  EXPECT_TRUE(child_surface1()->has_deadline());

  // Submitting a CompositorFrame to the parent frame creates a dependency
  // chain from the display to the parent to the child, allowing them all to
  // assume the same deadline.
  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame({child_id}, empty_surface_ranges(),
                          std::vector<TransferableResource>(),
                          MakeDefaultDeadline()));
  EXPECT_TRUE(parent_surface()->HasPendingFrame());
  EXPECT_FALSE(parent_surface()->HasActiveFrame());
  EXPECT_TRUE(parent_surface()->has_deadline());

  // Advancing the time by three BeginFrames should activate all the surfaces.
  for (int i = 0; i < 3; ++i) {
    EXPECT_TRUE(display_surface()->has_deadline());
    EXPECT_TRUE(parent_surface()->has_deadline());
    EXPECT_TRUE(child_surface1()->has_deadline());
    SendNextBeginFrame();
  }

  // Verify that all the CompositorFrames have activated.
  EXPECT_FALSE(display_surface()->HasPendingFrame());
  EXPECT_TRUE(display_surface()->HasActiveFrame());
  EXPECT_FALSE(display_surface()->has_deadline());

  EXPECT_FALSE(parent_surface()->HasPendingFrame());
  EXPECT_TRUE(parent_surface()->HasActiveFrame());
  EXPECT_FALSE(parent_surface()->has_deadline());

  EXPECT_FALSE(child_surface1()->HasPendingFrame());
  EXPECT_TRUE(child_surface1()->HasActiveFrame());
  EXPECT_FALSE(child_surface1()->has_deadline());
}

// This test verifies that no crash occurs if a CompositorFrame activates AFTER
// its FrameSink has been destroyed.
TEST_F(SurfaceSynchronizationTest, FrameActivationAfterFrameSinkDestruction) {
  const SurfaceId display_id = MakeSurfaceId(kDisplayFrameSink, 1);
  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 1);

  parent_support().SubmitCompositorFrame(parent_id.local_surface_id(),
                                         MakeDefaultCompositorFrame());

  EXPECT_FALSE(parent_surface()->has_deadline());
  EXPECT_TRUE(parent_surface()->HasActiveFrame());
  EXPECT_FALSE(parent_surface()->HasPendingFrame());

  // Submit a CompositorFrame that refers to to |parent_id|.
  display_support().SubmitCompositorFrame(
      display_id.local_surface_id(),
      MakeCompositorFrame(empty_surface_ids(), {SurfaceRange(parent_id)},
                          std::vector<TransferableResource>()));

  EXPECT_FALSE(display_surface()->has_deadline());
  EXPECT_FALSE(display_surface()->HasPendingFrame());
  EXPECT_TRUE(display_surface()->HasActiveFrame());
  EXPECT_THAT(GetChildReferences(display_id), UnorderedElementsAre(parent_id));

  // Submit a new CompositorFrame to the parent CompositorFrameSink. It should
  // now have a pending and active CompositorFrame.
  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame({child_id}, empty_surface_ranges(),
                          std::vector<TransferableResource>()));

  EXPECT_TRUE(parent_surface()->has_deadline());
  EXPECT_TRUE(parent_surface()->HasActiveFrame());
  EXPECT_TRUE(parent_surface()->HasPendingFrame());
  surface_observer().Reset();

  // Destroy the parent CompositorFrameSink. The parent_surface will be kept
  // alive by the display.
  DestroyFrameSink(kParentFrameSink);

  Surface* parent_surface = GetSurfaceForId(parent_id);
  ASSERT_NE(nullptr, parent_surface);

  EXPECT_TRUE(parent_surface->has_deadline());
  EXPECT_TRUE(parent_surface->HasActiveFrame());
  EXPECT_TRUE(parent_surface->HasPendingFrame());

  // Advance BeginFrames to trigger a deadline. This activates the
  // CompositorFrame submitted above.
  for (int i = 0; i < 4; ++i)
    SendNextBeginFrame();

  // The parent surface stays alive through the display.
  parent_surface = GetSurfaceForId(parent_id);
  EXPECT_NE(nullptr, parent_surface);
  EXPECT_TRUE(surface_observer().IsSurfaceDamaged(parent_id));

  // Submitting a new CompositorFrame to the display should free the parent.
  display_support().SubmitCompositorFrame(display_id.local_surface_id(),
                                          MakeDefaultCompositorFrame());

  frame_sink_manager().surface_manager()->GarbageCollectSurfaces();

  parent_surface = GetSurfaceForId(parent_id);
  EXPECT_EQ(nullptr, parent_surface);
}

TEST_F(SurfaceSynchronizationTest, PreviousFrameSurfaceId) {
  const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId parent_id2 = MakeSurfaceId(kParentFrameSink, 2);
  const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 1);

  // Submit a frame with no dependencies to |parent_id1|.
  parent_support().SubmitCompositorFrame(
      parent_id1.local_surface_id(),
      MakeCompositorFrame(empty_surface_ids(), empty_surface_ranges(),
                          std::vector<TransferableResource>()));

  // Submit a frame with unresolved dependencies to |parent_id2|. The frame
  // should become pending and previous_frame_surface_id() should return
  // |parent_id1|.
  parent_support().SubmitCompositorFrame(
      parent_id2.local_surface_id(),
      MakeCompositorFrame({child_id}, empty_surface_ranges(),
                          std::vector<TransferableResource>()));
  Surface* parent_surface2 =
      frame_sink_manager().surface_manager()->GetSurfaceForId(parent_id2);
  EXPECT_FALSE(parent_surface2->HasActiveFrame());
  EXPECT_TRUE(parent_surface2->HasPendingFrame());

  // Activate the pending frame in |parent_id2|. previous_frame_surface_id()
  // should still return |parent_id1|.
  parent_surface2->ActivatePendingFrameForDeadline(base::nullopt);
  EXPECT_TRUE(parent_surface2->HasActiveFrame());
  EXPECT_FALSE(parent_surface2->HasPendingFrame());
  EXPECT_EQ(parent_id1, parent_surface2->previous_frame_surface_id());
}

TEST_F(SurfaceSynchronizationTest, FrameIndexWithPendingFrames) {
  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
  constexpr int n_iterations = 7;

  // Submit a frame with no dependencies that will activate immediately. Record
  // the initial frame index.
  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame(empty_surface_ids(), empty_surface_ranges(),
                          std::vector<TransferableResource>()));
  Surface* parent_surface =
      frame_sink_manager().surface_manager()->GetSurfaceForId(parent_id);
  uint64_t initial_frame_index = parent_surface->GetActiveFrameIndex();

  // Submit frames with unresolved dependencies. GetActiveFrameIndex should
  // return the same value as before.
  for (int i = 0; i < n_iterations; i++) {
    parent_support().SubmitCompositorFrame(
        parent_id.local_surface_id(),
        MakeCompositorFrame({child_id1}, empty_surface_ranges(),
                            std::vector<TransferableResource>()));
    EXPECT_EQ(initial_frame_index, parent_surface->GetActiveFrameIndex());
  }

  // Activate the pending frame. GetActiveFrameIndex should return the frame
  // index of the newly activated frame.
  parent_surface->ActivatePendingFrameForDeadline(base::nullopt);
  EXPECT_EQ(initial_frame_index + n_iterations,
            parent_surface->GetActiveFrameIndex());
}

// This test verifies that a new surface with a pending CompositorFrame gets
// a temporary reference immediately, as opposed to when the surface activates.
TEST_F(SurfaceSynchronizationTest, PendingSurfaceKeptAlive) {
  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);

  // |parent_id| depends on |child_id1|. It shouldn't activate.
  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame({child_id1}, empty_surface_ranges(),
                          std::vector<TransferableResource>()));
  EXPECT_FALSE(parent_surface()->HasActiveFrame());
  EXPECT_TRUE(parent_surface()->HasPendingFrame());
  EXPECT_TRUE(HasTemporaryReference(parent_id));
}

// Tests getting the correct active frame index.
TEST_F(SurfaceSynchronizationTest, ActiveFrameIndex) {
  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
  const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 1);

  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame({child_id1, child_id2}, empty_surface_ranges(),
                          std::vector<TransferableResource>()));

  // parent_support is blocked on |child_id1| and |child_id2|.
  EXPECT_FALSE(parent_surface()->HasActiveFrame());
  EXPECT_EQ(0u, parent_surface()->GetActiveFrameIndex());

  child_support1().SubmitCompositorFrame(child_id1.local_surface_id(),
                                         MakeDefaultCompositorFrame());
  child_support2().SubmitCompositorFrame(child_id2.local_surface_id(),
                                         MakeDefaultCompositorFrame());
  EXPECT_TRUE(parent_surface()->HasActiveFrame());
  EXPECT_EQ(3u, parent_surface()->GetActiveFrameIndex());
}

// This test verifies that SurfaceManager::GetLatestInFlightSurface returns
// the latest child surface not yet set as a fallback by the parent.
// Alternatively, it returns the fallback surface specified, if no tempoary
// references to child surfaces are available. This mechanism is used by surface
// synchronization to present the freshest surfaces available at aggregation
// time.
TEST_F(SurfaceSynchronizationTest, LatestInFlightSurface) {
  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
  const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink1, 2);
  const SurfaceId child_id3 = MakeSurfaceId(kChildFrameSink1, 2, 2);
  const SurfaceId child_id4 = MakeSurfaceId(kChildFrameSink1, 2, 3);

  child_support1().SubmitCompositorFrame(child_id1.local_surface_id(),
                                         MakeDefaultCompositorFrame());

  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame({child_id1}, empty_surface_ranges(),
                          std::vector<TransferableResource>()));

  // Verify that the child CompositorFrame activates immediately.
  EXPECT_TRUE(child_surface1()->HasActiveFrame());
  EXPECT_FALSE(child_surface1()->HasPendingFrame());
  EXPECT_THAT(child_surface1()->activation_dependencies(), IsEmpty());

  // Verify that the parent Surface has activated.
  EXPECT_TRUE(parent_surface()->HasActiveFrame());
  EXPECT_FALSE(parent_surface()->HasPendingFrame());
  EXPECT_THAT(parent_surface()->activation_dependencies(), IsEmpty());

  // Verify that there is a temporary reference for the child and there is
  // no reference from the parent to the child yet.
  EXPECT_TRUE(HasTemporaryReference(child_id1));
  EXPECT_THAT(GetChildReferences(parent_id), IsEmpty());
  EXPECT_EQ(GetSurfaceForId(child_id1),
            GetLatestInFlightSurface(SurfaceRange(child_id1, child_id2)));

  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame(empty_surface_ids(), {SurfaceRange(child_id1)},
                          std::vector<TransferableResource>()));

  // Verify that the parent Surface has activated.
  EXPECT_TRUE(parent_surface()->HasActiveFrame());
  EXPECT_FALSE(parent_surface()->HasPendingFrame());
  EXPECT_THAT(parent_surface()->activation_dependencies(), IsEmpty());

  // Verify that there is no temporary reference for the child and there is
  // a reference from the parent to the child.
  EXPECT_FALSE(HasTemporaryReference(child_id1));
  EXPECT_THAT(GetChildReferences(parent_id), UnorderedElementsAre(child_id1));
  EXPECT_EQ(GetSurfaceForId(child_id1),
            GetLatestInFlightSurface(SurfaceRange(child_id1, child_id2)));

  // Submit a child CompositorFrame to a new SurfaceId and verify that
  // GetLatestInFlightSurface returns the right surface.
  child_support1().SubmitCompositorFrame(child_id2.local_surface_id(),
                                         MakeDefaultCompositorFrame());

  // Verify that there is a temporary reference for child_id2 and there is
  // a reference from the parent to child_id1.
  EXPECT_TRUE(HasTemporaryReference(child_id2));
  EXPECT_THAT(GetChildReferences(parent_id), UnorderedElementsAre(child_id1));

  EXPECT_EQ(GetSurfaceForId(child_id2),
            GetLatestInFlightSurface(SurfaceRange(child_id1, child_id3)));

  // If the primary surface is old, then we shouldn't return an in-flight
  // surface that is newer than the primary.
  EXPECT_EQ(GetSurfaceForId(child_id1),
            GetLatestInFlightSurface(SurfaceRange(child_id1)));

  // Submit a child CompositorFrame to a new SurfaceId and verify that
  // GetLatestInFlightSurface returns the right surface.
  child_support1().SubmitCompositorFrame(child_id3.local_surface_id(),
                                         MakeDefaultCompositorFrame());

  // Verify that there is a temporary reference for child_id3.
  EXPECT_TRUE(HasTemporaryReference(child_id3));

  // The surface corresponding to |child_id3| will not be activated until
  // a parent embeds it because it's a child initiated synchronization.
  EXPECT_EQ(GetSurfaceForId(child_id2),
            GetLatestInFlightSurface(SurfaceRange(child_id1, child_id4)));

  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame({child_id3}, {SurfaceRange(base::nullopt, child_id3)},
                          std::vector<TransferableResource>()));

  EXPECT_EQ(GetSurfaceForId(child_id3),
            GetLatestInFlightSurface(SurfaceRange(child_id1, child_id4)));
  EXPECT_THAT(GetChildReferences(parent_id), UnorderedElementsAre(child_id3));

  // If the primary surface is active, we return it.
  EXPECT_EQ(GetSurfaceForId(child_id3),
            GetLatestInFlightSurface(SurfaceRange(child_id1, child_id3)));
}

// This test verifies that GetLatestInFlightSurface will return nullptr
// if it has a bogus fallback SurfaceID.
TEST_F(SurfaceSynchronizationTest, LatestInFlightSurfaceWithBogusFallback) {
  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
  const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink1, 2);

  child_support1().SubmitCompositorFrame(child_id1.local_surface_id(),
                                         MakeDefaultCompositorFrame());

  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame({child_id1}, empty_surface_ranges(),
                          std::vector<TransferableResource>()));

  // Verify that the parent and child CompositorFrames are active.
  EXPECT_TRUE(child_surface1()->HasActiveFrame());
  EXPECT_FALSE(child_surface1()->HasPendingFrame());
  EXPECT_THAT(child_surface1()->activation_dependencies(), IsEmpty());

  EXPECT_TRUE(parent_surface()->HasActiveFrame());
  EXPECT_FALSE(parent_surface()->HasPendingFrame());
  EXPECT_THAT(parent_surface()->activation_dependencies(), IsEmpty());

  const SurfaceId bogus_child_id = MakeSurfaceId(kChildFrameSink1, 10);

  // If primary exists and active return it regardless of the fallback.
  EXPECT_EQ(GetSurfaceForId(child_id1),
            GetLatestInFlightSurface(SurfaceRange(bogus_child_id, child_id1)));

  // If primary is not active and fallback is doesn't exist, we always return
  // nullptr.
  EXPECT_EQ(nullptr,
            GetLatestInFlightSurface(SurfaceRange(bogus_child_id, child_id2)));
}

// This test verifies that GetLatestInFlightSurface will return the primary or
// nullptr if fallback is not specified.
// TODO(akaba): this would change after https://crbug.com/861769
TEST_F(SurfaceSynchronizationTest, LatestInFlightSurfaceWithoutFallback) {
  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
  const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink1, 2);

  child_support1().SubmitCompositorFrame(child_id1.local_surface_id(),
                                         MakeDefaultCompositorFrame());
  // Verify that |child_id1| is active.
  EXPECT_TRUE(child_surface1()->HasActiveFrame());
  EXPECT_FALSE(child_surface1()->HasPendingFrame());
  EXPECT_THAT(child_surface1()->activation_dependencies(), IsEmpty());

  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame({child_id2}, {SurfaceRange(child_id1, child_id2)},
                          std::vector<TransferableResource>()));

  // Verify that the |parent_id| is not active yet.
  EXPECT_FALSE(parent_surface()->HasActiveFrame());
  EXPECT_TRUE(parent_surface()->HasPendingFrame());
  EXPECT_THAT(parent_surface()->activation_dependencies(),
              UnorderedElementsAre(child_id2));

  // Verify that |child_id1| is the latest active surface.
  EXPECT_EQ(GetSurfaceForId(child_id1),
            GetLatestInFlightSurface(SurfaceRange(child_id1, child_id2)));

  // Fallback is not specified and |child_id1| is the latest.
  EXPECT_EQ(GetSurfaceForId(child_id1),
            GetLatestInFlightSurface(SurfaceRange(base::nullopt, child_id2)));

  // Activate |child_id2|
  child_support1().SubmitCompositorFrame(child_id2.local_surface_id(),
                                         MakeDefaultCompositorFrame());
  // Verify that child2 is active.
  EXPECT_TRUE(child_surface1()->HasActiveFrame());
  EXPECT_FALSE(child_surface1()->HasPendingFrame());
  EXPECT_THAT(child_surface1()->activation_dependencies(), IsEmpty());

  // Verify that |child_id2| is the latest active surface.
  EXPECT_EQ(GetSurfaceForId(child_id2),
            GetLatestInFlightSurface(SurfaceRange(child_id1, child_id2)));

  // Fallback is not specified but primary exists so we return it.
  EXPECT_EQ(GetSurfaceForId(child_id2),
            GetLatestInFlightSurface(SurfaceRange(base::nullopt, child_id2)));
}

// This test verifies that GetLatestInFlightSurface will not return null if the
// fallback is garbage collected, but instead returns the latest surface older
// than primary if that exists.
TEST_F(SurfaceSynchronizationTest, LatestInFlightSurfaceWithGarbageFallback) {
  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
  const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink1, 2);
  const SurfaceId child_id3 = MakeSurfaceId(kChildFrameSink1, 3);
  const SurfaceId child_id4 = MakeSurfaceId(kChildFrameSink1, 4);

  // Activate |child_id1|.
  child_support1().SubmitCompositorFrame(child_id1.local_surface_id(),
                                         MakeDefaultCompositorFrame());

  // Verify that |child_id1| CompositorFrames is active.
  EXPECT_TRUE(child_surface1()->HasActiveFrame());
  EXPECT_FALSE(child_surface1()->HasPendingFrame());
  EXPECT_THAT(child_surface1()->activation_dependencies(), IsEmpty());
  EXPECT_TRUE(HasTemporaryReference(child_id1));

  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame(empty_surface_ids(), {SurfaceRange(child_id1)},
                          std::vector<TransferableResource>()));

  // Verify that parent is referencing |child_id1|.
  EXPECT_TRUE(parent_surface()->HasActiveFrame());
  EXPECT_FALSE(parent_surface()->HasPendingFrame());
  EXPECT_THAT(parent_surface()->activation_dependencies(), IsEmpty());
  EXPECT_THAT(parent_surface()->active_referenced_surfaces(),
              UnorderedElementsAre(child_id1));
  EXPECT_FALSE(HasTemporaryReference(child_id1));

  // Activate |child_id2|.
  child_support1().SubmitCompositorFrame(child_id2.local_surface_id(),
                                         MakeDefaultCompositorFrame());

  // Verify that |child_id2| CompositorFrames is active and it has a temporary
  // reference.
  EXPECT_TRUE(child_surface1()->HasActiveFrame());
  EXPECT_FALSE(child_surface1()->HasPendingFrame());
  EXPECT_THAT(child_surface1()->activation_dependencies(), IsEmpty());
  EXPECT_TRUE(HasTemporaryReference(child_id2));

  // Activate |child_id3|.
  child_support1().SubmitCompositorFrame(child_id3.local_surface_id(),
                                         MakeDefaultCompositorFrame());

  // Verify that |child_id3| CompositorFrames is active.
  EXPECT_TRUE(child_surface1()->HasActiveFrame());
  EXPECT_FALSE(child_surface1()->HasPendingFrame());
  EXPECT_THAT(child_surface1()->activation_dependencies(), IsEmpty());
  EXPECT_TRUE(HasTemporaryReference(child_id3));

  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame(empty_surface_ids(), {SurfaceRange(child_id2)},
                          std::vector<TransferableResource>()));

  // Verify that parent is referencing |child_id2| which lost its temporary
  // reference, but |child_id3| still has a temporary reference.
  EXPECT_TRUE(parent_surface()->HasActiveFrame());
  EXPECT_FALSE(parent_surface()->HasPendingFrame());
  EXPECT_THAT(parent_surface()->activation_dependencies(), IsEmpty());
  EXPECT_THAT(parent_surface()->active_referenced_surfaces(),
              UnorderedElementsAre(child_id2));
  EXPECT_FALSE(HasTemporaryReference(child_id2));
  EXPECT_TRUE(HasTemporaryReference(child_id3));

  // Garbage collect |child_id1|.
  frame_sink_manager().surface_manager()->GarbageCollectSurfaces();

  // Make sure |child_id1| is garbage collected.
  EXPECT_EQ(frame_sink_manager().surface_manager()->GetSurfaceForId(child_id1),
            nullptr);

  EXPECT_EQ(GetSurfaceForId(child_id3),
            GetLatestInFlightSurface(SurfaceRange(child_id1, child_id4)));
}

// This test verifies that in the case of different frame sinks
// GetLatestInFlightSurface will return the latest surface in the primary's
// FrameSinkId or the latest in the fallback's FrameSinkId if no surface exists
// in the primary's.
TEST_F(SurfaceSynchronizationTest, LatestInFlightSurfaceDifferentFrameSinkIds) {
  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
  const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink1, 2);
  const SurfaceId child_id3 = MakeSurfaceId(kChildFrameSink2, 1);
  const SurfaceId child_id4 = MakeSurfaceId(kChildFrameSink2, 2);

  // Activate |child_id1|.
  child_support1().SubmitCompositorFrame(child_id1.local_surface_id(),
                                         MakeDefaultCompositorFrame());

  // Activate |child_id2|.
  child_support1().SubmitCompositorFrame(child_id2.local_surface_id(),
                                         MakeDefaultCompositorFrame());

  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame({child_id4}, {SurfaceRange(child_id1, child_id4)},
                          std::vector<TransferableResource>()));

  // Primary's frame sink id empty and |child_id2| is the latest in fallback's
  // frame sink.
  EXPECT_EQ(GetSurfaceForId(child_id2),
            GetLatestInFlightSurface(SurfaceRange(child_id1, child_id4)));

  // Activate |child_id3| which is in different frame sink.
  child_support2().SubmitCompositorFrame(child_id3.local_surface_id(),
                                         MakeDefaultCompositorFrame());

  // |child_id3| is the latest in primary's frame sink.
  EXPECT_EQ(GetSurfaceForId(child_id3),
            GetLatestInFlightSurface(SurfaceRange(child_id1, child_id4)));
}

// This test verifies that GetLatestInFlightSurface will return the
// primary surface ID if it is in the temporary reference queue.
TEST_F(SurfaceSynchronizationTest, LatestInFlightSurfaceReturnPrimary) {
  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
  const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink1, 2);
  const SurfaceId child_id3 = MakeSurfaceId(kChildFrameSink1, 3);

  child_support1().SubmitCompositorFrame(child_id1.local_surface_id(),
                                         MakeDefaultCompositorFrame());

  // Create a reference from |parent_id| to |child_id|.
  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame(empty_surface_ids(), {SurfaceRange(child_id1)},
                          std::vector<TransferableResource>()));

  child_support1().SubmitCompositorFrame(child_id2.local_surface_id(),
                                         MakeDefaultCompositorFrame());

  EXPECT_EQ(GetSurfaceForId(child_id2),
            GetLatestInFlightSurface(SurfaceRange(child_id1, child_id3)));

  child_support1().SubmitCompositorFrame(child_id3.local_surface_id(),
                                         MakeDefaultCompositorFrame());

  // GetLatestInFlightSurface will return the primary surface ID if it's
  // available.
  EXPECT_EQ(GetSurfaceForId(child_id3),
            GetLatestInFlightSurface(SurfaceRange(child_id1, child_id3)));
}

// This test verifies that GetLatestInFlightSurface can use persistent
// references to compute the latest surface.
TEST_F(SurfaceSynchronizationTest,
       LatestInFlightSurfaceUsesPersistentReferences) {
  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
  const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink1, 2);
  const SurfaceId child_id3 = MakeSurfaceId(kChildFrameSink1, 3);

  // Activate |child_id1|.
  child_support1().SubmitCompositorFrame(child_id1.local_surface_id(),
                                         MakeDefaultCompositorFrame());

  // |child_id1| now should have a temporary reference.
  EXPECT_TRUE(HasTemporaryReference(child_id1));
  EXPECT_FALSE(HasPersistentReference(child_id1));

  // Activate |child_id2|.
  child_support1().SubmitCompositorFrame(child_id2.local_surface_id(),
                                         MakeDefaultCompositorFrame());

  // |child_id2| now should have a temporary reference.
  EXPECT_TRUE(HasTemporaryReference(child_id2));
  EXPECT_FALSE(HasPersistentReference(child_id2));

  // Create a reference from |parent_id| to |child_id2|.
  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame(empty_surface_ids(), {SurfaceRange(child_id2)},
                          std::vector<TransferableResource>()));

  // |child_id1| have no references and can be garbage collected.
  EXPECT_FALSE(HasTemporaryReference(child_id1));
  EXPECT_FALSE(HasPersistentReference(child_id1));

  // |child_id2| has a persistent references now.
  EXPECT_FALSE(HasTemporaryReference(child_id2));
  EXPECT_TRUE(HasPersistentReference(child_id2));

  // Verify that GetLatestInFlightSurface returns |child_id2|.
  EXPECT_EQ(GetSurfaceForId(child_id2),
            GetLatestInFlightSurface(SurfaceRange(child_id1, child_id3)));
}

// This test verifies that GetLatestInFlightSurface will skip a surface if
// its nonce is different.
TEST_F(SurfaceSynchronizationTest, LatestInFlightSurfaceSkipDifferentNonce) {
  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
  const base::UnguessableToken nonce1(
      base::UnguessableToken::Deserialize(0, 1));
  const base::UnguessableToken nonce2(
      base::UnguessableToken::Deserialize(1, 1));
  const base::UnguessableToken nonce3(
      base::UnguessableToken::Deserialize(2, 1));
  const SurfaceId child_id1 =
      SurfaceId(kChildFrameSink1, LocalSurfaceId(1, nonce1));
  const SurfaceId child_id2 =
      SurfaceId(kChildFrameSink1, LocalSurfaceId(2, nonce1));
  const SurfaceId child_id3 =
      SurfaceId(kChildFrameSink1, LocalSurfaceId(3, nonce2));
  const SurfaceId child_id4 =
      SurfaceId(kChildFrameSink1, LocalSurfaceId(4, nonce2));
  const SurfaceId child_id5 =
      SurfaceId(kChildFrameSink1, LocalSurfaceId(5, nonce3));

  child_support1().SubmitCompositorFrame(child_id1.local_surface_id(),
                                         MakeDefaultCompositorFrame());

  // Create a reference from |parent_id| to |child_id|.
  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame(empty_surface_ids(), {SurfaceRange(child_id1)},
                          std::vector<TransferableResource>()));

  child_support1().SubmitCompositorFrame(child_id2.local_surface_id(),
                                         MakeDefaultCompositorFrame());

  EXPECT_EQ(GetSurfaceForId(child_id2),
            GetLatestInFlightSurface(SurfaceRange(child_id1, child_id4)));

  child_support1().SubmitCompositorFrame(child_id3.local_surface_id(),
                                         MakeDefaultCompositorFrame());

  // GetLatestInFlightSurface will return child_id3 because the nonce
  // matches that of child_id4.
  EXPECT_EQ(GetSurfaceForId(child_id3),
            GetLatestInFlightSurface(SurfaceRange(child_id1, child_id4)));

  // GetLatestInFlightSurface will return child_id2 because the nonce
  // doesn't match |child_id1| or |child_id5|.
  EXPECT_EQ(GetSurfaceForId(child_id2),
            GetLatestInFlightSurface(SurfaceRange(child_id1, child_id5)));
}

// This test verifies that if a child submits a LocalSurfaceId newer that the
// parent's dependency, then the parent will drop its dependency and activate
// if possible.
TEST_F(SurfaceSynchronizationTest, DropDependenciesThatWillNeverArrive) {
  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId child_id11 = MakeSurfaceId(kChildFrameSink1, 1);
  const SurfaceId child_id12 = MakeSurfaceId(kChildFrameSink1, 2);
  const SurfaceId child_id21 = MakeSurfaceId(kChildFrameSink2, 1);

  // |parent_id| depends on { child_id11, child_id21 }. It shouldn't activate.
  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame({child_id11, child_id21}, empty_surface_ranges(),
                          std::vector<TransferableResource>()));
  EXPECT_FALSE(parent_surface()->HasActiveFrame());
  EXPECT_TRUE(parent_surface()->HasPendingFrame());

  // The first child submits a new CompositorFrame to |child_id12|. |parent_id|
  // no longer depends on |child_id11| because it cannot expect it to arrive.
  // However, the parent is still blocked on |child_id21|.
  child_support1().SubmitCompositorFrame(
      child_id12.local_surface_id(),
      MakeCompositorFrame(empty_surface_ids(), empty_surface_ranges(),
                          std::vector<TransferableResource>()));
  EXPECT_FALSE(parent_surface()->HasActiveFrame());
  EXPECT_TRUE(parent_surface()->HasPendingFrame());
  EXPECT_THAT(parent_surface()->activation_dependencies(),
              UnorderedElementsAre(child_id21));

  // Finally, the second child submits a frame to the remaining dependency and
  // the parent activates.
  child_support2().SubmitCompositorFrame(
      child_id21.local_surface_id(),
      MakeCompositorFrame(empty_surface_ids(), empty_surface_ranges(),
                          std::vector<TransferableResource>()));
  EXPECT_TRUE(parent_surface()->HasActiveFrame());
  EXPECT_FALSE(parent_surface()->HasPendingFrame());
  EXPECT_THAT(parent_surface()->activation_dependencies(), IsEmpty());
}

// This test verifies that a surface will continue to observe a child surface
// until its dependency arrives.
TEST_F(SurfaceSynchronizationTest, ObserveDependenciesUntilArrival) {
  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId child_id21 = MakeSurfaceId(kChildFrameSink1, 2, 1);
  const SurfaceId child_id22 = MakeSurfaceId(kChildFrameSink1, 2, 2);

  // |parent_id| depends on |child_id22|. It shouldn't activate.
  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame({child_id22}, empty_surface_ranges(),
                          std::vector<TransferableResource>()));
  EXPECT_FALSE(parent_surface()->HasActiveFrame());
  EXPECT_TRUE(parent_surface()->HasPendingFrame());

  // The child submits to |child_id21|. The parent should not activate.
  child_support1().SubmitCompositorFrame(
      child_id21.local_surface_id(),
      MakeCompositorFrame(empty_surface_ids(), empty_surface_ranges(),
                          std::vector<TransferableResource>()));
  EXPECT_FALSE(parent_surface()->HasActiveFrame());
  EXPECT_TRUE(parent_surface()->HasPendingFrame());
  EXPECT_THAT(parent_surface()->activation_dependencies(),
              UnorderedElementsAre(child_id22));

  // The child submits to |child_id22|. The parent should activate.
  child_support1().SubmitCompositorFrame(
      child_id22.local_surface_id(),
      MakeCompositorFrame(empty_surface_ids(), empty_surface_ranges(),
                          std::vector<TransferableResource>()));
  EXPECT_TRUE(parent_surface()->HasActiveFrame());
  EXPECT_FALSE(parent_surface()->HasPendingFrame());
  EXPECT_THAT(parent_surface()->activation_dependencies(), IsEmpty());
}

// This test verifies that we don't mark the previous active surface for
// destruction until the new surface activates.
TEST_F(SurfaceSynchronizationTest,
       MarkPreviousSurfaceForDestructionAfterActivation) {
  const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId parent_id2 = MakeSurfaceId(kParentFrameSink, 2);
  const SurfaceId arbitrary_id = MakeSurfaceId(kArbitraryFrameSink, 1);

  // Submit a CompositorFrame that has no dependencies.
  parent_support().SubmitCompositorFrame(parent_id1.local_surface_id(),
                                         MakeDefaultCompositorFrame());

  // Verify that the CompositorFrame has been activated.
  Surface* parent_surface1 = GetSurfaceForId(parent_id1);
  EXPECT_TRUE(parent_surface1->HasActiveFrame());
  EXPECT_FALSE(parent_surface1->HasPendingFrame());
  EXPECT_THAT(parent_surface1->activation_dependencies(), IsEmpty());
  EXPECT_FALSE(IsMarkedForDestruction(parent_id1));

  parent_support().SubmitCompositorFrame(
      parent_id2.local_surface_id(),
      MakeCompositorFrame({arbitrary_id}, empty_surface_ranges(),
                          std::vector<TransferableResource>(),
                          MakeDefaultDeadline()));

  // Verify that the CompositorFrame to the new surface has not been activated.
  Surface* parent_surface2 = GetSurfaceForId(parent_id2);
  EXPECT_FALSE(parent_surface2->HasActiveFrame());
  EXPECT_TRUE(parent_surface2->HasPendingFrame());
  EXPECT_THAT(parent_surface2->activation_dependencies(),
              UnorderedElementsAre(arbitrary_id));
  EXPECT_FALSE(IsMarkedForDestruction(parent_id1));
  EXPECT_FALSE(IsMarkedForDestruction(parent_id2));

  // Advance BeginFrames to trigger a deadline.
  for (int i = 0; i < 3; ++i) {
    SendNextBeginFrame();
    EXPECT_TRUE(parent_surface2->has_deadline());
  }
  SendNextBeginFrame();
  EXPECT_FALSE(parent_surface2->has_deadline());

  // Verify that the CompositorFrame has been activated.
  EXPECT_TRUE(parent_surface2->HasActiveFrame());
  EXPECT_FALSE(parent_surface2->HasPendingFrame());
  EXPECT_THAT(parent_surface2->activation_dependencies(), IsEmpty());

  // Verify that the old surface is now marked for destruction.
  EXPECT_TRUE(IsMarkedForDestruction(parent_id1));
  EXPECT_FALSE(IsMarkedForDestruction(parent_id2));
}

// This test verifies that CompositorFrameSinkSupport does not refer to
// a valid but non-existant |last_activated_surface_id_|.
TEST_F(SurfaceSynchronizationTest, SetPreviousFrameSurfaceDoesntCrash) {
  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId parent_id2 = MakeSurfaceId(kParentFrameSink, 2);
  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);

  // The parent CompositorFrame is not blocked on anything and so it should
  // immediately activate.
  EXPECT_FALSE(parent_support().last_activated_surface_id().is_valid());
  parent_support().SubmitCompositorFrame(parent_id.local_surface_id(),
                                         MakeDefaultCompositorFrame());

  // Verify that the parent CompositorFrame has activated.
  EXPECT_FALSE(parent_surface()->has_deadline());
  EXPECT_TRUE(parent_surface()->HasActiveFrame());
  EXPECT_FALSE(parent_surface()->HasPendingFrame());
  EXPECT_THAT(parent_surface()->activation_dependencies(), IsEmpty());
  EXPECT_TRUE(parent_support().last_activated_surface_id().is_valid());

  // Submit another CompositorFrame to |parent_id|, but this time block it
  // on |child_id1|.
  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame({child_id1}, empty_surface_ranges(),
                          std::vector<TransferableResource>(),
                          MakeDefaultDeadline()));

  // Verify that the surface has both a pending and activate CompositorFrame.
  EXPECT_TRUE(parent_surface()->has_deadline());
  EXPECT_TRUE(parent_surface()->HasActiveFrame());
  EXPECT_TRUE(parent_surface()->HasPendingFrame());
  EXPECT_THAT(parent_surface()->activation_dependencies(),
              UnorderedElementsAre(child_id1));

  // Evict the activated surface in the parent_support.
  EXPECT_TRUE(parent_support().last_activated_surface_id().is_valid());
  parent_support().EvictSurface(
      parent_support().last_activated_surface_id().local_surface_id());
  EXPECT_FALSE(parent_support().last_activated_surface_id().is_valid());

  // The CompositorFrame in the evicted |parent_id| activates here because it
  // was blocked on |child_id1|.
  child_support1().SubmitCompositorFrame(child_id1.local_surface_id(),
                                         MakeDefaultCompositorFrame());

  // parent_support will be informed of the activation of a CompositorFrame
  // associated with |parent_id|, but we clear |last_active_surface_id_| because
  // it was evicted before.
  EXPECT_FALSE(parent_support().last_activated_surface_id().is_valid());

  // Perform a garbage collection. |parent_id| should no longer exist.
  EXPECT_NE(nullptr, GetSurfaceForId(parent_id));
  ExpireAllTemporaryReferencesAndGarbageCollect();
  EXPECT_EQ(nullptr, GetSurfaceForId(parent_id));

  // This should not crash as the previous surface was cleared in
  // CompositorFrameSinkSupport.
  parent_support().SubmitCompositorFrame(parent_id2.local_surface_id(),
                                         MakeDefaultCompositorFrame());
}

// This test verifies that a parent referencing a SurfaceRange get updated
// whenever a child surface activates inside this range. This should also update
// the SurfaceReferences tree.
TEST_F(SurfaceSynchronizationTest, SurfaceReferencesChangeOnChildActivation) {
  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
  const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink1, 2);
  const SurfaceId child_id3 = MakeSurfaceId(kChildFrameSink1, 3);
  const SurfaceId child_id4 = MakeSurfaceId(kChildFrameSink2, 1);

  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame(
          empty_surface_ids(), {SurfaceRange(child_id1, child_id4)},
          std::vector<TransferableResource>(), MakeDefaultDeadline()));

  // Verify that no references exist.
  EXPECT_THAT(GetReferencesFrom(parent_id), empty_surface_ids());

  // Activate |child_id1|.
  child_support1().SubmitCompositorFrame(child_id1.local_surface_id(),
                                         MakeDefaultCompositorFrame());

  // Verify that a reference is acquired.
  EXPECT_THAT(GetReferencesFrom(parent_id), UnorderedElementsAre(child_id1));

  // Activate |child_id2|.
  child_support1().SubmitCompositorFrame(child_id2.local_surface_id(),
                                         MakeDefaultCompositorFrame());

  // Verify that the reference is updated.
  EXPECT_THAT(GetReferencesFrom(parent_id), UnorderedElementsAre(child_id2));

  // Activate |child_id4| in a different frame sink.
  child_support2().SubmitCompositorFrame(child_id4.local_surface_id(),
                                         MakeDefaultCompositorFrame());

  // Verify that the reference is updated.
  EXPECT_THAT(GetReferencesFrom(parent_id), UnorderedElementsAre(child_id4));

  // Activate |child_id3|.
  child_support1().SubmitCompositorFrame(child_id3.local_surface_id(),
                                         MakeDefaultCompositorFrame());

  // Verify that the reference will not get updated since |child_id3| is in the
  // fallback's FrameSinkId.
  EXPECT_THAT(GetReferencesFrom(parent_id), UnorderedElementsAre(child_id4));
}

// This test verifies that once a frame sink become invalidated, it should
// immediately unblock all pending frames depending on that sink.
TEST_F(SurfaceSynchronizationTest,
       InvalidatedFrameSinkShouldNotBlockActivation) {
  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);

  // The parent submitted a frame that refers to a future child surface.
  EXPECT_FALSE(parent_support().last_activated_surface_id().is_valid());
  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(), MakeCompositorFrame({child_id1}, {}, {}));

  // The frame is pending because the child frame hasn't be submitted yet.
  EXPECT_FALSE(parent_surface()->HasActiveFrame());
  EXPECT_TRUE(parent_surface()->HasPendingFrame());
  EXPECT_FALSE(parent_support().last_activated_surface_id().is_valid());

  // Killing the child sink should unblock the frame because it is known
  // the dependency can never fulfill.
  frame_sink_manager().InvalidateFrameSinkId(kChildFrameSink1);
  EXPECT_TRUE(parent_surface()->HasActiveFrame());
  EXPECT_FALSE(parent_surface()->HasPendingFrame());
  EXPECT_EQ(parent_id, parent_support().last_activated_surface_id());
}

// If a parent CompositorFrame embeds a child Surface newer than the throttled
// child then the throttled child surface is immediately unthrottled. This
// unblocks the child to make progress to catch up with the parent.
TEST_F(SurfaceSynchronizationTest,
       ParentEmbeddingFutureChildUnblocksCurrentChildSurface) {
  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1, 1);
  const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink1, 1, 2);
  const SurfaceId child_id3 = MakeSurfaceId(kChildFrameSink1, 1, 3);

  // |child_id1| Surface should immediately activate.
  child_support1().SubmitCompositorFrame(child_id1.local_surface_id(),
                                         MakeDefaultCompositorFrame());
  Surface* child_surface1 = GetSurfaceForId(child_id1);
  ASSERT_NE(nullptr, child_surface1);
  EXPECT_FALSE(child_surface1->HasPendingFrame());
  EXPECT_TRUE(child_surface1->HasActiveFrame());

  // |child_id2| Surface should not activate because |child_id1| was never
  // added as a dependency by a parent.
  child_support1().SubmitCompositorFrame(
      child_id2.local_surface_id(),
      MakeCompositorFrame(empty_surface_ids(), empty_surface_ranges(),
                          std::vector<TransferableResource>(),
                          MakeDeadline(1u)));
  Surface* child_surface2 = GetSurfaceForId(child_id2);
  ASSERT_NE(nullptr, child_surface2);
  EXPECT_TRUE(child_surface2->HasPendingFrame());
  EXPECT_FALSE(child_surface2->HasActiveFrame());
  EXPECT_TRUE(child_surface2->has_deadline());

  FrameDeadline deadline = MakeDefaultDeadline();
  base::TimeTicks deadline_wall_time = deadline.ToWallTime();
  EXPECT_EQ(deadline_wall_time, child_surface2->deadline_for_testing());

  // The parent finally embeds a child surface that hasn't arrived which
  // activates |child_id2|'s Surface in order for the child to make forward
  // progress.
  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame({child_id3}, {SurfaceRange(base::nullopt, child_id3)},
                          std::vector<TransferableResource>(),
                          MakeDefaultDeadline()));

  EXPECT_FALSE(child_surface2->HasPendingFrame());
  EXPECT_TRUE(child_surface2->HasActiveFrame());
}

// A child surface can be blocked on its own activation dependencies and on a
// parent embedding it as an activation dependency. Even if a child's activation
// dependencies arrive, it may not activate until it is embedded.
TEST_F(SurfaceSynchronizationTest, ChildBlockedOnDependenciesAndParent) {
  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1, 1);
  const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink1, 1, 2);
  const SurfaceId child_id3 = MakeSurfaceId(kChildFrameSink2, 1);

  // |child_id1| Surface should immediately activate.
  child_support1().SubmitCompositorFrame(child_id1.local_surface_id(),
                                         MakeDefaultCompositorFrame());
  Surface* child_surface1 = GetSurfaceForId(child_id1);
  ASSERT_NE(nullptr, child_surface1);
  EXPECT_FALSE(child_surface1->HasPendingFrame());
  EXPECT_TRUE(child_surface1->HasActiveFrame());

  // |child_id2| Surface should not activate because |child_id1| was never
  // added as a dependency by a parent AND it depends on |child_id3| which has
  // not yet arrived.
  child_support1().SubmitCompositorFrame(
      child_id2.local_surface_id(),
      MakeCompositorFrame({child_id3}, {SurfaceRange(base::nullopt, child_id3)},
                          std::vector<TransferableResource>(),
                          MakeDefaultDeadline()));
  Surface* child_surface2 = GetSurfaceForId(child_id2);
  ASSERT_NE(nullptr, child_surface2);
  EXPECT_TRUE(child_surface2->HasPendingFrame());
  EXPECT_FALSE(child_surface2->HasActiveFrame());
  EXPECT_THAT(child_surface2->activation_dependencies(),
              UnorderedElementsAre(child_id3));

  // |child_id2|'s dependency has arrived but |child_id2| Surface has not
  // activated because it is still throttled by its parent. It will not
  // activate until its parent arrives.
  child_support2().SubmitCompositorFrame(child_id3.local_surface_id(),
                                         MakeDefaultCompositorFrame());
  EXPECT_THAT(child_surface2->activation_dependencies(), IsEmpty());
  EXPECT_TRUE(child_surface2->HasPendingFrame());
  EXPECT_FALSE(child_surface2->HasActiveFrame());

  // The parent finally embeds a |child_id2| which activates |child_id2|'s
  // Surface.
  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame({child_id2}, {SurfaceRange(base::nullopt, child_id2)},
                          std::vector<TransferableResource>(),
                          MakeDefaultDeadline()));

  EXPECT_FALSE(child_surface2->HasPendingFrame());
  EXPECT_TRUE(child_surface2->HasActiveFrame());
}

// Similar to the previous test, a child surface can be blocked on its own
// activation dependencies and on a parent embedding it as an activation
// dependency. In this case, the parent CompositorFrame arrives first, and then
// the activation dependency.
TEST_F(SurfaceSynchronizationTest, ChildBlockedOnDependenciesAndParent2) {
  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1, 1);
  const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink1, 1, 2);
  const SurfaceId child_id3 = MakeSurfaceId(kChildFrameSink2, 1);

  // |child_id1| Surface should immediately activate.
  child_support1().SubmitCompositorFrame(child_id1.local_surface_id(),
                                         MakeDefaultCompositorFrame());
  Surface* child_surface1 = GetSurfaceForId(child_id1);
  ASSERT_NE(nullptr, child_surface1);
  EXPECT_FALSE(child_surface1->HasPendingFrame());
  EXPECT_TRUE(child_surface1->HasActiveFrame());

  // |child_id2| Surface should not activate because |child_id1| was never
  // added as a dependency by a parent AND it depends on |child_id3| which has
  // not yet arrived.
  child_support1().SubmitCompositorFrame(
      child_id2.local_surface_id(),
      MakeCompositorFrame({child_id3}, {SurfaceRange(base::nullopt, child_id3)},
                          std::vector<TransferableResource>(),
                          MakeDefaultDeadline()));
  Surface* child_surface2 = GetSurfaceForId(child_id2);
  ASSERT_NE(nullptr, child_surface2);
  EXPECT_TRUE(child_surface2->HasPendingFrame());
  EXPECT_FALSE(child_surface2->HasActiveFrame());
  EXPECT_THAT(child_surface2->activation_dependencies(),
              UnorderedElementsAre(child_id3));
  EXPECT_FALSE(child_surface2->HasDependentFrame());

  // The parent embeds |child_id2| but |child_id2|'s Surface cannot activate
  // until its dependencies arrive.
  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame({child_id2}, {SurfaceRange(base::nullopt, child_id2)},
                          std::vector<TransferableResource>(),
                          MakeDefaultDeadline()));
  EXPECT_TRUE(child_surface2->HasPendingFrame());
  EXPECT_FALSE(child_surface2->HasActiveFrame());
  EXPECT_THAT(child_surface2->activation_dependencies(),
              UnorderedElementsAre(child_id3));
  EXPECT_TRUE(child_surface2->HasDependentFrame());

  // |child_id2|'s dependency has arrived and |child_id2|'s Surface finally
  // activates.
  child_support2().SubmitCompositorFrame(child_id3.local_surface_id(),
                                         MakeDefaultCompositorFrame());
  EXPECT_THAT(child_surface2->activation_dependencies(), IsEmpty());
  EXPECT_FALSE(child_surface2->HasPendingFrame());
  EXPECT_TRUE(child_surface2->HasActiveFrame());
}

// This test verifies that if a child-initiated synchronization is blocked
// on a parent, then the frame will still activate after a deadline passes.
TEST_F(SurfaceSynchronizationTest, ChildBlockedOnParentActivatesAfterDeadline) {
  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1, 1);
  const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink1, 1, 2);

  // |child_id1| Surface should immediately activate.
  child_support1().SubmitCompositorFrame(child_id1.local_surface_id(),
                                         MakeDefaultCompositorFrame());
  Surface* child_surface1 = GetSurfaceForId(child_id1);
  ASSERT_NE(nullptr, child_surface1);
  EXPECT_FALSE(child_surface1->HasPendingFrame());
  EXPECT_TRUE(child_surface1->HasActiveFrame());
  EXPECT_FALSE(child_surface1->HasDependentFrame());
  EXPECT_FALSE(child_surface1->has_deadline());

  // |child_id2| Surface should not activate because |child_id1| was never
  // added as a dependency by a parent.
  child_support1().SubmitCompositorFrame(
      child_id2.local_surface_id(),
      MakeCompositorFrame(empty_surface_ids(), empty_surface_ranges(),
                          std::vector<TransferableResource>(),
                          MakeDefaultDeadline()));
  Surface* child_surface2 = GetSurfaceForId(child_id2);
  ASSERT_NE(nullptr, child_surface2);
  EXPECT_TRUE(child_surface2->HasPendingFrame());
  EXPECT_FALSE(child_surface2->HasActiveFrame());
  EXPECT_FALSE(child_surface2->HasDependentFrame());
  EXPECT_TRUE(child_surface2->has_deadline());

  for (int i = 0; i < 3; ++i) {
    SendNextBeginFrame();
    // There is still a looming deadline! Eeek!
    EXPECT_TRUE(child_surface2->HasPendingFrame());
    EXPECT_FALSE(child_surface2->HasActiveFrame());
    EXPECT_FALSE(child_surface2->HasDependentFrame());
    EXPECT_TRUE(child_surface2->has_deadline());
  }

  SendNextBeginFrame();

  EXPECT_FALSE(child_surface2->HasPendingFrame());
  EXPECT_TRUE(child_surface2->HasActiveFrame());
  // We pretend this is true so that subsequent CompositorFrames to the same
  // surface do not block on the parent again.
  EXPECT_TRUE(child_surface2->HasDependentFrame());
  EXPECT_FALSE(child_surface2->has_deadline());
}

// This test verifies that if a child-initiated synchronization is initiated
// with a deadline in the past, then the frame will immediately activate and
// be marked as having a dependent frame so that it does not block again in
// the future.
TEST_F(SurfaceSynchronizationTest, ChildBlockedOnParentDeadlineInPast) {
  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1, 1);
  const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink1, 1, 2);

  // |child_id1| Surface should immediately activate.
  child_support1().SubmitCompositorFrame(child_id1.local_surface_id(),
                                         MakeDefaultCompositorFrame());
  Surface* child_surface1 = GetSurfaceForId(child_id1);
  ASSERT_NE(nullptr, child_surface1);
  EXPECT_FALSE(child_surface1->HasPendingFrame());
  EXPECT_TRUE(child_surface1->HasActiveFrame());
  EXPECT_FALSE(child_surface1->HasDependentFrame());
  EXPECT_FALSE(child_surface1->has_deadline());

  // Pick a deadline in the near future.
  FrameDeadline deadline = MakeDeadline(1u);

  // Advance time beyond the |deadline| above.
  SendLateBeginFrame();

  // |child_id2| Surface should activate because it was submitted with a
  // deadline in the past.
  child_support1().SubmitCompositorFrame(
      child_id2.local_surface_id(),
      MakeCompositorFrame(empty_surface_ids(), empty_surface_ranges(),
                          std::vector<TransferableResource>(), deadline));
  Surface* child_surface2 = GetSurfaceForId(child_id2);
  ASSERT_NE(nullptr, child_surface2);
  EXPECT_FALSE(child_surface2->HasPendingFrame());
  EXPECT_TRUE(child_surface2->HasActiveFrame());
  EXPECT_FALSE(child_surface2->has_deadline());

  EXPECT_TRUE(child_surface2->HasDependentFrame());
}

// A child may submit CompositorFrame corresponding to a child-initiated
// synchronization event followed by a CompositorFrame corresponding to a
// parent-initiated synchronization event.
TEST_F(SurfaceSynchronizationTest,
       ParentInitiatedAfterChildInitiatedSynchronization) {
  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1, 1);
  // Child-initiated synchronization event:
  const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink1, 1, 2);
  // Parent-initiated synchronizaton event:
  const SurfaceId child_id3 = MakeSurfaceId(kChildFrameSink1, 2, 2);

  // |child_id1| Surface should immediately activate.
  child_support1().SubmitCompositorFrame(child_id1.local_surface_id(),
                                         MakeDefaultCompositorFrame());
  Surface* child_surface1 = GetSurfaceForId(child_id1);
  ASSERT_NE(nullptr, child_surface1);
  EXPECT_FALSE(child_surface1->HasPendingFrame());
  EXPECT_TRUE(child_surface1->HasActiveFrame());

  // |child_id2| Surface should not activate because |child_id1| was never
  // added as a dependency by a parent.
  child_support1().SubmitCompositorFrame(child_id2.local_surface_id(),
                                         MakeDefaultCompositorFrame());
  Surface* child_surface2 = GetSurfaceForId(child_id2);
  ASSERT_NE(nullptr, child_surface2);
  EXPECT_TRUE(child_surface2->HasPendingFrame());
  EXPECT_FALSE(child_surface2->HasActiveFrame());
  EXPECT_TRUE(child_surface2->has_deadline());

  // |child_id3| Surface should activate immediately because it corresponds to a
  // parent-initiated synchronization event. |child_surface3| activating
  // triggers all predecessors to activate as well if they're blocked on a
  // parent.
  child_support1().SubmitCompositorFrame(child_id3.local_surface_id(),
                                         MakeDefaultCompositorFrame());
  Surface* child_surface3 = GetSurfaceForId(child_id3);
  ASSERT_NE(nullptr, child_surface3);
  EXPECT_FALSE(child_surface3->HasPendingFrame());
  EXPECT_TRUE(child_surface3->HasActiveFrame());
  EXPECT_FALSE(IsMarkedForDestruction(child_id3));

  // |child_surface2| should have activated now (and should be a candidate for
  // garbage collection).
  EXPECT_FALSE(child_surface2->HasPendingFrame());
  EXPECT_TRUE(child_surface2->HasActiveFrame());
  EXPECT_TRUE(IsMarkedForDestruction(child_id2));
}

TEST_F(SurfaceSynchronizationTest, EvictSurface) {
  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1, 1);
  // Child-initiated synchronization event:
  const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink1, 1, 2);
  // Parent-initiated synchronizaton event:
  const SurfaceId child_id3 = MakeSurfaceId(kChildFrameSink1, 2, 2);

  // Submit a CompositorFrame to |child_id1|.
  child_support1().SubmitCompositorFrame(child_id1.local_surface_id(),
                                         MakeDefaultCompositorFrame());

  // Evict |child_id1|. It should get marked for destruction immediately.
  child_support1().EvictSurface(child_id1.local_surface_id());
  EXPECT_TRUE(IsMarkedForDestruction(child_id1));

  // Submit a CompositorFrame to |child_id2|. This CompositorFrame should be
  // immediately rejected because |child_id2| has the same parent sequence
  // number as |child_id1|.
  child_support1().SubmitCompositorFrame(child_id2.local_surface_id(),
                                         MakeDefaultCompositorFrame());
  EXPECT_EQ(nullptr, GetSurfaceForId(child_id2));

  // Submit a CompositorFrame to |child_id3|. It should not be accepted and not
  // marked for destruction.
  child_support1().SubmitCompositorFrame(child_id3.local_surface_id(),
                                         MakeDefaultCompositorFrame());
  ASSERT_NE(nullptr, GetSurfaceForId(child_id3));
  EXPECT_FALSE(IsMarkedForDestruction(child_id3));
}

// If a parent CompositorFrame is blocked on the child, don't throttle child's
// surface to avoid a deadlock. In this variation of the test, parent's
// CompositorFrame arrives first.
TEST_F(SurfaceSynchronizationTest, ChildNotThrottledWhenParentBlocked1) {
  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1, 1);
  const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink1, 1, 2);
  const SurfaceId child_id3 = MakeSurfaceId(kChildFrameSink1, 2, 2);
  const SurfaceId child_id4 = MakeSurfaceId(kChildFrameSink1, 2, 3);
  const SurfaceId child_id5 = MakeSurfaceId(kChildFrameSink1, 2, 4);

  // The parent embeds |child_surface3|. This should avoid the child getting
  // throttled when it submits to |child_id2|.
  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame({child_id3}, {SurfaceRange(base::nullopt, child_id3)},
                          std::vector<TransferableResource>(),
                          MakeDefaultDeadline()));

  // |child_id1| Surface should immediately activate because it's the child's
  // first surface.
  child_support1().SubmitCompositorFrame(child_id1.local_surface_id(),
                                         MakeDefaultCompositorFrame());
  Surface* child_surface1 = GetSurfaceForId(child_id1);
  ASSERT_NE(nullptr, child_surface1);
  EXPECT_FALSE(child_surface1->HasPendingFrame());
  EXPECT_TRUE(child_surface1->HasActiveFrame());

  // |child_id2| would normally get throttled, but in this case it shouldn't
  // because the parent is blocked.
  child_support1().SubmitCompositorFrame(
      child_id2.local_surface_id(),
      MakeCompositorFrame(empty_surface_ids(), empty_surface_ranges(),
                          std::vector<TransferableResource>(),
                          MakeDeadline(1u)));
  Surface* child_surface2 = GetSurfaceForId(child_id2);
  ASSERT_NE(nullptr, child_surface2);
  EXPECT_FALSE(child_surface2->HasPendingFrame());
  EXPECT_TRUE(child_surface2->HasActiveFrame());

  // After this submission, the parent will be unblocked.
  Surface* parent_surface = GetSurfaceForId(parent_id);
  ASSERT_NE(nullptr, parent_surface);
  EXPECT_TRUE(parent_surface->HasPendingFrame());
  EXPECT_FALSE(parent_surface->HasActiveFrame());
  child_support1().SubmitCompositorFrame(child_id3.local_surface_id(),
                                         MakeDefaultCompositorFrame());
  Surface* child_surface3 = GetSurfaceForId(child_id3);
  ASSERT_NE(nullptr, child_surface3);
  EXPECT_FALSE(child_surface3->HasPendingFrame());
  EXPECT_TRUE(child_surface3->HasActiveFrame());
  EXPECT_FALSE(parent_surface->HasPendingFrame());
  EXPECT_TRUE(parent_surface->HasActiveFrame());

  // This is the first surface after the parent got unblocked. It will not get
  // throttled.
  child_support1().SubmitCompositorFrame(child_id4.local_surface_id(),
                                         MakeDefaultCompositorFrame());
  Surface* child_surface4 = GetSurfaceForId(child_id4);
  ASSERT_NE(nullptr, child_surface4);
  EXPECT_FALSE(child_surface4->HasPendingFrame());
  EXPECT_TRUE(child_surface4->HasActiveFrame());

  // This is the second surface after the parent got unblocked. It will get
  // throttled.
  child_support1().SubmitCompositorFrame(child_id5.local_surface_id(),
                                         MakeDefaultCompositorFrame());
  Surface* child_surface5 = GetSurfaceForId(child_id5);
  ASSERT_NE(nullptr, child_surface5);
  EXPECT_TRUE(child_surface5->HasPendingFrame());
  EXPECT_FALSE(child_surface5->HasActiveFrame());
}

// If a parent CompositorFrame is blocked on the child, don't throttle child's
// surface to avoid a deadlock. In this variation of the test, child's
// CompositorFrame arrives first.
TEST_F(SurfaceSynchronizationTest, ChildNotThrottledWhenParentBlocked2) {
  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1, 1);
  const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink1, 1, 2);
  const SurfaceId child_id3 = MakeSurfaceId(kChildFrameSink1, 2, 1);
  const SurfaceId child_id4 = MakeSurfaceId(kChildFrameSink1, 2, 2);
  const SurfaceId child_id5 = MakeSurfaceId(kChildFrameSink1, 2, 3);
  const SurfaceId child_id6 = MakeSurfaceId(kChildFrameSink1, 2, 4);

  // |child_id1| Surface should immediately activate.
  child_support1().SubmitCompositorFrame(child_id1.local_surface_id(),
                                         MakeDefaultCompositorFrame());
  Surface* child_surface1 = GetSurfaceForId(child_id1);
  ASSERT_NE(nullptr, child_surface1);
  EXPECT_FALSE(child_surface1->HasPendingFrame());
  EXPECT_TRUE(child_surface1->HasActiveFrame());

  // |child_id2| Surface should not activate because |child_id1| was never
  // added as a dependency by a parent.
  child_support1().SubmitCompositorFrame(
      child_id2.local_surface_id(),
      MakeCompositorFrame(empty_surface_ids(), empty_surface_ranges(),
                          std::vector<TransferableResource>(),
                          MakeDeadline(1u)));
  Surface* child_surface2 = GetSurfaceForId(child_id2);
  ASSERT_NE(nullptr, child_surface2);
  EXPECT_TRUE(child_surface2->HasPendingFrame());
  EXPECT_FALSE(child_surface2->HasActiveFrame());
  EXPECT_TRUE(child_surface2->has_deadline());

  FrameDeadline deadline = MakeDefaultDeadline();
  base::TimeTicks deadline_wall_time = deadline.ToWallTime();
  EXPECT_EQ(deadline_wall_time, child_surface2->deadline_for_testing());

  // The parent gets blocked on the child. The child should get unthrottled to
  // avoid deadlocks.
  parent_support().SubmitCompositorFrame(
      parent_id.local_surface_id(),
      MakeCompositorFrame({child_id3}, {SurfaceRange(base::nullopt, child_id3)},
                          std::vector<TransferableResource>(),
                          MakeDefaultDeadline()));
  EXPECT_FALSE(child_surface2->HasPendingFrame());
  EXPECT_TRUE(child_surface2->HasActiveFrame());

  // After this submission, the parent will be unblocked.
  Surface* parent_surface = GetSurfaceForId(parent_id);
  ASSERT_NE(nullptr, parent_surface);
  EXPECT_TRUE(parent_surface->HasPendingFrame());
  EXPECT_FALSE(parent_surface->HasActiveFrame());
  child_support1().SubmitCompositorFrame(child_id4.local_surface_id(),
                                         MakeDefaultCompositorFrame());
  Surface* child_surface4 = GetSurfaceForId(child_id4);
  ASSERT_NE(nullptr, child_surface4);
  EXPECT_FALSE(child_surface4->HasPendingFrame());
  EXPECT_TRUE(child_surface4->HasActiveFrame());
  EXPECT_FALSE(parent_surface->HasPendingFrame());
  EXPECT_TRUE(parent_surface->HasActiveFrame());

  // This is the first surface after the parent got unblocked. It will not get
  // throttled.
  child_support1().SubmitCompositorFrame(child_id5.local_surface_id(),
                                         MakeDefaultCompositorFrame());
  Surface* child_surface5 = GetSurfaceForId(child_id5);
  ASSERT_NE(nullptr, child_surface5);
  EXPECT_FALSE(child_surface5->HasPendingFrame());
  EXPECT_TRUE(child_surface5->HasActiveFrame());

  // This is the second surface after the parent got unblocked. It will get
  // throttled.
  child_support1().SubmitCompositorFrame(child_id6.local_surface_id(),
                                         MakeDefaultCompositorFrame());
  Surface* child_surface6 = GetSurfaceForId(child_id6);
  ASSERT_NE(nullptr, child_surface6);
  EXPECT_TRUE(child_surface6->HasPendingFrame());
  EXPECT_FALSE(child_surface6->HasActiveFrame());
}

// Tests that in cases where a pending-deletion surface (surface A) is
// activated during anothother surface (surface B)'s deletion, we don't attempt
// to delete surface A twice.
TEST_F(SurfaceSynchronizationTest, SurfaceActivationDuringDeletion) {
  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1, 1);
  // Child-initiated synchronization event:
  const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink1, 1, 2);

  // Submit a CompositorFrame to |child_id1|.
  child_support1().SubmitCompositorFrame(child_id1.local_surface_id(),
                                         MakeDefaultCompositorFrame());

  // Child 1 should not yet be active.
  Surface* child_surface1 = GetSurfaceForId(child_id1);
  ASSERT_NE(nullptr, child_surface1);
  EXPECT_FALSE(child_surface1->HasPendingFrame());
  EXPECT_TRUE(child_surface1->HasActiveFrame());

  // Submit a CompositorFrame to |child_id2|.
  child_support1().SubmitCompositorFrame(child_id2.local_surface_id(),
                                         MakeDefaultCompositorFrame());

  // Child 2 should not yet be active.
  Surface* child_surface2 = GetSurfaceForId(child_id2);
  ASSERT_NE(nullptr, child_surface2);
  EXPECT_TRUE(child_surface2->HasPendingFrame());
  EXPECT_FALSE(child_surface2->HasActiveFrame());

  // Evict |child_id2|. both surfaces should be marked for deletion.
  child_support1().EvictSurface(child_id1.local_surface_id());
  EXPECT_TRUE(IsMarkedForDestruction(child_id1));
  EXPECT_TRUE(IsMarkedForDestruction(child_id2));

  // Garbage collect to delete the above surfaces. This will activate
  // |child_id2|, which will cause it to attempt re-deletion.
  ExpireAllTemporaryReferencesAndGarbageCollect();

  // Neither should still be marked for deletion.
  EXPECT_FALSE(IsMarkedForDestruction(child_id1));
  EXPECT_FALSE(IsMarkedForDestruction(child_id2));
}

}  // namespace viz
