Project

General

Profile

Download (19.5 KB) Statistics
| Branch: | Tag: | Revision:

haketilo / test / haketilo_test / unit / test_indexeddb.py @ aec5c9ae

1 3a90084e Wojtek Kosior
# SPDX-License-Identifier: CC0-1.0
2
3
"""
4
Haketilo unit tests - IndexedDB access
5
"""
6
7
# This file is part of Haketilo
8
#
9 1c65dd5c Wojtek Kosior
# Copyright (C) 2021, 2022 Wojtek Kosior <koszko@koszko.org>
10 3a90084e Wojtek Kosior
#
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 b7378a99 Wojtek Kosior
import json
22
from selenium.webdriver.common.by import By
23
from selenium.webdriver.support.ui import WebDriverWait
24
from selenium.common.exceptions import WebDriverException
25 3a90084e Wojtek Kosior
26
from ..script_loader import load_script
27 19304cd1 Wojtek Kosior
from .utils import *
28 3a90084e Wojtek Kosior
29 b7378a99 Wojtek Kosior
# Sample resource definitions. They'd normally contain more fields but here we
30
# use simplified versions.
31
32
def make_sample_resource():
33
    return {
34
        'source_copyright': [
35 448820a1 Wojtek Kosior
            sample_file_ref('report.spdx'),
36
            sample_file_ref('LICENSES/somelicense.txt')
37 b7378a99 Wojtek Kosior
        ],
38
        'type': 'resource',
39
        'identifier': 'helloapple',
40 448820a1 Wojtek Kosior
        'scripts': [sample_file_ref('hello.js'), sample_file_ref('bye.js')]
41 b7378a99 Wojtek Kosior
    }
42
43
def make_sample_mapping():
44
    return {
45
        'source_copyright': [
46 448820a1 Wojtek Kosior
            sample_file_ref('report.spdx'),
47
            sample_file_ref('README.md')
48 b7378a99 Wojtek Kosior
        ],
49
        'type': 'mapping',
50
        'identifier': 'helloapple'
51
    }
52
53 aec5c9ae Wojtek Kosior
@pytest.mark.get_page('https://gotmyowndoma.in')
54
def test_haketilodb_update_1_0_1(driver, execute_in_page):
55
    """
56
    indexeddb.js modifies data when updating to database version 1.0.1. Verify
57
    the update procedure works properly.
58
    """
59
    execute_in_page(load_script('common/indexeddb.js'))
60
    execute_in_page('db_version_nr = version_nr([1, 0, 0]);')
61
    mock_broadcast(execute_in_page)
62
63
    # Start with no database.
64
    clear_indexeddb(execute_in_page)
65
66
    v1_url = 'https://hydrilla.koszko.org/api_v1/'
67
    v2_url = 'https://hydrilla.koszko.org/api_v2/'
68
    urls_v1 = {'https://sample.url/abc/', v1_url}
69
    urls_v2 = {'https://sample.url/abc/', v2_url}
70
71
    for url in urls_v1:
72
        execute_in_page('returnval(set_repo(arguments[0]));', url)
73
74
    assert urls_v1 == set(execute_in_page('returnval(get_repos());'))
75
76
    # Verify that url gets updated to v2 upon database update.
77
    driver.get(driver.execute_script('return window.location.href;'))
78
    execute_in_page(load_script('common/indexeddb.js'))
79
    mock_broadcast(execute_in_page)
80
81
    database_contents = get_db_contents(execute_in_page)
82
83
    assert set(execute_in_page('returnval(get_repos());')) == urls_v2
84
85
    # Verify that url does not get updated when there is no database update.
86
    execute_in_page('returnval(del_repo(arguments[0]));', v2_url)
87
    execute_in_page('returnval(set_repo(arguments[0]));', v1_url)
88
89
    driver.get(driver.execute_script('return window.location.href;'))
90
    execute_in_page(load_script('common/indexeddb.js'))
91
    mock_broadcast(execute_in_page)
92
93
    database_contents = get_db_contents(execute_in_page)
94
95
    assert set(execute_in_page('returnval(get_repos());')) == urls_v1
