zold 0.16.27 → 0.16.28

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 (70) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/bin/zold +19 -8
  4. data/fixtures/scripts/distribute-wallet.sh +1 -1
  5. data/fixtures/scripts/pull-on-start.sh +1 -1
  6. data/fixtures/scripts/push-and-pull.sh +1 -1
  7. data/fixtures/scripts/spread-wallets.sh +1 -1
  8. data/lib/zold/commands/alias.rb +4 -1
  9. data/lib/zold/commands/calculate.rb +4 -1
  10. data/lib/zold/commands/clean.rb +1 -1
  11. data/lib/zold/commands/create.rb +6 -3
  12. data/lib/zold/commands/diff.rb +4 -1
  13. data/lib/zold/commands/fetch.rb +4 -1
  14. data/lib/zold/commands/invoice.rb +4 -1
  15. data/lib/zold/commands/list.rb +12 -4
  16. data/lib/zold/commands/merge.rb +8 -1
  17. data/lib/zold/commands/next.rb +4 -1
  18. data/lib/zold/commands/node.rb +6 -3
  19. data/lib/zold/commands/pay.rb +4 -1
  20. data/lib/zold/commands/propagate.rb +4 -1
  21. data/lib/zold/commands/pull.rb +4 -1
  22. data/lib/zold/commands/push.rb +4 -1
  23. data/lib/zold/commands/remote.rb +6 -3
  24. data/lib/zold/commands/remove.rb +4 -1
  25. data/lib/zold/commands/routines/reconnect.rb +1 -1
  26. data/lib/zold/commands/routines/spread.rb +1 -1
  27. data/lib/zold/commands/show.rb +7 -3
  28. data/lib/zold/commands/taxes.rb +4 -1
  29. data/lib/zold/commands/thread_badge.rb +47 -0
  30. data/lib/zold/copies.rb +1 -1
  31. data/lib/zold/endless.rb +1 -1
  32. data/lib/zold/http.rb +3 -3
  33. data/lib/zold/key.rb +3 -0
  34. data/lib/zold/log.rb +52 -111
  35. data/lib/zold/metronome.rb +12 -10
  36. data/lib/zold/node/async_entrance.rb +2 -2
  37. data/lib/zold/node/entrance.rb +1 -1
  38. data/lib/zold/node/farm.rb +1 -1
  39. data/lib/zold/node/farmers.rb +1 -1
  40. data/lib/zold/node/front.rb +5 -5
  41. data/lib/zold/node/nodup_entrance.rb +1 -1
  42. data/lib/zold/node/spread_entrance.rb +1 -1
  43. data/lib/zold/node/sync_entrance.rb +1 -1
  44. data/lib/zold/patch.rb +2 -2
  45. data/lib/zold/remotes.rb +1 -1
  46. data/lib/zold/signature.rb +5 -1
  47. data/lib/zold/sync_wallets.rb +1 -1
  48. data/lib/zold/upgrades.rb +1 -1
  49. data/lib/zold/verbose_thread.rb +1 -1
  50. data/lib/zold/version.rb +1 -1
  51. data/lib/zold/version_file.rb +1 -1
  52. data/lib/zold/wallet.rb +2 -2
  53. data/resources/root.pub +14 -0
  54. data/test/commands/test_list.rb +2 -1
  55. data/test/commands/test_remote.rb +35 -4
  56. data/test/commands/test_show.rb +1 -1
  57. data/test/fake_home.rb +1 -1
  58. data/test/node/fake_node.rb +3 -2
  59. data/test/node/test_farm.rb +1 -1
  60. data/test/test__helper.rb +4 -3
  61. data/test/test_dir_items.rb +1 -1
  62. data/test/test_http.rb +44 -6
  63. data/test/test_key.rb +7 -0
  64. data/test/test_log.rb +12 -1
  65. data/test/test_remotes.rb +1 -1
  66. data/test/test_signature.rb +1 -0
  67. data/test/test_verbose_thread.rb +3 -3
  68. data/test/test_zold.rb +4 -3
  69. data/zold.gemspec +3 -2
  70. metadata +8 -5
