lavin 0.2.0 → 0.3.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d3a7216c049391b24ccad2eb6c6d6424114761a11b1b4aa15824c5c58ca2bf19
4
- data.tar.gz: 3ec27a41fdc255d3eafb3a168c39ad8b744b28ab5e436d38d8eaf9f94aa22f23
3
+ metadata.gz: 52a0a48c405e0aff4b816ff7bf91b27e8407929a838db819f8777d222b4f7674
4
+ data.tar.gz: 4acb3c0a928acd45ecbd8137089433e69cdc8235919a0db6fefefb40418bfd82
5
5
  SHA512:
6
- metadata.gz: c6689ccce7532d8438013a8e3af32052f5b8df828169a026270f03d16a9078f11677b36f2a6c8989ec27cd8bfa3248d4bb1a9bbd2ddc35cccd4d8f1df143e182
7
- data.tar.gz: 4b2b728d3d5c775471c3ffdcf52c7b2a475d6c7e76d6aae4288b1e1154747e6f81bc802bf3f04f951aa1dec02de690671f110e01db8baed5c5442717f93f2b85
6
+ metadata.gz: e2fe666e13f22d13dc4f085e8ab7e78c2242a973bd9b0d58054e0b4ada2cc17d1ca924e4103a3c55408bd88c4d1cd3efa8b3449cee7fd8a5d36794392218779c
7
+ data.tar.gz: b1f7f478a288492082a4f02462d345ce42703316638b3d6aee7848a92a539b22b750105e5e70fdf2ffe662ac26ed68a4f6a32c63154b18ba4faf96dee917b16b
checksums.yaml.gz.sig CHANGED
Binary file
data/lib/lavin/client.rb CHANGED
@@ -5,6 +5,13 @@ require 'async/http/internet'
5
5
  module Lavin
6
6
  class Client
7
7
  class Error < Lavin::Error; end
8
+
9
+ class ServerError < Error
10
+ def initialize(status)
11
+ super("Server responded with status: #{status}")
12
+ end
13
+ end
14
+
8
15
  class NoCurrentAsyncTaskError < Error
9
16
  def initialize(msg = nil)
10
17
  super(msg || "Trying to create a client outside of an Async task")
data/lib/lavin/error.rb CHANGED
@@ -2,4 +2,8 @@
2
2
 
3
3
  module Lavin
4
4
  class Error < StandardError; end
5
+
6
+ class RecoverableError < Error; end
7
+
8
+ class IrrecoverableError < Error; end
5
9
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'lavin/error'
4
+
5
+ module Lavin
6
+ module Failure
7
+ def failure(msg)
8
+ raise RecoverableError, msg
9
+ end
10
+
11
+ def failure!(msg)
12
+ raise IrrecoverableError, msg
13
+ end
14
+ end
15
+ end
data/lib/lavin/hook.rb CHANGED
@@ -1,13 +1,13 @@
1
1
  # frozen_string_literal: true
2
- #
3
2
 
4
3
  module Lavin
5
4
  class Hook
6
- attr_reader :user, :block
5
+ attr_reader :user, :block, :type
7
6
 
8
- def initialize(user:, &block)
7
+ def initialize(user:, type: :before, &block)
9
8
  @user = user
10
9
  @block = block
10
+ @type = type
11
11
  end
12
12
 
13
13
  def run(context: nil)
@@ -19,9 +19,11 @@ module Lavin
19
19
  report_statistics = context.client.report_statistics
20
20
  context.client.report_statistics = false
21
21
  context.instance_exec(&block)
22
+ rescue RecoverableError
22
23
  rescue => error
23
- puts "Caught an error - #{error.class}: #{error.message}"
24
- puts error.backtrace
24
+ puts "Caught #{error.class} in #{type} hook: #{error.message}"
25
+ puts error.backtrace unless error.is_a? IrrecoverableError
26
+ throw :failure
25
27
  ensure
26
28
  context.client.report_statistics = report_statistics
27
29
  end
@@ -17,27 +17,35 @@ module Lavin
17
17
  end
18
18
 
19
19
  def get(url, headers: {})
