blob: 38bd60cbf507e1de6b602b960ef72da181bfdabb [file] [log] [blame]
// Copyright 2020 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 "chrome/browser/ui/thumbnails/thumbnail_capture_driver.h"
#include "base/test/task_environment.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
class MockClient : public ThumbnailCaptureDriver::Client {
public:
MockClient() = default;
MOCK_METHOD(void, RequestCapture, (), (override));
MOCK_METHOD(void, StartCapture, (), (override));
MOCK_METHOD(void, StopCapture, (), (override));
};
class ThumbnailCaptureDriverTest : public ::testing::Test {
public:
ThumbnailCaptureDriverTest() = default;
~ThumbnailCaptureDriverTest() override = default;
protected:
base::test::SingleThreadTaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
// We strictly specify the interactions between ThumbnailCaptureDriver
// and its client.
::testing::StrictMock<MockClient> mock_client_;
ThumbnailCaptureDriver capture_driver_{&mock_client_};
};
} // namespace
using ::testing::AnyNumber;
using ::testing::Expectation;
using ::testing::InSequence;
TEST_F(ThumbnailCaptureDriverTest,
NoCaptureWhenPageIsVisibleAndThumbnailIsNot) {
EXPECT_CALL(mock_client_, RequestCapture()).Times(0);
EXPECT_CALL(mock_client_, StartCapture()).Times(0);
EXPECT_CALL(mock_client_, StopCapture()).Times(AnyNumber());
capture_driver_.UpdateThumbnailVisibility(false);
capture_driver_.UpdatePageVisibility(true);
// Simulate a page loading from start to finish
capture_driver_.UpdatePageReadiness(
ThumbnailReadinessTracker::Readiness::kNotReady);
capture_driver_.SetCanCapture(true);
capture_driver_.UpdatePageReadiness(
ThumbnailReadinessTracker::Readiness::kReadyForInitialCapture);
capture_driver_.UpdatePageReadiness(
ThumbnailReadinessTracker::Readiness::kReadyForFinalCapture);
}
TEST_F(ThumbnailCaptureDriverTest, NoCaptureWhenPageAndThumbnailAreNotVisible) {
EXPECT_CALL(mock_client_, RequestCapture()).Times(0);
EXPECT_CALL(mock_client_, StartCapture()).Times(0);
EXPECT_CALL(mock_client_, StopCapture()).Times(AnyNumber());
capture_driver_.UpdateThumbnailVisibility(false);
capture_driver_.UpdatePageVisibility(false);
// Simulate a page loading from start to finish
capture_driver_.UpdatePageReadiness(
ThumbnailReadinessTracker::Readiness::kNotReady);
capture_driver_.SetCanCapture(true);
capture_driver_.UpdatePageReadiness(
ThumbnailReadinessTracker::Readiness::kReadyForInitialCapture);
capture_driver_.UpdatePageReadiness(
ThumbnailReadinessTracker::Readiness::kReadyForFinalCapture);
}
TEST_F(ThumbnailCaptureDriverTest, CaptureRequestedWhenPageReady) {
// StopCapture() can be called unnecessarily at first.
Expectation stop_capture =
EXPECT_CALL(mock_client_, StopCapture()).Times(AnyNumber());
// This test should not trigger capture.
EXPECT_CALL(mock_client_, StartCapture()).Times(0);
// The common use case is capturing a thumbnail for a background tab.
capture_driver_.UpdateThumbnailVisibility(true);
capture_driver_.UpdatePageVisibility(false);
// Page becomes sufficiently loaded for capture, but no further, and
// the client never reports it's ready to capture. This should trigger
// a RequestCapture() call but nothing more.
capture_driver_.UpdatePageReadiness(
ThumbnailReadinessTracker::Readiness::kNotReady);
// Ensure the RequestCapture() call is ordered before any StopCapture() calls.
EXPECT_CALL(mock_client_, RequestCapture()).Times(1).After(stop_capture);
capture_driver_.UpdatePageReadiness(
ThumbnailReadinessTracker::Readiness::kReadyForInitialCapture);
}
TEST_F(ThumbnailCaptureDriverTest, CapturesPageWhenPossible) {
{
InSequence s;
EXPECT_CALL(mock_client_, StopCapture()).Times(AnyNumber());
EXPECT_CALL(mock_client_, RequestCapture());
EXPECT_CALL(mock_client_, StartCapture());
}
// The common use case is capturing a thumbnail for a background tab.
capture_driver_.UpdateThumbnailVisibility(true);
capture_driver_.UpdatePageVisibility(false);
capture_driver_.UpdatePageReadiness(
ThumbnailReadinessTracker::Readiness::kNotReady);
capture_driver_.UpdatePageReadiness(
ThumbnailReadinessTracker::Readiness::kReadyForInitialCapture);
capture_driver_.SetCanCapture(true);
}
TEST_F(ThumbnailCaptureDriverTest, RequestCaptureEvenIfAbleEarlier) {
{
InSequence s;
EXPECT_CALL(mock_client_, StopCapture()).Times(AnyNumber());
EXPECT_CALL(mock_client_, RequestCapture());
EXPECT_CALL(mock_client_, StartCapture());
}
// The common use case is capturing a thumbnail for a background tab.
capture_driver_.UpdateThumbnailVisibility(true);
capture_driver_.UpdatePageVisibility(false);
capture_driver_.UpdatePageReadiness(
ThumbnailReadinessTracker::Readiness::kNotReady);
capture_driver_.SetCanCapture(true);
capture_driver_.UpdatePageReadiness(
ThumbnailReadinessTracker::Readiness::kReadyForInitialCapture);
}
TEST_F(ThumbnailCaptureDriverTest, RestartsCaptureWhenPossible) {
Expectation stop_capture =
EXPECT_CALL(mock_client_, StopCapture()).Times(AnyNumber());
// The common use case is capturing a thumbnail for a background tab.
capture_driver_.UpdateThumbnailVisibility(true);
capture_driver_.UpdatePageVisibility(false);
// Start capture, but then temporarily report we can't capture. When
// we're able again, we should get another StartCapture() call.
capture_driver_.UpdatePageReadiness(
ThumbnailReadinessTracker::Readiness::kNotReady);
Expectation request_capture =
EXPECT_CALL(mock_client_, RequestCapture()).Times(1).After(stop_capture);
capture_driver_.UpdatePageReadiness(
ThumbnailReadinessTracker::Readiness::kReadyForInitialCapture);
Expectation start_capture =
EXPECT_CALL(mock_client_, StartCapture()).Times(1).After(request_capture);
capture_driver_.SetCanCapture(true);
capture_driver_.SetCanCapture(false);
EXPECT_CALL(mock_client_, StartCapture()).Times(1).After(start_capture);
capture_driver_.SetCanCapture(true);
}
TEST_F(ThumbnailCaptureDriverTest, StopsOngoingCaptureWhenPageNoLongerReady) {
{
InSequence s;
EXPECT_CALL(mock_client_, StopCapture()).Times(AnyNumber());
EXPECT_CALL(mock_client_, RequestCapture());
EXPECT_CALL(mock_client_, StartCapture());
EXPECT_CALL(mock_client_, StopCapture());
}
// The common use case is capturing a thumbnail for a background tab.
capture_driver_.UpdateThumbnailVisibility(true);
capture_driver_.UpdatePageVisibility(false);
capture_driver_.UpdatePageReadiness(
ThumbnailReadinessTracker::Readiness::kNotReady);
capture_driver_.UpdatePageReadiness(
ThumbnailReadinessTracker::Readiness::kReadyForInitialCapture);
capture_driver_.SetCanCapture(true);
capture_driver_.UpdatePageReadiness(
ThumbnailReadinessTracker::Readiness::kNotReady);
}
TEST_F(ThumbnailCaptureDriverTest, ContinuesCaptureWhenPageBecomesFinal) {
{
InSequence s;
EXPECT_CALL(mock_client_, StopCapture()).Times(AnyNumber());
EXPECT_CALL(mock_client_, RequestCapture());
EXPECT_CALL(mock_client_, StartCapture());
}
// The common use case is capturing a thumbnail for a background tab.
capture_driver_.UpdateThumbnailVisibility(true);
capture_driver_.UpdatePageVisibility(false);
capture_driver_.UpdatePageReadiness(
ThumbnailReadinessTracker::Readiness::kNotReady);
capture_driver_.UpdatePageReadiness(
ThumbnailReadinessTracker::Readiness::kReadyForInitialCapture);
capture_driver_.SetCanCapture(true);
capture_driver_.UpdatePageReadiness(
ThumbnailReadinessTracker::Readiness::kReadyForFinalCapture);
}
TEST_F(ThumbnailCaptureDriverTest, StopsCaptureOnFinalFrame) {
{
InSequence s;
EXPECT_CALL(mock_client_, StopCapture()).Times(AnyNumber());
EXPECT_CALL(mock_client_, RequestCapture());
EXPECT_CALL(mock_client_, StartCapture());
EXPECT_CALL(mock_client_, StopCapture());
}
// The common use case is capturing a thumbnail for a background tab.
capture_driver_.UpdateThumbnailVisibility(true);
capture_driver_.UpdatePageVisibility(false);
capture_driver_.UpdatePageReadiness(
ThumbnailReadinessTracker::Readiness::kNotReady);
capture_driver_.UpdatePageReadiness(
ThumbnailReadinessTracker::Readiness::kReadyForInitialCapture);
capture_driver_.SetCanCapture(true);
capture_driver_.UpdatePageReadiness(
ThumbnailReadinessTracker::Readiness::kReadyForFinalCapture);
capture_driver_.GotFrame();
task_environment_.FastForwardBy(ThumbnailCaptureDriver::kCooldownDelay);
}
TEST_F(ThumbnailCaptureDriverTest, RetriesWithinLimits) {
{
InSequence s;
EXPECT_CALL(mock_client_, StopCapture()).Times(AnyNumber());
EXPECT_CALL(mock_client_, RequestCapture());
EXPECT_CALL(mock_client_, StartCapture());
}
// The common use case is capturing a thumbnail for a background tab.
capture_driver_.UpdateThumbnailVisibility(true);
capture_driver_.UpdatePageVisibility(false);
capture_driver_.UpdatePageReadiness(
ThumbnailReadinessTracker::Readiness::kNotReady);
capture_driver_.UpdatePageReadiness(
ThumbnailReadinessTracker::Readiness::kReadyForInitialCapture);
capture_driver_.SetCanCapture(true);
capture_driver_.UpdatePageReadiness(
ThumbnailReadinessTracker::Readiness::kReadyForFinalCapture);
task_environment_.FastForwardBy(ThumbnailCaptureDriver::kMaxCooldownRetries *
ThumbnailCaptureDriver::kCooldownDelay);
}
TEST_F(ThumbnailCaptureDriverTest, StopsCaptureAtRetryLimit) {
{
InSequence s;
EXPECT_CALL(mock_client_, StopCapture()).Times(AnyNumber());
EXPECT_CALL(mock_client_, RequestCapture());
EXPECT_CALL(mock_client_, StartCapture());
EXPECT_CALL(mock_client_, StopCapture());
}
// The common use case is capturing a thumbnail for a background tab.
capture_driver_.UpdateThumbnailVisibility(true);
capture_driver_.UpdatePageVisibility(false);
capture_driver_.UpdatePageReadiness(
ThumbnailReadinessTracker::Readiness::kNotReady);
capture_driver_.UpdatePageReadiness(
ThumbnailReadinessTracker::Readiness::kReadyForInitialCapture);
capture_driver_.SetCanCapture(true);
capture_driver_.UpdatePageReadiness(
ThumbnailReadinessTracker::Readiness::kReadyForFinalCapture);
task_environment_.FastForwardBy(
(1 + ThumbnailCaptureDriver::kMaxCooldownRetries) *
ThumbnailCaptureDriver::kCooldownDelay);
}