Project

General

Profile

« Previous | Next » 

Revision 1e4ce148

Added by koszko over 1 year ago

improve IndexedDB use

View differences:

test/unit/test_indexeddb.py
28 28

  
29 29
def sample_file(contents):
30 30
    return {
31
        'sha256': sha256(contents.encode()).digest().hex(),
32
        contents: contents
31
        'hash_key': f'sha256-{sha256(contents.encode()).digest().hex()}',
32
        'contents': contents
33 33
    }
34 34

  
35 35
sample_files = {
......
37 37
    'LICENSES/somelicense.txt': sample_file('Permission is granted...'),
38 38
    'hello.js':                 sample_file('console.log("hello!");\n'),
39 39
    'bye.js':                   sample_file('console.log("bye!");\n'),
40
    'combined.js':              sample_file('console.log("hello!\\nbye!");\n'),
40 41
    'README.md':                sample_file('# Python Frobnicator\n...')
41 42
}
42 43

  
43
sample_files_sha256 = \
44
    dict([[file['sha256'], file] for file in sample_files.values()])
44
sample_files_by_hash = dict([[file['hash_key'], file['contents']]
45
                             for file in sample_files.values()])
45 46

  
46 47
def file_ref(file_name):
47
    return {'file': file_name, 'sha256': sample_files[file_name]['sha256']}
48
    return {'file': file_name, 'hash_key': sample_files[file_name]['hash_key']}
