sibit 0.18.8 → 0.19.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9754c11ebf54c9b04ce2b44bfc21f58a1758713d51c204b32c03e79e737db1e7
4
- data.tar.gz: 3abeb42d2a54d543825f0da9244da1cff4c842180e58f94bc8694a38595852ce
3
+ metadata.gz: ca53f721586f3a69839c0862f37fbb1d17cd06b880a6bfbe62d2df04b0f29e2e
4
+ data.tar.gz: 33734496a83daed1b161675b095cf478f0b9af5e3c96fa9755055fc867d6e606
5
5
  SHA512:
6
- metadata.gz: 286f4ac1cbd4244fb7dd7a867e01f36bab27d5cb91813c7d7a5fe5ce9e2a01441eb917e65e8c8f2dc7af87714e71227bfda39ca21e3d5cdc03af26ff950068cf
7
- data.tar.gz: 681f6f576a93c2ceb67c633022c57157026e8b516cd6a989ef56d7e1e2a6409859ab8db63e053a16ad34cca1046c6fa050354aa8b7113d3487b1376413b50f47
6
+ metadata.gz: ee8ecc223c8f29ba5b3ca0c1666ec16ba50e3823dbb8b30ebb3a77f058311c2a81a3f84ce78af8101fa2061cf7a51690f41e1bf980fa994ec0ec415d1cb68ed8
7
+ data.tar.gz: d2415fef9dcbf66038a3df1abd2ef70628049c3bb566d8229fd474a1d9f8ab12bc056f147020f0364400f6170db987740b8925c508fcc0a6314d753585c55830
@@ -4,6 +4,8 @@ AllCops:
4
4
  DisplayCopNames: true
5
5
  TargetRubyVersion: 2.3
6
6
 
7
+ Style/ClassAndModuleChildren:
8
+ Enabled: false
7
9
  Metrics/LineLength:
8
10
  Max: 100
9
11
  Layout/EndOfLine:
@@ -5,7 +5,7 @@ install: |
5
5
  sudo bundle install --no-color "--gemfile=$(pwd)/Gemfile"
6
6
  release:
7
7
  script: |-
8
- bundle exec rake
8
+ bundle exec rake clean test rubocop copyright
9
9
  sed -i "s/1\.0\.snapshot/${tag}/g" lib/sibit/version.rb
10
10
  git add lib/sibit/version.rb
11
11
  git commit -m "version set to ${tag}"
@@ -14,7 +14,7 @@ release:
14
14
  gem push *.gem --config-file ../rubygems.yml
15
15
  merge:
16
16
  script: |-
17
- bundle exec rake
17
+ bundle exec rake clean test rubocop copyright
18
18
  deploy:
19
19
  script: |-
20
20
  echo "There is nothing to deploy"
data/README.md CHANGED
@@ -145,7 +145,14 @@ will be used one by one, until a successful response is obtained:
145
145
  require 'sibit'
146
146
  require 'sibit/btc'
147
147
  require 'sibit/cryptoapis'