20
- client.request(:get, url:, headers:)
20
+ request(:get, url:, headers:)
21
21
  end
22
22
 
23
23
  def head(url, headers: {})
24
- client.request(:head, url:, headers:)
24
+ request(:head, url:, headers:)
25
25
  end
26
26
 
27
27
  def post(url, headers: {}, body: nil)
28
- client.request(:post, url:, headers:, body:)
28
+ request(:post, url:, headers:, body:)
29
29
  end
30
30
 
31
31
  def put(url, headers: {}, body: nil)
32
- client.request(:put, url:, headers:, body:)
32
+ request(:put, url:, headers:, body:)
33
33
  end
34
34
 
35
35
  def patch(url, headers: {}, body: nil)
36
- client.request(:patch, url:, headers:, body:)
36
+ request(:patch, url:, headers:, body:)
37
37
  end
38
38
 
39
39
  def delete(url, headers: {})
40
- client.request(:delete, url:, headers:)
40
+ request(:delete, url:, headers:)
41
+ end
42
+
43
+ private
44
+
45
+ def request(method, url:, headers:, body: nil)
46
+ client.request(method, url:, headers:, body:).tap do |response|
47
+ raise Lavin::Client::ServerError, response[:status] if response[:status] > 499
48
+ end
41
49
  end
42
50
  end
43
51
  end
data/lib/lavin/runner.rb CHANGED
@@ -62,9 +62,9 @@ module Lavin
62
62
  end
63
63
 
64
64
  def stop
65
- Statistics.stop
66
65
  thread&.kill
67
66
  self.thread = nil
67
+ Statistics.stop
68
68
  end
69
69
 
70
70
  def running?
@@ -53,6 +53,7 @@ module Lavin
53
53
  key = [user, step_name]
54
54
  data[:steps][key][:success] += 1 unless failure
55
55
  data[:steps][key][:failure] += 1 if failure
56
+ data[:failures][failure.to_s] += 1 if failure
56
57
  end
57
58
 
58
59
  def stats
@@ -62,9 +63,11 @@ module Lavin
62
63
  requests = data[:requests].map do |(method, url), requests|
63
64
  durations = []
64
65
  statuses = []
66
+ failed_requests = 0
65
67
  requests.each do |request|
66
68
  durations << request[:duration]
67
69
  statuses << request[:status]
70
+ failed_requests += 1 if request[:failure]
68
71
  end
69
72
  min_duration = durations.min
70
73
  max_duration = durations.max
@@ -75,9 +78,10 @@ module Lavin
75
78
  url: url,
76
79
  requests: requests.size,
77
80
  statuses: statuses.tally,
78
- avg_duration: avg_duration,
79
- min_duration: min_duration,
80
- max_duration: max_duration
81
+ failed_requests:,
82
+ avg_duration:,
83
+ min_duration:,
84
+ max_duration:
81
85
  }
82
86
  end
83
87
 
@@ -87,7 +91,8 @@ module Lavin
87
91
  rate: duration ? format("%.2f", total_requests / duration) : 0,
88
92
  step_summary: data[:step_summary],
89
93
  steps: data[:steps],
90
- requests: requests
94
+ requests: requests,
95
+ failures: data[:failures]
91
96
  ).tap do |stats|
92
97
  # FIXME remove!
93
98
  puts "Calculated stats in #{Time.now - time}s"
@@ -101,7 +106,7 @@ module Lavin
101
106
 
102
107
  show_steps(values) do |(user, step), hash|
103
108
  format(
104
- "%-24<user_step>s %8<success>d %8<failure>d",
109
+ "%-48<user_step>s %8<success>d %8<failure>d",
105
110
  user_step: "#{user}.#{step}",
106
111
  **hash
107
112
  )
@@ -113,6 +118,10 @@ module Lavin
113
118
  **request_values
114
119
  )
115
120
  end
121
+
122
+ show_failures(values) do |message, count|
123
+ format("%-64<message>s %6<count>d", message:, count:)
124
+ end
116
125
  end
117
126
 
118
127
  private
@@ -141,7 +150,8 @@ module Lavin
141
150
  failure: 0
142
151
  },
143
152
  steps: Hash.new { |h, k| h[k] = {success: 0, failure: 0} },
