cgminer_api_client 0.2.6

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.
@@ -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