1
|
# SPDX-License-Identifier: CC0-1.0
|
2
|
|
3
|
"""
|
4
|
Haketilo unit tests - serving indexeddb resource script files to content scripts
|
5
|
"""
|
6
|
|
7
|
# This file is part of Haketilo
|
8
|
#
|
9
|
# Copyright (C) 2021,2022 Wojtek Kosior <koszko@koszko.org>
|
10
|
#
|
11
|
# This program is free software: you can redistribute it and/or modify
|
12
|
# it under the terms of the CC0 1.0 Universal License as published by
|
13
|
# the Creative Commons Corporation.
|
14
|
#
|
15
|
# This program is distributed in the hope that it will be useful,
|
16
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
17
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
18
|
# CC0 1.0 Universal License for more details.
|
19
|
|
20
|
import pytest
|
21
|
import copy
|
22
|
from uuid import uuid4
|
23
|
from selenium.webdriver.support.ui import WebDriverWait
|
24
|
|
25
|
from ..script_loader import load_script
|
26
|
from .utils import *
|
27
|
|
28
|
"""
|
29
|
How many test resources we're going to have.
|
30
|
"""
|
31
|
count = 15
|
32
|
|
33
|
sample_files_list = [(f'file_{n}_{i}', f'contents {n} {i}')
|
34
|
for n in range(count) for i in range(2)]
|
35
|
|
36
|
sample_files = dict(sample_files_list)
|
37
|
|
38
|
sample_files, sample_files_by_sha256 = make_sample_files(sample_files)
|
39
|
|
40
|
def make_sample_resource_with_deps(n):
|
41
|
resource = make_sample_resource(with_files=False)
|
42
|
|
43
|
resource['identifier'] = f'res-{n}'
|
44
|
resource['dependencies'] = [{'identifier': f'res-{m}'}
|
45
|
for m in range(max(n - 4, 0), n)]
|
46
|
resource['scripts'] = [sample_file_ref(f'file_{n}_{i}', sample_files)
|
47
|
for i in range(2)]
|
48
|
|
49
|
return resource
|
50
|
|
51
|
resources = [make_sample_resource_with_deps(n) for n in range(count)]
|
52
|
|
53
|
sample_data = {
|
54
|
'resource': sample_data_dict(resources),
|
55
|
'mapping': {},
|
56
|
'file': {
|
57
|
'sha256': sample_files_by_sha256
|
58
|
}
|
59
|
}
|
60
|
|
61
|
def prepare_test_page(initial_indexeddb_data, execute_in_page):
|
62
|
js = load_script('background/indexeddb_files_server.js',
|
63
|
code_to_add='#IMPORT common/broadcast.js')
|
64
|
execute_in_page(js)
|
65
|
|
66
|
mock_broadcast(execute_in_page)
|
67
|
clear_indexeddb(execute_in_page)
|
68
|
|
69
|
execute_in_page(
|
70
|
'''
|
71
|
let registered_listener;
|
72
|
const new_addListener = cb => registered_listener = cb;
|
73
|
|
74
|
browser = {runtime: {onMessage: {addListener: new_addListener}}};
|
75
|
|
76
|
haketilodb.save_items(arguments[0]);
|
77
|
|
78
|
start();
|
79
|
''',
|
80
|
initial_indexeddb_data)
|
81
|
|
82
|
@pytest.mark.get_page('https://gotmyowndoma.in')
|
83
|
def test_indexeddb_files_server_normal_usage(driver, execute_in_page):
|
84
|
"""
|
85
|
Test querying resource files (with resource dependency resolution)
|
86
|
from IndexedDB and serving them in messages to content scripts.
|
87
|
"""
|
88
|
prepare_test_page(sample_data, execute_in_page)
|
89
|
|
90
|
# Verify other types of messages are ignored.
|
91
|
function_returned_value = execute_in_page(
|
92
|
'''
|
93
|
returnval(registered_listener(["???"], {},
|
94
|
() => location.reload()));
|
95
|
''')
|
96
|
assert function_returned_value == None
|
97
|
|
98
|
# Verify single resource's files get properly resolved.
|
99
|
function_returned_value = execute_in_page(
|
100
|
'''
|
101
|
var result_cb, contents_prom = new Promise(cb => result_cb = cb);
|
102
|
|
103
|
returnval(registered_listener(["indexeddb_files", "res-0"],
|
104
|
{}, result_cb));
|
105
|
''')
|
106
|
assert function_returned_value == True
|
107
|
|
108
|
assert execute_in_page('returnval(contents_prom);') == \
|
109
|
{'files': [tuple[1] for tuple in sample_files_list[0:2]]}
|
110
|
|
111
|
# Verify multiple resources' files get properly resolved.
|
112
|
function_returned_value = execute_in_page(
|
113
|
'''
|
114
|
var result_cb, contents_prom = new Promise(cb => result_cb = cb);
|
115
|
|
116
|
returnval(registered_listener(["indexeddb_files", arguments[0]],
|
117
|
{}, result_cb));
|
118
|
''',
|
119
|
f'res-{count - 1}')
|
120
|
assert function_returned_value == True
|
121
|
|
122
|
assert execute_in_page('returnval(contents_prom);') == \
|
123
|
{'files': [tuple[1] for tuple in sample_files_list]}
|
124
|
|
125
|
@pytest.mark.get_page('https://gotmyowndoma.in')
|
126
|
@pytest.mark.parametrize('error', [
|
127
|
'missing',
|
128
|
'circular',
|
129
|
'db',
|
130
|
'other'
|
131
|
])
|
132
|
def test_indexeddb_files_server_errors(driver, execute_in_page, error):
|
133
|
"""
|
134
|
Test reporting of errors when querying resource files (with resource
|
135
|
dependency resolution) from IndexedDB and serving them in messages to
|
136
|
content scripts.
|
137
|
"""
|
138
|
sample_data_copy = copy.deepcopy(sample_data)
|
139
|
|
140
|
if error == 'missing':
|
141
|
del sample_data_copy['resource']['res-3']
|
142
|
elif error == 'circular':
|
143
|
res3_defs = sample_data_copy['resource']['res-3'].values()
|
144
|
next(iter(res3_defs))['dependencies'].append({'identifier': 'res-8'})
|
145
|
|
146
|
prepare_test_page(sample_data_copy, execute_in_page)
|
147
|
|
148
|
if error == 'db':
|
149
|
execute_in_page('haketilodb.idb_get = t => t.onerror("oooops");')
|
150
|
elif error == 'other':
|
151
|
execute_in_page('haketilodb.idb_get = () => {throw "oooops"};')
|
152
|
|
153
|
response = execute_in_page(
|
154
|
'''
|
155
|
var result_cb, contents_prom = new Promise(cb => result_cb = cb);
|
156
|
|
157
|
registered_listener(["indexeddb_files", arguments[0]],
|
158
|
{}, result_cb);
|
159
|
|
160
|
returnval(contents_prom);
|
161
|
''',
|
162
|
f'res-{count - 1}')
|
163
|
|
164
|
assert response['error']['haketilo_error_type'] == error
|
165
|
|
166
|
if error == 'missing':
|
167
|
assert response['error']['id'] == 'res-3'
|
168
|
elif error == 'circular':
|
169
|
assert response['error']['id'] in ('res-3', 'res-8')
|
170
|
elif error not in ('db', 'other'):
|
171
|
raise Exception('made a typo in test function params?')
|