96
97 702eefd2 Wojtek Kosior
@pytest.mark.get_page('https://gotmyowndoma.in')
98
def test_haketilodb_item_modifications(driver, execute_in_page):
99
    """
100
    indexeddb.js facilitates operating on Haketilo's internal database.
101
    Verify database operations on mappings/resources work properly.
102
    """
103 e7d11c7c Wojtek Kosior
    execute_in_page(load_script('common/indexeddb.js'))
104 702eefd2 Wojtek Kosior
    mock_broadcast(execute_in_page)
105
106
    # Start with no database.
107
    clear_indexeddb(execute_in_page)
108 3a90084e Wojtek Kosior
109 b7378a99 Wojtek Kosior
    sample_item = make_sample_resource()
110
    sample_item['source_copyright'][0]['extra_prop'] = True
111 3a90084e Wojtek Kosior
112 702eefd2 Wojtek Kosior
    execute_in_page(
113 3a90084e Wojtek Kosior
        '''{
114 7218849a Wojtek Kosior
        const promise = start_items_transaction(["resource"], arguments[1])
115 1e4ce148 Wojtek Kosior
            .then(ctx => save_item(arguments[0], ctx).then(() => ctx))
116 702eefd2 Wojtek Kosior
            .then(finalize_transaction);
117 1e4ce148 Wojtek Kosior
        returnval(promise);
118 3a90084e Wojtek Kosior
        }''',
119 1c65dd5c Wojtek Kosior
        sample_item, {'sha256': sample_files_by_sha256})
120 702eefd2 Wojtek Kosior
121
    database_contents = get_db_contents(execute_in_page)
122
123 92fc67cf Wojtek Kosior
    assert len(database_contents['file']) == 4
124 1c65dd5c Wojtek Kosior
    assert all([sample_files_by_sha256[file['sha256']] == file['contents']
125 92fc67cf Wojtek Kosior
                for file in database_contents['file']])
126
    assert all([len(file) == 2 for file in database_contents['file']])
127 3a90084e Wojtek Kosior
128
    assert len(database_contents['file_uses']) == 4
129
    assert all([uses['uses'] == 1 for uses in database_contents['file_uses']])
130 1c65dd5c Wojtek Kosior
    assert set([uses['sha256'] for uses in database_contents['file_uses']]) \
131 92fc67cf Wojtek Kosior
        == set([file['sha256'] for file in database_contents['file']])
132 3a90084e Wojtek Kosior
133 7218849a Wojtek Kosior
    assert database_contents['mapping'] == []
134
    assert database_contents['resource'] == [sample_item]
135 1e4ce148 Wojtek Kosior
136
    # See if trying to add an item without providing all its files ends in an
137
    # exception and aborts the transaction as it should.
138 448820a1 Wojtek Kosior
    sample_item['scripts'].append(sample_file_ref('combined.js'))
139 1c65dd5c Wojtek Kosior
    incomplete_files = {**sample_files_by_sha256}
140
    incomplete_files.pop(sample_files['combined.js']['sha256'])
141 702eefd2 Wojtek Kosior
    exception = execute_in_page(
142 1e4ce148 Wojtek Kosior
        '''{
143 702eefd2 Wojtek Kosior
        const args = arguments;
144
        async function try_add_item()
145
        {
146 1e4ce148 Wojtek Kosior
            const context =
147 7218849a Wojtek Kosior
                await start_items_transaction(["resource"], args[1]);
148 1e4ce148 Wojtek Kosior
            try {
149 702eefd2 Wojtek Kosior
                await save_item(args[0], context);
150
                await finalize_transaction(context);
151
                return;
152 1e4ce148 Wojtek Kosior
            } catch(e) {
153 702eefd2 Wojtek Kosior
                return e;
154 1e4ce148 Wojtek Kosior
            }
155 702eefd2 Wojtek Kosior
        }
156
        returnval(try_add_item());
157 1e4ce148 Wojtek Kosior
        }''',
158 1c65dd5c Wojtek Kosior
        sample_item, {'sha256': incomplete_files})
159 1e4ce148 Wojtek Kosior
160 702eefd2 Wojtek Kosior
    previous_database_contents = database_contents
161
    database_contents = get_db_contents(execute_in_page)
162
163
    assert 'file not present' in exception
164 1e4ce148 Wojtek Kosior
    for key, val in database_contents.items():
