From 692039f712a2c05526c06a60c007b26c4ea7bbb3 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 9 Feb 2022 08:38:28 +1100 Subject: [PATCH] Add unit testing for uploading invalid BOM files --- InvenTree/part/test_bom_import.py | 145 ++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 InvenTree/part/test_bom_import.py diff --git a/InvenTree/part/test_bom_import.py b/InvenTree/part/test_bom_import.py new file mode 100644 index 0000000000..1438c3ee1c --- /dev/null +++ b/InvenTree/part/test_bom_import.py @@ -0,0 +1,145 @@ +""" +Unit testing for BOM upload / import functionality +""" + +import tablib + +from django.core.files.uploadedfile import SimpleUploadedFile +from django.urls import reverse + +from InvenTree.api_tester import InvenTreeAPITestCase + +from part.models import Part + + +class BomUploadTest(InvenTreeAPITestCase): + """ + Test BOM file upload API endpoint + """ + + roles = [ + 'part.add', + 'part.change', + ] + + def setUp(self): + super().setUp() + + self.part = Part.objects.create( + name='Assembly', + description='An assembled part', + assembly=True, + ) + + self.url = reverse('api-bom-extract') + + def post_bom(self, filename, file_data, part=None, clear_existing=None, expected_code=None, content_type='text/plain'): + + bom_file = SimpleUploadedFile( + filename, + file_data, + content_type=content_type, + ) + + if part is None: + part = self.part.pk + + if clear_existing is None: + clear_existing = False + + response = self.post( + self.url, + data={ + 'bom_file': bom_file, + 'part': part, + 'clear_existing': clear_existing, + }, + expected_code=expected_code, + format='multipart', + ) + + return response + + def test_missing_file(self): + """ + POST without a file + """ + + response = self.post( + self.url, + data={}, + expected_code=400 + ) + + self.assertIn('No file was submitted', str(response.data['bom_file'])) + self.assertIn('This field is required', str(response.data['part'])) + self.assertIn('This field is required', str(response.data['clear_existing'])) + + def test_unsupported_file(self): + """ + POST with an unsupported file type + """ + + response = self.post_bom( + 'sample.txt', + b'hello world', + expected_code=400, + ) + + self.assertIn('Unsupported file type', str(response.data['bom_file'])) + + def test_broken_file(self): + """ + Test upload with broken (corrupted) files + """ + + response = self.post_bom( + 'sample.csv', + b'', + expected_code=400, + ) + + self.assertIn('The submitted file is empty', str(response.data['bom_file'])) + + response = self.post_bom( + 'test.xls', + b'hello world', + expected_code=400, + content_type='application/xls', + ) + + self.assertIn('Unsupported format, or corrupt file', str(response.data['bom_file'])) + + def test_invalid_upload(self): + """ + Test upload of an invalid file + """ + + dataset = tablib.Dataset() + + dataset.headers = [ + 'apple', + 'banana', + ] + + dataset.append(['test', 'test']) + dataset.append(['hello', 'world']) + + response = self.post_bom( + 'test.csv', + bytes(dataset.csv, 'utf8'), + expected_code=400, + content_type='text/csv', + ) + + self.assertIn("Missing required column: 'quantity'", str(response.data)) + + # Try again, with an .xlsx file + response = self.post_bom( + 'bom.xlsx', + dataset.xlsx, + content_type='application/xlsx', + expected_code=400, + ) + + self.assertIn("Missing required column: 'quantity'", str(response.data))