48 49

  
49
def test_save_item(execute_in_page, indexeddb_code):
50
def test_save_remove_item(execute_in_page, indexeddb_code):
50 51
    """
51 52
    indexeddb.js facilitates operating on Haketilo's internal database.
52 53
    Verify database operations work properly.
......
79 80
    # Facilitate retrieving all IndexedDB contents.
80 81
    execute_in_page(
81 82
        '''
82
        async function get_database_contents(promise=Promise.resolve())
83
        async function get_database_contents()
83 84
        {
84
            if (promise)
85
                await promise;
86

  
87 85
            const db = await haketilodb.get();
88 86

  
89 87
            const transaction = db.transaction(db.objectStoreNames);
......
110 108
        'type': 'resource',
111 109
        'identifier': 'helloapple',
112 110
        'scripts': [file_ref('hello.js'), file_ref('bye.js')],
113
        'type': 'resource'
114 111
    }
115 112
    next(iter(sample_item['source_copyright']))['ugly_extra_property'] = True
116 113

  
117 114
    database_contents = execute_in_page(
118 115
        '''{
119
        const prom = haketilodb.get().then(db => save_item(...arguments, db));
120
        returnval(get_database_contents(prom));
116
        const promise = start_items_transaction(["resources"], arguments[1])
117
            .then(ctx => save_item(arguments[0], ctx).then(() => ctx))
118
            .then(finalize_items_transaction)
119
            .then(get_database_contents);
120
        returnval(promise);
121 121
        }''',
122
        sample_item, sample_files_sha256)
122
        sample_item, sample_files_by_hash)
123 123
    assert len(database_contents['files']) == 4
124
    assert all([sample_files_sha256[file['sha256']] == file['contents']
124
    assert all([sample_files_by_hash[file['hash_key']] == file['contents']
125 125
                for file in database_contents['files']])
126 126
    assert all([len(file) == 2 for file in database_contents['files']])
127 127

  
128 128
    assert len(database_contents['file_uses']) == 4
129 129
    assert all([uses['uses'] == 1 for uses in database_contents['file_uses']])
130
    assert set([uses['sha256'] for uses in database_contents['file_uses']]) \
131
        == set([file['sha256'] for file in database_contents['files']])
130
    assert set([uses['hash_key'] for uses in database_contents['file_uses']]) \
131
        == set([file['hash_key'] for file in database_contents['files']])
132 132

  
133 133
    assert database_contents['mappings'] == []
134 134
    assert database_contents['resources'] == [sample_item]
135

  
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
    sample_item['scripts'].append(file_ref('combined.js'))
139
    incomplete_files = {**sample_files_by_hash}
140
    incomplete_files.pop(sample_files['combined.js']['hash_key'])
141
    print ('incomplete files:', incomplete_files)
142
    print ('sample item:', sample_item)
143
    result = execute_in_page(
144
        '''{
145
        console.log('sample item', arguments[0]);
146
        const promise = (async () => {
147
            const context =
148
                await start_items_transaction(["resources"], arguments[1]);
149
            try {
150
                await save_item(arguments[0], context);
151
                await finalize_items_transaction(context);
152
                return {};
153
            } catch(e) {
154
                var exception = e;
155
            }
156

  
157
            return {exception, db_contents: await get_database_contents()};
158
        })();
159
        returnval(promise);
160
        }''',
161
        sample_item, incomplete_files)
162

  
163
    assert result
164
    assert 'file not present' in result['exception']
165
    for key, val in database_contents.items():
166
        keyfun = lambda item: item.get('hash_key') or item['identifier']
167
        assert sorted(result['db_contents'][key], key=keyfun) \
168
            == sorted(val,                        key=keyfun)
169

  
170
    # See if adding another item that partially uses first's files works OK.
171
    sample_item = {
172
        'source_copyright': [
173
            file_ref('report.spdx'),
174
            file_ref('README.md')
175
        ],
176
        'type': 'mapping',
177
        'identifier': 'helloapple',
178
    }
179
    database_contents = execute_in_page(
180
        '''{
181
        const promise = start_items_transaction(["mappings"], arguments[1])
182
            .then(ctx => save_item(arguments[0], ctx).then(() => ctx))
183
            .then(finalize_items_transaction)
184
            .then(get_database_contents);
185
        returnval(promise);
186
        }''',
187
        sample_item, sample_files_by_hash)
188

  
189
    names = ['README.md', 'report.spdx', 'LICENSES/somelicense.txt', 'hello.js',
190
             'bye.js']
191
    sample_files_list = [sample_files[name] for name in names]
192
    uses_list = [1, 2, 1, 1, 1]
193

  
194
    uses = dict([(uses['hash_key'], uses['uses'])
195
                 for uses in database_contents['file_uses']])
196
    assert uses  == dict([(file['hash_key'], nr)
197
                          for file, nr in zip(sample_files_list, uses_list)])
198

  
199
    files = dict([(file['hash_key'], file['contents'])
200
                  for file in database_contents['files']])
201
    assert files == dict([(file['hash_key'], file['contents'])
202
                          for file in sample_files_list])
203

  
204
    assert database_contents['mappings'] == [sample_item]
205

  
206
    # Try removing the items to get an empty database again.
207
    results = [None, None]
208
    for i, item_type in enumerate(['resource', 'mapping']):
209
         results[i] = execute_in_page(
210
            f'''{{
211
            const remover = remove_{item_type};
212
            const promise =
213
                start_items_transaction(["{item_type}s"], {{}})
214
                .then(ctx => remover('helloapple', ctx).then(() => ctx))
215
                .then(finalize_items_transaction)
216
                .then(get_database_contents);
217
            returnval(promise);
218
            }}''')
219

  
220
    names = ['README.md', 'report.spdx']
221
    sample_files_list = [sample_files[name] for name in names]
222
    uses_list = [1, 1]
223

  
224
    uses = dict([(uses['hash_key'], uses['uses'])
225
                 for uses in results[0]['file_uses']])
226
    assert uses  == dict([(file['hash_key'], 1) for file in sample_files_list])
227

  
228
    files = dict([(file['hash_key'], file['contents'])
229
                  for file in results[0]['files']])
230
    assert files == dict([(file['hash_key'], file['contents'])
231
                          for file in sample_files_list])
232

  
233
    assert results[0]['resources'] == []
234
    assert results[0]['mappings'] == [sample_item]
235

  
236
    assert results[1] == dict([(key, []) for key in  results[0].keys()])

Also available in: Unified diff