blob: 7df485ae4584915e7d06cbae506a9001f28ec68c [file] [log] [blame]
// Copyright 2018 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/resource_coordinator/tab_load_tracker_test_support.h"
#include "base/run_loop.h"
#if !defined(OS_ANDROID)
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#endif
namespace resource_coordinator {
namespace {
using LoadingState = TabLoadTracker::LoadingState;
enum class WaitForEvent { NO_LONGER_TRACKED };
class WaitForLoadingStateHelper : public TabLoadTracker::Observer {
public:
// Configures this helper to wait until the tab reaches the provided loading
// state.
WaitForLoadingStateHelper(content::WebContents* waiting_for_contents,
LoadingState waiting_for_state)
: waiting_for_contents_(waiting_for_contents),
waiting_for_state_(waiting_for_state),
waiting_for_no_longer_tracked_(false),
wait_successful_(false) {}
// Configures this helper to wait until the tab is no longer tracked.
WaitForLoadingStateHelper(content::WebContents* waiting_for_contents,
WaitForEvent no_longer_tracked_unused)
: waiting_for_contents_(waiting_for_contents),
waiting_for_state_(LoadingState::UNLOADED),
waiting_for_no_longer_tracked_(true),
wait_successful_(false) {}
#if !defined(OS_ANDROID)
// Configures this helper to wait until all tabs in |tab_strip_model| are have
// transitionned to |state|.
WaitForLoadingStateHelper(TabStripModel* waiting_for_tab_strip,
LoadingState waiting_for_state)
: waiting_for_tab_strip_(waiting_for_tab_strip),
waiting_for_state_(waiting_for_state),
waiting_for_no_longer_tracked_(false),
wait_successful_(false) {}
#endif // !defined(OS_ANDROID)
~WaitForLoadingStateHelper() override = default;
bool Wait() {
wait_successful_ = false;
auto* tracker = resource_coordinator::TabLoadTracker::Get();
// Early exit if the contents is already in the desired state.
if (!waiting_for_no_longer_tracked_ && AllContentsReachedState()) {
wait_successful_ = true;
return wait_successful_;
}
tracker->AddObserver(this);
base::RunLoop run_loop;
run_loop_quit_closure_ = run_loop.QuitClosure();
run_loop.Run();
tracker->RemoveObserver(this);
return wait_successful_;
}
protected:
bool AllContentsReachedState() const {
DCHECK(!waiting_for_no_longer_tracked_);
auto* tracker = resource_coordinator::TabLoadTracker::Get();
if (waiting_for_contents_) {
return tracker->GetLoadingState(waiting_for_contents_) ==
waiting_for_state_;
}
#if defined(OS_ANDROID)
return false;
#else
DCHECK(waiting_for_tab_strip_);
for (int i = 0; i < waiting_for_tab_strip_->count(); ++i) {
if (tracker->GetLoadingState(waiting_for_tab_strip_->GetWebContentsAt(
i)) != waiting_for_state_) {
return false;
}
}
return true;
#endif // defined(OS_ANDROID)
}
void OnLoadingStateChange(content::WebContents* web_contents,
LoadingState old_loading_state,
LoadingState new_loading_state) override {
if (waiting_for_no_longer_tracked_)
return;
if (AllContentsReachedState()) {
wait_successful_ = true;
run_loop_quit_closure_.Run();
}
}
void OnStopTracking(content::WebContents* web_contents,
LoadingState loading_state) override {
if (waiting_for_contents_ != web_contents)
return;
if (waiting_for_no_longer_tracked_) {
wait_successful_ = true;
} else if (waiting_for_contents_) {
wait_successful_ = (waiting_for_state_ == loading_state);
} else {
#if defined(OS_ANDROID)
NOTREACHED();
#else
DCHECK(waiting_for_tab_strip_);
wait_successful_ = AllContentsReachedState();
#endif // defined(OS_ANDROID)
}
run_loop_quit_closure_.Run();
}
private:
// The WebContents or TabStripModel and state that is being waited for.
content::WebContents* const waiting_for_contents_ = nullptr;
#if !defined(OS_ANDROID)
TabStripModel* const waiting_for_tab_strip_ = nullptr;
#endif
const LoadingState waiting_for_state_;
const bool waiting_for_no_longer_tracked_;
// Returns true if the wait was successful. This can be false if the contents
// stops being tracked (is destroyed) before encountering the desired state.
bool wait_successful_;
base::Closure run_loop_quit_closure_;
DISALLOW_COPY_AND_ASSIGN(WaitForLoadingStateHelper);
};
} // namespace
bool WaitForTransitionToLoadingState(content::WebContents* contents,
LoadingState loading_state) {
WaitForLoadingStateHelper waiter(contents, loading_state);
return waiter.Wait();
}
bool WaitForTransitionToUnloaded(content::WebContents* contents) {
return WaitForTransitionToLoadingState(contents, LoadingState::UNLOADED);
}
bool WaitForTransitionToLoading(content::WebContents* contents) {
return WaitForTransitionToLoadingState(contents, LoadingState::LOADING);
}
bool WaitForTransitionToLoaded(content::WebContents* contents) {
return WaitForTransitionToLoadingState(contents, LoadingState::LOADED);
}
bool WaitUntilNoLongerTracked(content::WebContents* contents) {
WaitForLoadingStateHelper waiter(contents, WaitForEvent::NO_LONGER_TRACKED);
return waiter.Wait();
}
#if !defined(OS_ANDROID)
bool WaitForTransitionToLoadingState(TabStripModel* tab_strip,
LoadingState loading_state) {
WaitForLoadingStateHelper waiter(tab_strip, loading_state);
return waiter.Wait();
}
bool WaitForTransitionToUnloaded(TabStripModel* tab_strip) {
return WaitForTransitionToLoadingState(tab_strip, LoadingState::UNLOADED);
}
bool WaitForTransitionToLoading(TabStripModel* tab_strip) {
return WaitForTransitionToLoadingState(tab_strip, LoadingState::LOADING);
}
bool WaitForTransitionToLoaded(TabStripModel* tab_strip) {
return WaitForTransitionToLoadingState(tab_strip, LoadingState::LOADED);
}
#endif // !defined(OS_ANDROID)
} // namespace resource_coordinator