165 1c65dd5c Wojtek Kosior
        keyfun = lambda item: item.get('sha256') or item['identifier']
166 702eefd2 Wojtek Kosior
        assert sorted(previous_database_contents[key], key=keyfun) \
167
            == sorted(val,                             key=keyfun)
168 1e4ce148 Wojtek Kosior
169
    # See if adding another item that partially uses first's files works OK.
170 b7378a99 Wojtek Kosior
    sample_item = make_sample_mapping()
171 1e4ce148 Wojtek Kosior
    database_contents = execute_in_page(
172
        '''{
173 7218849a Wojtek Kosior
        const promise = start_items_transaction(["mapping"], arguments[1])
174 1e4ce148 Wojtek Kosior
            .then(ctx => save_item(arguments[0], ctx).then(() => ctx))
175 702eefd2 Wojtek Kosior
            .then(finalize_transaction);
176 1e4ce148 Wojtek Kosior
        returnval(promise);
177
        }''',
178 1c65dd5c Wojtek Kosior
        sample_item, {'sha256': sample_files_by_sha256})
179 1e4ce148 Wojtek Kosior
180 702eefd2 Wojtek Kosior
    database_contents = get_db_contents(execute_in_page)
181
182 1e4ce148 Wojtek Kosior
    names = ['README.md', 'report.spdx', 'LICENSES/somelicense.txt', 'hello.js',
183
             'bye.js']
184
    sample_files_list = [sample_files[name] for name in names]
185
    uses_list = [1, 2, 1, 1, 1]
186
187 1c65dd5c Wojtek Kosior
    uses = dict([(uses['sha256'], uses['uses'])
188 1e4ce148 Wojtek Kosior
                 for uses in database_contents['file_uses']])
189 1c65dd5c Wojtek Kosior
    assert uses  == dict([(file['sha256'], nr)
190 1e4ce148 Wojtek Kosior
                          for file, nr in zip(sample_files_list, uses_list)])
191
192 1c65dd5c Wojtek Kosior
    files = dict([(file['sha256'], file['contents'])
193 92fc67cf Wojtek Kosior
                  for file in database_contents['file']])
194 1c65dd5c Wojtek Kosior
    assert files == dict([(file['sha256'], file['contents'])
195 1e4ce148 Wojtek Kosior
                          for file in sample_files_list])
196
197 7218849a Wojtek Kosior
    del database_contents['resource'][0]['source_copyright'][0]['extra_prop']
198
    assert database_contents['resource'] == [make_sample_resource()]
199
    assert database_contents['mapping']  == [sample_item]
200 1e4ce148 Wojtek Kosior
201
    # Try removing the items to get an empty database again.
202
    results = [None, None]
203
    for i, item_type in enumerate(['resource', 'mapping']):
204 702eefd2 Wojtek Kosior
         execute_in_page(
205 1e4ce148 Wojtek Kosior
            f'''{{
206 b590eaa2 Wojtek Kosior
            const remover = remove_{item_type};
207 1e4ce148 Wojtek Kosior
            const promise =
208 7218849a Wojtek Kosior
                start_items_transaction(["{item_type}"], {{}})
209 1e4ce148 Wojtek Kosior
                .then(ctx => remover('helloapple', ctx).then(() => ctx))
210 702eefd2 Wojtek Kosior
                .then(finalize_transaction);
211 1e4ce148 Wojtek Kosior
            returnval(promise);
212
            }}''')
213
214 702eefd2 Wojtek Kosior
         results[i] = get_db_contents(execute_in_page)
215
216 1e4ce148 Wojtek Kosior
    names = ['README.md', 'report.spdx']
217
    sample_files_list = [sample_files[name] for name in names]
218
    uses_list = [1, 1]
219
220 1c65dd5c Wojtek Kosior
    uses = dict([(uses['sha256'], uses['uses'])
221 1e4ce148 Wojtek Kosior
                 for uses in results[0]['file_uses']])
222 1c65dd5c Wojtek Kosior
    assert uses  == dict([(file['sha256'], 1) for file in sample_files_list])
223 1e4ce148 Wojtek Kosior
224 1c65dd5c Wojtek Kosior
    files = dict([(file['sha256'], file['contents'])
225 92fc67cf Wojtek Kosior
                  for file in results[0]['file']])
