zold-stress 0.1.0 → 0.2.0

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: 20a4f93a2a89ef506dbdfdbe3c55c2a5a56f91e675087bcd17c746453844cdf5
4
- data.tar.gz: 1cc77a327d0f2610421ada34ab62d49bd0bdd8697eba4df0c283c00f1ad80e43
3
+ metadata.gz: 9c66e8370c7f4e0f376bfd54769b05e920435277aa8d8ed691eb846799235587
4
+ data.tar.gz: dec502c2ef0ab965169f9758df1f5825eab376759999deccd16d0e6f8809fd71
5
5
  SHA512:
6
- metadata.gz: a4a09956cc8815c9f6fa944442e20f2fa51fa49106a6489b095535486ffaeae852da67af4ade4fbc2813fb4a4a08c838a963c843d1c20b9e865c1f11b6ef3dc2
7
- data.tar.gz: 2b20d477ffd5e30908331399153017ab37c5f2a5910437a85cf0fea2c85dbeff3ec25452c18537211b23ca6f16a66f69e34bc002c25a9d6a6b0bf48076ab287a
6
+ metadata.gz: 9e6116fcafeb7b9fd1a0b6c8e247c14ed30760132c46f06d225f9532c9c7233e14704d0bbe68f2ce6113b446bc02faca5de658a5b527854eb89fdc2a6d83440b
7
+ data.tar.gz: d9278d847c7fb6a718bab3afc4fd7007b15e57810d9f2386f7ba04ab8d9c6e0a7077f6f560113d2dbd4a5db9114803d38ec3dd14658d556ebfaec8010935d8ca
@@ -1,12 +1,15 @@
1
1
  assets:
2
2
  rubygems.yml: zerocracy/home#assets/rubygems.yml
3
3
  install: |-
4
+ sudo gem install zold
5
+ zold --version
4
6
  export GEM_HOME=~/.ruby
5
7
  export GEM_PATH=$GEM_HOME:$GEM_PATH
6
8
  release:
7
9
  script: |-
8
10
  bundle install
9
- rake
11
+ sudo rvm repair wrappers
12
+ rake --quiet
10
13
  rm -rf *.gem
11
14
  sed -i "s/0\.0\.0/${tag}/g" zold-stress.gemspec
12
15
  git add zold-stress.gemspec
@@ -22,5 +25,5 @@ merge:
22
25
  commanders: []
23
26
  script: |-
24
27
  bundle install
25
- rake
28
+ rake --quiet
26
29
  deploy: {}
@@ -1,7 +1,6 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.3.1
4
- - 2.3.3
3
+ - 2.5.1
5
4
  cache: bundler
6
5
  branches:
7
6
  only:
