aboutsummaryrefslogtreecommitdiff
path: root/test/haketilo_test/unit/test_indexeddb_files_server.py
blob: 6ddfba833c06287de5a230f0c3569c4f9a96a1f0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# SPDX-License-Identifier: CC0-1.0

"""
Haketilo unit tests - serving indexeddb resource script files to content scripts
"""

# This file is part of Haketilo
#
# Copyright (C) 2021,2022 Wojtek Kosior <koszko@koszko.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the CC0 1.0 Universal License as published by
# the Creative Commons Corporation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# CC0 1.0 Universal License for more details.

import pytest
import copy
from uuid import uuid4
from selenium.webdriver.support.ui import WebDriverWait

from ..script_loader import load_script
from .utils import *

"""
How many test resources we're going to have.
"""
count = 15

sample_files_list = [(f'file_{n}_{i}', f'contents {n} {i}')
                       for n in range(count) for i in range(2)]

sample_files = dict(sample_files_list)

sample_files, sample_files_by_sha256 = make_sample_files(sample_files)

def make_sample_resource_with_deps(n):
    resource = make_sample_resource(with_files=False)

    resource['identifier'] = f'res-{n}'
    resource['dependencies'] = [{'identifier': f'res-{m}'}
                                for m in range(max(n - 4, 0), n)]
    resource['scripts'] = [sample_file_ref(f'file_{n}_{i}', sample_files)
                           for i in range(2)]

    return resource

resources = [make_sample_resource_with_deps(n) for n in range(count)]

sample_data = {
    'resource': sample_data_dict(resources),
    'mapping': {},
    'file': {
        'sha256': sample_files_by_sha256
    }
}

def prepare_test_page(initial_indexeddb_data, execute_in_page):
    js = load_script('background/indexeddb_files_server.js',
                     code_to_add='#IMPORT common/broadcast.js')
    execute_in_page(js)

    mock_broadcast(execute_in_page)
    clear_indexeddb(execute_in_page)

    execute_in_page(
        '''
        let registered_listener;
        const new_addListener = cb => registered_listener = cb;

        browser = {runtime: {onMessage: {addListener: new_addListener}}};

        haketilodb.save_items(arguments[0]);

        start();
        ''',
        initial_indexeddb_data)

@pytest.mark.get_page('https://gotmyowndoma.in')
def test_indexeddb_files_server_normal_usage(driver, execute_in_page):
    """
    Test querying resource files (with resource dependency resolution)
    from IndexedDB and serving them in messages to content scripts.
    """
    prepare_test_page(sample_data, execute_in_page)

    # Verify other types of messages are ignored.
    function_returned_value = execute_in_page(
        '''
        returnval(registered_listener(["???"], {},
                                      () => location.reload()));
        ''')
    assert function_returned_value == None

    # Verify single resource's files get properly resolved.
    function_returned_value = execute_in_page(
        '''
        var result_cb, contents_prom = new Promise(cb => result_cb = cb);

        returnval(registered_listener(["indexeddb_files", "res-0"],
                                      {}, result_cb));
        ''')
    assert function_returned_value == True

    assert execute_in_page('returnval(contents_prom);') == \
        {'files': [tuple[1] for tuple in sample_files_list[0:2]]}

    # Verify multiple resources' files get properly resolved.
    function_returned_value = execute_in_page(
        '''
        var result_cb, contents_prom = new Promise(cb => result_cb = cb);

        returnval(registered_listener(["indexeddb_files", arguments[0]],
                                      {}, result_cb));
        ''',
        f'res-{count - 1}')
    assert function_returned_value == True

    assert execute_in_page('returnval(contents_prom);') == \
        {'files': [tuple[1] for tuple in sample_files_list]}

@pytest.mark.get_page('https://gotmyowndoma.in')
@pytest.mark.parametrize('error', [
    'missing',
    'circular',
    'db',
    'other'
])
def test_indexeddb_files_server_errors(driver, execute_in_page, error):
    """
    Test reporting of errors when querying resource files (with resource
    dependency resolution) from IndexedDB and serving them in messages to
    content scripts.
    """
    sample_data_copy = copy.deepcopy(sample_data)

    if error == 'missing':
        del sample_data_copy['resource']['res-3']
    elif error == 'circular':
        res3_defs = sample_data_copy['resource']['res-3'].values()
        next(iter(res3_defs))['dependencies'].append({'identifier': 'res-8'})

    prepare_test_page(sample_data_copy, execute_in_page)

    if error == 'db':
        execute_in_page('haketilodb.idb_get = t => t.onerror("oooops");')
    elif error == 'other':
        execute_in_page('haketilodb.idb_get = () => {throw "oooops"};')

    response = execute_in_page(
        '''
        var result_cb, contents_prom = new Promise(cb => result_cb = cb);

        registered_listener(["indexeddb_files", arguments[0]],
                            {}, result_cb);

        returnval(contents_prom);
        ''',
        f'res-{count - 1}')

    assert response['error']['haketilo_error_type'] == error

    if error == 'missing':
        assert response['error']['id'] == 'res-3'
    elif error == 'circular':
        assert response['error']['id'] in ('res-3', 'res-8')
    elif error not in ('db', 'other'):
        raise Exception('made a typo in test function params?')