Add REST endpoint for uploading snapshots from the Singlefile extension (#996)

* Extract asset logic

* Allow disabling HTML snapshot when creating bookmark

* Add endpoint for uploading singlefile snapshots

* Add URL parameter to disable HTML snapshots

* Allow using asset list in base Docker image

* Expose app version through profile
This commit is contained in:
Sascha Ißbrücker
2025-02-23 22:58:14 +01:00
committed by GitHub
parent 2e97b13bad
commit 2d81ea6f6e
18 changed files with 723 additions and 314 deletions

View File

@@ -1,7 +1,6 @@
import secrets
import gzip
import os
import subprocess
import tempfile
from unittest import mock
from django.test import TestCase, override_settings
@@ -11,34 +10,14 @@ from bookmarks.services import singlefile
class SingleFileServiceTestCase(TestCase):
def setUp(self):
self.html_content = "<html><body><h1>Hello, World!</h1></body></html>"
self.html_filepath = secrets.token_hex(8) + ".html.gz"
self.temp_html_filepath = self.html_filepath + ".tmp"
self.temp_html_filepath = None
def tearDown(self):
if os.path.exists(self.html_filepath):
os.remove(self.html_filepath)
if os.path.exists(self.temp_html_filepath):
if self.temp_html_filepath and os.path.exists(self.temp_html_filepath):
os.remove(self.temp_html_filepath)
def create_test_file(self, *args, **kwargs):
with open(self.temp_html_filepath, "w") as file:
file.write(self.html_content)
def test_create_snapshot(self):
mock_process = mock.Mock()
mock_process.wait.return_value = 0
self.create_test_file()
with mock.patch("subprocess.Popen", return_value=mock_process):
singlefile.create_snapshot("http://example.com", self.html_filepath)
self.assertTrue(os.path.exists(self.html_filepath))
self.assertFalse(os.path.exists(self.temp_html_filepath))
with gzip.open(self.html_filepath, "rt") as file:
content = file.read()
self.assertEqual(content, self.html_content)
self.temp_html_filepath = tempfile.mkstemp(suffix=".tmp")[1]
def test_create_snapshot_failure(self):
# subprocess fails - which it probably doesn't as single-file doesn't return exit codes
@@ -46,12 +25,12 @@ class SingleFileServiceTestCase(TestCase):
mock_popen.side_effect = subprocess.CalledProcessError(1, "command")
with self.assertRaises(singlefile.SingleFileError):
singlefile.create_snapshot("http://example.com", self.html_filepath)
singlefile.create_snapshot("http://example.com", "nonexistentfile.tmp")
# so also check that it raises error if output file isn't created
with mock.patch("subprocess.Popen"):
with self.assertRaises(singlefile.SingleFileError):
singlefile.create_snapshot("http://example.com", self.html_filepath)
singlefile.create_snapshot("http://example.com", "nonexistentfile.tmp")
def test_create_snapshot_empty_options(self):
mock_process = mock.Mock()
@@ -59,7 +38,7 @@ class SingleFileServiceTestCase(TestCase):
self.create_test_file()
with mock.patch("subprocess.Popen") as mock_popen:
singlefile.create_snapshot("http://example.com", self.html_filepath)
singlefile.create_snapshot("http://example.com", self.temp_html_filepath)
expected_args = [
"single-file",
@@ -68,7 +47,7 @@ class SingleFileServiceTestCase(TestCase):
'--browser-arg="--no-sandbox"',
'--browser-arg="--load-extension=uBOLite.chromium.mv3"',
"http://example.com",
self.html_filepath + ".tmp",
self.temp_html_filepath,
]
mock_popen.assert_called_with(expected_args, start_new_session=True)
@@ -81,7 +60,7 @@ class SingleFileServiceTestCase(TestCase):
self.create_test_file()
with mock.patch("subprocess.Popen") as mock_popen:
singlefile.create_snapshot("http://example.com", self.html_filepath)
singlefile.create_snapshot("http://example.com", self.temp_html_filepath)
expected_args = [
"single-file",
@@ -95,7 +74,7 @@ class SingleFileServiceTestCase(TestCase):
"another value",
"--third-option=third value",
"http://example.com",
self.html_filepath + ".tmp",
self.temp_html_filepath,
]
mock_popen.assert_called_with(expected_args, start_new_session=True)
@@ -105,7 +84,7 @@ class SingleFileServiceTestCase(TestCase):
self.create_test_file()
with mock.patch("subprocess.Popen", return_value=mock_process):
singlefile.create_snapshot("http://example.com", self.html_filepath)
singlefile.create_snapshot("http://example.com", self.temp_html_filepath)
mock_process.wait.assert_called_with(timeout=120)
@@ -116,6 +95,6 @@ class SingleFileServiceTestCase(TestCase):
self.create_test_file()
with mock.patch("subprocess.Popen", return_value=mock_process):
singlefile.create_snapshot("http://example.com", self.html_filepath)
singlefile.create_snapshot("http://example.com", self.temp_html_filepath)
mock_process.wait.assert_called_with(timeout=180)