rspec-bash 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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