@@ -36,7 +36,7 @@ require_relative '../dir_items'
36
36
  module Zold
37
37
  # The entrance
38
38
  class AsyncEntrance
39
- def initialize(entrance, dir, log: Log::Quiet.new, threads: [Concurrent.processor_count, 4].max)
39
+ def initialize(entrance, dir, log: Log::NULL, threads: [Concurrent.processor_count, 4].max)
40
40
  @entrance = entrance
41
41
  @dir = File.expand_path(dir)
42
42
  @log = log
@@ -103,7 +103,7 @@ in #{Age.new(start, limit: 0.05)}: #{uuid}")
103
103
  FileUtils.rm_f(item[:file])
104
104
  @entrance.push(item[:id], body)
105
105
  @log.debug("Pushed #{item[:id]}/#{Size.new(body.length)} to #{@entrance.class.name} \
106
- in #{Age.new(start, limit: 0.1)} (#{@queue.size} still in the queue)")
106
+ in #{Age.new(start, limit: 0.1)}#{@queue.size.zero? ? '' : "(#{@queue.size} still in the queue)"}")
107
107
  end
108
108
  end
109
109
  end
@@ -38,7 +38,7 @@ require_relative '../commands/push'
38
38
  module Zold
39
39
  # The entrance
40
40
  class Entrance
41
- def initialize(wallets, remotes, copies, address, log: Log::Quiet.new, network: 'test')
41
+ def initialize(wallets, remotes, copies, address, log: Log::NULL, network: 'test')
42
42
  @wallets = wallets
43
43
  @remotes = remotes
44
44
  @copies = copies
@@ -57,7 +57,7 @@ module Zold
57
57
  # <tt>lifetime</tt> is the amount of seconds for a score to live in the farm, by default
58
58
  # it's the entire day, since the Score expires in 24 hours; can be decreased for the
59
59
  # purpose of unit testing.
60
- def initialize(invoice, cache = File.join(Dir.pwd, 'farm'), log: Log::Quiet.new,
60
+ def initialize(invoice, cache = File.join(Dir.pwd, 'farm'), log: Log::NULL,
61
61
  farmer: Farmers::Plain.new, lifetime: 24 * 60 * 60)
62
62
  @log = log
63
63
  @cache = File.expand_path(cache)
@@ -44,7 +44,7 @@ module Zold
44
44
 
45
45
  # In a child process
46
46
  class Spawn
47
- def initialize(log: Log::Quiet.new)
47
+ def initialize(log: Log::NULL)
48
48
  @log = log
49
49
  end
50
50
 
@@ -434,18 +434,18 @@ in #{Age.new(@start, limit: 1)}")
434
434
  # takes a lot of time (when the amount of wallets is big, like 40K). However,
435
435
  # we must find a way to count them somehow faster.
436
436
  def total_wallets
437
- return 256 if settings.opts['network'] == Wallet::MAIN_NETWORK
437
+ return 256 if settings.opts['network'] == Wallet::MAINET
438
438
  settings.wallets.all.count
439
439
  end
440
440
 
441
441
  def all_remotes
442
- settings.zache.get(:remotes, lifetime: settings.opts['network'] == Wallet::MAIN_NETWORK ? 60 : 0) do
442
+ settings.zache.get(:remotes, lifetime: settings.opts['network'] == Wallet::MAINET ? 60 : 0) do
443
443
  settings.remotes.all
444
444
  end
445
445
  end
446
446
 
447
447
  def processes_count
448
- settings.zache.get(:processes, lifetime: settings.opts['network'] == Wallet::MAIN_NETWORK ? 60 : 0) do
448
+ settings.zache.get(:processes, lifetime: settings.opts['network'] == Wallet::MAINET ? 60 : 0) do
449
449
  processes.count
450
450
  end
451
451
  end
@@ -459,7 +459,7 @@ in #{Age.new(@start, limit: 1)}")
459
459
  end
460
460
 
461
461
  def score
462
- settings.zache.get(:score, lifetime: settings.opts['network'] == Wallet::MAIN_NETWORK ? 60 : 0) do
462
+ settings.zache.get(:score, lifetime: settings.opts['network'] == Wallet::MAINET ? 60 : 0) do
463
463
  b = settings.farm.best
464
464
  raise 'Score is empty, there is something wrong with the Farm!' if b.empty?
465
465
  b[0]
@@ -476,7 +476,7 @@ in #{Age.new(@start, limit: 1)}")
476
476
  end
477
477
  end
478
478
 
479
- def running_server?
479
+ def running_server
480
480
  false
481
481
  end
482
482
  end
@@ -33,7 +33,7 @@ require_relative '../wallet'
33
33
  module Zold
34
34
  # The safe entrance
35
35
  class NoDupEntrance
36
- def initialize(entrance, wallets, log: Log::Quiet.new)
36
+ def initialize(entrance, wallets, log: Log::NULL)
37
37
  @entrance = entrance
38
38
  @wallets = wallets
39
39
  @log = log
@@ -40,7 +40,7 @@ require_relative '../commands/clean'
40
40
  module Zold
41
41
  # The entrance
42
42
  class SpreadEntrance
43
- def initialize(entrance, wallets, remotes, address, log: Log::Quiet.new, ignore_score_weakeness: false)
43
+ def initialize(entrance, wallets, remotes, address, log: Log::NULL, ignore_score_weakeness: false)
44
44
  @entrance = entrance
45
45
  @wallets = wallets
46
46
  @remotes = remotes
@@ -33,7 +33,7 @@ require_relative '../verbose_thread'
33
33
  module Zold
34
34
  # The entrance that makes sure only one thread works with a wallet
35
35
  class SyncEntrance
36
- def initialize(entrance, dir, timeout: 30, log: Log::Quiet.new)
36
+ def initialize(entrance, dir, timeout: 30, log: Log::NULL)
37
37
  @entrance = entrance
38
38
  @dir = dir
39
39
  @timeout = timeout
@@ -32,7 +32,7 @@ require_relative 'signature'
32
32
  module Zold
33
33
  # A patch
34
34
  class Patch
35
- def initialize(wallets, log: Log::Quiet.new)
35
+ def initialize(wallets, log: Log::NULL)
36
36
  @wallets = wallets
37
37
  @txns = []
38
38
  @log = log
@@ -81,7 +81,7 @@ module Zold
81
81
  #{wallet.id}/#{Amount.new(zents: balance).to_zld}/#{@txns.size} negative: #{txn.to_text}")
82
82
  next
83
83
  end
84
- unless Signature.new.valid?(@key, wallet.id, txn)
84
+ unless Signature.new(@network).valid?(@key, wallet.id, txn)
85
85
  @log.error("Invalid RSA signature at transaction ##{txn.id} of #{wallet.id}: #{txn.to_text}")
86
86
  next
87
87
  end
@@ -74,7 +74,7 @@ module Zold
74
74
 
75
75
  # One remote.
76
76
  class Remote
77
- def initialize(host:, port:, score:, idx:, network: 'test', log: Log::Quiet.new)
77
+ def initialize(host:, port:, score:, idx:, network: 'test', log: Log::NULL)
78
78
  @host = host
79
79
  @port = port
80
80
  @score = score
@@ -33,6 +33,10 @@ require_relative 'txn'
33
33
  module Zold
34
34
  # A signature
35
35
  class Signature
36
+ def initialize(network = 'test')
37
+ @network = network
38
+ end
39
+
36
40
  # Sign the trasnsaction and return the signature.
37
41
  # +pvt+:: Private RSA key
38
42
  # +id+:: Paying wallet ID
@@ -52,7 +56,7 @@ module Zold
52
56
  raise 'pub must be of type Key' unless pub.is_a?(Key)
53
57
  raise 'id must be of type Id' unless id.is_a?(Id)
54
58
  raise 'txn must be of type Txn' unless txn.is_a?(Txn)
55
- pub.verify(txn.sign, body(id, txn))
59
+ pub.verify(txn.sign, body(id, txn)) && (@network != Wallet::MAINET || id != Id::ROOT || pub == Key::ROOT)
56
60
  end
57
61
 
58
62
  private
@@ -30,7 +30,7 @@ require_relative 'log'
30
30
  module Zold
31
31
  # Synchronized collection of wallets
32
32
  class SyncWallets
33
- def initialize(wallets, timeout: 30, log: Log::Quiet.new)
33
+ def initialize(wallets, timeout: 30, log: Log::NULL)
34
34
  @wallets = wallets
35
35
  @log = log
36
36
  @timeout = timeout
@@ -25,7 +25,7 @@ require_relative 'log'
25
25
  module Zold
26
26
  # Class to manage data upgrades (when zold itself upgrades).
27
27
  class Upgrades
28
- def initialize(version, directory, log: Log::Verbose.new)
28
+ def initialize(version, directory, log: Log::VERBOSE)
29
29
  @version = version
30
30
  @directory = directory
31
31
  @log = log
@@ -30,7 +30,7 @@ require_relative 'log'
30
30
  module Zold
31
31
  # Verbose thread
32
32
  class VerboseThread
33
- def initialize(log = Log::Quiet.new)
33
+ def initialize(log = Log::NULL)
34
34
  @log = log
35
35
  end
36
36
 
@@ -25,6 +25,6 @@
25
25
  # Copyright:: Copyright (c) 2018 Yegor Bugayenko
26
26
  # License:: MIT
27
27
  module Zold
28
- VERSION = '0.16.27'
28
+ VERSION = '0.16.28'
29
29
  PROTOCOL = 2
30
30
  end
@@ -26,7 +26,7 @@ require_relative 'log'
26
26
  module Zold
27
27
  # Read and write .zoldata/version.
28
28
  class VersionFile
29
- def initialize(path, log: Log::Verbose.new)
29
+ def initialize(path, log: Log::VERBOSE)
30
30
  @path = path
31
31
  @log = log
32
32
  end
@@ -49,7 +49,7 @@ module Zold
49
49
  class Wallet
50
50
  # The name of the main production network. All other networks
51
51
  # must have different names.
52
- MAIN_NETWORK = 'zold'
52
+ MAINET = 'zold'
53
53
 
54
54
  # The extension of the wallet files
55
55
  EXT = '.z'
@@ -136,7 +136,7 @@ module Zold
136
136
  details
137
137
  )
138
138
  txn = txn.signed(pvt, id)
139
- raise 'This is not the right private key for this wallet' unless Signature.new.valid?(key, id, txn)
139
+ raise "Invalid private key for the wallet #{id}" unless Signature.new(network).valid?(key, id, txn)
140
140
  add(txn)
141
141
  txn
142
142
  end
@@ -0,0 +1,14 @@
1
+ -----BEGIN PUBLIC KEY-----
2
+ MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA96lM5Y+QHYr9WvUucw/
3
+ wW+dJpnYBa2/nCij3DXroCaABYL5qG4mVIjGdCBbdS78tcOlcZS+WzPcmyepg56
4
+ cIwPkpYQop4MawaaCp6QC/nybu5sDwvnnDVWCsLveEAPbHos/BpVAJn89NeJO1M
5
+ aJgaRLKvtRK/P9bgd5tORGJKFq17yipfjLtXKSOCX6U2nPUNB8TCaAtESHNdbp6
6
+ kp2J063k+Mf8CT0yhFrAU5j/nRaUTKTwyyj6dcuRTn+FyfFdjfJi2mVOLMJrunN
7
+ CSr8TNhcMB1fE5MxtwYg46s6ZkqUhQ3oNgSKBgK7DuY2TMVMgsviIZ1xkUfLR4M
8
+ CNhjcwi9wVPNkEgTJUdjEK1m4TmNa2DWnX9oCQbYfPhze3Xv4Q3GCAUUSwvxZSO
9
+ qKh/MdqStYOB8ByXp1sEBDsLMpR7DfpmPJm18f5winZ0pEX0U4N/7VTqSIb+w8s
10
+ aT6YqA4WG+9ZYLKRSxwjYwkbj3cnbeq5bGXd02XjqitTHdonv1EPQvzVMxUO9RU
11
+ bxjpPHfDIA8AdBX4rA8F5FYe2K8yMlEgbJy7Za/CAKV9c5Fut5C5eYfxQegu5ff
12
+ mnQRuTyIZuAjZojIJWctLY2OT9SqRh0ilqJ4nq4q/eOfUuSJAUEQIZdQX9MBg3l
13
+ J0Pw9aSoSAp8iQWRdNTvqvuTZqExs3Tp1UCAwEAAQ==
14
+ -----END PUBLIC KEY-----
@@ -24,6 +24,7 @@ require 'minitest/autorun'
24
24
  require 'tmpdir'
25
25
  require_relative '../test__helper'
26
26
  require_relative '../../lib/zold/wallet'
27
+ require_relative '../../lib/zold/wallets'
27
28
  require_relative '../../lib/zold/key'
28
29
  require_relative '../../lib/zold/id'
29
30
  require_relative '../../lib/zold/commands/list'
@@ -39,7 +40,7 @@ class TestList < Zold::Test
39
40
  wallets = Zold::Wallets.new(dir)
40
41
  wallets.acq(id) do |wallet|
41
42
  wallet.init(Zold::Id.new, Zold::Key.new(file: 'fixtures/id_rsa.pub'))
42
- Zold::List.new(wallets: wallets, log: test_log).run
43
+ Zold::List.new(wallets: wallets, copies: File.join(dir, 'copies'), log: test_log).run
43
44
  end
44
45
  end
45
46
  end
@@ -166,11 +166,42 @@ class TestRemote < Zold::Test
166
166
  end
167
167
  end
168
168
 
169
- # @todo #329:30min Verify that the nodes that are being selected are
170
- # really the strongest ones. The strongest nodes are the ones with
171
- # the highest score.
172
169
  def test_select_selects_the_strongest_nodes
173
- skip
170
+ Dir.mktmpdir do |dir|
171
+ remotes = Zold::Remotes.new(file: File.join(dir, 'remotes.txt'))
172
+ cmd = Zold::Remote.new(remotes: remotes, log: test_log)
173
+ suffixes = []
174
+ (5000..5010).each do |port|
175
+ score = Zold::Score.new(
176
+ host: 'example.com',
177
+ port: port,
178
+ invoice: 'MYPREFIX@ffffffffffffffff',
179
+ suffixes: suffixes << '13f7f01'
180
+ )
181
+ stub_request(:get, "http://#{score.host}:#{score.port}/remotes").to_return(
182
+ status: 200,
183
+ body: {
184
+ version: Zold::VERSION,
185
+ score: score.to_h,
186
+ all: [
187
+ { host: 'localhost', port: port }
188
+ ]
189
+ }.to_json
190
+ )
191
+ stub_request(:get, "http://localhost:#{port}/version").to_return(
192
+ status: 200,
193
+ body: {
194
+ version: Zold::VERSION
195
+ }.to_json
196
+ )
197
+ cmd.run(%W[remote add localhost #{port}])
198
+ remotes.rescore('localhost', port, score)
199
+ end
200
+ cmd.run(%w[remote select --max-nodes=5])
201
+ assert_equal(5, remotes.all.count)
202
+ scores = remotes.all.map { |r| r[:score] }
203
+ assert_equal([11, 10, 9, 8, 7], scores)
204
+ end
174
205
  end
175
206
 
176
207
  def test_select_respects_max_nodes_option
@@ -40,7 +40,7 @@ class TestShow < Zold::Test
40
40
  wallets = Zold::Wallets.new(dir)
41
41
  wallets.acq(id) do |wallet|
42
42
  wallet.init(Zold::Id.new, Zold::Key.new(file: 'fixtures/id_rsa.pub'))
43
- balance = Zold::Show.new(wallets: wallets, log: test_log).run(['show', id.to_s])
43
+ balance = Zold::Show.new(wallets: wallets, copies: File.join(dir, 'c'), log: test_log).run(['show', id.to_s])
44
44
  assert_equal(Zold::Amount::ZERO, balance)
45
45
  end
46
46
  end
@@ -37,7 +37,7 @@ require_relative '../lib/zold/remotes'
37
37
  # License:: MIT
38
38
  class FakeHome
39
39
  attr_reader :dir
40
- def initialize(dir = __dir__, log: Zold::Log::Quiet.new)
40
+ def initialize(dir = __dir__, log: Zold::Log::NULL)
41
41
  @dir = dir
42
42
  @log = log
43
43
  end
@@ -34,7 +34,7 @@ require_relative '../../lib/zold/node/front'
34
34
  # Copyright:: Copyright (c) 2018 Yegor Bugayenko
35
35
  # License:: MIT
36
36
  class FakeNode
37
- def initialize(log: Zold::Log::Quiet.new)
37
+ def initialize(log: Zold::Log::NULL)
38
38
  @log = log
39
39
  end
40
40
 
@@ -43,6 +43,7 @@ class FakeNode
43
43
  FakeHome.new(log: @log).run do |home|
44
44
  RandomPort::Pool::SINGLETON.acquire do |port|
45
45
  node = Thread.new do
46
+ Thread.current.name = 'fake_node'
46
47
  Zold::VerboseThread.new(@log).run do
47
48
  Thread.current.abort_on_exception = true
48
49
  require_relative '../../lib/zold/commands/node'
@@ -67,7 +68,7 @@ class FakeNode
67
68
  loop do
68
69
  ping = Zold::Http.new(uri: uri).get
69
70
  break unless ping.status == 599 && node.alive?
70
- @log.debug("Waiting for #{uri} (attempt no.#{attempt}): ##{ping.status}...")
71
+ @log.info("Waiting for #{uri} (attempt no.#{attempt}): ##{ping.status}...")
71
72
  sleep 0.5
72
73
  attempt += 1
73
74
  break if attempt > 10
@@ -76,7 +76,7 @@ class FarmTest < Zold::Test
76
76
  farm.best
77
77
  Time.now - start
78
78
  end.inject(&:+) / cycles
79
- test_log.debug("Average speed is #{(speed * 1000).round(2)}ms in #{cycles} cycles")
79
+ test_log.info("Average speed is #{(speed * 1000).round(2)}ms in #{cycles} cycles")
80
80
  end
81
81
  end
82
82
  end
@@ -21,13 +21,14 @@
21
21
  # SOFTWARE.
22
22
 
23
23
  gem 'openssl'
24
- require 'minitest/fail_fast'
25
24
  require 'openssl'
26
25
  require 'minitest/autorun'
27
26
  require 'minitest/hooks/test'
28
27
  require 'concurrent'
29
28
  require 'timeout'
30
29
 
30
+ require 'minitest/fail_fast' if ENV['TEST_QUIET_LOG']
31
+
31
32
  STDOUT.sync = true
32
33
 
33
34
  ENV['RACK_ENV'] = 'test'
@@ -74,12 +75,12 @@ module Zold
74
75
 
75
76
  def test_log
76
77
  require_relative '../lib/zold/log'
77
- @test_log ||= Zold::Log::Sync.new(ENV['TEST_QUIET_LOG'] ? Zold::Log::Quiet.new : Zold::Log::Verbose.new)
78
+ @test_log ||= ENV['TEST_QUIET_LOG'] ? Zold::Log::NULL : Zold::Log::VERBOSE
78
79
  end
79
80
 
80
81
  class TestLogger
81
82
  attr_accessor :msgs
82
- def initialize(log = Zold::Log::Quiet.new)
83
+ def initialize(log = Zold::Log::NULL)
83
84
  @log = log
84
85
  @msgs = []
85
86
  end
@@ -46,7 +46,7 @@ class TestDirItems < Zold::Test
46
46
  File.open(file, 'w+') do |f|
47
47
  f.write('test')
48
48
  end
49
- test_log.debug("Saved in #{Zold::Age.new(start)}")
49
+ test_log.info("Saved in #{Zold::Age.new(start)}")
50
50
  sleep 1
51
51
  end
52
52
  back.kill
@@ -72,6 +72,24 @@ class TestHttp < Zold::Test
72
72
  assert_equal(200, res.status)
73
73
  end
74
74
 
75
+ def test_terminates_on_timeout
76
+ WebMock.allow_net_connect!
77
+ RandomPort::Pool::SINGLETON.acquire do |port|
78
+ thread = Thread.start do
79
+ Zold::VerboseThread.new(test_log).run do
80
+ server = TCPServer.new(port)
81
+ server.accept
82
+ sleep 400
83
+ end
84
+ end
85
+ sleep 0.25
86
+ res = Zold::Http.new(uri: "http://127.0.0.1:#{port}/").get(timeout: 0.1)
87
+ assert_equal(599, res.status, res)
88
+ thread.kill
89
+ thread.join
90
+ end
91
+ end
92
+
75
93
  def test_doesnt_terminate_on_long_call
76
94
  WebMock.allow_net_connect!
77
95
  RandomPort::Pool::SINGLETON.acquire do |port|
@@ -93,19 +111,39 @@ class TestHttp < Zold::Test
93
111
  end
94
112
  end
95
113
 
96
- def test_terminates_on_timeout
114
+ # @todo #444:30min It's obvious that the test works (I can see that in
115
+ # the console, but for some weird reason it doesn't work in Minitest. Try
116
+ # to run it: ruby test/test_http.rb -n test_sends_correct_http_headers
117
+ # If fails because of PUT HTTP request timeout. Let's find the problem,
118
+ # fix it, and un-skip the test.
119
+ def test_sends_correct_http_headers
120
+ skip
97
121
  WebMock.allow_net_connect!
122
+ body = ''
98
123
  RandomPort::Pool::SINGLETON.acquire do |port|
99
124
  thread = Thread.start do
100
125
  Zold::VerboseThread.new(test_log).run do
101
126
  server = TCPServer.new(port)
102
- server.accept
103
- sleep 400
127
+ socket = server.accept
128
+ loop do
129
+ line = socket.gets
130
+ break if line.nil?
131
+ test_log.info(line.inspect)
132
+ body += line
133
+ end
134
+ socket.print("HTTP/1.1 200 OK\r\n")
135
+ socket.print("Content-Length: 4\r\n")
136
+ socket.print("\r\n")
137
+ socket.print('Done')
138
+ socket.close
104
139
  end
105
140
  end
106
- sleep 0.25
107
- res = Zold::Http.new(uri: "http://127.0.0.1:#{port}/").get(timeout: 0.1)
108
- assert_equal(599, res.status, res)
141
+ res = Zold::Http.new(uri: "http://127.0.0.1:#{port}/").put('how are you?')
142
+ assert_equal(200, res.status, res)
143
+ assert(body.include?('Content-Length: 12'), body)
144
+ assert(body.include?('Content-Type: text/plain'))
145
+ headers = body.split("\n").select { |t| t =~ /^[a-zA-Z-]+:.+$/ }
146
+ assert_equal(headers.count, headers.uniq.count)
109
147
  thread.kill
110
148
  thread.join
111
149
  end