cgminer_api_client 0.2.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,134 @@
1
+ require 'spec_helper'
2
+
3
+ describe CgminerApiClient::MinerPool do
4
+ let(:mock_miner) { instance_double('CgminerApiClient::Miner') }
5
+ let(:host) { '127.0.0.1' }
6
+ let(:port) { 1234 }
7
+ let(:timeout) { 10 }
8
+ let(:mock_miner_from_yaml) { double('miner_from_yaml', :[] => {'host' => host, 'port' => port, 'timeout' => timeout} ) }
9
+ let(:instance) { CgminerApiClient::MinerPool.new }
10
+
11
+ before do
12
+ allow(CgminerApiClient::Miner).to receive(:new).and_return(mock_miner)
13
+ end
14
+
15
+ context 'attributes' do
16
+ context '@miners' do
17
+ before do
18
+ allow(File).to receive(:exist?).with('config/miners.yml').and_return(true)
19
+ allow_any_instance_of(CgminerApiClient::MinerPool).to receive(:load_miners!).and_return(true)
20
+ end
21
+
22
+ it 'should allow setting and getting' do
23
+ instance.miners = :foo
24
+ expect(instance.miners).to eq :foo
25
+ end
26
+ end
27
+ end
28
+
29
+ context '#initialize' do
30
+ it 'should load_miners!' do
31
+ expect_any_instance_of(CgminerApiClient::MinerPool).to receive(:load_miners!)
32
+ instance
33
+ end
34
+ end
35
+
36
+ context '#available_miners' do
37
+ it 'should not include unavailable miners'
38
+ it 'should include available miners'
39
+ end
40
+
41
+ context '#query' do
42
+ before do
43
+ allow(File).to receive(:exist?).with('config/miners.yml').and_return(true)
44
+ allow_any_instance_of(CgminerApiClient::MinerPool).to receive(:load_miners!).and_return(true)
45
+ allow(instance).to receive(:load_miners!).and_return(true)
46
+ instance.instance_variable_set(:@miners, [mock_miner])
47
+ end
48
+
49
+ it 'should run provided query on each miner' do
50
+ expect(mock_miner).to receive(:query).with(:foo)
51
+ instance.query(:foo)
52
+ end
53
+
54
+ it 'should pass parameters' do
55
+ expect(mock_miner).to receive(:query).with(:foo, :parameters)
56
+ instance.query(:foo, :parameters)
57
+ end
58
+
59
+ it 'should return an array' do
60
+ allow(mock_miner).to receive(:query).with(:foo)
61
+ expect(instance.query(:foo)).to be_kind_of(Array)
62
+ end
63
+ end
64
+
65
+ context '#method_missing' do
66
+ before do
67
+ allow(File).to receive(:exist?).with('config/miners.yml').and_return(true)
68
+ allow_any_instance_of(CgminerApiClient::MinerPool).to receive(:load_miners!).and_return(true)
69
+ allow(instance).to receive(:query).and_return(true)
70
+ end
71
+
72
+ it 'should query each miner with the method name' do
73
+ expect(instance).to receive(:query).with(:foo).and_return(true)
74
+ instance.method_missing(:foo)
75
+ end
76
+
77
+ it 'should pass arguments' do
78
+ expect(instance).to receive(:query).with(:foo, [:arguments])
79
+ instance.method_missing(:foo, [:arguments])
80
+ end
81
+ end
82
+
83
+ context '#reload_miners!' do
84
+ before do
85
+ allow(File).to receive(:exist?).with('config/miners.yml').and_return(true)
86
+ allow_any_instance_of(CgminerApiClient::MinerPool).to receive(:load_miners!).and_return(true)
87
+ end
88
+
89
+ it 'should call load_miners!' do
90
+ expect(instance).to receive(:load_miners!)
91
+ instance.reload_miners!
92
+ end
93
+ end
94
+
95
+ context 'private methods' do
96
+ context '#load_miners!' do
97
+ context 'without configuration file' do
98
+ before do
99
+ expect(File).to receive(:exist?).with('config/miners.yml').and_return(false)
100
+ end
101
+
102
+ it 'should raise an error' do
103
+ expect{
104
+ instance
105
+ }.to raise_error(RuntimeError)
106
+ end
107
+ end
108
+
109
+ context 'with configuration file' do
110
+ before do
111
+ allow(File).to receive(:exist?).with('config/miners.yml').and_return(true)
112
+ end
113
+
114
+ it 'should parse the configuration file' do
115
+ expect(YAML).to receive(:load_file).with('config/miners.yml').and_return([mock_miner_from_yaml]).at_least(:once)
116
+ instance.send(:load_miners!)
117
+ end
118
+
119
+ it 'should create new instances of CgminerApiClient::Miner' do
120
+ allow(YAML).to receive(:load_file).with('config/miners.yml').and_return([mock_miner_from_yaml])
121
+ expect(CgminerApiClient::Miner).to receive(:new).with(mock_miner_from_yaml[:host], mock_miner_from_yaml[:port], mock_miner_from_yaml[:timeout])
122
+ instance.send(:load_miners!)
123
+ end
124
+
125
+ it 'should assign the remote instances to @miners' do
126
+ allow(YAML).to receive(:load_file).with('config/miners.yml').and_return([mock_miner_from_yaml])
127
+ allow(CgminerApiClient::Miner).to receive(:new).with(mock_miner_from_yaml[:host], mock_miner_from_yaml[:port], mock_miner_from_yaml[:timeout]).and_return(mock_miner)
128
+ instance.send(:load_miners!)
129
+ expect(instance.miners).to eq [mock_miner]
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,296 @@
1
+ require 'spec_helper'
2
+
3
+ describe CgminerApiClient::Miner do
4
+ let(:host) { '127.0.0.1' }
5
+ let(:port) { 4028 }
6
+ let(:timeout) { 1 }
7
+ let(:instance) { CgminerApiClient::Miner.new(host, port, timeout) }
8
+
9
+ context 'attributes' do
10
+ context '@host' do
11
+ it 'should allow setting and getting' do
12
+ instance.host = :foo
13
+ expect(instance.host).to eq :foo
14
+ end
15
+ end
16
+
17
+ context '@port' do
18
+ it 'should allow setting and getting' do
19
+ instance.port = :foo
20
+ expect(instance.port).to eq :foo
21
+ end
22
+ end
23
+
24
+ context '@timeout' do
25
+ it 'should allow setting and getting' do
26
+ instance.timeout = :foo
27
+ expect(instance.timeout).to eq :foo
28
+ end
29
+ end
30
+ end
31
+
32
+ context '#initialize' do
33
+ it 'should not raise an argument error with 0 arguments' do
34
+ expect {
35
+ CgminerApiClient::Miner.new
36
+ }.to_not raise_error()
37
+ end
38
+
39
+ it 'should not raise an argument error with 1 arguments' do
40
+ expect {
41
+ CgminerApiClient::Miner.new(host)
42
+ }.to_not raise_error()
43
+ end
44
+
45
+ it 'should not raise an argument error with 2 arguments' do
46
+ expect {
47
+ CgminerApiClient::Miner.new(host, port)
48
+ }.to_not raise_error()
49
+ end
50
+
51
+ it 'should not raise an argument error with 3 arguments' do
52
+ expect {
53
+ CgminerApiClient::Miner.new(host, port, timeout)
54
+ }.to_not raise_error()
55
+ end
56
+
57
+ it 'should use defaults' do
58
+ miner = CgminerApiClient::Miner.new
59
+ expect(miner.host).to eq CgminerApiClient.default_host
60
+ expect(miner.port).to eq CgminerApiClient.default_port
61
+ expect(miner.timeout).to eq CgminerApiClient.default_timeout
62
+ end
63
+
64
+ it 'should set @host' do
65
+ expect(instance.host).to eq host
66
+ end
67
+
68
+ it 'should set @port' do
69
+ expect(instance.port).to eq port
70
+ end
71
+
72
+ it 'should set @timeout' do
73
+ expect(instance.timeout).to eq timeout
74
+ end
75
+ end
76
+
77
+ context '#available?' do
78
+ let(:mock_socket) { instance_double('Socket') }
79
+
80
+ context 'open_socket raises an error' do
81
+ before do
82
+ expect(instance).to receive(:open_socket).and_raise(SocketError)
83
+ end
84
+
85
+ it 'should return false' do
86
+ expect(instance.available?).to eq false
87
+ end
88
+ end
89
+
90
+ context 'open_socket does not raise an error' do
91
+ before do
92
+ expect(instance).to receive(:open_socket).and_return(mock_socket)
93
+ end
94
+
95
+ context 'socket #close raises an error' do
96
+ before do
97
+ expect(mock_socket).to receive(:close).and_raise(SocketError)
98
+ end
99
+
100
+ it 'should return false' do
101
+ expect(instance.available?).to eq false
102
+ end
103
+ end
104
+
105
+ context 'socket #close does not raise an error' do
106
+ before do
107
+ expect(mock_socket).to receive(:close).and_return(:foo)
108
+ end
109
+
110
+ it 'should return true' do
111
+ expect(instance.available?).to eq true
112
+ end
113
+ end
114
+ end
115
+
116
+ it 'should set an instance variable' do
117
+ expect(instance).to receive(:open_socket).and_return(mock_socket)
118
+ expect(mock_socket).to receive(:close).and_return(true)
119
+ instance.available?
120
+ expect(instance.instance_variable_get(:@available)).to eq true
121
+ end
122
+ end
123
+
124
+ context '#query' do
125
+ context 'unavailable' do
126
+ before do
127
+ expect(instance).to receive(:available?).and_return(false)
128
+ end
129
+
130
+ it 'should not perform a command request' do
131
+ expect(instance).to receive(:perform_request).never
132
+ instance.query(:foo)
133
+ end
134
+
135
+ it 'should return nil' do
136
+ expect(instance.query(:foo)).to eq nil
137
+ end
138
+ end
139
+
140
+ context 'available' do
141
+ before do
142
+ expect(instance).to receive(:available?).and_return(true)
143
+ end
144
+
145
+ context 'no parameters' do
146
+ it 'should perform a command request' do
147
+ expect(instance).to receive(:perform_request).with({:command => :foo}).and_return({'foo' => []})
148
+ instance.query(:foo)
149
+ end
150
+ end
151
+
152
+ context 'parameters' do
153
+ it 'should perform a command request with parameters' do
154
+ expect(instance).to receive(:perform_request).with({:command => :foo, :parameter => 'bar,123,\\456'}).and_return({'foo' => []})
155
+ instance.query(:foo, :bar, :'123', :'\456')
156
+ end
157
+ end
158
+
159
+ it 'should return sanitized data' do
160
+ mock_data = double('data')
161
+ expect(instance).to receive(:perform_request).and_return(mock_data)
162
+ expect(instance).to receive(:sanitized).with(mock_data).and_return({:foo => []})
163
+ expect(instance.query(:foo)).to eq []
164
+ end
165
+
166
+ it 'should return sanitized data for multiple commands' do
167
+ mock_data = double('data')
168
+ expect(instance).to receive(:perform_request).and_return(mock_data)
169
+ expect(instance).to receive(:sanitized).with(mock_data).and_return({:foo => [], :bar => []})
170
+ expect(instance.query('foo+bar')).to eq ({:foo => [], :bar => []})
171
+ end
172
+ end
173
+ end
174
+
175
+ context '#method_missing' do
176
+ before do
177
+ allow(instance).to receive(:query).and_return(true)
178
+ end
179
+
180
+ it 'should query the miner with the method name' do
181
+ expect(instance).to receive(:query).with(:foo).and_return(true)
182
+ instance.method_missing(:foo)
183
+ end
184
+
185
+ it 'should pass arguments' do
186
+ expect(instance).to receive(:query).with(:foo, [:arguments])
187
+ instance.method_missing(:foo, [:arguments])
188
+ end
189
+ end
190
+
191
+ context 'private methods' do
192
+ context '#open_socket' do
193
+ pending
194
+ end
195
+
196
+ context '#perform_request' do
197
+ context 'Socket cannot be opened' do
198
+ before do
199
+ expect(instance).to receive(:open_socket).and_raise(SocketError)
200
+ end
201
+
202
+ it 'should raise an exception' do
203
+ expect {
204
+ instance.send(:perform_request, {})
205
+ }.to raise_error(RuntimeError, 'Connection to 127.0.0.1:4028 failed')
206
+ end
207
+ end
208
+
209
+ context 'Socket can be opened' do
210
+ let(:mock_socket) { instance_double('Socket', {
211
+ :write => true,
212
+ :read => "{'json':true}",
213
+ :close => true
214
+ }) }
215
+
216
+ before do
217
+ expect(instance).to receive(:open_socket).and_return(mock_socket)
218
+ end
219
+
220
+ context 'single command' do
221
+ it 'should parse the response as JSON and check the status' do
222
+ expect(JSON).to receive(:parse).with(mock_socket.read)
223
+ expect(instance).to receive(:check_status).and_return(true)
224
+ instance.send(:perform_request, {})
225
+ end
226
+ end
227
+
228
+ context 'multiple commands' do
229
+ it 'should parse the response as JSON and check the status of each response element' do
230
+ expect(JSON).to receive(:parse).with(mock_socket.read).and_return({:foo => [{'STATUS' => 'ALL_GOOD'}], :bar => [{'STATUS' => 'NOT_SO_GOOD'}]})
231
+ expect(instance).to receive(:check_status).with({"STATUS" => 'ALL_GOOD'})
232
+ expect(instance).to receive(:check_status).with({"STATUS" => 'NOT_SO_GOOD'})
233
+ instance.send(:perform_request, {command: 'foo+bar'})
234
+ end
235
+ end
236
+ end
237
+ end
238
+
239
+ context '#check_status' do
240
+ let(:mock_response) { {} }
241
+
242
+ context 'with successful status' do
243
+ before do
244
+ mock_response['STATUS'] = [{'STATUS' => 'S'}]
245
+ end
246
+
247
+ it 'should not log a message or raise an error' do
248
+ expect(instance).to receive(:puts).never
249
+ expect(instance).to receive(:raise).never
250
+ instance.send(:check_status, mock_response)
251
+ end
252
+ end
253
+
254
+ context 'with info status' do
255
+ before do
256
+ mock_response['STATUS'] = [{'STATUS' => 'I'}]
257
+ end
258
+
259
+ it 'should log a message' do
260
+ expect(instance).to receive(:puts)
261
+ instance.send(:check_status, mock_response)
262
+ end
263
+ end
264
+
265
+ context 'with warning status' do
266
+ before do
267
+ mock_response['STATUS'] = [{'STATUS' => 'W'}]
268
+ end
269
+
270
+ it 'should log a message' do
271
+ expect(instance).to receive(:puts)
272
+ instance.send(:check_status, mock_response)
273
+ end
274
+ end
275
+
276
+ context 'with error' do
277
+ before do
278
+ mock_response['STATUS'] = [{'STATUS' => 'E'}]
279
+ end
280
+
281
+ it 'should raise an exception' do
282
+ expect(instance).to receive(:raise)
283
+ instance.send(:check_status, mock_response)
284
+ end
285
+ end
286
+ end
287
+
288
+ context '#sanitized' do
289
+ let(:mock_data) { {'Ugly Key' => :foo} }
290
+
291
+ it 'should produce sensible output' do
292
+ expect(instance.send(:sanitized, mock_data)).to eq ({:ugly_key => :foo})
293
+ end
294
+ end
295
+ end
296
+ end
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ describe CgminerApiClient do
4
+ subject { CgminerApiClient }
5
+
6
+ before do
7
+ subject.default_timeout = 5
8
+ subject.default_port = 4028
9
+ end
10
+
11
+ it 'should have a version constant with major.minor.patch' do
12
+ expect(subject::VERSION).to_not be_empty
13
+ expect(subject::VERSION.split(/\./).length).to eq(3)
14
+ end
15
+
16
+ context 'module attributes' do
17
+ context 'default_timeout' do
18
+ it 'should allow setting and getting' do
19
+ subject.default_timeout = :foo
20
+ expect(subject.default_timeout).to eq :foo
21
+ end
22
+ end
23
+
24
+ context 'default_port' do
25
+ it 'should allow setting and getting' do
26
+ subject.default_port = :foo
27
+ expect(subject.default_port).to eq :foo
28
+ end
29
+ end
30
+ end
31
+
32
+ context '.config' do
33
+ it 'should yield a block if given' do
34
+ expect {
35
+ subject.config do |config|
36
+ config.default_timeout = :foo
37
+ end
38
+ }.to change { subject.default_timeout }.from(subject.default_timeout).to(:foo)
39
+ end
40
+ end
41
+ end