summaryrefslogtreecommitdiff
path: root/test/unit
diff options
context:
space:
mode:
authorWojtek Kosior <koszko@koszko.org>2021-12-10 19:14:26 +0100
committerWojtek Kosior <koszko@koszko.org>2021-12-10 19:14:26 +0100
commit1e4ce148c54a16c96e273090d5ff03b2a4789469 (patch)
tree6f87bc287ad600cf31d3a8ce99306cf3f5d1f242 /test/unit
parent3a90084ec14a15d9b76fa4bfed9e85f15a09dad7 (diff)
downloadbrowser-extension-1e4ce148c54a16c96e273090d5ff03b2a4789469.tar.gz
browser-extension-1e4ce148c54a16c96e273090d5ff03b2a4789469.zip
improve IndexedDB use
Diffstat (limited to 'test/unit')
-rw-r--r--test/unit/test_indexeddb.py136
1 files changed, 119 insertions, 17 deletions
diff --git a/test/unit/test_indexeddb.py b/test/unit/test_indexeddb.py
index e5e1626..f1322fb 100644
--- a/test/unit/test_indexeddb.py
+++ b/test/unit/test_indexeddb.py
@@ -28,8 +28,8 @@ def indexeddb_code():
def sample_file(contents):
return {
- 'sha256': sha256(contents.encode()).digest().hex(),
- contents: contents
+ 'hash_key': f'sha256-{sha256(contents.encode()).digest().hex()}',
+ 'contents': contents
}
sample_files = {
@@ -37,16 +37,17 @@ sample_files = {
'LICENSES/somelicense.txt': sample_file('Permission is granted...'),
'hello.js': sample_file('console.log("hello!");\n'),
'bye.js': sample_file('console.log("bye!");\n'),
+ 'combined.js': sample_file('console.log("hello!\\nbye!");\n'),
'README.md': sample_file('# Python Frobnicator\n...')
}
-sample_files_sha256 = \
- dict([[file['sha256'], file] for file in sample_files.values()])
+sample_files_by_hash = dict([[file['hash_key'], file['contents']]
+ for file in sample_files.values()])
def file_ref(file_name):
- return {'file': file_name, 'sha256': sample_files[file_name]['sha256']}
+ return {'file': file_name, 'hash_key': sample_files[file_name]['hash_key']}
-def test_save_item(execute_in_page, indexeddb_code):
+def test_save_remove_item(execute_in_page, indexeddb_code):
"""
indexeddb.js facilitates operating on Haketilo's internal database.
Verify database operations work properly.
@@ -79,11 +80,8 @@ def test_save_item(execute_in_page, indexeddb_code):
# Facilitate retrieving all IndexedDB contents.
execute_in_page(
'''
- async function get_database_contents(promise=Promise.resolve())
+ async function get_database_contents()
{
- if (promise)
- await promise;
-
const db = await haketilodb.get();
const transaction = db.transaction(db.objectStoreNames);
@@ -110,25 +108,129 @@ def test_save_item(execute_in_page, indexeddb_code):
'type': 'resource',
'identifier': 'helloapple',
'scripts': [file_ref('hello.js'), file_ref('bye.js')],
- 'type': 'resource'
}
next(iter(sample_item['source_copyright']))['ugly_extra_property'] = True
database_contents = execute_in_page(
'''{
- const prom = haketilodb.get().then(db => save_item(...arguments, db));
- returnval(get_database_contents(prom));
+ const promise = start_items_transaction(["resources"], arguments[1])
+ .then(ctx => save_item(arguments[0], ctx).then(() => ctx))
+ .then(finalize_items_transaction)
+ .then(get_database_contents);
+ returnval(promise);
}''',
- sample_item, sample_files_sha256)
+ sample_item, sample_files_by_hash)
assert len(database_contents['files']) == 4
- assert all([sample_files_sha256[file['sha256']] == file['contents']
+ assert all([sample_files_by_hash[file['hash_key']] == file['contents']
for file in database_contents['files']])
assert all([len(file) == 2 for file in database_contents['files']])
assert len(database_contents['file_uses']) == 4
assert all([uses['uses'] == 1 for uses in database_contents['file_uses']])
- assert set([uses['sha256'] for uses in database_contents['file_uses']]) \
- == set([file['sha256'] for file in database_contents['files']])
+ assert set([uses['hash_key'] for uses in database_contents['file_uses']]) \
+ == set([file['hash_key'] for file in database_contents['files']])
assert database_contents['mappings'] == []
assert database_contents['resources'] == [sample_item]
+
+ # See if trying to add an item without providing all its files ends in an
+ # exception and aborts the transaction as it should.
+ sample_item['scripts'].append(file_ref('combined.js'))
+ incomplete_files = {**sample_files_by_hash}
+ incomplete_files.pop(sample_files['combined.js']['hash_key'])
+ print ('incomplete files:', incomplete_files)
+ print ('sample item:', sample_item)
+ result = execute_in_page(
+ '''{
+ console.log('sample item', arguments[0]);
+ const promise = (async () => {
+ const context =
+ await start_items_transaction(["resources"], arguments[1]);
+ try {
+ await save_item(arguments[0], context);
+ await finalize_items_transaction(context);
+ return {};
+ } catch(e) {
+ var exception = e;
+ }
+
+ return {exception, db_contents: await get_database_contents()};
+ })();
+ returnval(promise);
+ }''',
+ sample_item, incomplete_files)
+
+ assert result
+ assert 'file not present' in result['exception']
+ for key, val in database_contents.items():
+ keyfun = lambda item: item.get('hash_key') or item['identifier']
+ assert sorted(result['db_contents'][key], key=keyfun) \
+ == sorted(val, key=keyfun)
+
+ # See if adding another item that partially uses first's files works OK.
+ sample_item = {
+ 'source_copyright': [
+ file_ref('report.spdx'),
+ file_ref('README.md')
+ ],
+ 'type': 'mapping',
+ 'identifier': 'helloapple',
+ }
+ database_contents = execute_in_page(
+ '''{
+ const promise = start_items_transaction(["mappings"], arguments[1])
+ .then(ctx => save_item(arguments[0], ctx).then(() => ctx))
+ .then(finalize_items_transaction)
+ .then(get_database_contents);
+ returnval(promise);
+ }''',
+ sample_item, sample_files_by_hash)
+
+ names = ['README.md', 'report.spdx', 'LICENSES/somelicense.txt', 'hello.js',
+ 'bye.js']
+ sample_files_list = [sample_files[name] for name in names]
+ uses_list = [1, 2, 1, 1, 1]
+
+ uses = dict([(uses['hash_key'], uses['uses'])
+ for uses in database_contents['file_uses']])
+ assert uses == dict([(file['hash_key'], nr)
+ for file, nr in zip(sample_files_list, uses_list)])
+
+ files = dict([(file['hash_key'], file['contents'])
+ for file in database_contents['files']])
+ assert files == dict([(file['hash_key'], file['contents'])
+ for file in sample_files_list])
+
+ assert database_contents['mappings'] == [sample_item]
+
+ # Try removing the items to get an empty database again.
+ results = [None, None]
+ for i, item_type in enumerate(['resource', 'mapping']):
+ results[i] = execute_in_page(
+ f'''{{
+ const remover = remove_{item_type};
+ const promise =
+ start_items_transaction(["{item_type}s"], {{}})
+ .then(ctx => remover('helloapple', ctx).then(() => ctx))
+ .then(finalize_items_transaction)
+ .then(get_database_contents);
+ returnval(promise);
+ }}''')
+
+ names = ['README.md', 'report.spdx']
+ sample_files_list = [sample_files[name] for name in names]
+ uses_list = [1, 1]
+
+ uses = dict([(uses['hash_key'], uses['uses'])
+ for uses in results[0]['file_uses']])
+ assert uses == dict([(file['hash_key'], 1) for file in sample_files_list])
+
+ files = dict([(file['hash_key'], file['contents'])
+ for file in results[0]['files']])
+ assert files == dict([(file['hash_key'], file['contents'])
+ for file in sample_files_list])
+
+ assert results[0]['resources'] == []
+ assert results[0]['mappings'] == [sample_item]
+
+ assert results[1] == dict([(key, []) for key in results[0].keys()])