"""Tests for the warranty proof-of-cover document. A provider lookup answers whether a unit is covered; it does not produce the invoice or the extended-warranty certificate. Those had nowhere to live, so they stayed in somebody's mailbox. These pin the parts that are easy to get wrong: the document is authenticated on the way out, one per warranty, and the vendor's own filename survives so a download is recognisable. """ import io from plugins.warranty.models import Warranty def _warranty(db, vendor='Dell'): w = Warranty(vendor=vendor, servicetag='ABC123', provider='manual') db.session.add(w) db.session.commit() return w def test_upload_sets_url_and_keeps_the_original_filename(client, db, auth_headers): w = _warranty(db) response = client.post(f'/api/warranty/{w.warrantyid}/proof', data={'file': (io.BytesIO(b'%PDF-1.4 invoice'), 'Dell invoice 4471.pdf')}, content_type='multipart/form-data', headers=auth_headers) assert response.status_code == 200, response.get_json() body = response.get_json()['data'] assert body['proofurl'] == f'/api/warranty/proof/warranty-{w.warrantyid}.pdf' assert body['prooffilename'] == 'Dell invoice 4471.pdf' def test_download_needs_a_token_and_uses_the_vendor_filename(client, db, auth_headers): """An invoice carries pricing and a service tag - not open like an asset photo.""" w = _warranty(db) client.post(f'/api/warranty/{w.warrantyid}/proof', data={'file': (io.BytesIO(b'%PDF-1.4 invoice'), 'Dell invoice 4471.pdf')}, content_type='multipart/form-data', headers=auth_headers) path = f'/api/warranty/proof/warranty-{w.warrantyid}.pdf' assert client.get(path).status_code == 401 authed = client.get(path, headers=auth_headers) assert authed.status_code == 200 assert authed.data == b'%PDF-1.4 invoice' disposition = authed.headers.get('Content-Disposition', '') assert 'attachment' in disposition assert 'Dell invoice 4471.pdf' in disposition def test_rejects_an_unsupported_type(client, db, auth_headers): w = _warranty(db) response = client.post(f'/api/warranty/{w.warrantyid}/proof', data={'file': (io.BytesIO(b'MZ'), 'setup.exe')}, content_type='multipart/form-data', headers=auth_headers) assert response.status_code == 400 assert 'Unsupported document type' in response.get_data(as_text=True) def test_rejects_an_oversize_document(client, db, auth_headers, monkeypatch): from plugins.warranty.api import routes monkeypatch.setattr(routes, 'MAX_PROOF_BYTES', 512) w = _warranty(db) response = client.post(f'/api/warranty/{w.warrantyid}/proof', data={'file': (io.BytesIO(b'x' * 2048), 'scan.pdf')}, content_type='multipart/form-data', headers=auth_headers) assert response.status_code == 400 assert 'the limit is' in response.get_data(as_text=True) def test_replacing_keeps_one_document_per_warranty(client, db, auth_headers): import glob import os from flask import current_app w = _warranty(db) client.post(f'/api/warranty/{w.warrantyid}/proof', data={'file': (io.BytesIO(b'first'), 'scan.png')}, content_type='multipart/form-data', headers=auth_headers) client.post(f'/api/warranty/{w.warrantyid}/proof', data={'file': (io.BytesIO(b'%PDF second'), 'invoice.pdf')}, content_type='multipart/form-data', headers=auth_headers) proofdir = os.path.join(current_app.instance_path, 'warrantyproofs') files = glob.glob(os.path.join(proofdir, f'warranty-{w.warrantyid}.*')) assert len(files) == 1 and files[0].endswith('.pdf') def test_removing_clears_both_columns(client, db, auth_headers): w = _warranty(db) client.post(f'/api/warranty/{w.warrantyid}/proof', data={'file': (io.BytesIO(b'%PDF'), 'invoice.pdf')}, content_type='multipart/form-data', headers=auth_headers) response = client.delete(f'/api/warranty/{w.warrantyid}/proof', headers=auth_headers) body = response.get_json()['data'] assert body['proofurl'] is None assert body['prooffilename'] is None # --- a date that is not a date ----------------------------------------------- # # PUT /api/warranty/ with an unparseable enddate answered 200 "Warranty # updated" and stored NULL, which drops the record out of every expiry surface # it feeds. The local _parse_date swallowed the ValueError, so a typo and a # deliberate clear produced the same write. def _warranty_via_api(client, auth_headers, **fields): payload = {'vendor': 'Acme', 'servicetag': 'WD-1', 'enddate': '2027-06-30'} payload.update(fields) created = client.post('/api/warranty', headers=auth_headers, json=payload) assert created.status_code == 201, created.get_json() return created.get_json()['data']['warrantyid'] def test_a_mistyped_end_date_is_refused_not_stored_as_null(client, db, auth_headers): warrantyid = _warranty_via_api(client, auth_headers) refused = client.put(f'/api/warranty/{warrantyid}', headers=auth_headers, json={'enddate': '30-06-2027'}) assert refused.status_code == 400, refused.get_json() assert 'enddate' in refused.get_json()['data']['error']['message'] kept = db.session.get(Warranty, warrantyid) assert kept.enddate is not None, 'the stored cover date must survive a typo' assert str(kept.enddate) == '2027-06-30' def test_an_explicitly_empty_end_date_still_clears_it(client, db, auth_headers): warrantyid = _warranty_via_api(client, auth_headers, servicetag='WD-2') cleared = client.put(f'/api/warranty/{warrantyid}', headers=auth_headers, json={'enddate': ''}) assert cleared.status_code == 200, cleared.get_json() assert db.session.get(Warranty, warrantyid).enddate is None def test_a_mistyped_date_is_refused_at_create_too(client, db, auth_headers): refused = client.post('/api/warranty', headers=auth_headers, json={'vendor': 'Acme', 'servicetag': 'WD-3', 'startdate': 'yesterday'}) assert refused.status_code == 400, refused.get_json() assert Warranty.query.filter_by(servicetag='WD-3').first() is None