// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <cstdint>
#include <memory>
#include <utility>
#include "base/check_deref.h"
#include "base/test/bind.h"
#include "base/test/test_future.h"
#include "chrome/browser/chromeos/extensions/telemetry/api/common/base_telemetry_extension_browser_test.h"
#include "chrome/browser/chromeos/extensions/telemetry/api/routines/fake_diagnostic_routines_service.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/test/base/ui_test_utils.h"
#include "chromeos/crosapi/mojom/telemetry_diagnostic_routine_service.mojom.h"
#include "chromeos/crosapi/mojom/telemetry_extension_exception.mojom.h"
#include "content/public/test/browser_test.h"
#include "extensions/common/extension_features.h"
#include "testing/gtest/include/gtest/gtest.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "chrome/browser/chromeos/extensions/telemetry/api/routines/fake_diagnostic_routines_service_factory.h"
#include "chromeos/ash/components/telemetry_extension/routines/telemetry_diagnostic_routine_service_ash.h"
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
#if BUILDFLAG(IS_CHROMEOS_LACROS)
#include "chromeos/lacros/lacros_service.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#endif // BUILDFLAG(IS_CHROMEOS_LACROS)
namespace chromeos {
namespace {
namespace crosapi = ::crosapi::mojom;
} // namespace
class TelemetryExtensionDiagnosticsApiV2BrowserTest
: public BaseTelemetryExtensionBrowserTest {
public:
TelemetryExtensionDiagnosticsApiV2BrowserTest() = default;
~TelemetryExtensionDiagnosticsApiV2BrowserTest() override = default;
TelemetryExtensionDiagnosticsApiV2BrowserTest(
const TelemetryExtensionDiagnosticsApiV2BrowserTest&) = delete;
TelemetryExtensionDiagnosticsApiV2BrowserTest& operator=(
const TelemetryExtensionDiagnosticsApiV2BrowserTest&) = delete;
void SetUpOnMainThread() override {
BaseTelemetryExtensionBrowserTest::SetUpOnMainThread();
#if BUILDFLAG(IS_CHROMEOS_ASH)
fake_routines_service_ = new FakeDiagnosticRoutinesService();
fake_routines_service_factory_.SetCreateInstanceResponse(
std::unique_ptr<FakeDiagnosticRoutinesService>(
fake_routines_service_.get()));
ash::TelemetryDiagnosticsRoutineServiceAsh::Factory::SetForTesting(
&fake_routines_service_factory_);
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
#if BUILDFLAG(IS_CHROMEOS_LACROS)
fake_routines_service_ = std::make_unique<FakeDiagnosticRoutinesService>();
// Replace the production RoutineService with a fake for testing.
chromeos::LacrosService::Get()->InjectRemoteForTesting(
fake_routines_service_->receiver().BindNewPipeAndPassRemote());
#endif // BUILDFLAG(IS_CHROMEOS_LACROS)
}
void TearDownOnMainThread() override {
#if BUILDFLAG(IS_CHROMEOS_ASH)
fake_routines_service_ = nullptr;
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
BaseTelemetryExtensionBrowserTest::TearDownOnMainThread();
}
protected:
FakeDiagnosticRoutinesService& fake_service() {
return CHECK_DEREF(fake_routines_service_.get());
}
private:
#if BUILDFLAG(IS_CHROMEOS_ASH)
raw_ptr<FakeDiagnosticRoutinesService> fake_routines_service_;
FakeDiagnosticRoutinesServiceFactory fake_routines_service_factory_;
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
#if BUILDFLAG(IS_CHROMEOS_LACROS)
std::unique_ptr<FakeDiagnosticRoutinesService> fake_routines_service_;
#endif // BUILDFLAG(IS_CHROMEOS_LACROS)
};
IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticsApiV2BrowserTest,
IsRoutineArgSupportedParseArgumentsError) {
OpenAppUiAndMakeItSecure();
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function isRoutineArgSupported() {
await chrome.test.assertPromiseRejects(
chrome.os.diagnostics.isRoutineArgumentSupported({
memory: {
maxTestingMemKib: -1,
},
}),
'Error: Routine arguments are invalid.'
);
chrome.test.succeed();
}
]);
)");
}
IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticsApiV2BrowserTest,
IsRoutineArgSupportedInvalidArguments) {
OpenAppUiAndMakeItSecure();
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function isRoutineArgSupported() {
await chrome.test.assertPromiseRejects(
chrome.os.diagnostics.isRoutineArgumentSupported({
memory: {},
fan: {},
}),
'Error: Routine arguments are invalid.'
);
chrome.test.succeed();
}
]);
)");
}
IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticsApiV2BrowserTest,
IsRoutineArgSupportedApiInternalError) {
fake_service().SetIsRoutineArgumentSupportedResponse(
crosapi::TelemetryExtensionSupportStatus::NewUnmappedUnionField(0));
OpenAppUiAndMakeItSecure();
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function isRoutineArgSupported() {
await chrome.test.assertPromiseRejects(
chrome.os.diagnostics.isRoutineArgumentSupported({
memory: {},
}),
'Error: API internal error.'
);
chrome.test.succeed();
}
]);
)");
}
IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticsApiV2BrowserTest,
IsRoutineArgSupportedException) {
auto exception = crosapi::TelemetryExtensionException::New();
exception->debug_message = "TEST_MESSAGE";
fake_service().SetIsRoutineArgumentSupportedResponse(
crosapi::TelemetryExtensionSupportStatus::NewException(
std::move(exception)));
OpenAppUiAndMakeItSecure();
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function isRoutineArgSupported() {
await chrome.test.assertPromiseRejects(
chrome.os.diagnostics.isRoutineArgumentSupported({
memory: {},
}),
'Error: TEST_MESSAGE'
);
chrome.test.succeed();
}
]);
)");
}
IN_PROC_BROWSER_TEST_F(
TelemetryExtensionDiagnosticsApiV2BrowserTest,
IsRoutineArgSupportedSuccessWithUnrecognizedRoutineName) {
fake_service().SetIsRoutineArgumentSupportedResponse(
crosapi::TelemetryExtensionSupportStatus::NewUnsupported(
crosapi::TelemetryExtensionUnsupported::New("TEST_MESSAGE",
/*reason=*/nullptr)));
OpenAppUiAndMakeItSecure();
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function isRoutineArgSupported() {
const result = await chrome.os.diagnostics.isRoutineArgumentSupported({
newRoutine: {}
});
chrome.test.assertEq(result.status, 'unsupported');
chrome.test.succeed();
}
]);
)");
}
IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticsApiV2BrowserTest,
IsRoutineArgSupportedSuccess) {
fake_service().SetIsRoutineArgumentSupportedResponse(
crosapi::TelemetryExtensionSupportStatus::NewSupported(
crosapi::TelemetryExtensionSupported::New()));
OpenAppUiAndMakeItSecure();
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function isRoutineArgSupported() {
const result = await chrome.os.diagnostics.isRoutineArgumentSupported({
memory: {}
});
chrome.test.assertEq(result.status, 'supported');
chrome.test.succeed();
}
]);
)");
}
IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticsApiV2BrowserTest,
CreateRoutineInvalidArguments) {
OpenAppUiAndMakeItSecure();
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function createRoutineFail() {
await chrome.test.assertPromiseRejects(
chrome.os.diagnostics.createRoutine({
memory: {},
fan: {},
}),
'Error: Routine arguments are invalid.'
);
chrome.test.succeed();
}
]);
)");
}
IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticsApiV2BrowserTest,
CreateRoutineSuccessWithUnrecognizedRoutineName) {
OpenAppUiAndMakeItSecure();
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function createUnrecognizedRoutine() {
const result = await chrome.os.diagnostics.createRoutine({
newRoutine: {},
});
chrome.test.assertTrue(result !== undefined);
chrome.test.succeed();
}
]);
)");
}
IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticsApiV2BrowserTest,
CreateRoutineParseArgumentsError) {
OpenAppUiAndMakeItSecure();
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function createRoutineFail() {
await chrome.test.assertPromiseRejects(
chrome.os.diagnostics.createRoutine({
memory: {
maxTestingMemKib: -1,
},
}),
'Error: Routine arguments are invalid.'
);
chrome.test.succeed();
}
]);
)");
}
IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticsApiV2BrowserTest,
CreateRoutineCompanionUiNotOpenError) {
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function createRoutineFail() {
await chrome.test.assertPromiseRejects(
chrome.os.diagnostics.createRoutine({
memory: {}
}),
'Error: Companion app UI is not open.'
);
chrome.test.succeed();
}
]);
)");
}
IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticsApiV2BrowserTest,
CreateRoutineSuccess) {
OpenAppUiAndMakeItSecure();
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function createRoutine() {
let resolver;
// Set later once the routine was created.
var uuid = new Promise((resolve) => {
resolver = resolve;
});
chrome.os.diagnostics.onRoutineInitialized.addListener(
async (status) => {
chrome.test.assertEq(status.uuid, await uuid);
chrome.test.succeed();
});
const response = await chrome.os.diagnostics.createRoutine({
memory: {},
});
chrome.test.assertTrue(response !== undefined);
resolver(response.uuid);
}
]);
)");
}
IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticsApiV2BrowserTest,
LegacyCreateMemoryRoutineCompanionUiNotOpenError) {
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function createMemoryRoutineFail() {
await chrome.test.assertPromiseRejects(
chrome.os.diagnostics.createMemoryRoutine({
maxTestingMemKib: 42,
}),
'Error: Companion app UI is not open.'
);
chrome.test.succeed();
}
]);
)");
}
IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticsApiV2BrowserTest,
CreateRoutineResetConnectionResultsInException) {
fake_service().SetOnCreateRoutineCalled(base::BindLambdaForTesting([this]() {
auto* control = fake_service().GetCreatedRoutineControlForRoutineType(
crosapi::TelemetryDiagnosticRoutineArgument::Tag::kMemory);
ASSERT_TRUE(control);
control->receiver().ResetWithReason(
static_cast<uint32_t>(
crosapi::TelemetryExtensionException::Reason::kUnsupported),
"test message");
}));
OpenAppUiAndMakeItSecure();
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function createMemoryRoutineResetConnection() {
let resolver;
// Set later once the routine was created.
var uuid = new Promise((resolve) => {
resolver = resolve;
});
chrome.os.diagnostics.onRoutineException.addListener(async (status) => {
chrome.test.assertEq(status, {
"uuid": await uuid,
"reason": "unsupported",
"debugMessage": "test message"
});
chrome.test.succeed();
});
const response = await chrome.os.diagnostics.createMemoryRoutine({
maxTestingMemKib: 42,
});
chrome.test.assertTrue(response !== undefined);
resolver(response.uuid);
}
]);
)");
}
IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticsApiV2BrowserTest,
FinishedRoutineIsRemovedSuccess) {
fake_service().SetOnCreateRoutineCalled(base::BindLambdaForTesting([this]() {
auto* control = fake_service().GetCreatedRoutineControlForRoutineType(
crosapi::TelemetryDiagnosticRoutineArgument::Tag::kMemory);
ASSERT_TRUE(control);
auto mem_detail = crosapi::TelemetryDiagnosticMemoryRoutineDetail::New();
mem_detail->result = crosapi::TelemetryDiagnosticMemtesterResult::New();
auto finished_state =
crosapi::TelemetryDiagnosticRoutineStateFinished::New();
finished_state->detail =
crosapi::TelemetryDiagnosticRoutineDetail::NewMemory(
std::move(mem_detail));
finished_state->has_passed = true;
auto state = crosapi::TelemetryDiagnosticRoutineState::New();
state->state_union =
crosapi::TelemetryDiagnosticRoutineStateUnion::NewFinished(
std::move(finished_state));
control->SetState(std::move(state));
}));
OpenAppUiAndMakeItSecure();
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function createMemoryRoutine() {
let uuid_resolver;
let finished_resolver;
// Set later once the routine was created.
var uuid = new Promise((resolve) => {
uuid_resolver = resolve;
});
var on_finished = new Promise((resolve) => {
finished_resolver = resolve;
});
// Only resolve the test once we got the final event.
chrome.os.diagnostics.onMemoryRoutineFinished.addListener(
async (status) => {
chrome.test.assertEq(status.uuid, await uuid);
finished_resolver();
});
const response = await chrome.os.diagnostics.createMemoryRoutine({
maxTestingMemKib: 42,
});
chrome.test.assertTrue(response !== undefined);
uuid_resolver(response.uuid);
await on_finished;
// Test that we were successful by starting again and failing.
await chrome.test.assertPromiseRejects(
chrome.os.diagnostics.startRoutine({
uuid: response.uuid,
}),
'Error: Unknown routine id.'
);
chrome.test.succeed();
}
]);
)");
}
IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticsApiV2BrowserTest,
ClosingAppUiResultsInException) {
fake_service().SetOnCreateRoutineCalled(base::BindLambdaForTesting([this]() {
// Closing the tab results in an exception.
ASSERT_TRUE(browser()->tab_strip_model()->ContainsIndex(0));
browser()->tab_strip_model()->CloseWebContentsAt(0,
TabCloseTypes::CLOSE_NONE);
}));
OpenAppUiAndMakeItSecure();
// Open a second tab so that we don't close the browser.
ASSERT_TRUE(ui_test_utils::NavigateToURLWithDisposition(
browser(), GURL("chrome://version"),
WindowOpenDisposition::NEW_FOREGROUND_TAB,
ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP));
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function closingAppUiResultsInException() {
chrome.os.diagnostics.onRoutineException.addListener(async (status) => {
chrome.test.assertEq(status, {
"reason": "app_ui_closed",
});
chrome.test.succeed();
});
const response = await chrome.os.diagnostics.createMemoryRoutine({
maxTestingMemKib: 42,
});
chrome.test.assertTrue(response !== undefined);
}
]);
)");
}
IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticsApiV2BrowserTest,
LegacyCreateMemoryRoutineSuccess) {
fake_service().SetOnCreateRoutineCalled(base::BindLambdaForTesting([this]() {
auto* control = fake_service().GetCreatedRoutineControlForRoutineType(
crosapi::TelemetryDiagnosticRoutineArgument::Tag::kMemory);
ASSERT_TRUE(control);
auto memtester_result = crosapi::TelemetryDiagnosticMemtesterResult::New();
memtester_result->passed_items = {
crosapi::TelemetryDiagnosticMemtesterTestItemEnum::kSixteenBitWrites};
memtester_result->failed_items = {
crosapi::TelemetryDiagnosticMemtesterTestItemEnum::kEightBitWrites};
auto memory_detail = crosapi::TelemetryDiagnosticMemoryRoutineDetail::New();
memory_detail->bytes_tested = 42;
memory_detail->result = std::move(memtester_result);
auto finished_state =
crosapi::TelemetryDiagnosticRoutineStateFinished::New();
finished_state->detail =
crosapi::TelemetryDiagnosticRoutineDetail::NewMemory(
std::move(memory_detail));
finished_state->has_passed = true;
auto state = crosapi::TelemetryDiagnosticRoutineState::New();
state->state_union =
crosapi::TelemetryDiagnosticRoutineStateUnion::NewFinished(
std::move(finished_state));
control->SetState(std::move(state));
}));
OpenAppUiAndMakeItSecure();
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function createMemoryRoutine() {
let resolver;
// Set later once the routine was created.
var uuid = new Promise((resolve) => {
resolver = resolve;
});
let onInitCalled = false;
chrome.os.diagnostics.onRoutineInitialized.addListener(
async (status) => {
chrome.test.assertEq(status.uuid, await uuid);
onInitCalled = true;
});
// Only resolve the test once we got the final event.
chrome.os.diagnostics.onMemoryRoutineFinished.addListener(
async (status) => {
chrome.test.assertEq(status, {
"bytesTested": 42,
"has_passed": true,
"result": {
"failed_items": ["eight_bit_writes"],
"passed_items": ["sixteen_bit_writes"]
},
"uuid": await uuid,
});
chrome.test.assertTrue(onInitCalled);
chrome.test.succeed();
});
const response = await chrome.os.diagnostics.createMemoryRoutine({
maxTestingMemKib: 42,
});
chrome.test.assertTrue(response !== undefined);
resolver(response.uuid);
}
]);
)");
}
IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticsApiV2BrowserTest,
LegacyCreateMemoryRoutineNoOptionalConfigSuccess) {
fake_service().SetOnCreateRoutineCalled(base::BindLambdaForTesting([this]() {
auto* control = fake_service().GetCreatedRoutineControlForRoutineType(
crosapi::TelemetryDiagnosticRoutineArgument::Tag::kMemory);
ASSERT_TRUE(control);
auto memtester_result = crosapi::TelemetryDiagnosticMemtesterResult::New();
memtester_result->passed_items = {
crosapi::TelemetryDiagnosticMemtesterTestItemEnum::kSixteenBitWrites};
memtester_result->failed_items = {
crosapi::TelemetryDiagnosticMemtesterTestItemEnum::kEightBitWrites};
auto memory_detail = crosapi::TelemetryDiagnosticMemoryRoutineDetail::New();
memory_detail->bytes_tested = 42;
memory_detail->result = std::move(memtester_result);
auto finished_state =
crosapi::TelemetryDiagnosticRoutineStateFinished::New();
finished_state->detail =
crosapi::TelemetryDiagnosticRoutineDetail::NewMemory(
std::move(memory_detail));
finished_state->has_passed = true;
auto state = crosapi::TelemetryDiagnosticRoutineState::New();
state->state_union =
crosapi::TelemetryDiagnosticRoutineStateUnion::NewFinished(
std::move(finished_state));
control->SetState(std::move(state));
}));
OpenAppUiAndMakeItSecure();
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function createMemoryRoutine() {
let resolver;
// Set later once the routine was created.
var uuid = new Promise((resolve) => {
resolver = resolve;
});
let onInitCalled = false;
chrome.os.diagnostics.onRoutineInitialized.addListener(
async (status) => {
chrome.test.assertEq(status.uuid, await uuid);
onInitCalled = true;
});
// Only resolve the test once we got the final event.
chrome.os.diagnostics.onMemoryRoutineFinished.addListener(
async (status) => {
chrome.test.assertEq(status, {
"bytesTested": 42,
"has_passed": true,
"result": {
"failed_items": ["eight_bit_writes"],
"passed_items": ["sixteen_bit_writes"]
},
"uuid": await uuid,
});
chrome.test.assertTrue(onInitCalled);
chrome.test.succeed();
});
const response = await chrome.os.diagnostics.createMemoryRoutine({});
chrome.test.assertTrue(response !== undefined);
resolver(response.uuid);
}
]);
)");
}
IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticsApiV2BrowserTest,
StartRoutineUnknownUuidError) {
OpenAppUiAndMakeItSecure();
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function startRoutineFail() {
await chrome.test.assertPromiseRejects(
chrome.os.diagnostics.startRoutine({
uuid: '123',
}),
'Error: Unknown routine id.'
);
chrome.test.succeed();
}
]);
)");
}
IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticsApiV2BrowserTest,
StartRoutineSuccess) {
OpenAppUiAndMakeItSecure();
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function createMemoryRoutine() {
let resolver;
// Set later once the routine was created.
var uuid = new Promise((resolve) => {
resolver = resolve;
});
let onInitCalled = false;
chrome.os.diagnostics.onRoutineInitialized.addListener(
async (status) => {
chrome.test.assertEq(status.uuid, await uuid);
onInitCalled = true;
}
);
// Only resolve the test once we got the final event.
chrome.os.diagnostics.onRoutineRunning.addListener(
async (status) => {
chrome.test.assertEq(status.uuid, await uuid);
chrome.test.assertTrue(onInitCalled);
chrome.test.succeed();
}
);
const response = await chrome.os.diagnostics.createMemoryRoutine({
maxTestingMemKib: 42,
});
chrome.test.assertTrue(response !== undefined);
resolver(response.uuid);
await chrome.os.diagnostics.startRoutine({ uuid: response.uuid });
}
]);
)");
}
IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticsApiV2BrowserTest,
CancelRoutineSuccess) {
OpenAppUiAndMakeItSecure();
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function cancelRoutine() {
const response = await chrome.os.diagnostics.createMemoryRoutine({
maxTestingMemKib: 42,
});
chrome.test.assertTrue(response !== undefined);
// Start the routine.
await chrome.os.diagnostics.startRoutine({ uuid: response.uuid });
// Now cancel the routine.
await chrome.os.diagnostics.cancelRoutine({ uuid: response.uuid });
// Test that we were successful by starting again and failing.
await chrome.test.assertPromiseRejects(
chrome.os.diagnostics.startRoutine({
uuid: response.uuid,
}),
'Error: Unknown routine id.'
);
chrome.test.succeed();
}
]);
)");
}
IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticsApiV2BrowserTest,
LegacyIsMemoryRoutineArgSupportedApiInternalError) {
fake_service().SetIsRoutineArgumentSupportedResponse(
crosapi::TelemetryExtensionSupportStatus::NewUnmappedUnionField(0));
OpenAppUiAndMakeItSecure();
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function isMemoryRoutineArgSupported() {
await chrome.test.assertPromiseRejects(
chrome.os.diagnostics.isMemoryRoutineArgumentSupported({
maxTestingMemKib: 42,
}),
'Error: API internal error.'
);
chrome.test.succeed();
}
]);
)");
}
IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticsApiV2BrowserTest,
LegacyIsMemoryRoutineArgSupportedException) {
auto exception = crosapi::TelemetryExtensionException::New();
exception->debug_message = "TEST_MESSAGE";
fake_service().SetIsRoutineArgumentSupportedResponse(
crosapi::TelemetryExtensionSupportStatus::NewException(
std::move(exception)));
OpenAppUiAndMakeItSecure();
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function isMemoryRoutineArgSupported() {
await chrome.test.assertPromiseRejects(
chrome.os.diagnostics.isMemoryRoutineArgumentSupported({
maxTestingMemKib: 42,
}),
'Error: TEST_MESSAGE'
);
chrome.test.succeed();
}
]);
)");
}
IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticsApiV2BrowserTest,
LegacyIsMemoryRoutineArgSupportedSuccess) {
fake_service().SetIsRoutineArgumentSupportedResponse(
crosapi::TelemetryExtensionSupportStatus::NewSupported(
crosapi::TelemetryExtensionSupported::New()));
OpenAppUiAndMakeItSecure();
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function isMemoryRoutineArgSupported() {
const result = await chrome.os.diagnostics.
isMemoryRoutineArgumentSupported({
maxTestingMemKib: 42,
});
chrome.test.assertEq(result.status, 'supported');
chrome.test.succeed();
}
]);
)");
}
IN_PROC_BROWSER_TEST_F(
TelemetryExtensionDiagnosticsApiV2BrowserTest,
LegacyIsVolumeButtonRoutineArgSupportedApiInternalError) {
fake_service().SetIsRoutineArgumentSupportedResponse(
crosapi::TelemetryExtensionSupportStatus::NewUnmappedUnionField(0));
OpenAppUiAndMakeItSecure();
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function isVolumeButtonRoutineArgSupported() {
await chrome.test.assertPromiseRejects(
chrome.os.diagnostics.isVolumeButtonRoutineArgumentSupported({
button_type: "volume_up",
timeout_seconds: 10,
}),
'Error: API internal error.'
);
chrome.test.succeed();
}
]);
)");
}
IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticsApiV2BrowserTest,
LegacyIsVolumeButtonRoutineArgSupportedException) {
auto exception = crosapi::TelemetryExtensionException::New();
exception->debug_message = "TEST_MESSAGE";
fake_service().SetIsRoutineArgumentSupportedResponse(
crosapi::TelemetryExtensionSupportStatus::NewException(
std::move(exception)));
OpenAppUiAndMakeItSecure();
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function isVolumeButtonRoutineArgSupported() {
await chrome.test.assertPromiseRejects(
chrome.os.diagnostics.isVolumeButtonRoutineArgumentSupported({
button_type: "volume_up",
timeout_seconds: 10,
}),
'Error: TEST_MESSAGE'
);
chrome.test.succeed();
}
]);
)");
}
IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticsApiV2BrowserTest,
LegacyIsVolumeButtonRoutineArgSupportedSuccess) {
fake_service().SetIsRoutineArgumentSupportedResponse(
crosapi::TelemetryExtensionSupportStatus::NewSupported(
crosapi::TelemetryExtensionSupported::New()));
OpenAppUiAndMakeItSecure();
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function isVolumeButtonRoutineArgSupported() {
const result = await chrome.os.diagnostics.
isVolumeButtonRoutineArgumentSupported({
button_type: "volume_up",
timeout_seconds: 10,
});
chrome.test.assertEq(result.status, 'supported');
chrome.test.succeed();
}
]);
)");
}
IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticsApiV2BrowserTest,
LegacyCreateVolumeButtonRoutineCompanionUiNotOpenError) {
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function createVolumeButtonRoutineFail() {
await chrome.test.assertPromiseRejects(
chrome.os.diagnostics.createVolumeButtonRoutine({
button_type: "volume_up",
timeout_seconds: 10,
}),
'Error: Companion app UI is not open.'
);
chrome.test.succeed();
}
]);
)");
}
IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticsApiV2BrowserTest,
LegacyCreateVolumeButtonRoutineSuccess) {
fake_service().SetOnCreateRoutineCalled(base::BindLambdaForTesting([this]() {
auto* control = fake_service().GetCreatedRoutineControlForRoutineType(
crosapi::TelemetryDiagnosticRoutineArgument::Tag::kVolumeButton);
ASSERT_TRUE(control);
auto volume_button_detail =
crosapi::TelemetryDiagnosticVolumeButtonRoutineDetail::New();
auto finished_state =
crosapi::TelemetryDiagnosticRoutineStateFinished::New();
finished_state->detail =
crosapi::TelemetryDiagnosticRoutineDetail::NewVolumeButton(
std::move(volume_button_detail));
finished_state->has_passed = true;
auto state = crosapi::TelemetryDiagnosticRoutineState::New();
state->state_union =
crosapi::TelemetryDiagnosticRoutineStateUnion::NewFinished(
std::move(finished_state));
control->SetState(std::move(state));
}));
OpenAppUiAndMakeItSecure();
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function createVolumeButtonRoutine() {
let resolver;
// Set later once the routine was created.
var uuid = new Promise((resolve) => {
resolver = resolve;
});
let onInitCalled = false;
chrome.os.diagnostics.onRoutineInitialized.addListener(
async (status) => {
chrome.test.assertEq(status.uuid, await uuid);
onInitCalled = true;
});
// Only resolve the test once we got the final event.
chrome.os.diagnostics.onVolumeButtonRoutineFinished.addListener(
async (status) => {
chrome.test.assertEq(status, {
"has_passed": true,
"uuid": await uuid,
});
chrome.test.assertTrue(onInitCalled);
chrome.test.succeed();
});
const response = await chrome.os.diagnostics.createVolumeButtonRoutine({
button_type: "volume_up",
timeout_seconds: 10,
});
chrome.test.assertTrue(response !== undefined);
resolver(response.uuid);
}
]);
)");
}
IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticsApiV2BrowserTest,
LegacyIsFanRoutineArgSupportedApiInternalError) {
fake_service().SetIsRoutineArgumentSupportedResponse(
crosapi::TelemetryExtensionSupportStatus::NewUnmappedUnionField(0));
OpenAppUiAndMakeItSecure();
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function isFanRoutineArgSupported() {
await chrome.test.assertPromiseRejects(
chrome.os.diagnostics.isFanRoutineArgumentSupported({
}),
'Error: API internal error.'
);
chrome.test.succeed();
}
]);
)");
}
IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticsApiV2BrowserTest,
LegacyIsFanRoutineArgSupportedException) {
auto exception = crosapi::TelemetryExtensionException::New();
exception->debug_message = "TEST_MESSAGE";
fake_service().SetIsRoutineArgumentSupportedResponse(
crosapi::TelemetryExtensionSupportStatus::NewException(
std::move(exception)));
OpenAppUiAndMakeItSecure();
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function isFanRoutineArgSupported() {
await chrome.test.assertPromiseRejects(
chrome.os.diagnostics.isFanRoutineArgumentSupported({
}),
'Error: TEST_MESSAGE'
);
chrome.test.succeed();
}
]);
)");
}
IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticsApiV2BrowserTest,
LegacyIsFanRoutineArgSupportedSuccess) {
fake_service().SetIsRoutineArgumentSupportedResponse(
crosapi::TelemetryExtensionSupportStatus::NewSupported(
crosapi::TelemetryExtensionSupported::New()));
OpenAppUiAndMakeItSecure();
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function isFanRoutineArgSupported() {
const result = await chrome.os.diagnostics.
isFanRoutineArgumentSupported({
});
chrome.test.assertEq(result.status, 'supported');
chrome.test.succeed();
}
]);
)");
}
IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticsApiV2BrowserTest,
LegacyCreateFanRoutineCompanionUiNotOpenError) {
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function createFanRoutineFail() {
await chrome.test.assertPromiseRejects(
chrome.os.diagnostics.createFanRoutine({
}),
'Error: Companion app UI is not open.'
);
chrome.test.succeed();
}
]);
)");
}
IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticsApiV2BrowserTest,
LegacyCreateFanRoutineSuccess) {
fake_service().SetOnCreateRoutineCalled(base::BindLambdaForTesting([this]() {
auto* control = fake_service().GetCreatedRoutineControlForRoutineType(
crosapi::TelemetryDiagnosticRoutineArgument::Tag::kFan);
ASSERT_TRUE(control);
auto fan_detail = crosapi::TelemetryDiagnosticFanRoutineDetail::New();
fan_detail->passed_fan_ids = {0};
fan_detail->failed_fan_ids = {1};
fan_detail->fan_count_status =
crosapi::TelemetryDiagnosticHardwarePresenceStatus::kMatched;
auto finished_state =
crosapi::TelemetryDiagnosticRoutineStateFinished::New();
finished_state->detail = crosapi::TelemetryDiagnosticRoutineDetail::NewFan(
std::move(fan_detail));
finished_state->has_passed = true;
auto state = crosapi::TelemetryDiagnosticRoutineState::New();
state->state_union =
crosapi::TelemetryDiagnosticRoutineStateUnion::NewFinished(
std::move(finished_state));
control->SetState(std::move(state));
}));
OpenAppUiAndMakeItSecure();
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function createFanRoutine() {
let resolver;
// Set later once the routine was created.
var uuid = new Promise((resolve) => {
resolver = resolve;
});
let onInitCalled = false;
chrome.os.diagnostics.onRoutineInitialized.addListener(
async (status) => {
chrome.test.assertEq(status.uuid, await uuid);
onInitCalled = true;
});
// Only resolve the test once we got the final event.
chrome.os.diagnostics.onFanRoutineFinished.addListener(
async (status) => {
chrome.test.assertEq(status, {
"has_passed": true,
"uuid": await uuid,
"failed_fan_ids":[1],
"passed_fan_ids":[0],
"fan_count_status": "matched",
});
chrome.test.assertTrue(onInitCalled);
chrome.test.succeed();
});
const response = await chrome.os.diagnostics.createFanRoutine({
});
chrome.test.assertTrue(response !== undefined);
resolver(response.uuid);
}
]);
)");
}
IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticsApiV2BrowserTest,
ReplyToRoutineInquiryUnknownUuidError) {
OpenAppUiAndMakeItSecure();
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function replyToRoutineInquiryFail() {
await chrome.test.assertPromiseRejects(
chrome.os.diagnostics.replyToRoutineInquiry({
uuid: '123',
reply: {},
}),
'Error: Unknown routine id.'
);
chrome.test.succeed();
}
]);
)");
}
IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticsApiV2BrowserTest,
ReplyToRoutineInquirySuccess) {
base::test::TestFuture<crosapi::TelemetryDiagnosticRoutineInquiryReplyPtr>
on_reply_to_inquiry;
fake_service().SetOnCreateRoutineCalled(
base::BindLambdaForTesting([this, &on_reply_to_inquiry]() {
auto* control = fake_service().GetCreatedRoutineControlForRoutineType(
crosapi::TelemetryDiagnosticRoutineArgument::Tag::kMemory);
ASSERT_TRUE(control);
control->SetOnReplyToInquiryCalled(
on_reply_to_inquiry.GetRepeatingCallback());
}));
OpenAppUiAndMakeItSecure();
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function createMemoryRoutine() {
let resolver;
// Set later once the routine was created.
var uuid = new Promise((resolve) => {
resolver = resolve;
});
chrome.os.diagnostics.onRoutineInitialized.addListener(
async (status) => {
chrome.test.assertEq(status.uuid, await uuid);
}
);
// Only resolve the test once we got the final event.
chrome.os.diagnostics.onRoutineRunning.addListener(
async (status) => {
chrome.test.assertEq(status.uuid, await uuid);
await chrome.os.diagnostics.replyToRoutineInquiry({
uuid: response.uuid,
reply: {
checkLedLitUpState: {
state: "correct_color",
}
},
});
chrome.test.succeed();
}
);
const response = await chrome.os.diagnostics.createMemoryRoutine({});
chrome.test.assertTrue(response !== undefined);
resolver(response.uuid);
await chrome.os.diagnostics.startRoutine({ uuid: response.uuid });
}
]);
)");
auto reply = on_reply_to_inquiry.Take();
ASSERT_TRUE(reply);
ASSERT_TRUE(reply->is_check_led_lit_up_state());
EXPECT_EQ(reply->get_check_led_lit_up_state()->state,
crosapi::TelemetryDiagnosticCheckLedLitUpStateReply::State::
kCorrectColor);
}
IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticsApiV2BrowserTest,
CreateLedLitUpRoutineSuccess) {
base::test::TestFuture<void> routine_created_future;
fake_service().SetOnCreateRoutineCalled(
routine_created_future.GetRepeatingCallback());
OpenAppUiAndMakeItSecure();
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function createRoutine() {
let resolver;
// Set later once the routine was created.
var uuid = new Promise((resolve) => {
resolver = resolve;
});
chrome.os.diagnostics.onRoutineInitialized.addListener(
async (status) => {
chrome.test.assertEq(status.uuid, await uuid);
chrome.test.succeed();
});
const response = await chrome.os.diagnostics.createRoutine({
ledLitUp: {
name: 'battery',
color: 'red',
},
});
chrome.test.assertTrue(response !== undefined);
resolver(response.uuid);
}
]);
)");
EXPECT_TRUE(routine_created_future.Wait());
EXPECT_TRUE(fake_service().GetCreatedRoutineControlForRoutineType(
crosapi::TelemetryDiagnosticRoutineArgument::Tag::kLedLitUp));
}
IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticsApiV2BrowserTest,
CreateKeyboardBacklightRoutineSuccess) {
base::test::TestFuture<void> routine_created_future;
fake_service().SetOnCreateRoutineCalled(
routine_created_future.GetRepeatingCallback());
OpenAppUiAndMakeItSecure();
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function createRoutine() {
let resolver;
// Set later once the routine was created.
var uuid = new Promise((resolve) => {
resolver = resolve;
});
chrome.os.diagnostics.onRoutineInitialized.addListener(
async (status) => {
chrome.test.assertEq(status.uuid, await uuid);
chrome.test.succeed();
});
const response = await chrome.os.diagnostics.createRoutine({
keyboardBacklight: {},
});
chrome.test.assertTrue(response !== undefined);
resolver(response.uuid);
}
]);
)");
EXPECT_TRUE(routine_created_future.Wait());
EXPECT_TRUE(fake_service().GetCreatedRoutineControlForRoutineType(
crosapi::TelemetryDiagnosticRoutineArgument::Tag::kKeyboardBacklight));
}
IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticsApiV2BrowserTest,
ReplyToKeyboardBacklightRoutineInquirySuccess) {
base::test::TestFuture<crosapi::TelemetryDiagnosticRoutineInquiryReplyPtr>
on_reply_to_inquiry;
fake_service().SetOnCreateRoutineCalled(
base::BindLambdaForTesting([this, &on_reply_to_inquiry]() {
auto* control = fake_service().GetCreatedRoutineControlForRoutineType(
crosapi::TelemetryDiagnosticRoutineArgument::Tag::
kKeyboardBacklight);
ASSERT_TRUE(control);
control->SetOnReplyToInquiryCalled(
on_reply_to_inquiry.GetRepeatingCallback());
}));
OpenAppUiAndMakeItSecure();
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function createRoutine() {
let resolver;
// Set later once the routine was created.
var uuid = new Promise((resolve) => {
resolver = resolve;
});
chrome.os.diagnostics.onRoutineInitialized.addListener(
async (status) => {
chrome.test.assertEq(status.uuid, await uuid);
}
);
// Only resolve the test once we got the final event.
chrome.os.diagnostics.onRoutineRunning.addListener(
async (status) => {
chrome.test.assertEq(status.uuid, await uuid);
await chrome.os.diagnostics.replyToRoutineInquiry({
uuid: response.uuid,
reply: {
checkKeyboardBacklightState: {
state: "ok",
}
},
});
chrome.test.succeed();
}
);
const response = await chrome.os.diagnostics.createRoutine({
keyboardBacklight: {},
});
chrome.test.assertTrue(response !== undefined);
resolver(response.uuid);
await chrome.os.diagnostics.startRoutine({ uuid: response.uuid });
}
]);
)");
auto reply = on_reply_to_inquiry.Take();
ASSERT_TRUE(reply);
ASSERT_TRUE(reply->is_check_keyboard_backlight_state());
EXPECT_EQ(
reply->get_check_keyboard_backlight_state()->state,
crosapi::TelemetryDiagnosticCheckKeyboardBacklightStateReply::State::kOk);
}
IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticsApiV2BrowserTest,
CreateNetworkBandwidthRoutineSuccess) {
fake_service().SetOnCreateRoutineCalled(base::BindLambdaForTesting([this]() {
auto* control = fake_service().GetCreatedRoutineControlForRoutineType(
crosapi::TelemetryDiagnosticRoutineArgument::Tag::kNetworkBandwidth);
ASSERT_TRUE(control);
auto network_bandwidth_detail =
crosapi::TelemetryDiagnosticNetworkBandwidthRoutineDetail::New();
network_bandwidth_detail->download_speed_kbps = 123.0;
network_bandwidth_detail->upload_speed_kbps = 456.0;
auto finished_state =
crosapi::TelemetryDiagnosticRoutineStateFinished::New();
finished_state->detail =
crosapi::TelemetryDiagnosticRoutineDetail::NewNetworkBandwidth(
std::move(network_bandwidth_detail));
finished_state->has_passed = true;
auto state = crosapi::TelemetryDiagnosticRoutineState::New();
state->state_union =
crosapi::TelemetryDiagnosticRoutineStateUnion::NewFinished(
std::move(finished_state));
control->SetState(std::move(state));
}));
OpenAppUiAndMakeItSecure();
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function createNetworkBandwidthRoutine() {
let resolver;
// Set later once the routine was created.
var uuid = new Promise((resolve) => {
resolver = resolve;
});
let onInitCalled = false;
chrome.os.diagnostics.onRoutineInitialized.addListener(
async (status) => {
chrome.test.assertEq(status.uuid, await uuid);
onInitCalled = true;
});
// Only resolve the test once we got the final event.
chrome.os.diagnostics.onRoutineFinished.addListener(
async (status) => {
chrome.test.assertEq(status, {
"detail": {
"networkBandwidth": {
"downloadSpeedKbps": 123.0,
"uploadSpeedKbps": 456.0
}
},
"hasPassed": true,
"uuid": await uuid
});
chrome.test.assertTrue(onInitCalled);
chrome.test.succeed();
});
const response = await chrome.os.diagnostics.createRoutine({
networkBandwidth: {},
});
chrome.test.assertTrue(response !== undefined);
resolver(response.uuid);
}
]);
)");
}
IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticsApiV2BrowserTest,
CreateCameraFrameAnalysisRoutineSuccess) {
base::test::TestFuture<void> routine_created_future;
fake_service().SetOnCreateRoutineCalled(
routine_created_future.GetRepeatingCallback());
OpenAppUiAndMakeItSecure();
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function createRoutine() {
let resolver;
// Set later once the routine was created.
var uuid = new Promise((resolve) => {
resolver = resolve;
});
chrome.os.diagnostics.onRoutineInitialized.addListener(
async (status) => {
chrome.test.assertEq(status.uuid, await uuid);
chrome.test.succeed();
});
const response = await chrome.os.diagnostics.createRoutine({
cameraFrameAnalysis: {},
});
chrome.test.assertTrue(response !== undefined);
resolver(response.uuid);
}
]);
)");
EXPECT_TRUE(routine_created_future.Wait());
EXPECT_TRUE(fake_service().GetCreatedRoutineControlForRoutineType(
crosapi::TelemetryDiagnosticRoutineArgument::Tag::kCameraFrameAnalysis));
}
class NoExtraPermissionTelemetryExtensionDiagnosticsApiV2BrowserTest
: public TelemetryExtensionDiagnosticsApiV2BrowserTest {
public:
NoExtraPermissionTelemetryExtensionDiagnosticsApiV2BrowserTest() = default;
protected:
std::string GetManifestFile(const std::string& manifest_key,
const std::string& matches_origin) override {
return base::StringPrintf(R"(
{
"key": "%s",
"name": "Test Telemetry Extension",
"version": "1",
"manifest_version": 3,
"chromeos_system_extension": {},
"background": {
"service_worker": "sw.js"
},
"permissions": [ "os.diagnostics" ],
"externally_connectable": {
"matches": [
"%s"
]
},
"options_page": "options.html"
}
)",
manifest_key.c_str(), matches_origin.c_str());
}
};
IN_PROC_BROWSER_TEST_F(
NoExtraPermissionTelemetryExtensionDiagnosticsApiV2BrowserTest,
NetworkBandwidthRoutineNoPermissionFail) {
CreateExtensionAndRunServiceWorker(R"(
chrome.test.runTests([
async function createNetworkBandwidthRoutineNoPermission() {
await chrome.test.assertPromiseRejects(
chrome.os.diagnostics.createRoutine({
networkBandwidth: {},
}),
'Error: Unauthorized access to ' +
'chrome.os.diagnostics.CreateRoutine with networkBandwidth ' +
'argument. Extension doesn\'t have the permission.'
);
chrome.test.succeed();
}
]);
)");
}
} // namespace chromeos