File: command_wrapper_test.rb

package info (click to toggle)
ruby-train 3.13.4-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,208 kB
  • sloc: ruby: 10,002; sh: 17; makefile: 8
file content (181 lines) | stat: -rw-r--r-- 7,040 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# author: Dominik Richter
# author: Christoph Hartmann

require "helper"
require "train/transports/mock"
require "train/extras"
require "base64" unless defined?(Base64)

describe "linux command" do
  let(:cls) { Train::Extras::LinuxCommand }
  let(:cmd) { rand.to_s }
  let(:backend) do
    backend = Train::Transports::Mock.new.connection
    backend.mock_os({ family: "linux" })
    backend
  end

  describe "sudo wrapping" do
    it "wraps commands in sudo" do
      lc = cls.new(backend, { sudo: true })
      _(lc.run(cmd)).must_equal "sudo #{cmd}"
    end

    it "doesn't wrap commands in sudo if user == root" do
      lc = cls.new(backend, { sudo: true, user: "root" })
      _(lc.run(cmd)).must_equal cmd
    end

    it "wraps commands in sudo with all options" do
      opts = rand.to_s
      lc = cls.new(backend, { sudo: true, sudo_options: opts })
      _(lc.run(cmd)).must_equal "sudo #{opts} #{cmd}"
    end

    it "runs commands in sudo with password" do
      pw = rand.to_s
      lc = cls.new(backend, { sudo: true, sudo_password: pw })
      bpw = Base64.strict_encode64(pw + "\n")
      _(lc.run(cmd)).must_equal "echo #{bpw} | base64 --decode | sudo -S #{cmd}"
    end

    it "wraps commands in sudo_command instead of sudo" do
      sudo_command = rand.to_s
      lc = cls.new(backend, { sudo: true, sudo_command: sudo_command })
      _(lc.run(cmd)).must_equal "#{sudo_command} #{cmd}"
    end

    it "wraps commands in sudo_command with all options" do
      opts = rand.to_s
      sudo_command = rand.to_s
      lc = cls.new(backend, { sudo: true, sudo_command: sudo_command, sudo_options: opts })
      _(lc.run(cmd)).must_equal "#{sudo_command} #{opts} #{cmd}"
    end

    it "runs commands in sudo_command with password" do
      pw = rand.to_s
      sudo_command = rand.to_s
      lc = cls.new(backend, { sudo: true, sudo_command: sudo_command, sudo_password: pw })
      bpw = Base64.strict_encode64(pw + "\n")
      _(lc.run(cmd)).must_equal "echo #{bpw} | base64 --decode | #{sudo_command} -S #{cmd}"
    end
  end

  describe "shell wrapping" do
    it "wraps commands in a default shell with login" do
      lc = cls.new(backend, { shell: true, shell_options: "--login" })
      bcmd = Base64.strict_encode64(cmd)
      _(lc.run(cmd)).must_equal "echo #{bcmd} | base64 --decode | $SHELL --login"
    end

    it "wraps sudo commands in a default shell with login" do
      lc = cls.new(backend, { sudo: true, shell: true, shell_options: "--login" })
      bcmd = Base64.strict_encode64("sudo #{cmd}")
      _(lc.run(cmd)).must_equal "echo #{bcmd} | base64 --decode | $SHELL --login"
    end

    it "wraps sudo commands and sudo passwords in a default shell with login" do
      pw = rand.to_s
      lc = cls.new(backend, { sudo: true, sudo_password: pw, shell: true, shell_options: "--login" })
      bpw = Base64.strict_encode64(pw + "\n")
      bcmd = Base64.strict_encode64("echo #{bpw} | base64 --decode | sudo -S #{cmd}")
      _(lc.run(cmd)).must_equal "echo #{bcmd} | base64 --decode | $SHELL --login"
    end

    it "wraps commands in a default shell when shell is true" do
      lc = cls.new(backend, { shell: true })
      bcmd = Base64.strict_encode64(cmd)
      _(lc.run(cmd)).must_equal "echo #{bcmd} | base64 --decode | $SHELL"
    end

    it "doesnt wrap commands in a shell when shell is false" do
      lc = cls.new(backend, { shell: false })
      _(lc.run(cmd)).must_equal cmd
    end

    it "wraps commands in a `shell` instead of default shell" do
      lc = cls.new(backend, { shell: true, shell_command: "/bin/bash" })
      bcmd = Base64.strict_encode64(cmd)
      _(lc.run(cmd)).must_equal "echo #{bcmd} | base64 --decode | /bin/bash"
    end

    it "wraps commands in a default shell with login" do
      lc = cls.new(backend, { shell: true, shell_command: "/bin/bash", shell_options: "--login" })
      bcmd = Base64.strict_encode64(cmd)
      _(lc.run(cmd)).must_equal "echo #{bcmd} | base64 --decode | /bin/bash --login"
    end
  end

  describe "#verify" do
    def mock_connect_result(stderr, exit_status)
      OpenStruct.new(stdout: "", stderr: stderr, exit_status: exit_status)
    end

    it "returns nil on success" do
      backend.stubs(:run_command).returns(mock_connect_result(nil, 0))
      lc = cls.new(backend, { sudo: true })
      _(lc.verify).must_be_nil
    end

    it "error message for bad sudo password" do
      backend.stubs(:run_command).returns(mock_connect_result("Sorry, try again", 1))
      lc = cls.new(backend, { sudo: true })
      err = _ { lc.verify! }.must_raise Train::UserError
      _(err.reason.to_s).must_match("bad_sudo_password")
    end

    it "error message for sudo password required" do
      backend.stubs(:run_command).returns(mock_connect_result("sudo: no tty present and no program specified", 1))
      lc = cls.new(backend, { sudo: true })
      err = _ { lc.verify! }.must_raise Train::UserError
      _(err.message).must_match(/Sudo failed: sudo: no tty present and no program specified/)
    end

    it "error message for sudo: command not found" do
      backend.stubs(:run_command).returns(mock_connect_result("sudo: command not found", 1))
      lc = cls.new(backend, { sudo: true })
      err = _ { lc.verify! }.must_raise Train::UserError
      _(err.reason.to_s).must_match("sudo_command_not_found")
    end

    it "error message for requires tty" do
      backend.stubs(:run_command).returns(mock_connect_result("sudo: sorry, you must have a tty to run sudo", 1))
      lc = cls.new(backend, { sudo: true })
      err = _ { lc.verify! }.must_raise Train::UserError
      _(err.reason.to_s).must_match("sudo_no_tty")
    end

    it "error message for other sudo related errors" do
      backend.stubs(:run_command).returns(mock_connect_result("Other sudo related error", 1))
      lc = cls.new(backend, { sudo: true })
      err = _ { lc.verify! }.must_raise Train::UserError
      _(err.message).must_match(/Other sudo related error/)
    end

    it "error message for not enough sudo privileges for OS operations" do
      backend.stubs(:run_command).returns(mock_connect_result("sudo: a terminal is required to read the password; either use the -S option to read from standard input or configure an askpass helper", 1))
      lc = cls.new(backend, { sudo: true })
      err = _ { lc.verify! }.must_raise Train::UserError
      _(err.reason.to_s).must_match("sudo_missing_terminal")
    end
  end
end

describe "windows command" do
  let(:cls) { Train::Extras::WindowsCommand }
  let(:cmd) { rand.to_s }
  let(:backend) do
    backend = Train::Transports::Mock.new.connection
    backend.mock_os({ family: "windows" })
    backend
  end

  describe "shell wrapping" do
    it "wraps commands in a default powershell" do
      lc = cls.new(backend, { shell: true })
      wcmd = "$ProgressPreference='SilentlyContinue';" + cmd
      bcmd = Base64.strict_encode64(wcmd.encode("UTF-16LE", "UTF-8"))
      _(lc.run(cmd)).must_equal "powershell -NoProfile -EncodedCommand #{bcmd}"
    end
  end
end