From 3cdcdd0535d5a312dbd57ea335b10cc00946aa87 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Aug 2021 11:07:30 +1000 Subject: [PATCH 1/7] Create report templates when testing --- InvenTree/report/apps.py | 2 +- InvenTree/report/views.py | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) delete mode 100644 InvenTree/report/views.py diff --git a/InvenTree/report/apps.py b/InvenTree/report/apps.py index 43c52b1997..21b3cc380e 100644 --- a/InvenTree/report/apps.py +++ b/InvenTree/report/apps.py @@ -19,7 +19,7 @@ class ReportConfig(AppConfig): This function is called whenever the report app is loaded """ - if canAppAccessDatabase(): + if canAppAccessDatabase(allow_test=True): self.create_default_test_reports() self.create_default_build_reports() diff --git a/InvenTree/report/views.py b/InvenTree/report/views.py deleted file mode 100644 index a2b5079b33..0000000000 --- a/InvenTree/report/views.py +++ /dev/null @@ -1,2 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals From 44818ca0c5de96e49281c7116540b2b3e5e8d4da Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 11 Aug 2021 17:40:00 +1000 Subject: [PATCH 2/7] Some simple API unit tests --- InvenTree/report/tests.py | 86 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/InvenTree/report/tests.py b/InvenTree/report/tests.py index a2b5079b33..8cd87bb9b1 100644 --- a/InvenTree/report/tests.py +++ b/InvenTree/report/tests.py @@ -1,2 +1,88 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals + +from django.urls import reverse + +from InvenTree.api_tester import InvenTreeAPITestCase + +import report.models as report_models + + +class ReportTest(InvenTreeAPITestCase): + + fixtures = [ + 'category', + 'part', + 'company', + 'location', + 'supplier_part', + 'stock', + 'stock_tests', + ] + + model = None + list_url = None + detail_url = None + print_url = None + + def setUp(self): + super().setUp() + + def test_list_endpoint(self): + """ + Test that the LIST endpoint works for each report + """ + + if self.list_url: + url = reverse(self.list_url) + + print("URL:", url) + response = self.get(url) + self.assertEqual(response.status_code, 200) + print("Response:") + print(response) + print(response.data) + + +class TestReportTest(ReportTest): + + model = report_models.TestReport + + list_url = 'api-stockitem-testreport-list' + detail_url = 'api-stockitem-testreport-detail' + print_url = 'api-stockitem-testreport-print' + + +class BuildReportTest(ReportTest): + + model = report_models.BuildReport + + list_url = 'api-build-report-list' + detail_url = 'api-build-report-detail' + print_url = 'api-build-report-print' + + +class BOMReportTest(ReportTest): + + model = report_models.BillOfMaterialsReport + + list_url = 'api-bom-report-list' + detail_url = 'api-bom-report-detail' + print_url = 'api-bom-report-print' + + +class POReportTest(ReportTest): + + model = report_models.PurchaseOrderReport + + list_url = 'api-po-report-list' + detail_url = 'api-po-report-detail' + print_url = 'api-po-report-print' + +class SOReportTest(ReportTest): + + model = report_models.SalesOrderReport + + list_url = 'api-so-report-list' + detail_url = 'api-so-report-detail' + print_url = 'api-so-report-print' \ No newline at end of file From 032057c93a223e4b010f22a65c505c98a5f01615 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 12 Aug 2021 13:18:10 +1000 Subject: [PATCH 3/7] PEP fixes --- InvenTree/report/tests.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/InvenTree/report/tests.py b/InvenTree/report/tests.py index 8cd87bb9b1..a41abfff77 100644 --- a/InvenTree/report/tests.py +++ b/InvenTree/report/tests.py @@ -79,10 +79,11 @@ class POReportTest(ReportTest): detail_url = 'api-po-report-detail' print_url = 'api-po-report-print' + class SOReportTest(ReportTest): model = report_models.SalesOrderReport list_url = 'api-so-report-list' detail_url = 'api-so-report-detail' - print_url = 'api-so-report-print' \ No newline at end of file + print_url = 'api-so-report-print' From 96ec8c4eb60e54256e6c215b57f1b6cd301a0603 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 12 Aug 2021 13:40:08 +1000 Subject: [PATCH 4/7] Copy report templates across as part of test setUp --- InvenTree/report/tests.py | 101 +++++++++++++++++++++++++++++++++++--- 1 file changed, 93 insertions(+), 8 deletions(-) diff --git a/InvenTree/report/tests.py b/InvenTree/report/tests.py index a41abfff77..c30f2f4151 100644 --- a/InvenTree/report/tests.py +++ b/InvenTree/report/tests.py @@ -1,7 +1,11 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals +import os +import shutil + from django.urls import reverse +from django.conf import settings from InvenTree.api_tester import InvenTreeAPITestCase @@ -28,20 +32,89 @@ class ReportTest(InvenTreeAPITestCase): def setUp(self): super().setUp() + def copyReportTemplate(self, filename, description): + """ + Copy the provided report template into the required media directory + """ + + src_dir = os.path.join( + os.path.dirname(os.path.realpath(__file__)), + 'templates', + 'report' + ) + + template_dir = os.path.join( + 'report', + 'inventree', + self.model.getSubdir(), + ) + + dst_dir = os.path.join( + settings.MEDIA_ROOT, + template_dir + ) + + if not os.path.exists(dst_dir): + os.makedirs(dst_dir, exist_ok=True) + + src_file = os.path.join(src_dir, filename) + dst_file = os.path.join(dst_dir, filename) + + if not os.path.exists(dst_file): + shutil.copyfile(src_file, dst_file) + + # Convert to an "internal" filename + db_filename = os.path.join( + template_dir, + filename + ) + + # Create a database entry for this report template! + self.model.objects.create( + name=os.path.splitext(filename)[0], + description=description, + template=db_filename, + enabled=True + ) + def test_list_endpoint(self): """ Test that the LIST endpoint works for each report """ - if self.list_url: - url = reverse(self.list_url) + if not self.list_url: + return - print("URL:", url) - response = self.get(url) - self.assertEqual(response.status_code, 200) - print("Response:") - print(response) - print(response.data) + url = reverse(self.list_url) + + response = self.get(url) + self.assertEqual(response.status_code, 200) + + reports = self.model.objects.all() + + n = len(reports) + + # API endpoint must return correct number of reports + self.assertEqual(len(response.data), n) + + # Filter by "enabled" status + response = self.get(url, {'enabled': True}) + self.assertEqual(len(response.data), n) + + response = self.get(url, {'enabled': False}) + self.assertEqual(len(response.data), 0) + + # Disable each report + for report in reports: + report.enabled = False + report.save() + + # Filter by "enabled" status + response = self.get(url, {'enabled': True}) + self.assertEqual(len(response.data), 0) + + response = self.get(url, {'enabled': False}) + self.assertEqual(len(response.data), n) class TestReportTest(ReportTest): @@ -52,6 +125,12 @@ class TestReportTest(ReportTest): detail_url = 'api-stockitem-testreport-detail' print_url = 'api-stockitem-testreport-print' + def setUp(self): + + self.copyReportTemplate('inventree_test_report.html', 'stock item test report') + + return super().setUp() + class BuildReportTest(ReportTest): @@ -61,6 +140,12 @@ class BuildReportTest(ReportTest): detail_url = 'api-build-report-detail' print_url = 'api-build-report-print' + def setUp(self): + + self.copyReportTemplate('inventree_build_order.html', 'build order template') + + return super().setUp() + class BOMReportTest(ReportTest): From 6748f3740500c5d5062ea08698ba212a7184ebba Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 12 Aug 2021 14:43:04 +1000 Subject: [PATCH 5/7] Unit tests for report printing --- InvenTree/report/tests.py | 64 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/InvenTree/report/tests.py b/InvenTree/report/tests.py index c30f2f4151..6e3ec68eb5 100644 --- a/InvenTree/report/tests.py +++ b/InvenTree/report/tests.py @@ -4,12 +4,14 @@ from __future__ import unicode_literals import os import shutil +from django.http.response import StreamingHttpResponse from django.urls import reverse from django.conf import settings from InvenTree.api_tester import InvenTreeAPITestCase import report.models as report_models +from common.models import InvenTreeUserSetting class ReportTest(InvenTreeAPITestCase): @@ -22,6 +24,8 @@ class ReportTest(InvenTreeAPITestCase): 'supplier_part', 'stock', 'stock_tests', + 'bom', + 'build', ] model = None @@ -131,6 +135,31 @@ class TestReportTest(ReportTest): return super().setUp() + def test_print(self): + """ + Printing tests for the TestReport + """ + + report = self.model.objects.get(pk=1) + + url = reverse(self.print_url, kwargs={'pk': 1}) + + # Try to print without providing a valid StockItem + response = self.get(url, expected_code=400) + + # Try to print with an invalid StockItem + response = self.get(url, {'item': 9999}, expected_code=400) + + # Now print with a valid StockItem + response = self.get(url, {'item': 1}) + + # Response should be a StreamingHttpResponse (PDF file) + self.assertEqual(type(response), StreamingHttpResponse) + + headers = response.headers + + self.assertEqual(headers['Content-Type'], 'application/pdf') + class BuildReportTest(ReportTest): @@ -146,6 +175,41 @@ class BuildReportTest(ReportTest): return super().setUp() + def test_print(self): + """ + Printing tests for the BuildReport + """ + + report = self.model.objects.get(pk=1) + + url = reverse(self.print_url, kwargs={'pk': 1}) + + # Try to print without providing a valid BuildOrder + response = self.get(url, expected_code=400) + + # Try to print with an invalid BuildOrder + response = self.get(url, {'build': 9999}, expected_code=400) + + # Now print with a valid BuildOrder + response = self.get(url, {'build': 1}) + + self.assertEqual(type(response), StreamingHttpResponse) + + headers = response.headers + + self.assertEqual(headers['Content-Type'], 'application/pdf') + self.assertEqual(headers['Content-Disposition'], 'attachment; filename="report.pdf"') + + # Now, set the download type to be "inline" + inline = InvenTreeUserSetting.get_setting_object('REPORT_INLINE', self.user) + inline.value = True + inline.save() + + response = self.get(url, {'build': 1}) + headers = response.headers + self.assertEqual(headers['Content-Type'], 'application/pdf') + self.assertEqual(headers['Content-Disposition'], 'inline; filename="report.pdf"') + class BOMReportTest(ReportTest): From e36b1e6c7068997de757a958a13efdfbe11be425 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 12 Aug 2021 14:51:18 +1000 Subject: [PATCH 6/7] PEP fixes --- InvenTree/report/tests.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/InvenTree/report/tests.py b/InvenTree/report/tests.py index 6e3ec68eb5..141db9beee 100644 --- a/InvenTree/report/tests.py +++ b/InvenTree/report/tests.py @@ -140,8 +140,6 @@ class TestReportTest(ReportTest): Printing tests for the TestReport """ - report = self.model.objects.get(pk=1) - url = reverse(self.print_url, kwargs={'pk': 1}) # Try to print without providing a valid StockItem @@ -180,8 +178,6 @@ class BuildReportTest(ReportTest): Printing tests for the BuildReport """ - report = self.model.objects.get(pk=1) - url = reverse(self.print_url, kwargs={'pk': 1}) # Try to print without providing a valid BuildOrder @@ -209,7 +205,7 @@ class BuildReportTest(ReportTest): headers = response.headers self.assertEqual(headers['Content-Type'], 'application/pdf') self.assertEqual(headers['Content-Disposition'], 'inline; filename="report.pdf"') - + class BOMReportTest(ReportTest): From f59ed27cf9e40874726c42f6c716d678cc229bbd Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 12 Aug 2021 15:14:13 +1000 Subject: [PATCH 7/7] Remove reliance on hard-coded PK values --- InvenTree/report/tests.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/InvenTree/report/tests.py b/InvenTree/report/tests.py index 141db9beee..704f98fed0 100644 --- a/InvenTree/report/tests.py +++ b/InvenTree/report/tests.py @@ -12,6 +12,8 @@ from InvenTree.api_tester import InvenTreeAPITestCase import report.models as report_models from common.models import InvenTreeUserSetting +from stock.models import StockItem +from build.models import Build class ReportTest(InvenTreeAPITestCase): @@ -140,7 +142,9 @@ class TestReportTest(ReportTest): Printing tests for the TestReport """ - url = reverse(self.print_url, kwargs={'pk': 1}) + report = self.model.objects.first() + + url = reverse(self.print_url, kwargs={'pk': report.pk}) # Try to print without providing a valid StockItem response = self.get(url, expected_code=400) @@ -149,7 +153,9 @@ class TestReportTest(ReportTest): response = self.get(url, {'item': 9999}, expected_code=400) # Now print with a valid StockItem - response = self.get(url, {'item': 1}) + item = StockItem.objects.first() + + response = self.get(url, {'item': item.pk}) # Response should be a StreamingHttpResponse (PDF file) self.assertEqual(type(response), StreamingHttpResponse) @@ -178,7 +184,9 @@ class BuildReportTest(ReportTest): Printing tests for the BuildReport """ - url = reverse(self.print_url, kwargs={'pk': 1}) + report = self.model.objects.first() + + url = reverse(self.print_url, kwargs={'pk': report.pk}) # Try to print without providing a valid BuildOrder response = self.get(url, expected_code=400) @@ -187,7 +195,10 @@ class BuildReportTest(ReportTest): response = self.get(url, {'build': 9999}, expected_code=400) # Now print with a valid BuildOrder - response = self.get(url, {'build': 1}) + + build = Build.objects.first() + + response = self.get(url, {'build': build.pk}) self.assertEqual(type(response), StreamingHttpResponse)