"""Unit tests for product_store_eligibility_check script.""" import json from unittest.mock import AsyncMock, MagicMock, patch import product_store_eligibility_check as pec import pytest @pytest.mark.asyncio async def test_fetch_upc_success(): """Test fetch_upc returns status and body on success.""" # Mock the response object mock_response = AsyncMock() mock_response.status = 200 mock_response.text = AsyncMock(return_value='OK') # Mock the context manager from session.get mock_cm = AsyncMock() mock_cm.__aenter__.return_value = mock_response mock_cm.__aexit__.return_value = False session = MagicMock() session.get.return_value = mock_cm upc, status, text = await pec.fetch_upc( session, base_url='http://fake-api', store_id='123', delivery_type='delivery', upc='11111', timeout=5, retries=1, backoff_factor=0.5 ) assert upc == '11111' assert status == '200' assert text == 'OK' @pytest.mark.asyncio async def test_fetch_upc_failure(): """Test fetch_upc handles exceptions and returns ERROR.""" session = MagicMock() session.get.side_effect = Exception('Boom!') upc, status, text = await pec.fetch_upc( session, base_url='http://fake-api', store_id='123', delivery_type='pickup', upc='22222', timeout=5, retries=1, backoff_factor=0.5 ) assert upc == '22222' assert status == 'ERROR' assert 'Boom!' in text def test_load_upcs_valid(): """Test load_upcs removes duplicates and trims whitespace.""" upc_string = '12345,67890\n12345' upcs = pec.load_upcs(upc_string) assert sorted(upcs) == ['12345', '67890'] def test_load_upcs_empty(): """Test load_upcs exits when no UPCs provided.""" with pytest.raises(SystemExit): pec.load_upcs('') @pytest.mark.asyncio async def test_run_all(monkeypatch, caplog): """Test run_all executes fetch_upc for all UPCs.""" async def fake_fetch(session, base_url, store_id, delivery_type, upc, timeout, retries, backoff_factor): return upc, '200', 'OK' monkeypatch.setattr(pec, 'fetch_upc', fake_fetch) upcs = ['111', '222', '333'] await pec.run_all( upcs, base_url='http://fake', store_id='123', delivery_type='delivery', concurrency=2, timeout=5, retries=1, backoff_factor=0.5 ) for upc in upcs: assert any(f'[UPC {upc}] 200: OK' in msg for msg in caplog.messages) @patch('boto3.client') def test_upload_to_s3_calls_boto3(mock_boto): """Test upload_to_s3 calls boto3 with correct arguments.""" mock_client = MagicMock() mock_boto.return_value = mock_client pec.upload_to_s3('file.xlsx', 'my-bucket', 'prefix') mock_boto.assert_called_once_with('s3') mock_client.upload_file.assert_called_once_with('file.xlsx', 'my-bucket', 'prefix/file.xlsx') @patch('product_store_eligibility_check.Workbook') def test_save_results_to_excel_parses_json(mock_wb): """Unit test: verify rows are appended and saved correctly.""" # Mock workbook and worksheet mock_ws = MagicMock() mock_wb_instance = MagicMock() mock_wb_instance.active = mock_ws mock_wb.return_value = mock_wb_instance delivery_type = 'pickup' store_id = '100' results = [ ('11111', '200', json.dumps({'is_eligible': True, 'reason': None})), ('22222', '200', json.dumps({'is_eligible': False, 'reason': 'ACCOUNT_DELETED'})), ] filename = 'fake_results.xlsx' pec.save_results_to_excel(results, delivery_type, store_id, filename) # Verify header row mock_ws.append.assert_any_call(['UPC', 'DELIVERY_TYPE', 'STORE_ID', 'IS_ELIGIBLE', 'REASON', 'STATUS']) # Verify data rows mock_ws.append.assert_any_call(['11111', delivery_type, store_id, 'TRUE', 'NONE', '200']) mock_ws.append.assert_any_call(['22222', delivery_type, store_id, 'FALSE', 'ACCOUNT_DELETED', '200']) # Verify save called mock_wb_instance.save.assert_called_once_with(filename) def test_load_upcs_from_file_valid(tmp_path): """Test loading UPCs from a valid file removes duplicates and trims whitespace.""" file_path = tmp_path / 'upcs.txt' file_path.write_text('12345\n67890\n12345\n 11111 ') upcs = pec.load_upcs_from_file(str(file_path)) # Duplicates removed, whitespace trimmed assert sorted(upcs) == ['11111', '12345', '67890'] def test_load_upcs_from_file_missing(): """Test load_upcs_from_file exits if file does not exist.""" with pytest.raises(SystemExit): pec.load_upcs_from_file('nonexistent.txt')