# frozen_string_literal: true # Zero-dependency test for the Transcriber wrapper. Uses tiny Ruby STUB scripts in place of the # real transcribe.py, so the subprocess/exit-code/output logic is validated in milliseconds — no # 7 GB model, no CPU-minutes. (A real end-to-end run is a separate manual smoke.) # Run: ruby components/transcription-worker/test_transcriber.rb require_relative "transcriber" require "tmpdir" $pass = 0; $fail = 0 def ok(d); $pass += 1; puts " ok #{d}"; end def bad(d, g = nil); $fail += 1; puts " FAIL #{d}#{g.nil? ? '' : " (#{g.inspect})"}"; end def eq(a, b, d); a == b ? ok(d) : bad(d, a); end def truthy(x, d); x ? ok(d) : bad(d, x); end Dir.mktmpdir do |dir| # a stub that writes a [Speaker N] transcript to the -o path and exits with a chosen code write_stub = lambda do |name, ruby| p = File.join(dir, name); File.write(p, ruby); p end ok_stub = write_stub.call("ok.rb", <<~RB) o = ARGV[ARGV.index("-o") + 1] File.write(o, "[Speaker 1]: Ahoj.\\n[Speaker 2]: Nazdar.\\n") exit 0 RB empty_stub = write_stub.call("empty.rb", "o=ARGV[ARGV.index('-o')+1]; File.write(o,''); exit 0\n") gated_stub = write_stub.call("gated.rb", "exit 5\n") # HF terms not accepted (terminal) crash_stub = write_stub.call("crash.rb", "exit 137\n") # OOM-kill style (retryable) slow_stub = write_stub.call("slow.rb", "sleep 5\n") # to exercise the timeout tr = ->(stub, **kw) { Helpdesk::Transcriber.new(python: "ruby", script: stub, env_file: File.join(dir, ".none")).transcribe(File.join(dir, "audio.wav"), **kw) } puts "success path" r = tr.call(ok_stub) eq(r[:state], "transcribed", "exit 0 with output → transcribed") truthy(r[:transcript].include?("Ahoj"), "transcript captured from -o file") eq(r[:retryable], false, "success not retryable") puts "no-speech (empty output on exit 0)" eq(tr.call(empty_stub)[:state], "no_speech", "empty transcript → no_speech (not a failure)") puts "terminal config error" r = tr.call(gated_stub) eq(r[:state], "config_error", "exit 5 → config_error") eq(r[:retryable], false, "config error NOT retried") puts "retryable crash" r = tr.call(crash_stub) eq(r[:state], "failed", "exit 137 → failed") eq(r[:retryable], true, "crash/OOM IS retryable") puts "timeout kills the process and is retryable" r = tr.call(slow_stub, timeout: 1) eq(r[:state], "failed", "timeout → failed") eq(r[:retryable], true, "timeout is retryable") eq(r[:reason], "timeout", "reason=timeout") end puts "\n#{$pass} passed, #{$fail} failed" exit($fail.zero? ? 0 : 1)