226 1c65dd5c Wojtek Kosior
    assert files == dict([(file['sha256'], file['contents'])
227 1e4ce148 Wojtek Kosior
                          for file in sample_files_list])
228
229 7218849a Wojtek Kosior
    assert results[0]['resource'] == []
230
    assert results[0]['mapping'] == [sample_item]
231 1e4ce148 Wojtek Kosior
232
    assert results[1] == dict([(key, []) for key in  results[0].keys()])
233 b7378a99 Wojtek Kosior
234
    # Try initializing an empty database with sample initial data object.
235
    sample_resource = make_sample_resource()
236
    sample_mapping = make_sample_mapping()
237
    initial_data = {
238 92fc67cf Wojtek Kosior
        'resource': {
239 b7378a99 Wojtek Kosior
            'helloapple': {
240
                '1.12':   sample_resource,
241
                '0.9':    'something_that_should_get_ignored',
242
                '1':      'something_that_should_get_ignored',
243
                '1.1':    'something_that_should_get_ignored',
244
                '1.11.1': 'something_that_should_get_ignored',
245
            }
246
        },
247 92fc67cf Wojtek Kosior
        'mapping': {
248 b7378a99 Wojtek Kosior
            'helloapple': {
249
                '0.1.1': sample_mapping
250
            }
251
        },
252 1c65dd5c Wojtek Kosior
        'file': {
253
            'sha256': sample_files_by_sha256
254
        }
255 b7378a99 Wojtek Kosior
    }
256 702eefd2 Wojtek Kosior
257
    clear_indexeddb(execute_in_page)
258
    execute_in_page('initial_data = arguments[0];', initial_data)
259
    database_contents = get_db_contents(execute_in_page)
260
261 7218849a Wojtek Kosior
    assert database_contents['resource'] == [sample_resource]
262
    assert database_contents['mapping']  == [sample_mapping]
263 b7378a99 Wojtek Kosior
264 702eefd2 Wojtek Kosior
@pytest.mark.get_page('https://gotmyowndoma.in')
265
def test_haketilodb_settings(driver, execute_in_page):
266
    """
267
    indexeddb.js facilitates operating on Haketilo's internal database.
268 92fc67cf Wojtek Kosior
    Verify assigning/retrieving values of simple "setting" item works properly.
269 702eefd2 Wojtek Kosior
    """
270 e7d11c7c Wojtek Kosior
    execute_in_page(load_script('common/indexeddb.js'))
271 702eefd2 Wojtek Kosior
    mock_broadcast(execute_in_page)
272
273
    # Start with no database.
274
    clear_indexeddb(execute_in_page)
275
276 92fc67cf Wojtek Kosior
    assert get_db_contents(execute_in_page)['setting'] == []
277 702eefd2 Wojtek Kosior
278
    assert execute_in_page('returnval(get_setting("option15"));') == None
279
280
    execute_in_page('returnval(set_setting("option15", "disable"));')
281
    assert execute_in_page('returnval(get_setting("option15"));') == 'disable'
282
283
    execute_in_page('returnval(set_setting("option15", "enable"));')
284
    assert execute_in_page('returnval(get_setting("option15"));') == 'enable'
285
286 0feb9db2 Wojtek Kosior
@pytest.mark.get_page('https://gotmyowndoma.in')
287
def test_haketilodb_allowing(driver, execute_in_page):
288
    """
289
    indexeddb.js facilitates operating on Haketilo's internal database.
290
    Verify changing the "blocking" configuration for a URL works properly.
291
    """
292 e7d11c7c Wojtek Kosior
    execute_in_page(load_script('common/indexeddb.js'))
293 0feb9db2 Wojtek Kosior
    mock_broadcast(execute_in_page)
294
295
    # Start with no database.
296
    clear_indexeddb(execute_in_page)
297
298
    assert get_db_contents(execute_in_page)['blocking'] == []
299
300
    def run_with_sample_url(expr):
301
        return execute_in_page(f'returnval({expr});', 'https://example.com/**')
302
303
    assert None == run_with_sample_url('get_allowing(arguments[0])')
304
305
    run_with_sample_url('set_disallowed(arguments[0])')
