diff --git a/src/documents/tests/test_api.py b/src/documents/tests/test_api.py index 21d53be9d..b492181d8 100644 --- a/src/documents/tests/test_api.py +++ b/src/documents/tests/test_api.py @@ -4,8 +4,10 @@ import json import os import shutil import tempfile +import urllib.request import zipfile from unittest import mock +from unittest.mock import MagicMock import pytest from django.conf import settings @@ -21,6 +23,7 @@ from documents.models import MatchingModel from documents.models import SavedView from documents.models import Tag from documents.tests.utils import DirectoriesMixin +from paperless import version from rest_framework.test import APITestCase from whoosh.writing import AsyncWriter @@ -2094,3 +2097,170 @@ class TestApiAuth(APITestCase): response = self.client.get("/api/") self.assertIn("X-Api-Version", response) self.assertIn("X-Version", response) + + +class TestRemoteVersion(APITestCase): + ENDPOINT = "/api/remote_version/" + + def setUp(self): + super().setUp() + + def test_remote_version_default(self): + response = self.client.get(self.ENDPOINT) + + self.assertEqual(response.status_code, 200) + self.assertDictEqual( + response.data, + { + "version": "0.0.0", + "update_available": False, + "feature_is_set": False, + }, + ) + + @override_settings( + ENABLE_UPDATE_CHECK=False, + ) + def test_remote_version_disabled(self): + response = self.client.get(self.ENDPOINT) + + self.assertEqual(response.status_code, 200) + self.assertDictEqual( + response.data, + { + "version": "0.0.0", + "update_available": False, + "feature_is_set": True, + }, + ) + + @override_settings( + ENABLE_UPDATE_CHECK=True, + ) + @mock.patch("urllib.request.urlopen") + def test_remote_version_enabled_no_update_prefix(self, urlopen_mock): + + cm = MagicMock() + cm.getcode.return_value = 200 + cm.read.return_value = json.dumps({"tag_name": "ngx-1.6.0"}).encode() + cm.__enter__.return_value = cm + urlopen_mock.return_value = cm + + response = self.client.get(self.ENDPOINT) + + self.assertEqual(response.status_code, 200) + self.assertDictEqual( + response.data, + { + "version": "1.6.0", + "update_available": False, + "feature_is_set": True, + }, + ) + + @override_settings( + ENABLE_UPDATE_CHECK=True, + ) + @mock.patch("urllib.request.urlopen") + def test_remote_version_enabled_no_update_no_prefix(self, urlopen_mock): + + cm = MagicMock() + cm.getcode.return_value = 200 + cm.read.return_value = json.dumps( + {"tag_name": version.__full_version_str__}, + ).encode() + cm.__enter__.return_value = cm + urlopen_mock.return_value = cm + + response = self.client.get(self.ENDPOINT) + + self.assertEqual(response.status_code, 200) + self.assertDictEqual( + response.data, + { + "version": version.__full_version_str__, + "update_available": False, + "feature_is_set": True, + }, + ) + + @override_settings( + ENABLE_UPDATE_CHECK=True, + ) + @mock.patch("urllib.request.urlopen") + def test_remote_version_enabled_update(self, urlopen_mock): + + new_version = ( + version.__version__[0], + version.__version__[1], + version.__version__[2] + 1, + ) + new_version_str = ".".join(map(str, new_version)) + + cm = MagicMock() + cm.getcode.return_value = 200 + cm.read.return_value = json.dumps( + {"tag_name": new_version_str}, + ).encode() + cm.__enter__.return_value = cm + urlopen_mock.return_value = cm + + response = self.client.get(self.ENDPOINT) + + self.assertEqual(response.status_code, 200) + self.assertDictEqual( + response.data, + { + "version": new_version_str, + "update_available": True, + "feature_is_set": True, + }, + ) + + @override_settings( + ENABLE_UPDATE_CHECK=True, + ) + @mock.patch("urllib.request.urlopen") + def test_remote_version_bad_json(self, urlopen_mock): + + cm = MagicMock() + cm.getcode.return_value = 200 + cm.read.return_value = b'{ "blah":' + cm.__enter__.return_value = cm + urlopen_mock.return_value = cm + + response = self.client.get(self.ENDPOINT) + + self.assertEqual(response.status_code, 200) + self.assertDictEqual( + response.data, + { + "version": "0.0.0", + "update_available": False, + "feature_is_set": True, + }, + ) + + @override_settings( + ENABLE_UPDATE_CHECK=True, + ) + @mock.patch("urllib.request.urlopen") + def test_remote_version_exception(self, urlopen_mock): + + cm = MagicMock() + cm.getcode.return_value = 200 + cm.read.side_effect = urllib.error.URLError("an error") + cm.__enter__.return_value = cm + urlopen_mock.return_value = cm + + response = self.client.get(self.ENDPOINT) + + self.assertEqual(response.status_code, 200) + self.assertDictEqual( + response.data, + { + "version": "0.0.0", + "update_available": False, + "feature_is_set": True, + }, + ) diff --git a/src/documents/views.py b/src/documents/views.py index f43581550..5d179da02 100644 --- a/src/documents/views.py +++ b/src/documents/views.py @@ -692,7 +692,10 @@ class RemoteVersionView(GenericAPIView): remote = response.read().decode("utf-8") try: remote_json = json.loads(remote) - remote_version = remote_json["tag_name"].removeprefix("ngx-") + remote_version = remote_json["tag_name"] + # Basically PEP 616 but that only went in 3.9 + if remote_version.startswith("ngx-"): + remote_version = remote_version[len("ngx-") :] except ValueError: logger.debug("An error occurred parsing remote version json") except urllib.error.URLError: