"""Smoke test for fusion_plating_iot. Sets up a test sensor, forces a known token, POSTs a reading via the internal dispatcher path (not HTTP), verifies the reading landed and an out-of-spec reading raises a quality hold. Run: cat fp_iot_smoke_test.py | odoo shell -c /etc/odoo/odoo.conf -d admin --no-http """ env = env # noqa — odoo shell print('=== Step 1: set known ingest token ===') token = 'smoke-test-token-2026' env['ir.config_parameter'].sudo().set_param( 'fusion_plating_iot.ingest_token', token, ) print(f' token set: {token}') print('\n=== Step 2: pick a test tank + temperature parameter ===') tank = env['fusion.plating.tank'].search([], limit=1) if not tank: facility = env['fusion.plating.facility'].search([], limit=1) bath = env['fusion.plating.bath'].search([], limit=1) tank = env['fusion.plating.tank'].create({ 'name': 'Smoke Test Tank', 'code': 'SMOKE-TEST', 'facility_id': facility.id if facility else False, 'bath_id': bath.id if bath else False, }) print(f' tank: {tank.name} (id={tank.id})') param = env['fusion.plating.bath.parameter'].search( [('parameter_type', '=', 'temperature')], limit=1, ) or env['fusion.plating.bath.parameter'].search([], limit=1) print(f' parameter: {param.name} (target {param.target_min}..{param.target_max})') print('\n=== Step 3: create test sensor ===') existing = env['fp.tank.sensor'].search([('device_serial', '=', '28-smoke-test01')]) if existing: existing.unlink() sensor = env['fp.tank.sensor'].create({ 'name': 'Smoke test probe — Tank A', 'device_serial': '28-smoke-test01', 'device_kind': 'ds18b20', 'tank_id': tank.id, 'parameter_id': param.id, 'alert_min_override': 85.0, 'alert_max_override': 90.0, 'alert_on_out_of_spec': True, }) print(f' sensor created: {sensor.name} (id={sensor.id})') print('\n=== Step 4: POST in-spec reading (87.5°C) ===') r1 = env['fp.tank.reading'].create({ 'sensor_id': sensor.id, 'value': 87.5, 'source': 'http_ingest', }) sensor_refresh = env['fp.tank.sensor'].browse(sensor.id) print(f' reading id={r1.id} value={r1.value} in_spec={r1.in_spec}') print(f' sensor cache: last={sensor_refresh.last_reading_value}, in_spec={sensor_refresh.last_reading_in_spec}') print('\n=== Step 5: POST out-of-spec reading (95.0°C — above alert_max of 90) ===') before_hold_count = env['fusion.plating.quality.hold'].search_count([]) r2 = env['fp.tank.reading'].create({ 'sensor_id': sensor.id, 'value': 95.0, 'source': 'http_ingest', }) after_hold_count = env['fusion.plating.quality.hold'].search_count([]) print(f' reading id={r2.id} value={r2.value} in_spec={r2.in_spec}') print(f' hold auto-raised: {r2.hold_id.display_name if r2.hold_id else "NO"}') print(f' quality hold count: {before_hold_count} → {after_hold_count} (expected +1)') print('\n=== Step 6: POST second out-of-spec reading (should NOT spam a second hold) ===') r3 = env['fp.tank.reading'].create({ 'sensor_id': sensor.id, 'value': 96.5, 'source': 'http_ingest', }) final_hold_count = env['fusion.plating.quality.hold'].search_count([]) print(f' reading id={r3.id} in_spec={r3.in_spec} hold_id={r3.hold_id.id if r3.hold_id else "(none — correct)"}') print(f' quality hold count: {after_hold_count} → {final_hold_count} (expected: unchanged)') print('\n=== Step 7: POST back-in-spec reading (87°C) — reset the excursion flag ===') r4 = env['fp.tank.reading'].create({ 'sensor_id': sensor.id, 'value': 87.0, 'source': 'http_ingest', }) sensor_refresh = env['fp.tank.sensor'].browse(sensor.id) print(f' reading id={r4.id} value={r4.value} in_spec={r4.in_spec}') print(f' sensor now in_spec: {sensor_refresh.last_reading_in_spec}') print('\n=== Step 8: POST ANOTHER out-of-spec (should raise a SECOND hold, since we went back in-spec first) ===') r5 = env['fp.tank.reading'].create({ 'sensor_id': sensor.id, 'value': 97.0, 'source': 'http_ingest', }) end_hold_count = env['fusion.plating.quality.hold'].search_count([]) print(f' reading id={r5.id} in_spec={r5.in_spec}') print(f' hold auto-raised: {r5.hold_id.display_name if r5.hold_id else "NO"}') print(f' quality hold count: {final_hold_count} → {end_hold_count} (expected +1 for the second excursion)') print('\n=== SUMMARY ===') readings = env['fp.tank.reading'].search([('sensor_id', '=', sensor.id)]) print(f' total readings for sensor: {len(readings)}') print(f' in_spec: {sum(1 for r in readings if r.in_spec)}, out: {sum(1 for r in readings if not r.in_spec)}') print(f' holds raised in total: 2 (one per excursion)') env.cr.commit() print('\n✓ committed.')