306
    assert False == run_with_sample_url('get_allowing(arguments[0])')
307
308
    run_with_sample_url('set_allowed(arguments[0])')
309
    assert True == run_with_sample_url('get_allowing(arguments[0])')
310
311
    run_with_sample_url('set_default_allowing(arguments[0])')
312
    assert None == run_with_sample_url('get_allowing(arguments[0])')
313
314
@pytest.mark.get_page('https://gotmyowndoma.in')
315
def test_haketilodb_repos(driver, execute_in_page):
316
    """
317
    indexeddb.js facilitates operating on Haketilo's internal database.
318
    Verify operations on repositories list work properly.
319
    """
320 e7d11c7c Wojtek Kosior
    execute_in_page(load_script('common/indexeddb.js'))
321 0feb9db2 Wojtek Kosior
    mock_broadcast(execute_in_page)
322
323
    # Start with no database.
324
    clear_indexeddb(execute_in_page)
325
326 92fc67cf Wojtek Kosior
    assert get_db_contents(execute_in_page)['repo'] == []
327 0feb9db2 Wojtek Kosior
328
    sample_urls = ['https://hdrlla.example.com/', 'https://hdrlla.example.org']
329
330
    assert [] == execute_in_page('returnval(get_repos());')
331
332
    execute_in_page('returnval(set_repo(arguments[0]));', sample_urls[0])
333
    assert [sample_urls[0]] == execute_in_page('returnval(get_repos());')
334
335
    execute_in_page('returnval(set_repo(arguments[0]));', sample_urls[1])
336
    assert set(sample_urls) == set(execute_in_page('returnval(get_repos());'))
337
338
    execute_in_page('returnval(del_repo(arguments[0]));', sample_urls[0])
339
    assert [sample_urls[1]] == execute_in_page('returnval(get_repos());')
340
341 b7378a99 Wojtek Kosior
test_page_html = '''
342
<!DOCTYPE html>
343
<script src="/testpage.js"></script>
344 0feb9db2 Wojtek Kosior
<body>
345
</body>
346 b7378a99 Wojtek Kosior
'''
347
348
@pytest.mark.ext_data({
349
    'background_script': broker_js,
350
    'test_page':         test_page_html,
351
    'extra_files': {
352 e7d11c7c Wojtek Kosior
        'testpage.js':   lambda: load_script('common/indexeddb.js')
353 b7378a99 Wojtek Kosior
    }
354
})
355
@pytest.mark.usefixtures('webextension')
356
def test_haketilodb_track(driver, execute_in_page, wait_elem_text):
357
    """
358
    Verify IndexedDB object change notifications are correctly broadcasted
359
    through extension's background script and allow for object store contents
360
    to be tracked in any execution context.
361
    """
362 0feb9db2 Wojtek Kosior
    # Let's open the same extension's test page in a second window. Window 1
363
    # will be used to make changes to IndexedDB and window 0 to "track" those
364 b7378a99 Wojtek Kosior
    # changes.
365
    driver.execute_script('window.open(window.location.href, "_blank");')
366 4c6a2323 Wojtek Kosior
    WebDriverWait(driver, 10).until(lambda d: len(d.window_handles) == 2)
367 b7378a99 Wojtek Kosior
    windows = [*driver.window_handles]
368
369 0feb9db2 Wojtek Kosior
    # Create elements that will have tracked data inserted under them.
370
    driver.switch_to.window(windows[0])
371 ad69f9c8 Wojtek Kosior
    execute_in_page(
372
        '''
373
        for (const store_name of trackable) {
374
            const h2 = document.createElement("h2");
375
            h2.innerText = store_name;
376
            document.body.append(h2);
377
378
            const ul = document.createElement("ul");
379
            ul.id = store_name;
380
            document.body.append(ul);
381
        }
382
        ''')
383 0feb9db2 Wojtek Kosior
384 b7378a99 Wojtek Kosior
    # Mock initial_data.
385
    sample_resource = make_sample_resource()
386
    sample_mapping = make_sample_mapping()
