rspec-bash 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +8 -0
  3. data/Gemfile +1 -0
  4. data/README.md +23 -0
  5. data/Rakefile +15 -4
  6. data/bin/bash_stub.sh +92 -0
  7. data/bin/bash_wrapper.sh.erb +12 -0
  8. data/bin/ruby_stub.rb +33 -0
  9. data/lib/rspec/bash.rb +5 -4
  10. data/lib/rspec/bash/command.rb +5 -0
  11. data/lib/rspec/bash/command/call_configuration.rb +76 -0
  12. data/lib/rspec/bash/command/call_configuration_manager.rb +24 -0
  13. data/lib/rspec/bash/command/call_log.rb +48 -0
  14. data/lib/rspec/bash/command/call_log_manager.rb +38 -0
  15. data/lib/rspec/bash/command/stubbed_command.rb +64 -0
  16. data/lib/rspec/bash/server.rb +3 -0
  17. data/lib/rspec/bash/server/bash_stub_marshaller.rb +19 -0
  18. data/lib/rspec/bash/server/ruby_stub_marshaller.rb +13 -0
  19. data/lib/rspec/bash/server/stub_server.rb +47 -0
  20. data/lib/rspec/bash/stubbed_env.rb +75 -54
  21. data/lib/rspec/bash/util/call_conf_argument_list_matcher.rb +5 -5
  22. data/lib/rspec/bash/util/call_log_argument_list_matcher.rb +1 -1
  23. data/lib/rspec/bash/wrapper.rb +4 -0
  24. data/lib/rspec/bash/wrapper/bash_stub_script.rb +15 -0
  25. data/lib/rspec/bash/wrapper/bash_wrapper.rb +54 -0
  26. data/lib/rspec/bash/wrapper/ruby_stub_script.rb +15 -0
  27. data/lib/rspec/bash/wrapper/stub_function.rb +36 -0
  28. data/rspec-bash.gemspec +2 -1
  29. data/spec/classes/command/call_configuration_manager_spec.rb +68 -0
  30. data/spec/classes/{call_configuration_spec.rb → command/call_configuration_spec.rb} +51 -114
  31. data/spec/classes/command/call_log_manager_spec.rb +83 -0
  32. data/spec/classes/{call_log_spec.rb → command/call_log_spec.rb} +23 -82
  33. data/spec/classes/command/stubbed_command_spec.rb +118 -0
  34. data/spec/classes/server/bash_stub_marshaller_spec.rb +38 -0
  35. data/spec/classes/server/ruby_stub_marshaller_spec.rb +31 -0
  36. data/spec/classes/server/stub_server_spec.rb +121 -0
  37. data/spec/classes/stubbed_env_spec.rb +141 -280
  38. data/spec/classes/util/call_conf_argument_list_matcher_spec.rb +17 -17
  39. data/spec/classes/util/call_log_argument_list_matcher_spec.rb +24 -18
  40. data/spec/classes/wrapper/bash_wrapper_spec.rb +37 -0
  41. data/spec/classes/wrapper/ruby_stub_script_spec.rb +204 -0
  42. data/spec/helper/string_file_io.rb +1 -1
  43. data/spec/integration/call_log/called_with_args_spec.rb +8 -4
  44. data/spec/integration/call_log/called_with_no_args_spec.rb +1 -1
  45. data/spec/integration/call_log/stdin_spec.rb +10 -4
  46. data/spec/integration/edge_cases_spec.rb +34 -0
  47. data/spec/integration/matchers/be_called_with_arguments_spec.rb +12 -13
  48. data/spec/integration/matchers/be_called_with_no_arguments_spec.rb +6 -7
  49. data/spec/integration/stubbed_command/outputs_spec.rb +111 -91
  50. data/spec/integration/stubbed_command/returns_exitstatus_spec.rb +46 -37
  51. data/spec/integration/stubbed_env/execute_with_env_vars_spec.rb +3 -4
  52. data/spec/integration/stubbed_env/execute_with_path_spec.rb +6 -7
  53. data/spec/integration/stubbed_env/execute_with_stub_wrapper_spec.rb +4 -12
  54. data/spec/integration/stubbed_env/override_spec.rb +354 -0
  55. data/spec/integration/wrapper/bash_stub_script_spec.rb +383 -0
  56. data/spec/integration/wrapper/bash_wrapper_spec.rb +48 -0
  57. data/spec/scripts/function_library.sh +9 -1
  58. data/spec/spec_helper.rb +2 -0
  59. metadata +65 -21
  60. data/bin/function_override.sh.erb +0 -7
  61. data/bin/function_override_wrapper.sh.erb +0 -19
  62. data/bin/stub.rb.erb +0 -56
  63. data/lib/rspec/bash/call_configuration.rb +0 -62
  64. data/lib/rspec/bash/call_log.rb +0 -71
  65. data/lib/rspec/bash/stubbed_command.rb +0 -88
  66. data/spec/classes/stub_spec.rb +0 -510
  67. data/spec/classes/stubbed_command_spec.rb +0 -134
  68. data/spec/integration/assert_called_spec.rb +0 -0
