blob: f3d75d77d6f6a62b7ebf78c44f1b009de2825810 [file] [log] [blame]
// Copyright 2016 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 "core/timing/Performance.h"
#include "core/frame/PerformanceMonitor.h"
#include "core/loader/DocumentLoadTiming.h"
#include "core/loader/DocumentLoader.h"
#include "core/testing/DummyPageHolder.h"
#include "core/timing/DOMWindowPerformance.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace blink {
class PerformanceTest : public ::testing::Test {
protected:
void SetUp() override {
page_holder_ = DummyPageHolder::Create(IntSize(800, 600));
page_holder_->GetDocument().SetURL(KURL(KURL(), "https://example.com"));
performance_ = Performance::Create(&page_holder_->GetFrame());
// Create another dummy page holder and pretend this is the iframe.
another_page_holder_ = DummyPageHolder::Create(IntSize(400, 300));
another_page_holder_->GetDocument().SetURL(
KURL(KURL(), "https://iframed.com/bar"));
}
bool ObservingLongTasks() {
return PerformanceMonitor::InstrumentingMonitor(
performance_->GetExecutionContext());
}
void AddLongTaskObserver() {
// simulate with filter options.
performance_->observer_filter_options_ |= PerformanceEntry::kLongTask;
}
void RemoveLongTaskObserver() {
// simulate with filter options.
performance_->observer_filter_options_ = PerformanceEntry::kInvalid;
}
void SimulateDidProcessLongTask() {
auto* monitor = GetFrame()->GetPerformanceMonitor();
monitor->WillExecuteScript(GetDocument());
monitor->DidExecuteScript();
monitor->DidProcessTask(nullptr, 0, 1);
}
LocalFrame* GetFrame() const { return &page_holder_->GetFrame(); }
Document* GetDocument() const { return &page_holder_->GetDocument(); }
LocalFrame* AnotherFrame() const { return &another_page_holder_->GetFrame(); }
Document* AnotherDocument() const {
return &another_page_holder_->GetDocument();
}
String SanitizedAttribution(ExecutionContext* context,
bool has_multiple_contexts,
LocalFrame* observer_frame) {
return Performance::SanitizedAttribution(context, has_multiple_contexts,
observer_frame)
.first;
}
Persistent<Performance> performance_;
std::unique_ptr<DummyPageHolder> page_holder_;
std::unique_ptr<DummyPageHolder> another_page_holder_;
};
TEST_F(PerformanceTest, LongTaskObserverInstrumentation) {
performance_->UpdateLongTaskInstrumentation();
EXPECT_FALSE(ObservingLongTasks());
// Adding LongTask observer (with filer option) enables instrumentation.
AddLongTaskObserver();
performance_->UpdateLongTaskInstrumentation();
EXPECT_TRUE(ObservingLongTasks());
// Removing LongTask observer disables instrumentation.
RemoveLongTaskObserver();
performance_->UpdateLongTaskInstrumentation();
EXPECT_FALSE(ObservingLongTasks());
}
TEST_F(PerformanceTest, SanitizedLongTaskName) {
// Unable to attribute, when no execution contents are available.
EXPECT_EQ("unknown", SanitizedAttribution(nullptr, false, GetFrame()));
// Attribute for same context (and same origin).
EXPECT_EQ("self", SanitizedAttribution(GetDocument(), false, GetFrame()));
// Unable to attribute, when multiple script execution contents are involved.
EXPECT_EQ("multiple-contexts",
SanitizedAttribution(GetDocument(), true, GetFrame()));
}
TEST_F(PerformanceTest, SanitizedLongTaskName_CrossOrigin) {
// Unable to attribute, when no execution contents are available.
EXPECT_EQ("unknown", SanitizedAttribution(nullptr, false, GetFrame()));
// Attribute for same context (and same origin).
EXPECT_EQ("cross-origin-unreachable",
SanitizedAttribution(AnotherDocument(), false, GetFrame()));
}
// https://crbug.com/706798: Checks that after navigation that have replaced the
// window object, calls to not garbage collected yet Performance belonging to
// the old window do not cause a crash.
TEST_F(PerformanceTest, NavigateAway) {
AddLongTaskObserver();
performance_->UpdateLongTaskInstrumentation();
EXPECT_TRUE(ObservingLongTasks());
// Simulate navigation commit.
DocumentInit init(KURL(), GetFrame());
GetDocument()->Shutdown();
GetFrame()->SetDOMWindow(LocalDOMWindow::Create(*GetFrame()));
GetFrame()->DomWindow()->InstallNewDocument(AtomicString(), init);
// m_performance is still alive, and should not crash when notified.
SimulateDidProcessLongTask();
}
// Checks that Performance object and its fields (like PerformanceTiming)
// function correctly after transition to another document in the same window.
// This happens when a page opens a new window and it navigates to a same-origin
// document.
TEST(PerformanceLifetimeTest, SurviveContextSwitch) {
std::unique_ptr<DummyPageHolder> page_holder =
DummyPageHolder::Create(IntSize(800, 600));
Performance* perf =
DOMWindowPerformance::performance(*page_holder->GetFrame().DomWindow());
PerformanceTiming* timing = perf->timing();
auto* document_loader = page_holder->GetFrame().Loader().GetDocumentLoader();
ASSERT_TRUE(document_loader);
document_loader->GetTiming().SetNavigationStart(
MonotonicallyIncreasingTime());
EXPECT_EQ(&page_holder->GetFrame(), perf->GetFrame());
EXPECT_EQ(&page_holder->GetFrame(), timing->GetFrame());
auto navigation_start = timing->navigationStart();
EXPECT_NE(0U, navigation_start);
// Simulate changing the document while keeping the window.
page_holder->GetDocument().Shutdown();
page_holder->GetFrame().DomWindow()->InstallNewDocument(
AtomicString(), DocumentInit(KURL(), &page_holder->GetFrame()));
EXPECT_EQ(perf, DOMWindowPerformance::performance(
*page_holder->GetFrame().DomWindow()));
EXPECT_EQ(timing, perf->timing());
EXPECT_EQ(&page_holder->GetFrame(), perf->GetFrame());
EXPECT_EQ(&page_holder->GetFrame(), timing->GetFrame());
EXPECT_EQ(navigation_start, timing->navigationStart());
}
}