387
    initial_data = {
388 92fc67cf Wojtek Kosior
        'resource': {
389 b7378a99 Wojtek Kosior
            'helloapple': {
390
                '1.0': sample_resource
391
            }
392
        },
393 92fc67cf Wojtek Kosior
        'mapping': {
394 b7378a99 Wojtek Kosior
            'helloapple': {
395
                '0.1.1': sample_mapping
396
            }
397
        },
398 1c65dd5c Wojtek Kosior
        'file': {
399
            'sha256': sample_files_by_sha256
400
        }
401 b7378a99 Wojtek Kosior
    }
402 0feb9db2 Wojtek Kosior
    driver.switch_to.window(windows[1])
403
    execute_in_page('initial_data = arguments[0];', initial_data)
404
    execute_in_page('returnval(set_setting("option15", "123"));')
405
    execute_in_page('returnval(set_repo("https://hydril.la"));')
406
    execute_in_page('returnval(set_disallowed("file:///*"));')
407 702eefd2 Wojtek Kosior
408
    # See if track.*() functions properly return the already-existing items.
409 0feb9db2 Wojtek Kosior
    driver.switch_to.window(windows[0])
410 b7378a99 Wojtek Kosior
    execute_in_page(
411
        '''
412
        function update_item(store_name, change)
413
        {
414 702eefd2 Wojtek Kosior
            const elem_id = `${store_name}_${change.key}`;
415 b7378a99 Wojtek Kosior
            let elem = document.getElementById(elem_id);
416
            elem = elem || document.createElement("li");
417
            elem.id = elem_id;
418
            elem.innerText = JSON.stringify(change.new_val);
419
            document.getElementById(store_name).append(elem);
420
            if (change.new_val === undefined)
421
                elem.remove();
422
        }
423
424
        let resource_tracking, resource_items, mapping_tracking, mapping_items;
425
426 702eefd2 Wojtek Kosior
        async function start_reporting()
427 b7378a99 Wojtek Kosior
        {
428 0feb9db2 Wojtek Kosior
            const props = new Map(stores.map(([sn, opt]) => [sn, opt.keyPath]));
429
            for (const store_name of trackable) {
430 702eefd2 Wojtek Kosior
                [tracking, items] =
431
                    await track[store_name](ch => update_item(store_name, ch));
432 0feb9db2 Wojtek Kosior
                const prop = props.get(store_name);
433 702eefd2 Wojtek Kosior
                for (const item of items)
434
                    update_item(store_name, {key: item[prop], new_val: item});
435
            }
436 b7378a99 Wojtek Kosior
        }
437
438 702eefd2 Wojtek Kosior
        returnval(start_reporting());
439 b7378a99 Wojtek Kosior
        ''')
440
441 0feb9db2 Wojtek Kosior
    item_counts = execute_in_page(
442
        '''{
443 b7378a99 Wojtek Kosior
        const childcount = id => document.getElementById(id).childElementCount;
444 0feb9db2 Wojtek Kosior
        returnval(trackable.map(childcount));
445
        }''')
446
    assert item_counts == [1 for _ in item_counts]
447
    for elem_id, json_value in [
448 7218849a Wojtek Kosior
            ('resource_helloapple', sample_resource),
449
            ('mapping_helloapple', sample_mapping),
450 92fc67cf Wojtek Kosior
            ('setting_option15', {'name': 'option15', 'value': '123'}),
451
            ('repo_https://hydril.la', {'url': 'https://hydril.la'}),
452 0feb9db2 Wojtek Kosior
            ('blocking_file:///*', {'pattern': 'file:///*', 'allow': False})
453
    ]:
454
        assert json.loads(driver.find_element_by_id(elem_id).text) == json_value
455 b7378a99 Wojtek Kosior
456
    # See if item additions get tracked properly.
457
    driver.switch_to.window(windows[1])
458
    sample_resource2 = make_sample_resource()
459
    sample_resource2['identifier'] = 'helloapple-copy'
460
    sample_mapping2 = make_sample_mapping()
461
    sample_mapping2['identifier'] = 'helloapple-copy'
