Files
OSIT-AE-App-Native-Electron/tests/test_device_lookup.py
Scott Idem bab08cd8a7 fix(packaging): workaround yauzl/Node 26 hang + fix API bootstrap contract
Packaging was silently hanging forever because yauzl 2.10.0 read streams
emit no data events under Node 26, causing extract-zip to block indefinitely
inside @electron/packager 20. Fix: postinstall script patches
@electron/packager/dist/unzip.js to use bsdtar (libarchive) instead.
bsdtar was chosen over 7z because 7z refuses chained symlinks in macOS
.app framework bundles. Both package:linux and package:mac now produce
correct output.

Also corrects the V3 API bootstrap contract in api_client.ts:
- SearchQuery body was wrapped in an extra {search_query: ...} layer — removed
- x-no-account-id header standardised to 'bypass'
- Redundant x-no-account-id removed from file download headers
- Smoke test rewritten to validate the real two-step bootstrap path

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 16:48:15 -04:00

91 lines
3.1 KiB
Python

import requests
import json
def test_bootstrap(device_id, api_key, base_url='https://dev-api.oneskyit.com'):
"""
Replicates the two-step bootstrap sequence in api_client.ts:
Step 1: GET event_device → extract account_id + app_base_url (fqdn)
Step 2: POST site_domain/search → returns the correct site context
"""
print(f'\n=== Bootstrap test ===')
print(f'Device: {device_id}')
print(f'Base URL: {base_url}')
# --- Step 1: Get Device Config ---
device_url = f'{base_url}/v3/crud/event_device/{device_id}'
headers_step1 = {
'Content-Type': 'application/json',
'x-aether-api-key': api_key,
'x-no-account-id': 'bypass',
}
print(f'\n-- Step 1: GET {device_url}')
try:
r1 = requests.get(device_url, headers=headers_step1)
print(f' Status: {r1.status_code}')
if r1.status_code != 200:
print(f' Error: {r1.text}')
return
device_data = r1.json().get('data', {})
important_fields = [
'account_id', 'app_base_url', 'code', 'name',
'event_id', 'event_location_id',
'local_file_cache_path', 'host_file_temp_path', 'recording_path',
]
for field in important_fields:
print(f' {field}: {device_data.get(field, "MISSING")}')
account_id = device_data.get('account_id') or device_data.get('account_id_random')
fqdn = device_data.get('app_base_url', 'native-demo.oneskyit.com')
except Exception as e:
print(f' Request failed: {e}')
return
# --- Step 2: Get Site Context ---
search_url = f'{base_url}/v3/crud/site_domain/search?limit=1'
headers_step2 = {
'Content-Type': 'application/json',
'x-aether-api-key': api_key,
'x-account-id': account_id or '',
}
body = {
'and': [{'field': 'fqdn', 'op': 'eq', 'value': fqdn}]
}
print(f'\n-- Step 2: POST {search_url}')
print(f' Searching for fqdn: {fqdn}')
try:
r2 = requests.post(search_url, headers=headers_step2, json=body)
print(f' Status: {r2.status_code}')
if r2.status_code != 200:
print(f' Error: {r2.text}')
return
results = r2.json().get('data', [])
print(f' Results returned: {len(results)}')
if results:
sd = results[0]
print(f' fqdn: {sd.get("fqdn")}')
print(f' account_id: {sd.get("account_id")}')
print(f' site_id: {sd.get("site_id")}')
if sd.get('account_id') != account_id:
print(f' WARNING: site_domain account_id does not match device account_id!')
else:
print(f' OK: account_id matches device.')
else:
print(f' WARNING: No site_domain found for fqdn "{fqdn}"')
except Exception as e:
print(f' Request failed: {e}')
if __name__ == '__main__':
# Dev device (dev-api)
test_bootstrap(
device_id='dbgMWS3KEHE',
api_key='INSdG85ANwsEIru3nUttMw',
base_url='https://dev-api.oneskyit.com',
)