data/README.md CHANGED
@@ -8,9 +8,11 @@
8
8
  [![We recommend RubyMine](http://www.elegantobjects.org/rubymine.svg)](https://www.jetbrains.com/ruby/)
9
9
 
10
10
  [![Build Status](https://travis-ci.org/zold-io/zold-stress.svg)](https://travis-ci.org/zold-io/zold-stress)
11
+ [![Build status](https://ci.appveyor.com/api/projects/status/ds9i925foqfu30cg?svg=true)](https://ci.appveyor.com/project/yegor256/zold-stress)
11
12
  [![PDD status](http://www.0pdd.com/svg?name=zold-io/zold-stress)](http://www.0pdd.com/p?name=zold-io/zold-stress)
12
13
  [![Gem Version](https://badge.fury.io/rb/zold-stress.svg)](http://badge.fury.io/rb/zold-stress)
13
14
  [![Test Coverage](https://img.shields.io/codecov/c/github/zold-io/zold-stress.svg)](https://codecov.io/github/zold-io/zold-stress?branch=master)
15
+ [![Maintainability](https://api.codeclimate.com/v1/badges/ad51dc27597d1e728979/maintainability)](https://codeclimate.com/github/zold-io/zold-stress/maintainability)
14
16
 
15
17
  Here is the [White Paper](https://papers.zold.io/wp.pdf).
16
18
 
@@ -18,7 +20,17 @@ Join our [Telegram group](https://t.me/zold_io) to discuss it all live.
18
20
 
19
21
  The license is [MIT](https://github.com/zold-io/zold-stress/blob/master/LICENSE.txt).
20
22
 
21
- This is a command line testing toolkit.
23
+ This is a command line Zold network stress testing toolkit. First, you
24
+ create an empty directory. Then, create or pull a Zold wallet there. The
25
+ wallet has to have some money. Preferrably, a small amount, like 1 ZLD. Then,
26
+ you install `zold-stress` Ruby gem, run it, and read the output:
27
+
28
+ ```
29
+ $ gem install zold-stress
30
+ $ zold-stress --help
31
+ ```
32
+
33
+ You will have to install [Ruby](https://www.ruby-lang.org/en/) 2.5.1+ first.
22
34
 
23
35
  # How to contribute
24
36
 
@@ -0,0 +1,38 @@
1
+ version: '{build}'
2
+ skip_tags: true
3
+ clone_depth: 10
4
+ branches:
5
+ only:
6
+ - master
7
+ except:
8
+ - gh-pages
9
+ os: Windows Server 2012
10
+ environment:
11
+ matrix:
12
+ - ruby_version: "23-x64"
13
+ - ruby_version: "24-x64"
14
+ - ruby_version: "25-x64"
15
+ install:
16
+ - ps: |
17
+ $Env:PATH = "C:\Ruby${Env:ruby_version}\bin;${Env:PATH}"
18
+ if ($Env:ruby_version -match "^23" ) {
19
+ # RubyInstaller; download OpenSSL headers from OpenKnapsack Project
20
+ $Env:openssl_dir = "C:\Ruby${Env:ruby_version}"
21
+ appveyor DownloadFile http://dl.bintray.com/oneclick/OpenKnapsack/x64/openssl-1.0.2j-x64-windows.tar.lzma
22
+ 7z e openssl-1.0.2j-x64-windows.tar.lzma
23
+ 7z x -y -oC:\Ruby${Env:ruby_version} openssl-1.0.2j-x64-windows.tar
24
+ } else {
25
+ # RubyInstaller2; openssl package seems to be installed already
26
+ $Env:openssl_dir = "C:\msys64\mingw64"
27
+ }
28
+ - bundle config --local path vendor/bundle
29
+ - bundle config build.openssl --with-openssl-dir=%openssl_dir%
30
+ - ruby -v
31
+ - bundle -v
32
+ build_script:
33
+ - bundle update
34
+ - bundle install
35
+ test_script:
36
+ - bundle exec rake --quiet
37
+ cache:
38
+ - vendor/bundle
@@ -23,8 +23,6 @@
23
23
 
24
24
  STDOUT.sync = true
25
25
 
26
- start = Time.now
27
-
28
26
  require 'slop'
29
27
  require 'rainbow'
30
28
  require 'zold/log'
@@ -34,8 +32,10 @@ require 'zold/wallets'
34
32
  require 'zold/sync_wallets'
35
33
  require 'zold/cached_wallets'
36
34
  require 'zold/remotes'
35
+ require 'zold/commands/list'
37
36
  require_relative '../lib/zold/stress/round'
38
37
  require_relative '../lib/zold/stress/stats'
38
+ require_relative '../lib/zold/stress/summary'
39
39
  require_relative '../lib/zold/stress/air'
40
40
 
41
41
  Thread.current.name = 'main'
@@ -44,6 +44,7 @@ Encoding.default_external = Encoding::UTF_8
44
44
  Encoding.default_internal = Encoding::UTF_8
45
45
 
46
46
  log = Zold::Log::Regular.new
47
+ vlog = Zold::Log::Quiet.new
47
48
 
48
49
  begin
49
50
  opts = Slop.parse(ARGV, strict: false, suppress_errors: true) do |o|
@@ -52,6 +53,9 @@ Available options:"
52
53
  o.integer '-r', '--rounds',
53
54
  'Total amount of paying rounds to complete (default: 16)',
54
55
  default: 16
56
+ o.integer '-w', '--wait',
57
+ 'For how to long to wait for all payments to arrive (default: 600 seconds)',
58
+ default: 600
55
59
  o.integer '-p', '--pool',
56
60
  'From how many wallets to send payments (default: 8)',
57
61
  default: 8
@@ -73,12 +77,17 @@ Available options:"
73
77
  required: true,
74
78
  default: Zold::Wallet::MAIN_NETWORK
75
79
  o.bool '-h', '--help', 'Show these instructions'
80
+ o.on '--verbose', 'Enable extra logging information' do
81
+ log = Zold::Log::Verbose.new
82
+ vlog = Zold::Log::Regular.new
83
+ end
76
84
  o.on '--no-colors', 'Disable colors in the ouput' do
77
85
  Rainbow.enabled = false
78
86
  end
79
87
  end
80
88
 
81
89
  log = Zold::Log::Sync.new(log)
90
+ vlog = Zold::Log::Sync.new(vlog)
82
91
 
83
92
  if opts.help?
84
93
  log.info(opts.to_s)
@@ -96,27 +105,45 @@ Available options:"
96
105
  log: log
97
106
  )
98
107
  remotes = Zold::Remotes.new(file: File.join(zoldata, 'remotes'), network: opts['network'])
99
- remotes.defaults
108
+ if remotes.all.empty?
109
+ remotes.defaults
110
+ log.info("The list of remotes has got default nodes, there are #{remotes.all.count} total")
111
+ end
100
112
  copies = File.join(zoldata, 'copies')
101
113
 
102
114
  stats = Zold::Stress::Stats.new
115
+ summary = Zold::Stress::Summary.new(stats, opts['batch'])
103
116
  air = Zold::Stress::Air.new
104
117
  round = Zold::Stress::Round.new(
105
118
  pvt: Zold::Key.new(file: opts['private-key']),
106
119
  wallets: wallets, remotes: remotes, copies: copies,
107
- stats: stats, air: air, log: log, opts: opts
120
+ stats: stats, air: air, log: log, vlog: vlog, opts: opts
108
121
  )
109
- opts['rounds'].times do
110
- round.update
111
- round.prepare
122
+
123
+ start = Time.now
124
+ round.update
125
+ round.prepare
126
+ opts['rounds'].times do |r|
112
127
  round.send
113
128
  round.pull
114
129
  round.match
115
- log.info(stats.to_console)
130
+ log.info(summary)
131
+ Zold::List.new(wallets: wallets, log: log).run(['list'] + opts.arguments) if (r % 10).zero?
116
132
  end
133
+ s = Time.now
134
+ loop do
135
+ break if Time.now > s + opts['wait']
136
+ break if air.fetch.empty?
137
+ round.pull
138
+ round.match
139
+ log.info(summary)
140
+ end
141
+ unless air.fetch.empty?
142
+ raise "#{air.fetch.count} payments out of #{stats.total('paid')} are still somewhere, we lost them :("
143
+ end
144
+ log.info("Successfully sent and received #{Rainbow(stats.total('arrived')).green} transactions \
145
+ in #{Zold::Age.new(start)}")
117
146
  rescue StandardError => ex
118
147
  log.error(Backtrace.new(ex))
119
148
  exit(-1)
120
149
  end
121
-
122
- log.info("Successfully finished in #{Zold::Age.new(start)}")
@@ -0,0 +1,58 @@
1
+ #!/bin/bash
2
+ set -e
3
+ set -x
4
+ shopt -s expand_aliases
5
+
6
+ export RUBYOPT="-W0"
7
+
8
+ alias zold="zold --network=test"
9
+ alias zold-stress="$1 --network=test"
10
+
11
+ function reserve_port {
12
+ python -c 'import socket; s=socket.socket(); s.bind(("", 0)); print(s.getsockname()[1]); s.close()'
13
+ }
14
+
15
+ function wait_for_url {
16
+ i=0
17
+ while ! curl --silent --fail $1 > /dev/null; do
18
+ ((i++)) || sleep 0
19
+ if ((i==30)); then
20
+ echo "URL $1 is not available after ${i} attempts"
21
+ exit 12
22
+ fi
23
+ sleep 2
24
+ done
25
+ }
26
+
27
+ function wait_for_port {
28
+ i=0
29
+ while ! nc -z localhost $1; do
30
+ ((i++)) || sleep 0
31
+ if ((i==30)); then
32
+ echo "Port $1 is not available after ${i} attempts"
33
+ exit 13
34
+ fi
35
+ sleep 2
36
+ done
37
+ }
38
+
39
+ function halt_nodes {
40
+ for p in "$@"; do
41
+ pid=$(curl --silent "http://localhost:$p/pid?halt=test" || echo 'absent')
42
+ if [[ "${pid}" =~ ^[0-9]+$ ]]; then
43
+ i=0
44
+ while kill -0 ${pid}; do
45
+ ((i++)) || sleep 0
46
+ if ((i==30)); then
47
+ echo "Process ${pid} didn't die, it's a bug"
48
+ exit 15
49
+ fi
50
+ echo "Still waiting for process ${pid} to die, attempt no.${i}"
51
+ sleep 2
52
+ done
53
+ echo "Process ${pid} is dead!"
54
+ fi
55
+ echo "Node at TCP port ${p} stopped!"
56
+ done
57
+ }
58
+
@@ -0,0 +1,32 @@
1
+ #!/bin/bash
2
+
3
+ function start_node {
4
+ port=$(reserve_port)
5
+ mkdir ${port}
6
+ cd ${port}
7
+ zold node --trace --invoice=SPREADWALLETS@ffffffffffffffff \
8
+ --host=localhost --port=${port} --bind-port=${port} --dump-errors \
9
+ --standalone --no-metronome --halt-code=test \
10
+ --threads=0 > log.txt &
11
+ pid=$!
12
+ echo ${pid} > pid
13
+ cd ..
14
+ wait_for_url http://localhost:${port}/
15
+ echo ${port}
16
+ }
17
+
18
+ zold --version
19
+
20
+ port=$(start_node)
21
+ trap "halt_nodes ${port}" EXIT
22
+ zold remote clean
23
+ zold remote add localhost ${port}
24
+
25
+ zold --public-key=id_rsa.pub create 0000000000000000
26
+ zold --public-key=id_rsa.pub create abcdabcdabcdabcd
27
+ zold pay --private-key=id_rsa 0000000000000000 abcdabcdabcdabcd 4.95 'To test'
28
+ zold push 0000000000000000
29
+ zold remove 0000000000000000
30
+
31
+ # zold-stress --rounds=1000 --wait=5 --threads=12 --pool=16 --batch=8 --private-key=id_rsa
32
+ zold-stress --rounds=4 --wait=5 --threads=4 --pool=4 --batch=4 --private-key=id_rsa
@@ -38,7 +38,7 @@ module Zold::Stress
38
38
 
39
39
  def add(pmt)
40
40
  @mutex.synchronize do
41
- @all << pmt
41
+ @all << pmt.merge(pushed: Time.now)
42
42
  end
43
43
  end
44
44
 
@@ -47,5 +47,11 @@ module Zold::Stress
47
47
  @all.delete(pmt)
48
48
  end
49
49
  end
50
+
51
+ def pulled(id)
52
+ @mutex.synchronize do
53
+ @all.select { |a| a[:target] == id }.each { |a| a[:pulled] = Time.now }
54
+ end
55
+ end
50
56
  end
51
57
  end
@@ -20,6 +20,7 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
21
  # SOFTWARE.
22
22
 
23
+ require 'securerandom'
23
24
  require 'zold/key'
24
25
  require 'zold/tax'
25
26
  require 'zold/commands/pay'
@@ -67,8 +67,9 @@ module Zold::Stress
67
67
  )
68
68
  end
69
69
  end
70
- return unless balances[0][:balance].zero?
71
- raise "There is no money in the pool of #{balances.count} wallets at #{@wallets.path}"
70
+ return if balances.find { |b| b[:balance].positive? }
71
+ raise "There is not a single wallet among #{balances.count} with a positive balance, in #{@wallets.path}: \
72
+ #{balances.map { |b| "#{b[:id]}: #{b[:balance]}" }.join("\n")}"
72
73
  end
73
74
  end
74
75
  end
@@ -56,11 +56,12 @@ module Zold::Stress
56
56
  cmd = Zold::Remote.new(remotes: @remotes, log: @vlog)
57
57
  args = ['remote'] + @opts.arguments
58
58
  cmd.run(args + ['trim'])
59
- cmd.run(args + ['reset']) if @remotes.all.empty?
59
+ cmd.run(args + ['reset']) if @remotes.all.empty? && @opts['network'] != 'test'
60
60
  @stats.exec('update') do
61
61
  cmd.run(args + ['update'])
62
62
  end
63
63
  cmd.run(args + ['select'])
64
+ raise 'There are no remote nodes left' if @remotes.all.empty?
64
65
  @log.info("List of remotes updated in #{Zold::Age.new(start)}, #{@remotes.all.count} nodes in the list")
65
66
  end
66
67
 
@@ -80,7 +81,7 @@ module Zold::Stress
80
81
  end
81
82
  end
82
83
  @log.info("There are #{@wallets.all.count} wallets in the pool \
83
- with #{@wallets.all.map { |id| @wallets.find(id, &:balance) }.inject(&:+)} \
84
+ with #{@wallets.all.map { |id| @wallets.find(id, &:balance) }.inject(&:+)} total, \
84
85
  in #{Zold::Age.new(start)}")
85
86
  end
86
87
 
@@ -101,44 +102,45 @@ in #{Zold::Age.new(start)}")
101
102
  mutex.synchronize do
102
103
  a[1].each { |p| @air.add(p) }
103
104
  end
105
+ @stats.put('output', @wallets.find(a[0], &:size))
104
106
  end
105
107
  end
106
- @log.info("#{sent.count} payments sent from #{sources.count} wallets, \
107
- in #{Zold::Age.new(start)}, #{@air.fetch.count} are now in the air:
108
- #{sent.map { |p| "#{p[:source]} -> #{p[:target]} #{p[:amount]}" }.join("\n ")}")
108
+ @log.info("#{sent.count} payments for #{sent.map { |s| s[:amount] }.inject(&:+)} \
109
+ sent from #{sources.count} wallets, \
110
+ in #{Zold::Age.new(start)}, #{@air.fetch.count} are now in the air, \
111
+ #{Zold::Age.new(@air.fetch.map { |a| a[:pushed] }.reverse[0] || Time.now)} is the oldest")
112
+ @log.debug(" #{sent.map { |p| "#{p[:source]} -> #{p[:target]} #{p[:amount]}" }.join("\n ")}")
109
113
  end
110
114
 
111
115
  def pull
112
116
  start = Time.now
113
117
  targets = @air.fetch.group_by { |p| p[:target] }.map { |a| a[0] }
114
- targets.each do |id|
115
- next unless @wallets.find(id, &:exists?)
116
- Zold::Remove.new(wallets: @wallets, log: @vlog).run(
117
- ['remove', id.to_s]
118
- )
119
- end
120
118
  targets.peach(@opts['threads']) do |id|
121
119
  @stats.exec('pull') do
122
120
  Zold::Pull.new(wallets: @wallets, remotes: @remotes, copies: @copies, log: @vlog).run(
123
121
  ['pull', id.to_s, "--network=#{@opts['network']}"] + @opts.arguments
124
122
  )
125
123
  end
124
+ @air.pulled(id)
125
+ @stats.put('input', @wallets.find(id, &:size))
126
126
  end
127
127
  @log.info("There are #{@wallets.all.count} wallets left, \
128
128
  after the pull of #{targets.count} in #{Zold::Age.new(start)}")
129
129
  end
130
130
 
131
131
  def match
132
+ total = 0
132
133
  @air.fetch.each do |p|
133
134
  next unless @wallets.find(p[:target], &:exists?)
134
135
  t = @wallets.find(p[:target], &:txns).find { |x| x.details == p[:details] && x.bnf == p[:source] }
135
136
  next if t.nil?
136
- @stats.put('arrived', Time.now - p[:start])
137
- @log.info("#{p[:amount]} arrived from #{p[:source]} to #{p[:target]} \
137
+ @stats.put('arrived', p[:pulled] - p[:pushed])
138
+ total += 1
139
+ @log.debug("#{p[:amount]} arrived from #{p[:source]} to #{p[:target]} \
138
140
  in txn ##{t.id} in #{Zold::Age.new(p[:start])}: #{t.details}")
139
141
  @air.delete(p)
140
142
  end
141
- @log.info("#{@air.fetch.count} payments are still in the air")
143
+ @log.info("#{total} payments just arrived, #{@air.fetch.count} still in the air")
142
144
  end
143
145
  end
144
146
  end
@@ -26,7 +26,7 @@ require 'backtrace'
26
26
  require 'zold/log'
27
27
  require 'zold/age'
28
28
 
29
- # Pool of wallets.
29
+ # Statistics.
30
30
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
31
31
  # Copyright:: Copyright (c) 2018 Yegor Bugayenko
32
32
  # License:: MIT
@@ -34,25 +34,12 @@ module Zold::Stress
34
34
  # Stats
35
35
  class Stats
36
36
  def initialize
37
- @start = Time.now
38
37
  @history = {}
39
38
  @mutex = Mutex.new
40
39
  end
41
40
 
42
- def to_console
43
- [
44
- "#{(total('arrived') / (Time.now - @start)).round(2)} tps",
45
- %w[update push pull paid].map do |m|
46
- if @history[m]
47
- t = "#{m}: #{total(m)}/#{Zold::Age.new(Time.now - avg(m), limit: 1)}"
48
- errors = total(m + '_error')
49
- t += errors.zero? ? '' : '/' + Rainbow(errors.to_s).red
50
- t
51
- else
52
- "#{m}: none"
53
- end
54
- end
55
- ].join('; ')
41
+ def exists?(metric)
42
+ !@history[metric].nil?
56
43
  end
57
44
 
58
45
  def total(metric)
@@ -60,10 +47,12 @@ module Zold::Stress
60
47
  end
61
48
 
62
49
  def avg(metric)
50
+ sum(metric).to_f / [total(metric), 1].max
51
+ end
52
+
53
+ def sum(metric)
63
54
  array = @history[metric].map { |a| a[:value] } || []
64
- sum = array.inject(&:+) || 0
65
- count = [array.count, 1].max
66
- sum.to_f / count
55
+ array.inject(&:+) || 0
67
56
  end
68
57
 
69
58
  def to_json
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2018 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 NONINFRINGEMENT. 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 'time'
24
+ require 'rainbow'
25
+ require 'backtrace'
26
+ require 'zold/log'
27
+ require 'zold/age'
28
+ require 'zold/size'
29
+
30
+ # Summary line.
31
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
32
+ # Copyright:: Copyright (c) 2018 Yegor Bugayenko
33
+ # License:: MIT
34
+ module Zold::Stress
35
+ # Summary line
36
+ class Summary
37
+ def initialize(stats, batch = 0)
38
+ @stats = stats
39
+ @batch = batch
40
+ end
41
+
42
+ def tps
43
+ @batch / @stats.avg('arrived')
44
+ end
45
+
46
+ def to_s
47
+ [
48
+ "#{tps.round(2)} tps",
49
+ %w[update push pull paid arrived].map do |m|
50
+ if @stats.exists?(m)
51
+ t = "#{m}: #{@stats.total(m)}/#{Zold::Age.new(Time.now - @stats.avg(m), limit: 1)}"
52
+ errors = @stats.total(m + '_error')
53
+ t += errors.zero? ? '' : '/' + Rainbow(errors.to_s).red
54
+ t
55
+ else
56
+ "#{m}: none"
57
+ end
58
+ end,
59
+ "in: #{Zold::Size.new(@stats.sum('input'))}",
60
+ "out: #{Zold::Size.new(@stats.sum('output'))}"
61
+ ].join('; ')
62
+ end
63
+ end
64
+ end
@@ -33,9 +33,9 @@ class AirTest < Minitest::Test
33
33
  air.add(pmt)
34
34
  assert_equal(1, air.fetch.count)
35
35
  air.fetch.each do |p|
36
- assert_equal(pmt, p)
36
+ assert_equal(pmt[:details], p[:details])
37
37
  end
38
- air.delete(pmt)
38
+ air.delete(air.fetch[0])
39
39
  assert_equal(0, air.fetch.count)
40
40
  end
41
41
  end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2018 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 'tmpdir'
25
+ require 'open3'
26
+ require 'English'
27
+ require 'zold/age'
28
+ require_relative '../test__helper'
29
+
30
+ # Bin test.
31
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
32
+ # Copyright:: Copyright (c) 2018 Yegor Bugayenko
33
+ # License:: MIT
34
+ class TestBin < Minitest::Test
35
+ Dir.new('fixtures/scripts').select { |f| f =~ /\.sh$/ && !f.start_with?('_') }.each do |f|
36
+ define_method("test_script_#{f.gsub(/[^a-z]/, '_')}") do
37
+ start = Time.now
38
+ test_log.debug("\n\n#{f} running...")
39
+ Dir.mktmpdir do |dir|
40
+ FileUtils.cp('fixtures/id_rsa.pub', dir)
41
+ FileUtils.cp('fixtures/id_rsa', dir)
42
+ script = File.join(dir, f)
43
+ IO.write(script, IO.read('fixtures/scripts/_head.sh') + IO.read(File.join('fixtures/scripts', f)))
44
+ bin = File.join(Dir.pwd, 'bin/zold-stress')
45
+ out = []
46
+ Dir.chdir(dir) do
47
+ Open3.popen2e("/bin/bash #{f} #{bin} 2>&1") do |stdin, stdout, thr|
48
+ stdin.close
49
+ until stdout.eof?
50
+ line = stdout.gets
51
+ test_log.debug(line)
52
+ out << line
53
+ end
54
+ code = thr.value.to_i
55
+ assert_equal(0, code, "#{f}\n#{out.join}")
56
+ end
57
+ end
58
+ end
59
+ test_log.debug("\n\n#{f} done in #{Zold::Age.new(start)}")
60
+ end
61
+ end
62
+
63
+ private
64
+
65
+ def exec(tail, dir = Dir.pwd)
66
+ bin = File.expand_path(File.join(Dir.pwd, 'bin/zold-stress'))
67
+ stdout = `cd #{dir} && #{bin} #{tail} 2>&1`
68
+ unless $CHILD_STATUS.exitstatus.zero?
69
+ puts stdout
70
+ assert_equal($CHILD_STATUS.exitstatus, 0)
71
+ end
72
+ stdout
73
+ end
74
+ end
@@ -39,6 +39,9 @@ require 'tmpdir'
39
39
  require_relative '../test__helper'
40
40
  require_relative 'fake_node'
41
41
  require_relative '../../../lib/zold/stress/round'
42
+ require_relative '../../../lib/zold/stress/stats'
43
+ require_relative '../../../lib/zold/stress/summary'
44
+ require_relative '../../../lib/zold/stress/air'
42
45
 
43
46
  class StressTest < Minitest::Test
44
47
  def test_runs_a_few_full_cycles
@@ -57,6 +60,7 @@ class StressTest < Minitest::Test
57
60
  stats = Zold::Stress::Stats.new
58
61
  air = Zold::Stress::Air.new
59
62
  batch = 20
63
+ summary = Zold::Stress::Summary.new(stats, batch)
60
64
  round = Zold::Stress::Round.new(
61
65
  pvt: Zold::Key.new(file: 'fixtures/id_rsa'),
62
66
  wallets: wallets, remotes: remotes,
@@ -74,7 +78,7 @@ class StressTest < Minitest::Test
74
78
  break if attempt > 50
75
79
  round.pull
76
80
  round.match
77
- test_log.info(stats.to_console)
81
+ test_log.info(summary)
78
82
  attempt += 1
79
83
  sleep 0.2
80
84
  end
@@ -32,12 +32,13 @@ ENV['RACK_ENV'] = 'test'
32
32
  # end
33
33
 
34
34
  require 'concurrent'
35
+ require 'slop'
35
36
  require 'minitest/autorun'
36
37
  module Minitest
37
38
  class Test
38
39
  def test_log
39
40
  require 'zold/log'
40
- @test_log ||= Zold::Log::Sync.new(Zold::Log::Verbose.new)
41
+ @test_log ||= Zold::Log::Sync.new(ENV['TEST_QUIET_LOG'] ? Zold::Log::Quiet.new : Zold::Log::Verbose.new)
41
42
  end
42
43
 
43
44
  def test_opts(*argv)
@@ -27,7 +27,7 @@ Gem::Specification.new do |s|
27
27
  s.rubygems_version = '2.2'
28
28
  s.required_ruby_version = '>=2.3'
29
29
  s.name = 'zold-stress'
30
- s.version = '0.1.0'
30
+ s.version = '0.2.0'
31
31
  s.license = 'MIT'
32
32
  s.summary = 'Zold stress test'
33
33
  s.description = 'Stress testing toolkit for Zold network'
@@ -41,7 +41,7 @@ Gem::Specification.new do |s|
41
41
  s.extra_rdoc_files = ['README.md', 'LICENSE.txt']
42
42
  s.add_runtime_dependency 'backtrace', '0.3.0'
43
43
  s.add_runtime_dependency 'parallelize', '0.4.1'
44
- s.add_runtime_dependency 'zold'
44
+ s.add_runtime_dependency 'zold', '0.16.18'
45
45
  s.add_development_dependency 'codecov', '0.1.13'
46
46
  s.add_development_dependency 'minitest', '5.11.3'
47
47
  s.add_development_dependency 'random-port', '0.3.0'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zold-stress
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-11-08 00:00:00.000000000 Z
11
+ date: 2018-11-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: backtrace
@@ -42,16 +42,16 @@ dependencies:
42
42
  name: zold
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ">="
45
+ - - '='
46
46
  - !ruby/object:Gem::Version
47
- version: '0'
47
+ version: 0.16.18
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ">="
52
+ - - '='
53
53
  - !ruby/object:Gem::Version
54
- version: '0'
54
+ version: 0.16.18
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: codecov
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -171,6 +171,7 @@ files:
171
171
  - LICENSE.txt
172
172
  - README.md
173
173
  - Rakefile
174
+ - appveyor.yml
174
175
  - bin/zold-stress
175
176
  - features/cli.feature
176
177
  - features/gem_package.feature
@@ -178,13 +179,17 @@ files:
178
179
  - features/support/env.rb
179
180
  - fixtures/id_rsa
180
181
  - fixtures/id_rsa.pub
182
+ - fixtures/scripts/_head.sh
183
+ - fixtures/scripts/simple-stress.sh
181
184
  - lib/zold/stress/air.rb
182
185
  - lib/zold/stress/pmnts.rb
183
186
  - lib/zold/stress/pool.rb
184
187
  - lib/zold/stress/round.rb
185
188
  - lib/zold/stress/stats.rb
189
+ - lib/zold/stress/summary.rb
186
190
  - test/zold/stress/fake_node.rb
187
191
  - test/zold/stress/test_air.rb
192
+ - test/zold/stress/test_bin.rb
188
193
  - test/zold/stress/test_pmnts.rb
189
194
  - test/zold/stress/test_pool.rb
190
195
  - test/zold/stress/test_round.rb
@@ -223,6 +228,7 @@ test_files:
223
228
  - features/support/env.rb
224
229
  - test/zold/stress/fake_node.rb
225
230
  - test/zold/stress/test_air.rb
231
+ - test/zold/stress/test_bin.rb
226
232
  - test/zold/stress/test_pmnts.rb
227
233
  - test/zold/stress/test_pool.rb
228
234
  - test/zold/stress/test_round.rb