462
    sample_data = {
463 92fc67cf Wojtek Kosior
        'resource': {
464 b7378a99 Wojtek Kosior
            'helloapple-copy': {
465
                '1.0': sample_resource2
466
            }
467
        },
468 92fc67cf Wojtek Kosior
        'mapping': {
469 b7378a99 Wojtek Kosior
            'helloapple-copy': {
470
                '0.1.1': sample_mapping2
471
            }
472
        },
473 1c65dd5c Wojtek Kosior
        'file': {
474
            'sha256': sample_files_by_sha256
475 5ed09841 Wojtek Kosior
        },
476
        'repo': [
477
            'https://hydril2.la/'
478
        ]
479 b7378a99 Wojtek Kosior
    }
480 b590eaa2 Wojtek Kosior
    execute_in_page('returnval(save_items(arguments[0]));', sample_data)
481 702eefd2 Wojtek Kosior
    execute_in_page('returnval(set_setting("option22", "abc"));')
482 5ed09841 Wojtek Kosior
    execute_in_page('returnval(set_repo("https://hydril3.la/"));')
483 0feb9db2 Wojtek Kosior
    execute_in_page('returnval(set_allowed("ftp://a.bc/"));')
484 b7378a99 Wojtek Kosior
485
    driver.switch_to.window(windows[0])
486
    driver.implicitly_wait(10)
487 0feb9db2 Wojtek Kosior
    for elem_id, json_value in [
488 7218849a Wojtek Kosior
            ('resource_helloapple-copy', sample_resource2),
489
            ('mapping_helloapple-copy', sample_mapping2),
490 92fc67cf Wojtek Kosior
            ('setting_option22', {'name': 'option22', 'value': 'abc'}),
491 5ed09841 Wojtek Kosior
            ('repo_https://hydril2.la/', {'url': 'https://hydril2.la/'}),
492
            ('repo_https://hydril3.la/', {'url': 'https://hydril3.la/'}),
493 0feb9db2 Wojtek Kosior
            ('blocking_ftp://a.bc/', {'pattern': 'ftp://a.bc/', 'allow': True})
494
    ]:
495
        assert json.loads(driver.find_element_by_id(elem_id).text) == json_value
496 b7378a99 Wojtek Kosior
    driver.implicitly_wait(0)
497
498 0feb9db2 Wojtek Kosior
    # See if item deletions/modifications get tracked properly.
499 b7378a99 Wojtek Kosior
    driver.switch_to.window(windows[1])
500
    execute_in_page(
501
        '''{
502 0feb9db2 Wojtek Kosior
        async function change_remove_items()
503 b7378a99 Wojtek Kosior
        {
504 7218849a Wojtek Kosior
            const store_names = ["resource", "mapping"];
505 b590eaa2 Wojtek Kosior
            const ctx = await start_items_transaction(store_names, {});
506
            await remove_resource("helloapple", ctx);
507
            await remove_mapping("helloapple-copy", ctx);
508 702eefd2 Wojtek Kosior
            await finalize_transaction(ctx);
509
            await set_setting("option22", null);
510 0feb9db2 Wojtek Kosior
            await del_repo("https://hydril.la");
511
            await set_default_allowing("file:///*");
512
            await set_disallowed("ftp://a.bc/");
513 b7378a99 Wojtek Kosior
        }
514 0feb9db2 Wojtek Kosior
        returnval(change_remove_items());
515 b7378a99 Wojtek Kosior
        }''')
516
517 7218849a Wojtek Kosior
    removed_ids = ['mapping_helloapple-copy', 'resource_helloapple',
518 92fc67cf Wojtek Kosior
                   'repo_https://hydril.la', 'blocking_file:///*']
519 0feb9db2 Wojtek Kosior
    def condition_items_absent_and_changed(driver):
520 b7378a99 Wojtek Kosior
        for id in removed_ids:
521
            try:
522
                driver.find_element_by_id(id)
523
                return False
524
            except WebDriverException:
525
                pass
526 0feb9db2 Wojtek Kosior
527 92fc67cf Wojtek Kosior
        option_text = driver.find_element_by_id('setting_option22').text
528 0feb9db2 Wojtek Kosior
        blocking_text = driver.find_element_by_id('blocking_ftp://a.bc/').text
529
        return (json.loads(option_text)['value'] == None and
530
                json.loads(blocking_text)['allow'] == False)
531 b7378a99 Wojtek Kosior
532
    driver.switch_to.window(windows[0])
533 0feb9db2 Wojtek Kosior
    WebDriverWait(driver, 10).until(condition_items_absent_and_changed)