Class: Test::Command

Inherits:
Object
  • Object
show all
Defined in:
lib/test/cmd.rb

Overview

test-cmd.rb provides an object oriented interface for spawning a command

Defined Under Namespace

Classes: Pipe

IO collapse

Predicates collapse

Callbacks collapse

Instance Method Summary collapse

Constructor Details

#initialize(cmd, *argv) ⇒ Test::Command

Parameters:

  • cmd (String)

    A command to spawn

  • argv (Array<String>)

    Zero or more command-line arguments



26
27
28
29
30
31
32
33
34
35
# File 'lib/test/cmd.rb', line 26

def initialize(cmd, *argv)
  @cmd = cmd
  @argv = argv.dup
  @env = {}
  @status = nil
  @spawned = false
  @stdout = ""
  @stderr = ""
  @enoent = false
end

Instance Method Details

#alive?Boolean Also known as: running?

Returns true when a command is running

Returns:

  • (Boolean)

    Returns true when a command is running



160
161
162
# File 'lib/test/cmd.rb', line 160

def alive?
  @producer&.alive?
end

#argv(*argv) ⇒ Test::Command

Parameters:

  • argv (Array<String, #to_s>)

    Command-line arguments

Returns:



41
42
43
# File 'lib/test/cmd.rb', line 41

def argv(*argv)
  tap { @argv.concat(argv) }
end

#command_not_found?Boolean Also known as: not_found?

Returns true when a command can't be found

Returns:

  • (Boolean)

    Returns true when a command can't be found



176
177
178
179
180
# File 'lib/test/cmd.rb', line 176

def command_not_found?
  spawn
  consume
  @enoent
end

#env(env) ⇒ Test::Command

Parameters:

  • env (Hash{String => String})

    Environment variables to set for the spawned command

Returns:



49
50
51
# File 'lib/test/cmd.rb', line 49

def env(env)
  tap { @env.merge!(env) }
end

#exit_statusInteger Also known as: exitstatus

Returns the exit status of a process

Returns:

  • (Integer)

    Returns the exit status of a process



113
114
115
# File 'lib/test/cmd.rb', line 113

def exit_status
  status.exitstatus
end

#failure {|cmd| ... } ⇒ Test::Command

Examples:

Test::Command.new("ruby", "-e", "exit 1").failure do
  print "fail pid #{_1.pid}", "\n"
end

Yield Parameters:

Returns:



211
212
213
214
215
216
217
# File 'lib/test/cmd.rb', line 211

def failure
  tap do
    spawn
    consume
    status.success? ? nil : yield(self)
  end
end

#kill!void

This method returns an undefined value.

Sends SIGKILL to a running command



168
169
170
171
# File 'lib/test/cmd.rb', line 168

def kill!
  return unless alive?
  Process.kill("SIGKILL", @pid)
end

#pidInteger

Returns the process ID of a spawned command

Returns:

  • (Integer)

    Returns the process ID of a spawned command



106
107
108
# File 'lib/test/cmd.rb', line 106

def pid
  status.pid
end

#spawnTest::Command

Spawns a command

Returns:



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/test/cmd.rb', line 56

def spawn
  return self if @spawned
  tap do
    @spawned = true
    @out, @err = Pipe.pair, Pipe.pair
    ##
    # Spawn in the calling thread so the command's fds are
    # wired up before the reader thread starts. We then close
    # our own copies of the write ends so the reader thread
    # observes EOF the moment the child exits, and reads both
    # streams with whole-buffer reads rather than a byte at
    # a time.
    @pid = Process.spawn(
      @env,
      @cmd, *@argv,
      {out: @out.w, err: @err.w, in: IO::NULL}
    )
    @out.w.close
    @err.w.close
    @producer = Thread.new do
      @stdout = @out.r.read
      @stderr = @err.r.read
      Process.wait
      @status = $?
    ensure
      @out.r.close
      @err.r.close
    end
  end
rescue Errno::ENOENT => ex
  @stderr = ex.message
  @enoent = true
  ##
  # Capture a real non-zero status so predicates like
  # #success? work even though the command never spawned.
  @status = Process.waitpid2(Process.spawn("false")).last
end

#spawned?Boolean

Returns true when a command has been spawned

Returns:

  • (Boolean)

    Returns true when a command has been spawned



153
154
155
# File 'lib/test/cmd.rb', line 153

def spawned?
  @spawned
end

#statusProcess::Status

Returns the status of a process

Returns:

  • (Process::Status)

    Returns the status of a process



97
98
99
100
101
# File 'lib/test/cmd.rb', line 97

def status
  spawn
  consume
  @status
end

#stderrString

Returns the contents of stderr

Returns:

  • (String)

    Returns the contents of stderr



133
134
135
136
137
# File 'lib/test/cmd.rb', line 133

def stderr
  spawn
  consume
  @stderr
end

#stdoutString

Returns the contents of stdout

Returns:

  • (String)

    Returns the contents of stdout



124
125
126
127
128
# File 'lib/test/cmd.rb', line 124

def stdout
  spawn
  consume
  @stdout
end

#success {|cmd| ... } ⇒ Test::Command

Examples:

Test::Command.new("ruby", "-e", "exit 0").success do
  print "ok pid #{_1.pid}", "\n"
end

Yield Parameters:

Returns:



195
196
197
198
199
200
201
# File 'lib/test/cmd.rb', line 195

def success
  tap do
    spawn
    consume
    status.success? ? yield(self) : nil
  end
end

#success?Boolean

Returns true when a command exited successfully

Returns:

  • (Boolean)

    Returns true when a command exited successfully



146
147
148
# File 'lib/test/cmd.rb', line 146

def success?
  status.success?
end