144
- requests: Hash.new { |h, k| h[k] = [] }
153
+ requests: Hash.new { |h, k| h[k] = [] },
154
+ failures: Hash.new { |h, k| h[k] = 0 }
145
155
  }
146
156
  end
147
157
 
@@ -155,26 +165,25 @@ module Lavin
155
165
 
156
166
  Total number of steps: #{values.total_steps}
157
167
  Step success rate: #{format("%.2f %%", 100 * values.successful_steps.to_f / values.total_steps)}
158
-
159
168
  RESULT
160
169
  end
161
170
 
162
171
  def show_steps(values)
163
172
  puts format(
164
- "%-24<user_step>s %8<success>s %8<failure>s",
173
+ "\n%-48<user_step>s %8<success>s %8<failure>s",
165
174
  user_step: "Steps",
166
175
  success: "Success",
167
176
  failure: "Failure"
168
177
  )
169
- divider = "-" * 42
178
+ divider = "-" * 66
170
179
  puts divider
171
180
  values.each_step { |step_values| puts yield step_values }
172
- puts "#{divider}\n\n"
181
+ puts divider
173
182
  end
174
183
 
175
184
  def show_table(values)
176
185
  puts format(
177
- "%-6<method>s %-100<url>s %-6<requests>s %12<avg_duration>s %12<min_duration>s %12<max_duration>s",
186
+ "\n%-6<method>s %-100<url>s %-6<requests>s %12<avg_duration>s %12<min_duration>s %12<max_duration>s",
178
187
  method: "Method",
179
188
  url: "URL",
180
189
  requests: "Requests",
@@ -188,6 +197,14 @@ module Lavin
188
197
  values.each_request { |request_values| puts yield request_values }
189
198
  puts divider
190
199
  end
200
+
201
+ def show_failures(values)
202
+ puts format("\n%-64<message>s %6<count>s", message: "Failures", count: "Count")
203
+ divider = "-" * 71
204
+ puts divider
205
+ values.each_failure { |failures| puts yield failures }
206
+ puts divider
207
+ end
191
208
  end
192
209
  end
193
210
  end
data/lib/lavin/stats.rb CHANGED
@@ -2,15 +2,16 @@
2
2
 
3
3
  module Lavin
4
4
  class Stats
5
- attr_reader :duration, :total_requests, :rate, :requests, :step_summary, :steps
5
+ attr_reader :duration, :total_requests, :rate, :requests, :step_summary, :steps, :failures
6
6
 
7
- def initialize(duration:, total_requests:, rate:, requests: [], step_summary: {}, steps: [])
7
+ def initialize(duration:, total_requests:, rate:, requests: [], step_summary: {}, steps: [], failures: [])
8
8
  @duration = duration
9
9
  @total_requests = total_requests
10
10
  @rate = rate
11
11
  @requests = requests
12
12
  @step_summary = step_summary
13
13
  @steps = steps
14
+ @failures = failures
14
15
  end
15
16
 
16
17
  def empty?
@@ -24,7 +25,8 @@ module Lavin
24
25
  rate:,
25
26
  requests:,
26
27
  step_summary:,
27
- steps:
28
+ steps:,
29
+ failures:
28
30
  }
29
31
  end
30
32
 
@@ -47,5 +49,9 @@ module Lavin
47
49
  def each_request(&block)
48
50
  requests.each(&block)
49
51
  end
52
+
53
+ def each_failure(&block)
54
+ failures.each(&block)
55
+ end
50
56
  end
51
57
  end
data/lib/lavin/step.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
- #
2
+
3
+ require 'lavin/error'
3
4
 
4
5
  module Lavin
5
6
  class Step
@@ -22,9 +23,10 @@ module Lavin
22
23
  def call(context:)
23
24
  context.instance_exec(&block)
24
25
  Statistics.register_step(user: user.name, step_name: name)
26
+ rescue IrrecoverableError => error
27
+ Statistics.register_step(user: user.name, step_name: name, failure: error.message)
28
+ throw :failure
25
29
  rescue => error
