extends SceneTree const FacilityInstanceType = preload("res://scripts/facility/facility_instance.gd") const ServiceInstanceType = preload("res://scripts/facility/service_instance.gd") const FacilityServiceType = preload("res://scripts/facility/facility_service.gd") var _checks := 0 var _failures := 0 func _initialize() -> void: call_deferred("_run") func _run() -> void: print("S2: Facility Service") _test_state_priority_and_opening_hours() _test_policy_revision_and_request_snapshot() _test_deterministic_queue_and_departure() _test_capacity_progress_and_boundaries() _test_interruption_and_recovery() _test_determinism() _test_snapshot_round_trip_is_atomic() if _failures == 0: print("PASS: %d checks" % _checks) else: push_error("FAIL: %d of %d checks failed" % [_failures, _checks]) quit(_failures) func _test_state_priority_and_opening_hours() -> void: var facility := _facility(&"priority_room", 1, 4, 1, 2) facility.set_operational_conditions({&"active_staff_ids": []}, 0) _expect(facility.state == FacilityInstanceType.State.NO_STAFF, "staff shortage initially blocks opening") facility.set_operational_conditions({ &"durability": 0, &"access_available": false, &"power_available": false, &"operator_open": false, &"active_staff_ids": [], &"degraded_reasons": [&"DIRTY"], }, 600) _expect(facility.state == FacilityInstanceType.State.BROKEN, "BROKEN wins over every other state") _expect(facility.state_reasons.size() == 6, "all simultaneous state reasons are retained") facility.set_operational_conditions({ &"durability": 5_000, &"access_available": false, &"power_available": false, &"operator_open": false, &"active_staff_ids": [], &"degraded_reasons": [], }, 600) _expect(facility.state == FacilityInstanceType.State.NO_ACCESS, "NO_ACCESS wins after repair") facility.set_operational_conditions({&"access_available": true}, 600) _expect(facility.state == FacilityInstanceType.State.NO_POWER, "NO_POWER wins over staffing and closure") facility.set_operational_conditions({&"power_available": true}, 600) _expect(facility.state == FacilityInstanceType.State.NO_STAFF, "NO_STAFF wins over manual closure") facility.set_operational_conditions({&"active_staff_ids": [&"staff_a"]}, 600) _expect(facility.state == FacilityInstanceType.State.CLOSED, "manual closure follows operational failures") facility.set_operational_conditions({&"operator_open": true, &"durability": 2_999}, 600) _expect(facility.state == FacilityInstanceType.State.DEGRADED, "low durability produces DEGRADED") facility.set_operational_conditions({&"durability": 5_000}, 600) _expect(facility.state == FacilityInstanceType.State.OPEN, "healthy staffed facility opens") _expect(facility.set_opening_hours(600, 1_200), "valid opening hours are accepted") facility.evaluate_state(500) _expect(facility.state == FacilityInstanceType.State.CLOSED, "schedule closes facility before opening") facility.evaluate_state(600) _expect(facility.state == FacilityInstanceType.State.OPEN, "opening minute is inclusive") facility.evaluate_state(1_200) _expect(facility.state == FacilityInstanceType.State.CLOSED, "closing minute is exclusive") _expect(facility.set_opening_hours(1_200, 0), "midnight close creates a valid overnight interval") _expect(facility.is_within_opening_hours(1_300), "midnight-close schedule remains open late at night") func _test_policy_revision_and_request_snapshot() -> void: var service := FacilityServiceType.new() var facility := _facility(&"policy_room", 1, 3, 0, 1) _expect(service.register_instance(facility).is_success(), "facility instance registers") _expect(not service.register_instance(facility).is_success(), "duplicate facility instance ID is rejected") var changed = service.set_policy(facility.instance_id, {&"price_mode": &"standard"}) _expect(changed.is_success() and facility.policy_revision == 1, "immediate policy patch increments revision") var request := service.create_request( &"policy_request", facility.instance_id, [&"guest_a"], &"meal", 100, {&"quoted_price": 120} ) _expect(service.enqueue_request(request, 100).is_success(), "policy-quoted request enters queue") service.set_policy(facility.instance_id, {&"price_mode": &"premium"}) _expect(request.policy_snapshot[&"price_mode"] == &"standard", "queued request retains original policy snapshot") _expect(request.policy_revision == 1 and facility.policy_revision == 2, "request retains original policy revision") var scheduled = service.set_policy(facility.instance_id, {&"risk_mode": true}, 120) _expect(scheduled.is_success() and facility.policy_pending_revision == 3, "future policy receives pending revision") service.advance_one_minute(119) _expect(not facility.policy_current.has(&"risk_mode"), "pending policy does not apply early") service.advance_one_minute(120) _expect(facility.policy_current.get(&"risk_mode", false), "pending policy applies at exact minute") _expect(facility.policy_revision == 3, "scheduled application increments current revision once") func _test_deterministic_queue_and_departure() -> void: var service := FacilityServiceType.new() var facility := _facility(&"queue_room", 1, 3, 0, 2) service.register_instance(facility) var request_b := _request(service, facility, &"request_b", 10, 0, 2) var request_a := _request(service, facility, &"request_a", 10, 0, 2) var request_high := _request(service, facility, &"request_high", 11, 5, 2) _expect(service.enqueue_request(request_b, 10).is_success(), "first request enters queue") _expect(service.enqueue_request(request_a, 10).is_success(), "same-minute request enters queue") _expect(service.enqueue_request(request_high, 11).is_success(), "later high-priority request enters queue") _expect( _queue_ids(service, facility.instance_id) == [&"request_high", &"request_a", &"request_b"], "queue sorts by priority, arrival minute, then request ID" ) _expect(request_high.expected_wait == 0, "high-priority request wait estimate excludes requests behind it") _expect(not service.enqueue_request(request_a, 12).is_success(), "duplicate request ID is rejected permanently") var overflow := _request(service, facility, &"request_overflow", 12, 0, 2) _expect(not service.enqueue_request(overflow, 12).is_success(), "queue capacity rejects overflow") _expect(service.leave_queue(facility.instance_id, &"request_a").is_success(), "guest can leave queue") _expect(_queue_ids(service, facility.instance_id) == [&"request_high", &"request_b"], "queue departure removes entry immediately") _expect(not service.enqueue_request(request_a, 13).is_success(), "departed request ID cannot be reused") func _test_capacity_progress_and_boundaries() -> void: var service := FacilityServiceType.new() var facility := _facility(&"capacity_room", 2, 4, 0, 2) service.register_instance(facility) var starts: Array[StringName] = [] var completions: Array[StringName] = [] service.configure_callbacks( func(request: ServiceRequest, _facility_instance: FacilityInstance, _minute: int) -> bool: starts.append(request.request_id) return true, func(service_instance: ServiceInstance, _request_value: ServiceRequest, _facility_instance: FacilityInstance, _minute: int) -> bool: completions.append(service_instance.service_id) return true ) for request_id: StringName in [&"request_c", &"request_a", &"request_b"]: service.enqueue_request(_request(service, facility, request_id, 100, 0, 2), 100) var filled := service.fill_available_slots(facility.instance_id, 100) _expect(filled.size() == 2 and filled[0].is_success() and filled[1].is_success(), "capacity opens exactly two slots") _expect(starts == [&"request_a", &"request_b"], "slot starts follow deterministic request-ID tie break") _expect(facility.active_services.size() == 2, "two services occupy both slots") _expect(not service.start_next_service(facility.instance_id, 100).is_success(), "full facility cannot start a third service") service.advance_one_minute(101) _expect(completions.is_empty(), "two-minute service does not complete after one tick") service.advance_one_minute(102) _expect(completions.size() == 2, "both occupied slots complete independently") _expect(facility.active_services.size() == 1, "completion fills one freed slot from queue") _expect(starts == [&"request_a", &"request_b", &"request_c"], "next queued request is promoted after completion") var rejecting := FacilityServiceType.new() var rejection_room := _facility(&"rejection_room", 1, 2, 0, 1) rejecting.register_instance(rejection_room) rejecting.configure_callbacks( func(_request_value: ServiceRequest, _instance: FacilityInstance, _minute: int) -> bool: return true, func(_service_value: ServiceInstance, _request_value: ServiceRequest, _instance: FacilityInstance, _minute: int) -> String: return "ledger transaction rejected" ) rejecting.enqueue_request(_request(rejecting, rejection_room, &"atomic_request", 0, 0, 1), 0) var started = rejecting.start_next_service(rejection_room.instance_id, 0) var service_id: StringName = started.details[&"service_id"] var results := rejecting.advance_one_minute(1) _expect(results.any(func(result: CommandResult) -> bool: return not result.is_success()), "completion callback failure is surfaced") _expect(rejection_room.active_services.has(service_id), "failed completion transaction leaves service active") _expect(rejecting.get_request(&"atomic_request") != null, "failed completion transaction retains request") func _test_interruption_and_recovery() -> void: var service := FacilityServiceType.new() var facility := _facility(&"interrupt_room", 1, 2, 0, 3) service.register_instance(facility) service.enqueue_request(_request(service, facility, &"interrupt_request", 0, 0, 3), 0) var started = service.start_next_service(facility.instance_id, 0) var service_id: StringName = started.details[&"service_id"] service.set_operational_status(facility.instance_id, {&"power_available": false}, 1) service.advance_one_minute(1) var active := service.get_service(service_id) _expect(active.state == ServiceInstanceType.State.PAUSED, "power loss safely pauses active service") _expect(active.elapsed_minutes == 0, "paused service makes no progress") service.set_operational_status(facility.instance_id, {&"power_available": true}, 2) service.advance_one_minute(2) _expect(active.state == ServiceInstanceType.State.ACTIVE and active.elapsed_minutes == 1, "power restoration resumes service") service.interrupt_service(service_id, FacilityServiceType.INTERRUPTION_PLAYER_CLOSED, 2) _expect(active.state == ServiceInstanceType.State.ACTIVE, "normal player closure lets active service finish") service.set_operational_status(facility.instance_id, {&"durability": 0}, 3) service.advance_one_minute(3) _expect(active.state == ServiceInstanceType.State.FAILED, "facility breakage immediately fails active service") _expect(facility.active_services.is_empty(), "failed service frees its capacity slot") var grace_service := FacilityServiceType.new() var grace_room := _facility(&"grace_room", 1, 1, 0, 3) grace_service.register_instance(grace_room) grace_service.enqueue_request(_request(grace_service, grace_room, &"grace_request", 10, 0, 3), 10) var grace_started = grace_service.start_next_service(grace_room.instance_id, 10) var grace_id: StringName = grace_started.details[&"service_id"] grace_service.interrupt_service(grace_id, FacilityServiceType.INTERRUPTION_STAFF_UNAVAILABLE, 10) grace_service.advance_one_minute(14) _expect(grace_service.get_service(grace_id).state == ServiceInstanceType.State.WAITING_FOR_STAFF, "staff replacement waits through minute four") grace_service.advance_one_minute(15) _expect(grace_service.get_service(grace_id).state == ServiceInstanceType.State.FAILED, "staff replacement fails at five-minute deadline") func _test_determinism() -> void: var first := _deterministic_run() var second := _deterministic_run() _expect(first == second, "identical commands produce byte-equivalent facility snapshots") func _test_snapshot_round_trip_is_atomic() -> void: var service := FacilityServiceType.new() var facility := _facility(&"save_room", 1, 3, 0, 4) service.register_instance(facility) service.set_policy(facility.instance_id, {&"mode": &"quiet"}) service.set_policy(facility.instance_id, {&"mode": &"busy"}, 500) service.enqueue_request(_request(service, facility, &"active_request", 400, 2, 4), 400) service.enqueue_request(_request(service, facility, &"queued_request", 401, 0, 4), 401) service.start_next_service(facility.instance_id, 401) service.advance_one_minute(402) var snapshot := service.create_snapshot() var restored := FacilityServiceType.new() _expect(restored.restore_snapshot(snapshot), "valid facility snapshot restores") _expect(restored.create_snapshot() == snapshot, "snapshot round trip preserves full facility state") var before_invalid := restored.create_snapshot() var corrupt := snapshot.duplicate(true) corrupt[&"requests"].append(corrupt[&"requests"][0].duplicate(true)) _expect(not restored.restore_snapshot(corrupt), "duplicate request in snapshot is rejected") _expect(restored.create_snapshot() == before_invalid, "rejected restore leaves live state untouched") var corrupt_reference := snapshot.duplicate(true) corrupt_reference[&"instances"][0][&"queue_entries"] = ["missing_request"] _expect(not restored.restore_snapshot(corrupt_reference), "orphan queue reference is rejected") _expect(restored.create_snapshot() == before_invalid, "orphan rejection is also atomic") func _deterministic_run() -> Dictionary: var service := FacilityServiceType.new() var facility := _facility(&"deterministic_room", 2, 6, 0, 2) service.register_instance(facility) for request_data: Array in [ [&"request_d", 0], [&"request_b", 1], [&"request_c", 1], [&"request_a", 0], ]: var request_id: StringName = request_data[0] var priority: int = request_data[1] service.enqueue_request(_request(service, facility, request_id, 50, priority, 2), 50) service.fill_available_slots(facility.instance_id, 50) service.advance_one_minute(51) service.advance_one_minute(52) service.advance_one_minute(53) return service.create_snapshot() func _facility( instance_id: StringName, capacity: int, queue_capacity: int, staff_min: int, service_minutes: int ) -> FacilityInstance: return FacilityInstanceType.new().configure( instance_id, &"test_facility", { &"capacity": capacity, &"queue_capacity": queue_capacity, &"staff_min": staff_min, &"staff_max": maxi(staff_min, 2), &"active_staff_ids": [&"staff_a"] if staff_min > 0 else [], &"base_service_minutes": service_minutes, &"base_quality": 75, &"base_price": 100, } ) func _request( service: FacilityService, facility: FacilityInstance, request_id: StringName, created_at: int, priority: int, service_minutes: int ) -> ServiceRequest: return service.create_request( request_id, facility.instance_id, [StringName("guest_%s" % request_id)], &"test_service", created_at, {&"priority": priority, &"service_minutes": service_minutes} ) func _queue_ids(service: FacilityService, instance_id: StringName) -> Array[StringName]: var ids: Array[StringName] = [] for request: ServiceRequest in service.get_queue(instance_id): ids.append(request.request_id) return ids func _expect(condition: bool, label: String) -> void: _checks += 1 if condition: print(" ✓ %s" % label) return _failures += 1 push_error(" ✗ %s" % label)