148
- sibit = Sibit.new(api: [Sibit::Btc.new, Sibit::Cryptoapis.new('key')])
148
+ sibit = Sibit.new(
149
+ api: Sibit::FirstOf.new(
150
+ [
151
+ Sibit::Btc.new,
152
+ Sibit::Cryptoapis.new('key')
153
+ ]
154
+ )
155
+ )
149
156
  ```
150
157
 
151
158
  If you think we may need to use some other API, you can submit a ticket,
data/bin/sibit CHANGED
@@ -32,6 +32,7 @@ require_relative '../lib/sibit/blockchain'
32
32
  require_relative '../lib/sibit/btc'
33
33
  require_relative '../lib/sibit/bitcoinchain'
34
34
  require_relative '../lib/sibit/earn'
35
+ require_relative '../lib/sibit/firstof'
35
36
 
36
37
  begin
37
38
  begin
@@ -86,7 +87,7 @@ Options are:"
86
87
  api = RetriableProxy.for_object(api, on: Sibit::Error) if opts[:attempts] > 1
87
88
  api
88
89
  end
89
- sibit = Sibit.new(log: log, api: apis)
90
+ sibit = Sibit.new(log: log, api: Sibit::FirstOf.new(apis, log: log))
90
91
  case opts.arguments[0]
91
92
  when 'price'
92
93
  puts sibit.price
@@ -55,9 +55,7 @@ class Sibit
55
55
 
56
56
  # Current price of 1 BTC in USD (or another currency), float returned.
57
57
  def price(currency = 'USD')
58
- first_one do |api|
59
- api.price(currency)
60
- end
58
+ @api.price(currency)
61
59
  end
62
60
 
63
61
  # Generates new Bitcon private key and returns in Hash160 format.
@@ -76,29 +74,23 @@ class Sibit
76
74
 
77
75
  # Gets the balance of the address, in satoshi.
78
76
  def balance(address)
79
- first_one do |api|
80
- api.balance(address)
81
- end
77
+ @api.balance(address)
82
78
  end
83
79
 
84
80
  # Get the height of the block.
85
81
  def height(hash)
86
- first_one do |api|
87
- api.height(hash)
88
- end
82
+ @api.height(hash)
89
83
  end
90
84
 
91
85
  # Get the hash of the next block.
92
86
  def next_of(hash)
93
- first_one do |api|
94
- api.next_of(hash)
95
- end
87
+ @api.next_of(hash)
96
88
  end
97
89
 
98
90
  # Get recommended fees, in satoshi per byte. The method returns
99
91
  # a hash: { S: 12, M: 45, L: 100, XL: 200 }
100
92
  def fees
101
- first_one(&:fees)
93
+ @api.fees
102
94
  end
103
95
 
104
96
  # Sends a payment and returns the transaction hash.
@@ -124,7 +116,7 @@ class Sibit
124
116
  builder = Bitcoin::Builder::TxBuilder.new
125
117
  unspent = 0
126
118
  size = 100
127
- utxos = first_one { |api| api.utxos(sources.keys) }
119
+ utxos = @api.utxos(sources.keys)
128
120
  @log.info("#{utxos.count} UTXOs found, these will be used \
129
121
  (value/confirmations at tx_hash):")
130
122
  utxos.each do |utxo|
@@ -170,15 +162,13 @@ class Sibit
170
162
  Amount: #{num(satoshi, p)}
171
163
  Target address: #{target}
172
164
  Change address is #{change}")
173
- first_one do |api|
174
- api.push(tx.to_payload.bth)
175
- end
165
+ @api.push(tx.to_payload.bth)
176
166
  tx.hash
177
167
  end
178
168
 
179
169
  # Gets the hash of the latest block.
180
170
  def latest
181
- first_one(&:latest)
171
+ @api.latest
182
172
  end
183
173
 
184
174
  # You call this method and provide a callback. You provide the hash
@@ -197,7 +187,7 @@ class Sibit
197
187
  wrong = []
198
188
  json = {}
199
189
  loop do
200
- json = first_one { |api| api.block(block) }
190
+ json = @api.block(block)
201
191
  if json[:orphan]
202
192
  steps = 4
203
193
  @log.info("Orphan block found at #{block}, moving #{steps} steps back...")
@@ -206,7 +196,7 @@ class Sibit
206
196
  block = json[:previous]
207
197
  wrong << block
208
198
  @log.info("Moved back to #{block}")
209
- json = first_one { |api| api.block(block) }
199
+ json = @api.block(block)
210
200
  end
211
201
  next
212
202
  end
@@ -224,13 +214,13 @@ class Sibit
224
214
  end
225
215
  checked += 1
226
216
  end
217
+ count += 1
227
218
  @log.info("We checked #{checked} txns and #{checked_outputs} outputs in block #{block}")
228
219
  block = json[:next]
229
220
  if block.nil?
230
221
  @log.info("The next_block is empty in block #{json[:hash]}, this is the end of Blockchain")
231
222
  break
232
223
  end
233
- count += 1
234
224
  if count > max
235
225
  @log.info("Too many blocks (#{count}) in one go, let's get back to it next time")
236
226
  break
@@ -242,26 +232,6 @@ class Sibit
242
232
 
243
233
  private
244
234
 
245
- def first_one
246
- return yield @api unless @api.is_a?(Array)
247
- done = false
248
- result = nil
249
- @api.each do |api|
250
- begin
251
- result = yield api
252
- done = true
253
- break
254
- rescue Sibit::Error => e
255
- @log.info("The API #{api.class.name} failed: #{e.message}")
256
- end
257
- end
258
- unless done
259
- raise Sibit::Error, "No APIs out of #{@api.length} managed to succeed: \
260
- #{@api.map { |a| a.class.name }.join(', ')}"
261
- end
262
- result
263
- end
264
-
265
235
  def num(satoshi, usd)
266
236
  format(
267
237
  '%<satoshi>ss/$%<dollars>0.2f',
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2019-2020 Yegor Bugayenko
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the 'Software'), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ require_relative 'error'
24
+ require_relative 'log'
25
+
26
+ # API best of.
27
+ #
28
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
29
+ # Copyright:: Copyright (c) 2019-2020 Yegor Bugayenko
30
+ # License:: MIT
31
+ class Sibit
32
+ # Best of API.
33
+ class BestOf
34
+ # Constructor.
35
+ def initialize(list, log: Sibit::Log.new)
36
+ @list = list
37
+ @log = log
38
+ end
39
+
40
+ # Current price of BTC in USD (float returned).
41
+ def price(currency = 'USD')
42
+ best_of('price') do |api|
43
+ api.price(currency)
44
+ end
45
+ end
46
+
47
+ # Gets the balance of the address, in satoshi.
48
+ def balance(address)
49
+ best_of('balance') do |api|
50
+ api.balance(address)
51
+ end
52
+ end
53
+
54
+ # Get the height of the block.
55
+ def height(hash)
56
+ best_of('height') do |api|
57
+ api.height(hash)
58
+ end
59
+ end
60
+
61
+ # Get the hash of the next block.
62
+ def next_of(hash)
63
+ best_of('next_of') do |api|
64
+ api.next_of(hash)
65
+ end
66
+ end
67
+
68
+ # Get recommended fees, in satoshi per byte. The method returns
69
+ # a hash: { S: 12, M: 45, L: 100, XL: 200 }
70
+ def fees
71
+ best_of('fees', &:fees)
72
+ end
73
+
74
+ # Fetch all unspent outputs per address.
75
+ def utxos(keys)
76
+ best_of('utxos') do |api|
77
+ api.utxos(keys)
78
+ end
79
+ end
80
+
81
+ # Latest block hash.
82
+ def latest
83
+ best_of('latest', &:latest)
84
+ end
85
+
86
+ # Push this transaction (in hex format) to the network.
87
+ def push(hex)
88
+ best_of('push') do |api|
89
+ api.push(hex)
90
+ end
91
+ end
92
+
93
+ # This method should fetch a block and return as a hash.
94
+ def block(hash)
95
+ best_of('block') do |api|
96
+ api.block(hash)
97
+ end
98
+ end
99
+
100
+ private
101
+
102
+ def best_of(method)
103
+ return yield @list unless @list.is_a?(Array)
104
+ results = []
105
+ @list.each do |api|
106
+ begin
107
+ results << yield(api)
108
+ rescue Sibit::Error => e
109
+ @log.info("The API #{api.class.name} failed at #{method}(): #{e.message}")
110
+ end
111
+ end
112
+ if results.empty?
113
+ raise Sibit::Error, "No APIs out of #{@list.length} managed to succeed at #{method}(): \
114
+ #{@list.map { |a| a.class.name }.join(', ')}"
115
+ end
116
+ results.group_by(&:to_s).values.max_by(&:size)[0]
117
+ end
118
+ end
119
+ end
@@ -58,7 +58,16 @@ class Sibit
58
58
  @log.info("The balance of #{address} is zero (not found)")
59
59
  return 0
60
60
  end
61
- txns = json['data']['list']
61
+ data = json['data']
62
+ if data.nil?
63
+ @log.info("The balance of #{address} is probably zero (not found)")
64
+ return 0
65
+ end
66
+ txns = data['list']
67
+ if txns.nil?
68
+ @log.info("The balance of #{address} is probably zero (not found)")
69
+ return 0
70
+ end
62
71
  balance = txns.map { |tx| tx['value'] }.inject(&:+) || 0
63
72
  @log.info("The balance of #{address} is #{balance}, total txns: #{txns.count}")
64
73
  balance
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2019-2020 Yegor Bugayenko
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the 'Software'), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ require_relative 'error'
24
+ require_relative 'log'
25
+
26
+ # API first of.
27
+ #
28
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
29
+ # Copyright:: Copyright (c) 2019-2020 Yegor Bugayenko
30
+ # License:: MIT
31
+ class Sibit
32
+ # First of API.
33
+ class FirstOf
34
+ # Constructor.
35
+ def initialize(list, log: Sibit::Log.new)
36
+ @list = list
37
+ @log = log
38
+ end
39
+
40
+ # Current price of BTC in USD (float returned).
41
+ def price(currency = 'USD')
42
+ first_of('price') do |api|
43
+ api.price(currency)
44
+ end
45
+ end
46
+
47
+ # Gets the balance of the address, in satoshi.
48
+ def balance(address)
49
+ first_of('balance') do |api|
50
+ api.balance(address)
51
+ end
52
+ end
53
+
54
+ # Get the height of the block.
55
+ def height(hash)
56
+ first_of('height') do |api|
57
+ api.height(hash)
58
+ end
59
+ end
60
+
61
+ # Get the hash of the next block.
62
+ def next_of(hash)
63
+ first_of('next_of') do |api|
64
+ api.next_of(hash)
65
+ end
66
+ end
67
+
68
+ # Get recommended fees, in satoshi per byte. The method returns
69
+ # a hash: { S: 12, M: 45, L: 100, XL: 200 }
70
+ def fees
71
+ first_of('fees', &:fees)
72
+ end
73
+
74
+ # Fetch all unspent outputs per address.
75
+ def utxos(keys)
76
+ first_of('utxos') do |api|
77
+ api.utxos(keys)
78
+ end
79
+ end
80
+
81
+ # Latest block hash.
82
+ def latest
83
+ first_of('latest', &:latest)
84
+ end
85
+
86
+ # Push this transaction (in hex format) to the network.
87
+ def push(hex)
88
+ first_of('push') do |api|
89
+ api.push(hex)
90
+ end
91
+ end
92
+
93
+ # This method should fetch a block and return as a hash.
94
+ def block(hash)
95
+ first_of('block') do |api|
96
+ api.block(hash)
97
+ end
98
+ end
99
+
100
+ private
101
+
102
+ def first_of(method)
103
+ return yield @list unless @list.is_a?(Array)
104
+ done = false
105
+ result = nil
106
+ @list.each do |api|
107
+ begin
108
+ result = yield api
109
+ done = true
110
+ break
111
+ rescue Sibit::Error => e
112
+ @log.info("The API #{api.class.name} failed at #{method}(): #{e.message}")
113
+ end
114
+ end
115
+ unless done
116
+ raise Sibit::Error, "No APIs out of #{@list.length} managed to succeed at #{method}(): \
117
+ #{@list.map { |a| a.class.name }.join(', ')}"
118
+ end
119
+ result
120
+ end
121
+ end
122
+ end
@@ -26,5 +26,5 @@
26
26
  # License:: MIT
27
27
  class Sibit
28
28
  # Current version of the library.
29
- VERSION = '0.18.8'
29
+ VERSION = '0.19.4'
30
30
  end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2019-2020 Yegor Bugayenko
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the 'Software'), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ require 'minitest/autorun'
24
+ require_relative '../lib/sibit'
25
+ require_relative '../lib/sibit/fake'
26
+ require_relative '../lib/sibit/bestof'
27
+
28
+ # Sibit::BestOf test.
29
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
30
+ # Copyright:: Copyright (c) 2019-2020 Yegor Bugayenko
31
+ # License:: MIT
32
+ class TestBestOf < Minitest::Test
33
+ def test_not_array
34
+ sibit = Sibit::BestOf.new(Sibit::Fake.new)
35
+ assert_equal(64, sibit.latest.length)
36
+ assert_equal(12, sibit.fees[:S])
37
+ end
38
+
39
+ def test_one_apis
40
+ sibit = Sibit::BestOf.new([Sibit::Fake.new])
41
+ assert_equal(64, sibit.latest.length)
42
+ assert_equal(12, sibit.fees[:S])
43
+ end
44
+
45
+ def test_two_apis
46
+ sibit = Sibit::BestOf.new([Sibit::Fake.new, Sibit::Fake.new])
47
+ assert_equal(64, sibit.latest.length)
48
+ assert_equal(12, sibit.fees[:S])
49
+ end
50
+
51
+ def test_all_fail
52
+ api = Class.new do
53
+ def latest
54
+ raise Sibit::Error, 'intentionally'
55
+ end
56
+ end.new
57
+ sibit = Sibit::BestOf.new([api, api])
58
+ assert_raises Sibit::Error do
59
+ sibit.latest
60
+ end
61
+ end
62
+ end
@@ -42,6 +42,28 @@ class TestBtc < Minitest::Test
42
42
  assert_equal(0, balance)
43
43
  end
44
44
 
45
+ def test_get_zero_balance_no_txns
46
+ stub_request(
47
+ :get,
48
+ 'https://chain.api.btc.com/v3/address/1MZT1fa6y8H9UmbZV6HqKF4UY41o9MGT5f/unspent'
49
+ ).to_return(body: '{"data":{}}')
50
+ sibit = Sibit::Btc.new
51
+ balance = sibit.balance('1MZT1fa6y8H9UmbZV6HqKF4UY41o9MGT5f')
52
+ assert(balance.is_a?(Integer))
53
+ assert_equal(0, balance)
54
+ end
55
+
56
+ def test_get_broken_balance
57
+ stub_request(
58
+ :get,
59
+ 'https://chain.api.btc.com/v3/address/1MZT1fa6y8H9UmbZV6HqKF4UY41o9MGT5f/unspent'
60
+ ).to_return(body: '{}')
61
+ sibit = Sibit::Btc.new
62
+ balance = sibit.balance('1MZT1fa6y8H9UmbZV6HqKF4UY41o9MGT5f')
63
+ assert(balance.is_a?(Integer))
64
+ assert_equal(0, balance)
65
+ end
66
+
45
67
  def test_get_empty_balance
46
68
  stub_request(
47
69
  :get,
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2019-2020 Yegor Bugayenko
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the 'Software'), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ require 'minitest/autorun'
24
+ require_relative '../lib/sibit'
25
+ require_relative '../lib/sibit/fake'
26
+ require_relative '../lib/sibit/firstof'
27
+
28
+ # Sibit::FirstOf test.
29
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
30
+ # Copyright:: Copyright (c) 2019-2020 Yegor Bugayenko
31
+ # License:: MIT
32
+ class TestFirstOf < Minitest::Test
33
+ def test_not_array
34
+ sibit = Sibit::FirstOf.new(Sibit::Fake.new)
35
+ assert_equal(64, sibit.latest.length)
36
+ assert_equal(12, sibit.fees[:S])
37
+ end
38
+
39
+ def test_one_apis
40
+ sibit = Sibit::FirstOf.new([Sibit::Fake.new])
41
+ assert_equal(64, sibit.latest.length)
42
+ assert_equal(12, sibit.fees[:S])
43
+ end
44
+
45
+ def test_two_apis
46
+ sibit = Sibit::FirstOf.new([Sibit::Fake.new, Sibit::Fake.new])
47
+ assert_equal(64, sibit.latest.length)
48
+ assert_equal(12, sibit.fees[:S])
49
+ end
50
+
51
+ def test_all_fail
52
+ api = Class.new do
53
+ def latest
54
+ raise Sibit::Error, 'intentionally'
55
+ end
56
+ end.new
57
+ sibit = Sibit::FirstOf.new([api, api])
58
+ assert_raises Sibit::Error do
59
+ sibit.latest
60
+ end
61
+ end
62
+ end
@@ -27,6 +27,8 @@ require_relative '../lib/sibit'
27
27
  require_relative '../lib/sibit/earn'
28
28
  require_relative '../lib/sibit/fake'
29
29
  require_relative '../lib/sibit/blockchain'
30
+ require_relative '../lib/sibit/firstof'
31
+ require_relative '../lib/sibit/bestof'
30
32
 
31
33
  # Sibit.
32
34
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
@@ -127,7 +129,7 @@ class TestSibit < Minitest::Test
127
129
  'https://blockchain.info/unspent?active=1JvCsJtLmCxEk7ddZFnVkGXpr9uhxZPmJi&limit=1000'
128
130
  ).to_return(body: JSON.pretty_generate(json))
129
131
  stub_request(:post, 'https://blockchain.info/pushtx').to_return(status: 200)
130
- sibit = Sibit.new(api: [Sibit::Earn.new, Sibit::Blockchain.new])
132
+ sibit = Sibit.new(api: Sibit::FirstOf.new([Sibit::Earn.new, Sibit::Blockchain.new]))
131
133
  target = sibit.create(sibit.generate)
132
134
  change = sibit.create(sibit.generate)
133
135
  tx = sibit.pay(
@@ -156,7 +158,7 @@ class TestSibit < Minitest::Test
156
158
  :get,
157
159
  'https://blockchain.info/unspent?active=1JvCsJtLmCxEk7ddZFnVkGXpr9uhxZPmJi&limit=1000'
158
160
  ).to_return(body: JSON.pretty_generate(json))
159
- sibit = Sibit.new
161
+ sibit = Sibit.new(api: Sibit::BestOf.new([Sibit::Fake.new, Sibit::Fake.new]))
160
162
  target = sibit.create(sibit.generate)
161
163
  change = sibit.create(sibit.generate)
162
164
  assert_raises Sibit::Error do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sibit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.18.8
4
+ version: 0.19.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-05-28 00:00:00.000000000 Z
11
+ date: 2020-07-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: backtrace
@@ -281,6 +281,7 @@ files:
281
281
  - features/step_definitions/steps.rb
282
282
  - features/support/env.rb
283
283
  - lib/sibit.rb
284
+ - lib/sibit/bestof.rb
284
285
  - lib/sibit/bitcoinchain.rb
285
286
  - lib/sibit/blockchain.rb
286
287
  - lib/sibit/blockchair.rb
@@ -290,6 +291,7 @@ files:
290
291
  - lib/sibit/earn.rb
291
292
  - lib/sibit/error.rb
292
293
  - lib/sibit/fake.rb
294
+ - lib/sibit/firstof.rb
293
295
  - lib/sibit/http.rb
294
296
  - lib/sibit/json.rb
295
297
  - lib/sibit/log.rb
@@ -297,6 +299,7 @@ files:
297
299
  - logo.svg
298
300
  - sibit.gemspec
299
301
  - test/test__helper.rb
302
+ - test/test_bestof.rb
300
303
  - test/test_bitcoinchain.rb
301
304
  - test/test_blockchain.rb
302
305
  - test/test_blockchair.rb
@@ -304,6 +307,7 @@ files:
304
307
  - test/test_cex.rb
305
308
  - test/test_cryptoapis.rb
306
309
  - test/test_fake.rb
310
+ - test/test_firstof.rb
307
311
  - test/test_json.rb
308
312
  - test/test_live.rb
309
313
  - test/test_sibit.rb
@@ -337,6 +341,7 @@ test_files:
337
341
  - features/step_definitions/steps.rb
338
342
  - features/support/env.rb
339
343
  - test/test__helper.rb
344
+ - test/test_bestof.rb
340
345
  - test/test_bitcoinchain.rb
341
346
  - test/test_blockchain.rb
342
347
  - test/test_blockchair.rb
@@ -344,6 +349,7 @@ test_files:
344
349
  - test/test_cex.rb
345
350
  - test/test_cryptoapis.rb
346
351
  - test/test_fake.rb
352
+ - test/test_firstof.rb
347
353
  - test/test_json.rb
348
354
  - test/test_live.rb
349
355
  - test/test_sibit.rb