26
- puts "Caught an error - #{error.class}: #{error.message}"
27
- puts error.backtrace
28
30
  Statistics.register_step(user: user.name, step_name: name, failure: error.message)
29
31
  end
30
32
  end
data/lib/lavin/user.rb CHANGED
@@ -4,6 +4,7 @@ require "set"
4
4
  require "lavin/user_config"
5
5
  require "lavin/worker"
6
6
  require "lavin/http_client"
7
+ require "lavin/failure"
7
8
 
8
9
  module Lavin
9
10
  class User
@@ -12,6 +13,7 @@ module Lavin
12
13
  subclass.include UserConfig
13
14
  subclass.include Worker
14
15
  subclass.include HttpClient
16
+ subclass.include Failure
15
17
  all_personas << subclass
16
18
  end
17
19
 
data/lib/lavin/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Lavin
4
- VERSION = "0.2.0"
4
+ VERSION = "0.3.0"
5
5
  end
@@ -40,6 +40,11 @@ module Lavin
40
40
  redirect to('/statistics')
41
41
  end
42
42
 
43
+ post '/stop' do
44
+ Lavin::Runner.stop
45
+ redirect to('/statistics')
46
+ end
47
+
43
48
  get '/statistics' do
44
49
  stats = Statistics.stats
45
50
  running = Lavin::Runner.running?
@@ -50,6 +55,16 @@ module Lavin
50
55
  end
51
56
  end
52
57
 
58
+ get '/failures' do
59
+ stats = Statistics.stats
60
+ running = Lavin::Runner.running?
61
+ if stats.empty? && !running
62
+ redirect to('/')
63
+ else
64
+ erb :failures, locals: {stats:, running:}
65
+ end
66
+ end
67
+
53
68
  get '/edit' do
54
69
  persona = find_persona
55
70
  raise Sinatra::NotFound unless persona
data/lib/lavin/worker.rb CHANGED
@@ -9,13 +9,13 @@ module Lavin
9
9
  def before(&block)
10
10
  return @before unless block
11
11
 
12
- @before = Hook.new(user: self, &block)
12
+ @before = Hook.new(user: self, type: :before, &block)
13
13
  end
14
14
 
15
15
  def after(&block)
16
16
  return @after unless block
17
17
 
18
- @after = Hook.new(user: self, &block)
18
+ @after = Hook.new(user: self, type: :after, &block)
19
19
  end
20
20
 
21
21
  def steps
@@ -40,11 +40,15 @@ module Lavin
40
40
  end
41
41
 
42
42
  def run
43
- self.class.before.run(context: self).then { Runner.yield } if self.class.before
43
+ catch(:failure) do
44
+ self.class.before.run(context: self).then { Runner.yield } if self.class.before
44
45
 
45
- run_step until finished?
46
+ run_step until finished?
47
+ end
46
48
 
47
- self.class.after.run(context: self).then { Runner.yield } if self.class.after
49
+ catch(:failure) do
50
+ self.class.after.run(context: self).then { Runner.yield } if self.class.after
51
+ end
48
52
  end
49
53
 
50
54
  private
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lavin
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sammy Henningsson
@@ -29,7 +29,7 @@ cert_chain:
29
29
  DVzXaUnsmwP+jQ1PkDa5q8ibBzMd2c6Hmm87UDqPxZtML0bF9SjrpbyLMjwtXaMA
30
30
  WDPp0ajpdUZ9GPHsrVNYXiOfQIqcmlmpYVsH1o7vuneUIcIDMrnMDChh
31
31
  -----END CERTIFICATE-----
32
- date: 2022-10-31 00:00:00.000000000 Z
32
+ date: 2022-11-02 00:00:00.000000000 Z
33
33
  dependencies:
34
34
  - !ruby/object:Gem::Dependency
35
35
  name: async
@@ -113,6 +113,7 @@ files:
113
113
  - lib/lavin.rb
114
114
  - lib/lavin/client.rb
115
115
  - lib/lavin/error.rb
116
+ - lib/lavin/failure.rb
116
117
  - lib/lavin/hook.rb
117
118
  - lib/lavin/http_client.rb
118
119
  - lib/lavin/runner.rb
metadata.gz.sig CHANGED
Binary file