@@ -3,11 +3,11 @@ include Rspec::Bash
3
3
  include Rspec::Bash::Util
4
4
 
5
5
  describe 'CallLog' do
6
- let(:stubbed_env) { create_stubbed_env }
7
- let(:mock_log_file) { StringFileIO.new }
8
- let(:mock_log_pathname) { instance_double(Pathname) }
6
+ subject { CallLog.new }
7
+
9
8
  let(:mock_call_log_matcher) { instance_double(CallLogArgumentListMatcher) }
10
- before(:each) do
9
+
10
+ before do
11
11
  allow(mock_call_log_matcher).to receive(:get_call_log_matches).and_return(
12
12
  [
13
13
  {
@@ -28,77 +28,73 @@ describe 'CallLog' do
28
28
  allow(mock_call_log_matcher).to receive(:args_match?).and_return(true)
29
29
  allow(CallLogArgumentListMatcher).to receive(:new).with(any_args)
30
30
  .and_return(mock_call_log_matcher)
31
- allow(mock_log_pathname).to receive(:open).with('r').and_yield(mock_log_file)
32
- allow(mock_log_pathname).to receive(:open).with('w').and_yield(mock_log_file)
33
31
  end
34
32
 
35
- subject { CallLog.new(mock_log_pathname) }
36
-
37
33
  context '#stdin_for_args' do
38
34
  it 'returns the first matching stdin via the specialized matcher' do
39
35
  expect(mock_call_log_matcher).to receive(:get_call_log_matches)
40
36
  .with(any_args)
41
- expect(subject.stdin_for_args('first_argument', 'second_argument')).to eql 'first_stdin'
37
+
38
+ expect(subject.stdin_for_args(%w(first_argument second_argument))).to eql 'first_stdin'
42
39
  end
43
40
  end
41
+
44
42
  context '#call_count?' do
45
43
  it 'returns the expected call count via the specialized matcher' do
46
44
  expect(mock_call_log_matcher).to receive(:get_call_count)
47
45
  .with(any_args)
48
- expect(subject.call_count('first_argument', 'second_argument')).to eql 3
46
+
47
+ expect(subject.call_count(%w(first_argument second_argument))).to eql 3
49
48
  end
50
49
  end
50
+
51
51
  context '#called_with_args' do
52
52
  it 'returns the expected value via the specialized matcher' do
53
53
  expect(mock_call_log_matcher).to receive(:args_match?)
54
54
  .with(any_args)
55
- expect(subject.called_with_args?('first_argument', 'second_argument')).to eql true
55
+
56
+ expect(subject.called_with_args?(%w(first_argument second_argument))).to eql true
56
57
  end
57
58
  end
59
+
58
60
  context '#called_with_no_args?' do
59
61
  it 'returns false if no call log is found' do
60
- @subject = Rspec::Bash::CallLog.new(mock_log_pathname)
61
- @subject.call_log = []
62
+ subject.call_log = []
62
63
 
63
- expect(@subject.called_with_no_args?).to be_falsey
64
+ expect(subject.called_with_no_args?).to be_falsey
64
65
  end
65
66
  it 'returns true if no arguments are in call log' do
66
67
  actual_call_log = [{
67
68
  args: nil,
68
69
  stdin: []
69
70
  }]
70
- @subject = Rspec::Bash::CallLog.new(mock_log_pathname)
71
- @subject.call_log = actual_call_log
71
+ subject.call_log = actual_call_log
72
72
 
73
- expect(@subject.called_with_no_args?).to be_truthy
73
+ expect(subject.called_with_no_args?).to be_truthy
74
74
  end
75
75
  it 'returns fails if a single argument is in call log' do
76
76
  actual_call_log = [{
77
77
  args: ['I am an argument'],
78
78
  stdin: []
79
79
  }]
80
- @subject = Rspec::Bash::CallLog.new(mock_log_pathname)
81
- @subject.call_log = actual_call_log
80
+ subject.call_log = actual_call_log
82
81
 
83
- expect(@subject.called_with_no_args?).to be_falsey
82
+ expect(subject.called_with_no_args?).to be_falsey
84
83
  end
85
84
  it 'returns fails if multiple arguments is in call log' do
86
85
  actual_call_log = [{
87
86
  args: ['I am an argument', 'as am I'],
88
87
  stdin: []
89
88
  }]
90
- @subject = Rspec::Bash::CallLog.new(mock_log_pathname)
91
- @subject.call_log = actual_call_log
89
+ subject.call_log = actual_call_log
92
90
 
93
- expect(@subject.called_with_no_args?).to be_falsey
91
+ expect(subject.called_with_no_args?).to be_falsey
94
92
  end
95
93
  end
96
94
 
97
95
  context '#add_log' do
98
96
  context 'with any setup' do
99
- subject { Rspec::Bash::CallLog.new(mock_log_pathname) }
100
-
101
- context 'with no existing configuration' do
97
+ context 'with no existing log' do
102
98
  let(:expected_log) do
103
99
  [
104
100
  {
@@ -111,11 +107,6 @@ describe 'CallLog' do
111
107
  subject.add_log('first_stdin', %w(first_argument second_argument))
112
108
  expect(subject.call_log).to eql expected_log
113
109
  end
114
-
115
- it 'writes that log to its log file' do
116
- expect(mock_log_file).to receive(:write).with(expected_log.to_yaml)
117
- subject.add_log('first_stdin', %w(first_argument second_argument))
118
- end
119
110
  end
120
111
  context 'with an existing log' do
121
112
  let(:expected_log) do
@@ -130,7 +121,7 @@ describe 'CallLog' do
130
121
  }
131
122
  ]
132
123
  end
133
- before(:each) do
124
+ before do
134
125
  subject.call_log = [
135
126
  {
136
127
  args: %w(first_argument second_argument),
@@ -142,64 +133,14 @@ describe 'CallLog' do
142
133
  subject.add_log('second_stdin', %w(first_argument))
143
134
  expect(subject.call_log).to eql expected_log
144
135
  end
145
-
146
- it 'writes that log to its log file' do
147
- expect(mock_log_file).to receive(:write).with(expected_log.to_yaml)
148
- subject.add_log('second_stdin', %w(first_argument))
149
- end
150
- end
151
- end
152
- context 'with no config_path' do
153
- subject { Rspec::Bash::CallConfiguration.new(nil, anything) }
154
- it 'raises an error' do
155
- expect do
156
- subject.add_output('new_content', :stderr, %w(first_argument second_argument))
157
- end.to raise_exception(NoMethodError)
158
136
  end
159
137
  end
160
138
  end
161
139
  context '#call_log' do
162
- context 'when there is no call_log_path' do
163
- subject { Rspec::Bash::CallLog.new(nil) }
164
- it 'returns an empty array' do
165
- expect(subject.call_log).to eql []
166
- end
167
- end
168
140
  context 'when the call log exists but is empty' do
169
- subject { Rspec::Bash::CallLog.new(mock_log_pathname) }
170
- before(:each) do
171
- allow(mock_log_file).to receive(:read).and_return('')
172
- end
173
- it 'returns an empty array' do
174
- expect(subject.call_log).to eql []
175
- end
176
- end
177
- context 'when the call log file open throws a file not found exception' do
178
- subject { Rspec::Bash::CallLog.new(mock_log_pathname) }
179
- before(:each) do
180
- allow(mock_log_pathname).to receive(:open).with('r').and_raise(Errno::ENOENT)
181
- end
182
141
  it 'returns an empty array' do
183
142
  expect(subject.call_log).to eql []
184
143
  end
185
144
  end
186
- context 'when setup is valid' do
187
- subject { Rspec::Bash::CallLog.new(mock_log_pathname) }
188
- let(:log) do
189
- [{
190
- args: %w(first_argument second_argument),
191
- stdin: 'first_stdin'
192
- }]
193
- end
194
- context 'and a call log exists' do
195
- before(:each) do
196
- allow(mock_log_file).to receive(:read).and_return(log.to_yaml)
197
- end
198
-
199
- it 'reads out what was in its configuration file' do
200
- expect(subject.call_log).to eql log
201
- end
202
- end
203
- end
204
145
  end
205
146
  end
@@ -0,0 +1,118 @@
1
+ require 'spec_helper'
2
+ include Rspec::Bash
3
+
4
+ describe 'StubbedCommand' do
5
+ let(:call_log_manager) { double(CallLogManager) }
6
+ let(:call_conf_manager) { double(CallConfigurationManager) }
7
+
8
+ subject { StubbedCommand.new('command', call_log_manager, call_conf_manager) }
9
+
10
+ context '#called_with_args?' do
11
+ context 'with only a series of arguments' do
12
+ it 'passes the check to its CallLog\'s #called_with_args? method' do
13
+ expect(call_log_manager).to receive(:called_with_args?)
14
+ .with('command', %w(first_argument second_argument))
15
+ .and_return(true)
16
+ subject.called_with_args?('first_argument', 'second_argument')
17
+ end
18
+ end
19
+ end
20
+
21
+ context '#with_args' do
22
+ before do
23
+ subject.with_args('argument_one', 'argument_two')
24
+ end
25
+
26
+ it 'sets the arguments array on the StubbedCommand to the arguments that were passed in' do
27
+ expect(subject.arguments).to eql %w(argument_one argument_two)
28
+ end
29
+ end
30
+
31
+ context '#call_count' do
32
+ it 'returns value returned from call_log argument count when there are no arguments' do
33
+ expect(call_log_manager).to(
34
+ receive(:call_count)
35
+ .with('command', [])
36
+ .and_return('arbitrary return value')
37
+ )
38
+
39
+ expect(subject.call_count).to eql 'arbitrary return value'
40
+ end
41
+ it 'returns value returned from call_log argument count when there is only one argument' do
42
+ expect(call_log_manager).to receive(:call_count)
43
+ .with('command', ['only arg'])
44
+ .and_return('arbitrary return value')
45
+
46
+ expect(subject.call_count('only arg')).to eql 'arbitrary return value'
47
+ end
48
+ it 'returns value returned from call_log argument count when there are multiple arguments' do
49
+ expect(call_log_manager).to receive(:call_count)
50
+ .with('command', ['first arg', 'second arg'])
51
+ .and_return('arbitrary return value')
52
+
53
+ expect(subject.call_count('first arg', 'second arg')).to eql 'arbitrary return value'
54
+ end
55
+ end
56
+
57
+ context '#called?' do
58
+ it 'returns false when call_log is not called with args' do
59
+ expect(call_log_manager).to receive(:called_with_args?).and_return(false)
60
+
61
+ expect(subject.called?).to be_falsey
62
+ end
63
+ it 'returns true when call_log is called with args' do
64
+ expect(call_log_manager).to receive(:called_with_args?).and_return(true)
65
+
66
+ expect(subject.called?).to be_truthy
67
+ end
68
+ end
69
+
70
+ context '#stdin' do
71
+ it 'returns stdin from call log when call_log exists' do
72
+ expect(call_log_manager).to receive(:stdin_for_args).and_return('arbitrary stdin')
73
+
74
+ expect(subject.stdin).to eql 'arbitrary stdin'
75
+ end
76
+ end
77
+
78
+ context '#returns_exitstatus' do
79
+ it 'sets the exitcode on call_configuration' do
80
+ expect(call_conf_manager).to receive(:set_exitcode).with('command', 'exit code', anything)
81
+
82
+ subject.returns_exitstatus 'exit code'
83
+ end
84
+ it 'returns itself' do
85
+ expect(call_conf_manager).to receive(:set_exitcode)
86
+
87
+ expect(subject.returns_exitstatus(anything)).to eql subject
88
+ end
89
+ end
90
+
91
+ context '#outputs' do
92
+ it 'sets the output on the call_configuration' do
93
+ expect(call_conf_manager).to receive(:add_output).with(
94
+ 'command',
95
+ 'contents',
96
+ 'stderr',
97
+ anything
98
+ )
99
+
100
+ subject.outputs('contents', to: 'stderr')
101
+ end
102
+ it 'sets the "to" value for the output to stdout by default' do
103
+ expect(call_conf_manager).to receive(:add_output).with(
104
+ 'command',
105
+ 'contents',
106
+ :stdout,
107
+ anything
108
+ )
109
+
110
+ subject.outputs('contents')
111
+ end
112
+ it 'returns itself' do
113
+ expect(call_conf_manager).to receive(:add_output)
114
+
115
+ expect(subject.outputs(anything)).to eql subject
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+ include Rspec::Bash
3
+
4
+ describe 'BashStubMarshaller' do
5
+ subject { BashStubMarshaller.new }
6
+
7
+ context '#unmarshal' do
8
+ before do
9
+ allow(JSON).to receive(:parse)
10
+ .with('message_to_unmarshal')
11
+ .and_return('message.child' => 'unmarshalled')
12
+ allow(Sparsify).to receive(:unsparse)
13
+ .with('message.child' => 'unmarshalled')
14
+ .and_return(message: { child: 'unmarshalled' })
15
+ allow(JSON).to receive(:parse)
16
+ .with('{"message":{"child":"unmarshalled"}}', symbolize_names: true)
17
+ .and_return(message: { child: 'unmarshalled' })
18
+ end
19
+ it 'uses the JSON and sparsify libraries to unflatten the data' do
20
+ expect(subject.unmarshal('message_to_unmarshal'))
21
+ .to eql(message: { child: 'unmarshalled' })
22
+ end
23
+ end
24
+ context '#marshal' do
25
+ before do
26
+ allow(Sparsify).to receive(:sparse)
27
+ .with({ message: { child: 'unmarshalled' } }, sparse_array: true)
28
+ .and_return(:'message.child' => 'unmarshalled')
29
+ allow(JSON).to receive(:pretty_generate)
30
+ .with({ :'message.child' => 'unmarshalled' }, indent: '', space: '')
31
+ .and_return("{\n\"message.child\":\"unmarshalled\"\n}")
32
+ end
33
+ it 'uses the JSON and sparsify libraries to flatten the data' do
34
+ expect(subject.marshal(message: { child: 'unmarshalled' }))
35
+ .to eql("{\n\"message.child\":\"unmarshalled\"\n}")
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+ include Rspec::Bash
3
+
4
+ describe 'RubyStubMarshaller' do
5
+ subject { RubyStubMarshaller.new }
6
+
7
+ context '#unmarshal' do
8
+ before do
9
+ allow(Marshal).to receive(:load)
10
+ .with('message_to_unmarshal')
11
+ .and_return(message: 'unmarshalled')
12
+ end
13
+
14
+ it 'uses the built-in marshal library to unmarshal the data' do
15
+ expect(subject.unmarshal('message_to_unmarshal'))
16
+ .to eql(message: 'unmarshalled')
17
+ end
18
+ end
19
+ context '#marshal' do
20
+ before do
21
+ allow(Marshal).to receive(:dump)
22
+ .with(message: 'unmarshalled')
23
+ .and_return('marshalled_message')
24
+ end
25
+
26
+ it 'uses the built-in marshal library to marshal the data' do
27
+ expect(subject.marshal(message: 'unmarshalled'))
28
+ .to eql('marshalled_message')
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,121 @@
1
+ require 'spec_helper'
2
+ include Rspec::Bash
3
+
4
+ describe 'StubServer' do
5
+ let(:call_log_manager) { double(CallLogManager) }
6
+ let(:call_conf_manager) { double(CallConfigurationManager) }
7
+ let(:stub_marshaller) { double(RubyStubMarshaller) }
8
+ let(:tcp_server) { double(TCPServer) }
9
+ let(:accept_thread) { double(Thread) }
10
+
11
+ subject { StubServer.new(call_log_manager, call_conf_manager, stub_marshaller) }
12
+
13
+ context '#start' do
14
+ before do
15
+ allow(accept_thread).to receive(:kill)
16
+ allow(subject).to receive(:accept_loop)
17
+ allow(Thread).to receive(:new)
18
+ .and_yield
19
+ .and_return(accept_thread)
20
+ end
21
+
22
+ it 'returns the thread that the server is accepting connections on' do
23
+ expect(subject.start(tcp_server)).to eql(accept_thread)
24
+ end
25
+ it 'enters the accept loop' do
26
+ expect(subject).to receive(:accept_loop)
27
+ .with(tcp_server)
28
+ subject.start(tcp_server)
29
+ end
30
+ end
31
+ context '#accept_loop' do
32
+ let(:tcp_server) { double(TCPServer) }
33
+ let(:tcp_socket) { double(TCPSocket) }
34
+
35
+ before do
36
+ allow(tcp_server).to receive(:accept)
37
+ .and_return(tcp_socket)
38
+ allow(tcp_socket).to receive(:read)
39
+ .and_return('client_message')
40
+ allow(subject).to receive(:process)
41
+ .with('client_message')
42
+ .and_return('server_message')
43
+ end
44
+ it 'accepts the connection and replies' do
45
+ expect(tcp_socket).to receive(:write)
46
+ .with('server_message')
47
+ expect(tcp_socket).to receive(:close)
48
+
49
+ subject.accept_loop(tcp_server, false)
50
+ end
51
+ end
52
+ context '#process' do
53
+ let(:client_message) do
54
+ {
55
+ command: 'first_command',
56
+ stdin: 'stdin',
57
+ args: %w(first_argument second_argument)
58
+ }
59
+ end
60
+ let(:server_message) do
61
+ {
62
+ args: %w(first_argument second_argument),
63
+ exitcode: 0,
64
+ outputs: []
65
+ }
66
+ end
67
+ it 'calls its marshaller to serialize and deserialize messages' do
68
+ expect(stub_marshaller).to receive(:unmarshal)
69
+ .with('client_message')
70
+ .and_return(client_message)
71
+
72
+ expect(subject).to receive(:process_stub_call)
73
+ .with(client_message)
74
+ .and_return(server_message)
75
+
76
+ expect(stub_marshaller).to receive(:marshal)
77
+ .with(server_message)
78
+ .and_return('server_message')
79
+
80
+ expect(subject.process('client_message'))
81
+ .to eql 'server_message'
82
+ end
83
+ end
84
+ context '#process_stub_call' do
85
+ before do
86
+ allow(call_log_manager).to receive(:add_log)
87
+ allow(call_conf_manager).to receive(:get_best_call_conf)
88
+ .with('first_command', %w(first_argument second_argument))
89
+ .and_return(
90
+ args: %w(first_argument second_argument),
91
+ exitcode: 0,
92
+ outputs: []
93
+ )
94
+ end
95
+
96
+ it 'logs the call for the command' do
97
+ expect(call_log_manager).to receive(:add_log)
98
+ .with('first_command', 'stdin', %w(first_argument second_argument))
99
+
100
+ subject.process_stub_call(
101
+ command: 'first_command',
102
+ stdin: 'stdin',
103
+ args: %w(first_argument second_argument)
104
+ )
105
+ end
106
+
107
+ it 'returns the best matching call configuration for the command' do
108
+ expect(
109
+ subject.process_stub_call(
110
+ command: 'first_command',
111
+ stdin: 'stdin',
112
+ args: %w(first_argument second_argument)
113
+ )
114
+ ).to eql(
115
+ args: %w(first_argument second_argument),
116
+ exitcode: 0,
117
+ outputs: []
118
+ )
119
+ end
120
+ end
121
+ end