about summary refs log tree commit homepage
path: root/test/player_integration.rb
diff options
context:
space:
mode:
Diffstat (limited to 'test/player_integration.rb')
-rw-r--r--test/player_integration.rb121
1 files changed, 121 insertions, 0 deletions
diff --git a/test/player_integration.rb b/test/player_integration.rb
new file mode 100644
index 0000000..6580194
--- /dev/null
+++ b/test/player_integration.rb
@@ -0,0 +1,121 @@
+# -*- encoding: binary -*-
+# Copyright (C) 2013, Eric Wong <normalperson@yhbt.net>
+# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+require './test/helper'
+require 'dtas/player'
+require 'dtas/state_file'
+require 'yaml'
+require 'tempfile'
+require 'shellwords'
+require 'timeout'
+
+module PlayerIntegration
+  def setup
+    sock_tmp = Tempfile.new(%w(dtas-test .sock))
+    @state_tmp = Tempfile.new(%w(dtas-test .yml))
+    @sock_path = sock_tmp.path
+    sock_tmp.close!
+    @player = DTAS::Player.new
+    @player.socket = @sock_path
+    @player.state_file = DTAS::StateFile.new(@state_tmp.path)
+    @player.bind
+    @out = Tempfile.new(%w(dtas-test .out))
+    @err = Tempfile.new(%w(dtas-test .err))
+    @out.sync = @err.sync = true
+    @pid = fork do
+      at_exit { @player.close }
+      ENV["SOX_OPTS"] = "#{ENV['SOX_OPTS']} -R"
+      unless $DEBUG
+        $stdout.reopen(@out)
+        $stderr.reopen(@err)
+      end
+      @player.run
+    end
+
+    # null playback device with delay to simulate a real device
+    @fmt = DTAS::Format.new
+    @period = 0.01
+    @period_size = @fmt.bytes_per_sample * @fmt.channels * @fmt.rate * @period
+    @cmd = "exec 2>/dev/null " \
+           "ruby -e " \
+           "\"b=%q();loop{STDIN.readpartial(#@period_size,b);sleep(#@period)}\""
+
+    # FIXME gross...
+    @player.instance_eval do
+      @sink_buf.close!
+    end
+  end
+
+  module PlayerClient
+    def preq(args)
+      args = Shellwords.join(args) if Array === args
+      send(args, Socket::MSG_EOR)
+    end
+  end
+
+  def client_socket
+    s = Socket.new(:AF_UNIX, :SOCK_SEQPACKET, 0)
+    s.connect(Socket.pack_sockaddr_un(@sock_path))
+    s.extend(PlayerClient)
+    s
+  end
+
+  def wait_pid_dead(pid, time = 5)
+    Timeout.timeout(time) do
+      begin
+        Process.kill(0, pid)
+        sleep(0.01)
+      rescue Errno::ESRCH
+        return
+      end while true
+    end
+  end
+
+  def wait_files_not_empty(*files)
+    files = Array(files)
+    Timeout.timeout(5) { sleep(0.01) until files.all? { |f| f.size > 0 } }
+  end
+
+  def default_sink_pid(s)
+    default_pid = Tempfile.new(%w(dtas-test .pid))
+    pf = "echo $$ >> #{default_pid.path}; "
+    s.send("sink ed default command='#{pf}#@cmd'", Socket::MSG_EOR)
+    assert_equal "OK", s.readpartial(666)
+    default_pid
+  end
+
+  def teardown
+    Process.kill(:TERM, @pid) if @pid
+    Process.waitall
+    refute File.exist?(@sock_path)
+    @state_tmp.close!
+    @out.close! if @out
+    @err.close! if @err
+  end
+
+  def read_pid_file(file)
+    file.rewind
+    pid = file.read.to_i
+    assert_operator pid, :>, 0
+    pid
+  end
+
+  def tmp_noise(len = 5)
+    noise = Tempfile.open(%w(junk .sox))
+    cmd = %W(sox -R -n -r44100 -c2 #{noise.path} synth #{len} pluck)
+    assert system(*cmd), cmd
+    [ noise, len ]
+  end
+
+  def dethrottle_decoder(s)
+    s.send("sink ed default active=false", Socket::MSG_EOR)
+    assert_equal "OK", s.readpartial(666)
+  end
+
+  def stop_playback(pid_file, s)
+    s.send("skip", Socket::MSG_EOR)
+    assert_equal "OK", s.readpartial(666)
+    pid = read_pid_file(pid_file)
+    wait_pid_dead(pid)
+  end
+end