zold 0.31.10 → 0.32.1
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.
- checksums.yaml +4 -4
- data/Dockerfile +11 -27
- data/Gemfile +21 -33
- data/Gemfile.lock +181 -126
- data/Guardfile +0 -0
- data/INSTALL.md +80 -59
- data/LICENSE.txt +1 -1
- data/LICENSES/MIT.txt +21 -0
- data/README.md +183 -154
- data/REUSE.toml +40 -0
- data/Rakefile +4 -38
- data/bin/zold +7 -37
- data/deploy.sh +4 -22
- data/lib/zold/age.rb +3 -20
- data/lib/zold/amount.rb +3 -20
- data/lib/zold/cached_wallets.rb +3 -20
- data/lib/zold/commands/alias.rb +4 -21
- data/lib/zold/commands/args.rb +4 -21
- data/lib/zold/commands/calculate.rb +5 -22
- data/lib/zold/commands/clean.rb +6 -23
- data/lib/zold/commands/create.rb +5 -22
- data/lib/zold/commands/diff.rb +5 -22
- data/lib/zold/commands/fetch.rb +6 -23
- data/lib/zold/commands/invoice.rb +5 -22
- data/lib/zold/commands/list.rb +5 -22
- data/lib/zold/commands/merge.rb +7 -24
- data/lib/zold/commands/next.rb +5 -22
- data/lib/zold/commands/node.rb +4 -21
- data/lib/zold/commands/pay.rb +6 -23
- data/lib/zold/commands/propagate.rb +5 -22
- data/lib/zold/commands/pull.rb +5 -22
- data/lib/zold/commands/push.rb +5 -22
- data/lib/zold/commands/remote.rb +7 -24
- data/lib/zold/commands/remove.rb +5 -22
- data/lib/zold/commands/routines/audit.rb +4 -21
- data/lib/zold/commands/routines/gc.rb +6 -23
- data/lib/zold/commands/routines/reconcile.rb +5 -22
- data/lib/zold/commands/routines/reconnect.rb +4 -21
- data/lib/zold/commands/routines/retire.rb +4 -21
- data/lib/zold/commands/routines/spread.rb +5 -22
- data/lib/zold/commands/routines.rb +3 -20
- data/lib/zold/commands/show.rb +5 -22
- data/lib/zold/commands/taxes.rb +5 -22
- data/lib/zold/commands/thread_badge.rb +3 -20
- data/lib/zold/copies.rb +6 -25
- data/lib/zold/dir_items.rb +3 -20
- data/lib/zold/endless.rb +5 -22
- data/lib/zold/gem.rb +3 -20
- data/lib/zold/hands.rb +6 -23
- data/lib/zold/head.rb +4 -21
- data/lib/zold/hexnum.rb +3 -20
- data/lib/zold/http.rb +3 -20
- data/lib/zold/hungry_wallets.rb +6 -23
- data/lib/zold/id.rb +3 -20
- data/lib/zold/json_page.rb +5 -22
- data/lib/zold/key.rb +3 -20
- data/lib/zold/metronome.rb +5 -22
- data/lib/zold/node/async_entrance.rb +6 -23
- data/lib/zold/node/entrance.rb +7 -24
- data/lib/zold/node/farm.rb +5 -22
- data/lib/zold/node/farmers.rb +15 -32
- data/lib/zold/node/front.rb +6 -23
- data/lib/zold/node/journaled_pipeline.rb +8 -25
- data/lib/zold/node/nodup_entrance.rb +6 -23
- data/lib/zold/node/nospam_entrance.rb +6 -23
- data/lib/zold/node/pipeline.rb +6 -23
- data/lib/zold/node/safe_entrance.rb +4 -22
- data/lib/zold/node/soft_error.rb +3 -20
- data/lib/zold/node/spread_entrance.rb +5 -22
- data/lib/zold/node/sync_entrance.rb +5 -22
- data/lib/zold/node/trace.rb +3 -20
- data/lib/zold/patch.rb +6 -23
- data/lib/zold/prefixes.rb +3 -20
- data/lib/zold/remotes.rb +5 -22
- data/lib/zold/signature.rb +3 -20
- data/lib/zold/size.rb +3 -20
- data/lib/zold/sync_wallets.rb +5 -22
- data/lib/zold/tax.rb +4 -21
- data/lib/zold/thread_pool.rb +4 -21
- data/lib/zold/tree_wallets.rb +3 -20
- data/lib/zold/txn.rb +4 -21
- data/lib/zold/txns.rb +4 -21
- data/lib/zold/upgrades.rb +4 -21
- data/lib/zold/verbose_thread.rb +5 -22
- data/lib/zold/version.rb +4 -21
- data/lib/zold/version_file.rb +4 -21
- data/lib/zold/wallet.rb +6 -23
- data/lib/zold/wallets.rb +5 -23
- data/lib/zold.rb +3 -21
- data/resources/banned-wallets.log +6 -6
- data/upgrades/2.rb +3 -20
- data/upgrades/delete_banned_wallets.rb +3 -20
- data/upgrades/move_wallets_into_tree.rb +3 -20
- data/upgrades/protocol_up.rb +3 -20
- data/upgrades/rename_foreign_wallets.rb +3 -20
- data/views/journal.haml +25 -0
- data/views/layout.haml +25 -0
- data/views/wallet.haml +25 -0
- data/zold.gemspec +6 -22
- metadata +26 -174
- data/.0pdd.yml +0 -29
- data/.gitattributes +0 -9
- data/.github/workflows/actionlint.yml +0 -41
- data/.github/workflows/codecov.yml +0 -40
- data/.github/workflows/copyrights.yml +0 -30
- data/.github/workflows/pdd.yml +0 -34
- data/.github/workflows/rake.yml +0 -45
- data/.github/workflows/xcop.yml +0 -30
- data/.github/workflows/yamllint.yml +0 -34
- data/.gitignore +0 -12
- data/.pdd +0 -7
- data/.rubocop.yml +0 -70
- data/.ruby-version +0 -1
- data/.rultor.yml +0 -57
- data/.simplecov +0 -36
- data/cucumber.yml +0 -23
- data/features/cli.feature +0 -16
- data/features/gem_package.feature +0 -26
- data/features/step_definitions/steps.rb +0 -84
- data/features/support/env.rb +0 -26
- data/fixtures/448b451bc62e8e16.z +0 -1005
- data/fixtures/id_rsa +0 -51
- data/fixtures/id_rsa-2 +0 -51
- data/fixtures/id_rsa-2.pub +0 -1
- data/fixtures/id_rsa.pub +0 -1
- data/fixtures/keys/1.pub +0 -1
- data/fixtures/keys/2 +0 -51
- data/fixtures/keys/2.pub +0 -1
- data/fixtures/merge/asserts.rb +0 -36
- data/fixtures/merge/id_rsa +0 -51
- data/fixtures/merge/id_rsa.pub +0 -1
- data/fixtures/merge/into_no_wallet/assert.rb +0 -25
- data/fixtures/merge/into_no_wallet/copies/0123456789abcdef/1.zc +0 -6
- data/fixtures/merge/into_no_wallet/copies/0123456789abcdef/scores.zc +0 -1
- data/fixtures/merge/into_no_wallet/opts +0 -1
- data/fixtures/merge/legacy_negatives_stay/0123456789abcdef.z +0 -6
- data/fixtures/merge/legacy_negatives_stay/assert.rb +0 -25
- data/fixtures/merge/legacy_negatives_stay/copies/0123456789abcdef/1.zc +0 -6
- data/fixtures/merge/legacy_negatives_stay/copies/0123456789abcdef/scores.zc +0 -1
- data/fixtures/merge/legacy_negatives_stay/opts +0 -2
- data/fixtures/merge/missed_wallets/0000000000000000.z +0 -6
- data/fixtures/merge/missed_wallets/0123456789abcdef.z +0 -6
- data/fixtures/merge/missed_wallets/assert.rb +0 -25
- data/fixtures/merge/missed_wallets/copies/0123456789abcdef/1.zc +0 -8
- data/fixtures/merge/missed_wallets/copies/0123456789abcdef/scores.zc +0 -1
- data/fixtures/merge/missed_wallets/opts +0 -3
- data/fixtures/merge/negative_overwriting/0123456789abcdef.z +0 -6
- data/fixtures/merge/negative_overwriting/146b852f2d9ad984.z +0 -6
- data/fixtures/merge/negative_overwriting/assert.rb +0 -25
- data/fixtures/merge/negative_overwriting/copies/0123456789abcdef/1.zc +0 -6
- data/fixtures/merge/negative_overwriting/copies/0123456789abcdef/scores.zc +0 -1
- data/fixtures/merge/negative_overwriting/opts +0 -2
- data/fixtures/merge/negatives_in_between/0000000000000000.z +0 -6
- data/fixtures/merge/negatives_in_between/0123456789abcdef.z +0 -5
- data/fixtures/merge/negatives_in_between/assert.rb +0 -25
- data/fixtures/merge/negatives_in_between/copies/0123456789abcdef/1.zc +0 -6
- data/fixtures/merge/negatives_in_between/copies/0123456789abcdef/2.zc +0 -7
- data/fixtures/merge/negatives_in_between/copies/0123456789abcdef/3.zc +0 -6
- data/fixtures/merge/negatives_in_between/copies/0123456789abcdef/scores.zc +0 -3
- data/fixtures/merge/negatives_in_between/opts +0 -1
- data/fixtures/merge/random_expenses/0000000000000000.z +0 -6
- data/fixtures/merge/random_expenses/0123456789abcdef.z +0 -6
- data/fixtures/merge/random_expenses/assert.rb +0 -25
- data/fixtures/merge/random_expenses/copies/0123456789abcdef/1.zc +0 -7
- data/fixtures/merge/random_expenses/copies/0123456789abcdef/2.zc +0 -7
- data/fixtures/merge/random_expenses/copies/0123456789abcdef/3.zc +0 -7
- data/fixtures/merge/random_expenses/copies/0123456789abcdef/4.zc +0 -7
- data/fixtures/merge/random_expenses/copies/0123456789abcdef/5.zc +0 -7
- data/fixtures/merge/random_expenses/copies/0123456789abcdef/scores.zc +0 -5
- data/fixtures/merge/random_expenses/opts +0 -1
- data/fixtures/merge/simple_case/0000000000000000.z +0 -6
- data/fixtures/merge/simple_case/0123456789abcdef.z +0 -4
- data/fixtures/merge/simple_case/assert.rb +0 -25
- data/fixtures/merge/simple_case/copies/0123456789abcdef/1.zc +0 -6
- data/fixtures/merge/simple_case/copies/0123456789abcdef/scores.zc +0 -1
- data/fixtures/merge/simple_case/opts +0 -1
- data/fixtures/merge/unconfirmed_income/0123456789abcdef.z +0 -4
- data/fixtures/merge/unconfirmed_income/assert.rb +0 -25
- data/fixtures/merge/unconfirmed_income/copies/0123456789abcdef/1.zc +0 -6
- data/fixtures/merge/unconfirmed_income/copies/0123456789abcdef/scores.zc +0 -1
- data/fixtures/merge/unconfirmed_income/opts +0 -3
- data/fixtures/scripts/_head.sh +0 -89
- data/fixtures/scripts/calculate-scores.sh +0 -22
- data/fixtures/scripts/distribute-wallet.sh +0 -105
- data/fixtures/scripts/print-helps.sh +0 -27
- data/fixtures/scripts/pull-on-start.sh +0 -52
- data/fixtures/scripts/push-and-pull.sh +0 -63
- data/fixtures/scripts/redeploy-on-upgrade.sh +0 -56
- data/fixtures/scripts/spread-wallets.sh +0 -72
- data/lib/zold/log.rb +0 -139
- data/renovate.json +0 -6
- data/test/commands/routines/test_audit.rb +0 -41
- data/test/commands/routines/test_gc.rb +0 -70
- data/test/commands/routines/test_reconcile.rb +0 -51
- data/test/commands/routines/test_reconnect.rb +0 -46
- data/test/commands/routines/test_retire.rb +0 -40
- data/test/commands/test_alias.rb +0 -76
- data/test/commands/test_calculate.rb +0 -40
- data/test/commands/test_clean.rb +0 -73
- data/test/commands/test_create.rb +0 -50
- data/test/commands/test_diff.rb +0 -61
- data/test/commands/test_fetch.rb +0 -162
- data/test/commands/test_invoice.rb +0 -50
- data/test/commands/test_list.rb +0 -47
- data/test/commands/test_merge.rb +0 -129
- data/test/commands/test_node.rb +0 -68
- data/test/commands/test_pay.rb +0 -221
- data/test/commands/test_propagate.rb +0 -51
- data/test/commands/test_pull.rb +0 -70
- data/test/commands/test_push.rb +0 -93
- data/test/commands/test_remote.rb +0 -265
- data/test/commands/test_remove.rb +0 -66
- data/test/commands/test_show.rb +0 -48
- data/test/commands/test_taxes.rb +0 -76
- data/test/fake_home.rb +0 -104
- data/test/node/fake_entrance.rb +0 -43
- data/test/node/fake_node.rb +0 -105
- data/test/node/test_async_entrance.rb +0 -103
- data/test/node/test_entrance.rb +0 -82
- data/test/node/test_farm.rb +0 -177
- data/test/node/test_farmers.rb +0 -76
- data/test/node/test_front.rb +0 -399
- data/test/node/test_nodup_entrance.rb +0 -49
- data/test/node/test_nospam_entrance.rb +0 -49
- data/test/node/test_safe_entrance.rb +0 -59
- data/test/node/test_spread_entrance.rb +0 -67
- data/test/node/test_sync_entrance.rb +0 -41
- data/test/node/test_trace.rb +0 -36
- data/test/test__helper.rb +0 -112
- data/test/test_age.rb +0 -55
- data/test/test_amount.rb +0 -81
- data/test/test_cached_wallets.rb +0 -73
- data/test/test_copies.rb +0 -145
- data/test/test_dir_items.rb +0 -90
- data/test/test_gem.rb +0 -41
- data/test/test_hands.rb +0 -69
- data/test/test_hexnum.rb +0 -36
- data/test/test_http.rb +0 -225
- data/test/test_hungry_wallets.rb +0 -90
- data/test/test_id.rb +0 -79
- data/test/test_json_page.rb +0 -47
- data/test/test_key.rb +0 -99
- data/test/test_log.rb +0 -49
- data/test/test_metronome.rb +0 -89
- data/test/test_patch.rb +0 -178
- data/test/test_prefixes.rb +0 -49
- data/test/test_remotes.rb +0 -319
- data/test/test_signature.rb +0 -49
- data/test/test_size.rb +0 -39
- data/test/test_sync_wallets.rb +0 -57
- data/test/test_tax.rb +0 -171
- data/test/test_thread_pool.rb +0 -89
- data/test/test_tree_wallets.rb +0 -83
- data/test/test_txn.rb +0 -89
- data/test/test_upgrades.rb +0 -99
- data/test/test_verbose_thread.rb +0 -55
- data/test/test_version.rb +0 -35
- data/test/test_wallet.rb +0 -318
- data/test/test_wallets.rb +0 -85
- data/test/test_zold.rb +0 -99
- data/test/upgrades/test_delete_banned_wallets.rb +0 -47
- data/test/upgrades/test_protocol_up.rb +0 -42
data/test/node/fake_node.rb
DELETED
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# Copyright (c) 2018-2024 Zerocracy
|
|
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 'tmpdir'
|
|
24
|
-
require 'webmock/minitest'
|
|
25
|
-
require 'random-port'
|
|
26
|
-
require_relative '../fake_home'
|
|
27
|
-
require_relative '../../lib/zold/log'
|
|
28
|
-
require_relative '../../lib/zold/http'
|
|
29
|
-
require_relative '../../lib/zold/verbose_thread'
|
|
30
|
-
require_relative '../../lib/zold/node/front'
|
|
31
|
-
|
|
32
|
-
# Fake node.
|
|
33
|
-
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
34
|
-
# Copyright:: Copyright (c) 2018-2024 Zerocracy
|
|
35
|
-
# License:: MIT
|
|
36
|
-
class FakeNode
|
|
37
|
-
def initialize(log: Zold::Log::NULL)
|
|
38
|
-
@log = log
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
# This is a pretty weird situation: we have to acquire a single port
|
|
42
|
-
# number an reuse it for all tests. If we use different port numbers,
|
|
43
|
-
# acquiring them for each instance of FakeNode, we get port collisions,
|
|
44
|
-
# sometimes. Maybe this can be fixed sometimes.
|
|
45
|
-
# rubocop:disable Style/ClassVars
|
|
46
|
-
@@port = RandomPort::Pool::SINGLETON.acquire
|
|
47
|
-
# rubocop:enable Style/ClassVars
|
|
48
|
-
|
|
49
|
-
def run(args = ['--standalone', '--no-metronome'])
|
|
50
|
-
WebMock.allow_net_connect!
|
|
51
|
-
FakeHome.new(log: @log).run do |home|
|
|
52
|
-
node = Thread.new do
|
|
53
|
-
Thread.current.name = 'fake_node'
|
|
54
|
-
Thread.current.abort_on_exception = false
|
|
55
|
-
Zold::VerboseThread.new(@log).run do
|
|
56
|
-
require_relative '../../lib/zold/commands/node'
|
|
57
|
-
Zold::Node.new(wallets: home.wallets, remotes: home.remotes, copies: home.copies.root, log: @log).run(
|
|
58
|
-
[
|
|
59
|
-
'--home', home.dir,
|
|
60
|
-
'--network=test',
|
|
61
|
-
'--port', @@port.to_s,
|
|
62
|
-
'--host=localhost',
|
|
63
|
-
'--bind-port', @@port.to_s,
|
|
64
|
-
'--threads=1',
|
|
65
|
-
'--dump-errors',
|
|
66
|
-
'--strength=2',
|
|
67
|
-
'--halt-code=test',
|
|
68
|
-
'--routine-immediately',
|
|
69
|
-
'--invoice=NOPREFIX@ffffffffffffffff'
|
|
70
|
-
] + args
|
|
71
|
-
)
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
uri = "http://localhost:#{@@port}/"
|
|
75
|
-
attempt = 0
|
|
76
|
-
loop do
|
|
77
|
-
ping = Zold::Http.new(uri: uri).get
|
|
78
|
-
unless ping.status == 599 && node.alive?
|
|
79
|
-
@log.debug("The URL #{uri} is probably alive, after #{attempt} attempts")
|
|
80
|
-
break
|
|
81
|
-
end
|
|
82
|
-
unless node.alive?
|
|
83
|
-
@log.debug("The URL #{uri} is dead, after #{attempt} attempts")
|
|
84
|
-
break
|
|
85
|
-
end
|
|
86
|
-
@log.debug("Waiting for #{uri} (attempt no.#{attempt}): ##{ping.status}...")
|
|
87
|
-
sleep 0.5
|
|
88
|
-
attempt += 1
|
|
89
|
-
if attempt > 10
|
|
90
|
-
@log.error("Waiting for too long for #{uri} (#{attempt} attempts)")
|
|
91
|
-
break
|
|
92
|
-
end
|
|
93
|
-
end
|
|
94
|
-
raise "The node is dead at #{uri}" unless node.alive?
|
|
95
|
-
begin
|
|
96
|
-
yield @@port
|
|
97
|
-
ensure
|
|
98
|
-
Zold::Http.new(uri: "#{uri}?halt=test").get
|
|
99
|
-
node.join
|
|
100
|
-
sleep 0.1 # stupid sleep to make sure all threads are terminated
|
|
101
|
-
end
|
|
102
|
-
@log.debug("Thread with fake node stopped: #{node.alive?}")
|
|
103
|
-
end
|
|
104
|
-
end
|
|
105
|
-
end
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# Copyright (c) 2018-2024 Zerocracy
|
|
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 'threads'
|
|
25
|
-
require_relative '../fake_home'
|
|
26
|
-
require_relative '../test__helper'
|
|
27
|
-
require_relative '../../lib/zold/id'
|
|
28
|
-
require_relative '../../lib/zold/node/async_entrance'
|
|
29
|
-
require_relative 'fake_entrance'
|
|
30
|
-
|
|
31
|
-
# AsyncEntrance test.
|
|
32
|
-
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
33
|
-
# Copyright:: Copyright (c) 2018-2024 Zerocracy
|
|
34
|
-
# License:: MIT
|
|
35
|
-
class TestAsyncEntrance < Zold::Test
|
|
36
|
-
def test_renders_json
|
|
37
|
-
FakeHome.new(log: fake_log).run do |home|
|
|
38
|
-
Zold::AsyncEntrance.new(FakeEntrance.new, home.dir, log: fake_log).start do |e|
|
|
39
|
-
assert_equal(0, e.to_json[:queue])
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def test_sends_through_once
|
|
45
|
-
FakeHome.new(log: fake_log).run do |home|
|
|
46
|
-
wallet = home.create_wallet
|
|
47
|
-
amount = Zold::Amount.new(zld: 39.99)
|
|
48
|
-
key = Zold::Key.new(file: 'fixtures/id_rsa')
|
|
49
|
-
wallet.sub(amount, "NOPREFIX@#{Zold::Id.new}", key)
|
|
50
|
-
basic = CountingEntrance.new
|
|
51
|
-
Zold::AsyncEntrance.new(basic, File.join(home.dir, 'a/b/c'), log: fake_log).start do |e|
|
|
52
|
-
e.push(wallet.id, File.read(wallet.path))
|
|
53
|
-
assert_equal_wait(1) { basic.count }
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
def test_sends_through
|
|
59
|
-
FakeHome.new(log: fake_log).run do |home|
|
|
60
|
-
basic = CountingEntrance.new
|
|
61
|
-
Zold::AsyncEntrance.new(basic, File.join(home.dir, 'a/b/c'), log: fake_log, queue_limit: 1000).start do |e|
|
|
62
|
-
Threads.new(20).assert do
|
|
63
|
-
wallet = home.create_wallet
|
|
64
|
-
amount = Zold::Amount.new(zld: 39.99)
|
|
65
|
-
key = Zold::Key.new(file: 'fixtures/id_rsa')
|
|
66
|
-
wallet.sub(amount, "NOPREFIX@#{Zold::Id.new}", key)
|
|
67
|
-
5.times { e.push(wallet.id, File.read(wallet.path)) }
|
|
68
|
-
end
|
|
69
|
-
assert_equal_wait(true) { basic.count >= 20 }
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
def test_handles_broken_entrance_gracefully
|
|
75
|
-
FakeHome.new(log: fake_log).run do |home|
|
|
76
|
-
wallet = home.create_wallet
|
|
77
|
-
id = wallet.id
|
|
78
|
-
body = File.read(wallet.path)
|
|
79
|
-
Zold::AsyncEntrance.new(BrokenEntrance.new, home.dir, log: fake_log).start do |e|
|
|
80
|
-
e.push(id, body)
|
|
81
|
-
end
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
class CountingEntrance < FakeEntrance
|
|
86
|
-
attr_reader :count
|
|
87
|
-
|
|
88
|
-
def initialize
|
|
89
|
-
super
|
|
90
|
-
@count = 0
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
def push(_, _)
|
|
94
|
-
@count += 1
|
|
95
|
-
end
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
class BrokenEntrance < FakeEntrance
|
|
99
|
-
def push(_, _)
|
|
100
|
-
raise 'It intentionally crashes'
|
|
101
|
-
end
|
|
102
|
-
end
|
|
103
|
-
end
|
data/test/node/test_entrance.rb
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# Copyright (c) 2018-2024 Zerocracy
|
|
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 '../fake_home'
|
|
25
|
-
require_relative '../test__helper'
|
|
26
|
-
require_relative '../../lib/zold/wallet'
|
|
27
|
-
require_relative '../../lib/zold/wallets'
|
|
28
|
-
require_relative '../../lib/zold/remotes'
|
|
29
|
-
require_relative '../../lib/zold/id'
|
|
30
|
-
require_relative '../../lib/zold/key'
|
|
31
|
-
require_relative '../../lib/zold/node/entrance'
|
|
32
|
-
require_relative '../../lib/zold/node/pipeline'
|
|
33
|
-
require_relative '../../lib/zold/commands/pay'
|
|
34
|
-
|
|
35
|
-
# ENTRANCE test.
|
|
36
|
-
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
37
|
-
# Copyright:: Copyright (c) 2018-2024 Zerocracy
|
|
38
|
-
# License:: MIT
|
|
39
|
-
class TestEntrance < Zold::Test
|
|
40
|
-
def test_pushes_wallet
|
|
41
|
-
sid = Zold::Id::ROOT
|
|
42
|
-
tid = Zold::Id.new
|
|
43
|
-
body = FakeHome.new(log: fake_log).run do |home|
|
|
44
|
-
source = home.create_wallet(sid)
|
|
45
|
-
target = home.create_wallet(tid)
|
|
46
|
-
Zold::Pay.new(wallets: home.wallets, copies: home.dir, remotes: home.remotes, log: fake_log).run(
|
|
47
|
-
[
|
|
48
|
-
'pay', '--force', '--private-key=fixtures/id_rsa',
|
|
49
|
-
source.id.to_s, target.id.to_s, '19.99', 'testing'
|
|
50
|
-
]
|
|
51
|
-
)
|
|
52
|
-
File.read(source.path)
|
|
53
|
-
end
|
|
54
|
-
FakeHome.new(log: fake_log).run do |home|
|
|
55
|
-
source = home.create_wallet(sid)
|
|
56
|
-
target = home.create_wallet(tid)
|
|
57
|
-
ledger = File.join(home.dir, 'ledger.csv')
|
|
58
|
-
e = Zold::Entrance.new(
|
|
59
|
-
home.wallets,
|
|
60
|
-
Zold::Pipeline.new(home.remotes, home.copies(source).root, 'x', ledger: ledger),
|
|
61
|
-
log: fake_log
|
|
62
|
-
)
|
|
63
|
-
modified = e.push(source.id, body)
|
|
64
|
-
assert_equal(2, modified.count)
|
|
65
|
-
assert_equal(Zold::Amount.new(zld: -19.99), source.balance)
|
|
66
|
-
assert_equal(Zold::Amount.new(zld: 19.99), target.balance)
|
|
67
|
-
assert(modified.include?(sid))
|
|
68
|
-
assert(modified.include?(tid))
|
|
69
|
-
assert_equal(1, File.read(ledger).split("\n").count)
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def test_renders_json
|
|
74
|
-
FakeHome.new(log: fake_log).run do |home|
|
|
75
|
-
wallet = home.create_wallet
|
|
76
|
-
e = Zold::Entrance.new(home.wallets, Zold::Pipeline.new(home.remotes, home.copies.root, 'x'), log: fake_log)
|
|
77
|
-
e.push(wallet.id, File.read(wallet.path))
|
|
78
|
-
assert(e.to_json[:history].include?(wallet.id.to_s))
|
|
79
|
-
assert(!e.to_json[:speed].negative?)
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
end
|
data/test/node/test_farm.rb
DELETED
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# Copyright (c) 2018-2024 Zerocracy
|
|
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 'rack/test'
|
|
25
|
-
require 'tmpdir'
|
|
26
|
-
require_relative '../test__helper'
|
|
27
|
-
require_relative '../../lib/zold/log'
|
|
28
|
-
require_relative '../../lib/zold/node/farm'
|
|
29
|
-
|
|
30
|
-
class FarmTest < Zold::Test
|
|
31
|
-
def test_renders_in_json
|
|
32
|
-
Dir.mktmpdir do |dir|
|
|
33
|
-
farm = Zold::Farm.new('NOPREFIX6@ffffffffffffffff', File.join(dir, 'f'), log: fake_log, strength: 2)
|
|
34
|
-
farm.start('localhost', 80, threads: 2) do
|
|
35
|
-
assert_wait { !farm.best.empty? && !farm.best[0].value.zero? }
|
|
36
|
-
count = 0
|
|
37
|
-
100.times { count += farm.to_json[:best].length }
|
|
38
|
-
assert(count.positive?)
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def test_renders_in_text
|
|
44
|
-
Dir.mktmpdir do |dir|
|
|
45
|
-
farm = Zold::Farm.new('NOPREFIX7@ffffffffffffffff', File.join(dir, 'f'), log: fake_log, strength: 1)
|
|
46
|
-
farm.start('localhost', 80, threads: 2) do
|
|
47
|
-
assert(!farm.to_text.nil?)
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def test_makes_many_scores
|
|
53
|
-
Dir.mktmpdir do |dir|
|
|
54
|
-
farm = Zold::Farm.new('NOPREFIX6@ffffffffffffffff', File.join(dir, 'f'),
|
|
55
|
-
log: fake_log, lifetime: 10, farmer: Zold::Farmers::Plain.new, strength: 1)
|
|
56
|
-
farm.start('localhost', 80, threads: 4) do
|
|
57
|
-
assert_wait { farm.best.length == 4 }
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
# @todo #527:30min This test takes too long. The speed should be less than
|
|
63
|
-
# a few milliseconds, however, if you run it a few times, you will see
|
|
64
|
-
# that it is over 100ms sometimes. This is way too slow. I can't understand
|
|
65
|
-
# what's going on. It seems that IO.read() is taking too long sometimes.
|
|
66
|
-
# Try to measure its time of execution in Farm.load() and you will see
|
|
67
|
-
# that it's usually a few microseconds, but sometimes over 200ms.
|
|
68
|
-
def test_reads_scores_at_high_speed
|
|
69
|
-
Dir.mktmpdir do |dir|
|
|
70
|
-
farm = Zold::Farm.new('NOPREFIX6@ffffffffffffffff', File.join(dir, 'f'), log: fake_log, strength: 4)
|
|
71
|
-
farm.start('localhost', 80, threads: 4) do
|
|
72
|
-
assert_wait { !farm.best.empty? && !farm.best[0].value.zero? }
|
|
73
|
-
cycles = 100
|
|
74
|
-
speed = (0..cycles - 1).map do
|
|
75
|
-
start = Time.now
|
|
76
|
-
farm.best
|
|
77
|
-
Time.now - start
|
|
78
|
-
end.inject(&:+) / cycles
|
|
79
|
-
fake_log.info("Average speed is #{(speed * 1000).round(2)}ms in #{cycles} cycles")
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
def test_makes_best_score_in_background
|
|
85
|
-
Dir.mktmpdir do |dir|
|
|
86
|
-
farm = Zold::Farm.new('NOPREFIX1@ffffffffffffffff', File.join(dir, 'f'), log: fake_log, strength: 3)
|
|
87
|
-
farm.start('localhost', 80, threads: 1) do
|
|
88
|
-
assert_wait { !farm.best.empty? && farm.best[0].value >= 3 }
|
|
89
|
-
score = farm.best[0]
|
|
90
|
-
assert(!score.expired?)
|
|
91
|
-
assert(score.value >= 3)
|
|
92
|
-
end
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
def test_correct_score_from_empty_farm
|
|
97
|
-
Dir.mktmpdir do |dir|
|
|
98
|
-
farm = Zold::Farm.new('NOPREFIX2@cccccccccccccccc', File.join(dir, 'f'), log: fake_log, strength: 1)
|
|
99
|
-
farm.start('example.com', 8080, threads: 0) do
|
|
100
|
-
score = farm.best[0]
|
|
101
|
-
assert(!score.expired?)
|
|
102
|
-
assert_equal(0, score.value)
|
|
103
|
-
assert_equal('example.com', score.host)
|
|
104
|
-
assert_equal(8080, score.port)
|
|
105
|
-
end
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
def test_pre_loads_history
|
|
110
|
-
Dir.mktmpdir do |dir|
|
|
111
|
-
cache = File.join(dir, 'a/b/c/cache')
|
|
112
|
-
farm = Zold::Farm.new('NOPREFIX3@cccccccccccccccc', cache, log: fake_log, strength: 1)
|
|
113
|
-
farm.start('example.com', 8080, threads: 0) do
|
|
114
|
-
score = farm.best[0]
|
|
115
|
-
assert(!score.nil?, 'The list of best scores can\'t be empty!')
|
|
116
|
-
assert(File.exist?(cache), 'The cache file has to be created!')
|
|
117
|
-
assert_equal(0, score.value)
|
|
118
|
-
assert(!score.expired?)
|
|
119
|
-
assert_equal('example.com', score.host)
|
|
120
|
-
assert_equal(8080, score.port)
|
|
121
|
-
end
|
|
122
|
-
end
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
def test_drops_expired_scores_from_history
|
|
126
|
-
Dir.mktmpdir do |dir|
|
|
127
|
-
cache = File.join(dir, 'cache')
|
|
128
|
-
score = Zold::Score.new(
|
|
129
|
-
time: Time.parse('2017-07-19T21:24:51Z'),
|
|
130
|
-
host: 'some-host', port: 9999, invoice: 'NOPREFIX4@ffffffffffffffff',
|
|
131
|
-
suffixes: %w[13f7f01 b2b32b 4ade7e],
|
|
132
|
-
strength: 6
|
|
133
|
-
)
|
|
134
|
-
File.write(cache, score.to_s)
|
|
135
|
-
farm = Zold::Farm.new('NOPREFIX4@ffffffffffffffff', cache, log: fake_log, strength: score.strength)
|
|
136
|
-
farm.start(score.host, score.port, threads: 1) do
|
|
137
|
-
100.times do
|
|
138
|
-
sleep(0.1)
|
|
139
|
-
b = farm.best[0]
|
|
140
|
-
assert(!b.nil?)
|
|
141
|
-
break if b.value.zero?
|
|
142
|
-
end
|
|
143
|
-
assert_equal(0, farm.best[0].value)
|
|
144
|
-
end
|
|
145
|
-
end
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
def test_garbage_farm_file
|
|
149
|
-
log = TestLogger.new
|
|
150
|
-
Dir.mktmpdir do |dir|
|
|
151
|
-
file = File.join(dir, 'corrupted_farm')
|
|
152
|
-
[
|
|
153
|
-
'some garbage',
|
|
154
|
-
'some other garbage'
|
|
155
|
-
].each do |score_garbage_line|
|
|
156
|
-
valid_score = Zold::Score.new(
|
|
157
|
-
time: Time.parse('2017-07-19T21:24:51Z'),
|
|
158
|
-
host: 'some-host', port: 9999, invoice: 'NOPREFIX5@ffffffffffffffff',
|
|
159
|
-
suffixes: %w[13f7f01 b2b32b 4ade7e], strength: 6
|
|
160
|
-
)
|
|
161
|
-
File.open(file, 'w') do |f|
|
|
162
|
-
f.puts(score_garbage_line)
|
|
163
|
-
f.puts(valid_score)
|
|
164
|
-
end
|
|
165
|
-
farm = Zold::Farm.new('NOPREFIX5@ffffffffffffffff', file, log: log)
|
|
166
|
-
assert_equal(1, farm.best.count)
|
|
167
|
-
assert(log.msgs.find { |m| m.include?('Invalid score') }, log.msgs)
|
|
168
|
-
end
|
|
169
|
-
end
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
def test_terminates_farm_entirely
|
|
173
|
-
Zold::Farm.new('NOPREFIX4@ffffffffffffffff', log: fake_log, strength: 10).start('localhost', 4096, threads: 1) do
|
|
174
|
-
sleep 1
|
|
175
|
-
end
|
|
176
|
-
end
|
|
177
|
-
end
|
data/test/node/test_farmers.rb
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# Copyright (c) 2018-2024 Zerocracy
|
|
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 'time'
|
|
25
|
-
require 'zold/score'
|
|
26
|
-
require_relative '../test__helper'
|
|
27
|
-
require_relative '../../lib/zold/node/farmers'
|
|
28
|
-
require_relative '../../lib/zold/verbose_thread'
|
|
29
|
-
|
|
30
|
-
class FarmersTest < Zold::Test
|
|
31
|
-
# Types to test
|
|
32
|
-
TYPES = [
|
|
33
|
-
Zold::Farmers::Plain,
|
|
34
|
-
Zold::Farmers::Spawn,
|
|
35
|
-
Zold::Farmers::Fork
|
|
36
|
-
].freeze
|
|
37
|
-
|
|
38
|
-
def test_calculates_next_score
|
|
39
|
-
before = Zold::Score.new(host: 'some-host', port: 9999, invoice: 'NOPREFIX4@ffffffffffffffff', strength: 3)
|
|
40
|
-
TYPES.each do |farmer_class|
|
|
41
|
-
farmer = farmer_class.new(log: fake_log)
|
|
42
|
-
after = farmer.up(before)
|
|
43
|
-
assert_equal(1, after.value)
|
|
44
|
-
assert(!after.expired?)
|
|
45
|
-
assert_equal('some-host', after.host)
|
|
46
|
-
assert_equal(9999, after.port)
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def test_calculates_large_score
|
|
51
|
-
TYPES.each do |type|
|
|
52
|
-
log = TestLogger.new(fake_log)
|
|
53
|
-
thread = Thread.start do
|
|
54
|
-
farmer = type.new(log: log)
|
|
55
|
-
farmer.up(Zold::Score.new(host: 'a', port: 1, invoice: 'NOPREFIX4@ffffffffffffffff', strength: 20))
|
|
56
|
-
end
|
|
57
|
-
sleep(0.1)
|
|
58
|
-
thread.kill
|
|
59
|
-
thread.join
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def test_kills_farmer
|
|
64
|
-
TYPES.each do |type|
|
|
65
|
-
farmer = type.new(log: fake_log)
|
|
66
|
-
thread = Thread.start do
|
|
67
|
-
Zold::VerboseThread.new(fake_log).run do
|
|
68
|
-
farmer.up(Zold::Score.new(host: 'some-host', invoice: 'NOPREFIX4@ffffffffffffffff', strength: 32))
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
sleep(1)
|
|
72
|
-
thread.kill
|
|
73
|
-
thread.join
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
end
|