POSA_LEAKSMS/tests/heartbeat_timeout_test.php
cw2007 0b1e86c84a feat(sht30): 누수 노드에 온습도 동일-id 통합 (소스·서버예시·테스트·문서)
누수 노드(Pi-A=sensor_id 1, Pi-C=sensor_id 3)에 SHT30 온습도를 "같은
sensor_id"로 보고하는 구성을 반영. 노드는 기존 sht30_sensor.py를 별도
systemd 서비스로 얹고(불안정한 누수 코드 무변경), config_local로 SENSOR_ID만 지정.

- raspberry_pi4_sht30/config.py: config_local로 SENSOR_ID/SENSOR_NAME 오버라이드
  지원(미지정 시 기본 2 유지 — Pi-B 하위호환)
- php/config.local.example.php: METRIC_SENSOR_IDS=[1,2,3] 예시 +
  SENSOR_HEARTBEAT_TIMEOUT_SEC[1,3]=1800(1·3이 온습도 목록에 들어가도 누수
  오프라인 감지 속도 유지)
- tests/heartbeat_timeout_test.php: 동일-id 통합 시 1·3 누수 타임아웃 유지 검증
- docs/superpowers/{specs,plans}: 설계 문서 + 구현 계획

설치 패키지(deploy/* — gitignored)는 온디스크 산출물로 별도 반영(sht30 서브폴더,
install.sh 체이닝, WIRING/SETUP/README, 서버 SETUP 절차).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Nd7QvbgEWCjSQtUYnGNvvV
2026-07-15 10:16:49 +09:00

61 lines
2.7 KiB
PHP

<?php
declare(strict_types=1);
// 센서별 히트비트(오프라인 판정) 타임아웃 해소 순수 로직 테스트 (DB/네트워크 없음).
// resolve_heartbeat_timeout(): 명시 오버라이드 > 온습도(METRIC) 기본 > 전역 기본.
$root = dirname(__DIR__);
require_once $root . '/php/config.php'; // resolve_heartbeat_timeout() 포함
$failures = [];
function check(bool $cond, string $msg): void {
global $failures;
if (!$cond) { $failures[] = $msg; }
}
check(function_exists('resolve_heartbeat_timeout'), 'resolve_heartbeat_timeout() should exist.');
$overrides = [3 => 900]; // 3번만 명시 오버라이드
$metricIds = [2, 4]; // 온습도 센서
$metricDef = 7500;
$globalDef = 1200;
// ── 1) 명시 오버라이드 최우선(온습도여도) ──
check(resolve_heartbeat_timeout(3, $overrides, $metricIds, $metricDef, $globalDef) === 900,
'explicit override wins');
// ── 2) 온습도 센서 → METRIC 기본 ──
check(resolve_heartbeat_timeout(2, $overrides, $metricIds, $metricDef, $globalDef) === 7500,
'metric sensor -> metric default');
check(resolve_heartbeat_timeout(4, $overrides, $metricIds, $metricDef, $globalDef) === 7500,
'metric sensor 4 -> metric default');
// ── 3) 그 외(누수 등) → 전역 기본 ──
check(resolve_heartbeat_timeout(1, $overrides, $metricIds, $metricDef, $globalDef) === 1200,
'leak/other sensor -> global default');
// ── 4) 명시 오버라이드가 온습도 기본을 이긴다 ──
$ov2 = [2 => 4000];
check(resolve_heartbeat_timeout(2, $ov2, $metricIds, $metricDef, $globalDef) === 4000,
'explicit override beats metric default for a metric sensor');
// ── 5) 동일-id 온습도 통합: 누수 노드(1·3)가 METRIC_SENSOR_IDS 에도 포함돼도,
// 명시 오버라이드가 metric 기본(7500)을 이겨 누수 타임아웃(1800)을 유지해야 한다. ──
$sameIdOverride = [1 => 1800, 3 => 1800];
$sameIdMetric = [1, 2, 3]; // 1·3 은 온습도도 같은 id 로 보고 → 목록에 포함
check(resolve_heartbeat_timeout(1, $sameIdOverride, $sameIdMetric, 7500, 1200) === 1800,
'same-id leak(1) keeps leak timeout despite metric membership');
check(resolve_heartbeat_timeout(3, $sameIdOverride, $sameIdMetric, 7500, 1200) === 1800,
'same-id leak(3) keeps leak timeout despite metric membership');
check(resolve_heartbeat_timeout(2, $sameIdOverride, $sameIdMetric, 7500, 1200) === 7500,
'pure metric(2) still uses metric default');
if ($failures) {
fwrite(STDERR, "Heartbeat timeout test failures:\n");
foreach ($failures as $f) {
fwrite(STDERR, "- {$f}\n");
}
exit(1);
}
echo "Heartbeat timeout resolution checks passed.\n";