lavin 0.3.0 → 0.5.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: 52a0a48c405e0aff4b816ff7bf91b27e8407929a838db819f8777d222b4f7674
4
- data.tar.gz: 4acb3c0a928acd45ecbd8137089433e69cdc8235919a0db6fefefb40418bfd82
3
+ metadata.gz: f992df4f0b4f330811a5c440e4f2cc0f2d514c6adc93520851b5a3f37c1807d0
4
+ data.tar.gz: 1ab740ad5a07113568023f7a46e2d36a722422ad4c3ea75dbcd7974dd79db570
5
5
  SHA512:
6
- metadata.gz: e2fe666e13f22d13dc4f085e8ab7e78c2242a973bd9b0d58054e0b4ada2cc17d1ca924e4103a3c55408bd88c4d1cd3efa8b3449cee7fd8a5d36794392218779c
7
- data.tar.gz: b1f7f478a288492082a4f02462d345ce42703316638b3d6aee7848a92a539b22b750105e5e70fdf2ffe662ac26ed68a4f6a32c63154b18ba4faf96dee917b16b
6
+ metadata.gz: '07319fe5d1f1cdfbd5cd86519ce6b273f773397ff11707cef85bda11c65a1b77a27fc5a739c7c1aa3c61f20726103a08d9d45afd0d1d811849c30820717d0d1b'
7
+ data.tar.gz: 3049f57b36562110c1bc09ffe0a7bfe7648cb8134c9cff73f9d74c6e66590749177158999d2c4f7f41cd0d8ad7e712d90410a05b56dc36222d878ab3a8879f0e
checksums.yaml.gz.sig CHANGED
@@ -1,3 +1,2 @@
1
- >�����r$
2
- b���{
3
- �l[GLfT�9��=y����ӄ�$�i�q���}%����N�B»�
1
+ 0S���Q��dUw�ל��\�<,��� �����ϸ�;ߤ"*��CU�#̬�D�
2
+ �i������tNG70,$����#{Ɠ`d��M�8��ȁ�g4nk����c.ljV�<�;W�;56߫��[a���@]���͜T"��qH����pT��ng���t�{@�ؚQ��/�ُr:����_:`���#�U�x�\Yb�j�����
data/lib/lavin/error.rb CHANGED
@@ -6,4 +6,8 @@ module Lavin
6
6
  class RecoverableError < Error; end
7
7
 
8
8
  class IrrecoverableError < Error; end
9
+
10
+ class SuccessfulStep < Error; end
11
+
12
+ class SuccessfulUser < Error; end
9
13
  end
data/lib/lavin/hook.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'lavin/error'
4
+
3
5
  module Lavin
4
6
  class Hook
5
7
  attr_reader :user, :block, :type
@@ -19,11 +21,11 @@ module Lavin
19
21
  report_statistics = context.client.report_statistics
20
22
  context.client.report_statistics = false
21
23
  context.instance_exec(&block)
22
- rescue RecoverableError
24
+ rescue SuccessfulStep, RecoverableError
25
+ rescue SuccessfulUser, IrrecoverableError
26
+ throw :stop_user
23
27
  rescue => error
24
- puts "Caught #{error.class} in #{type} hook: #{error.message}"
25
- puts error.backtrace unless error.is_a? IrrecoverableError
26
- throw :failure
28
+ puts "Exception in #{user.name}.#{type} block - #{error.class}: #{error.message}"
27
29
  ensure
28
30
  context.client.report_statistics = report_statistics
29
31
  end
data/lib/lavin/step.rb CHANGED
@@ -23,10 +23,14 @@ module Lavin
23
23
  def call(context:)
24
24
  context.instance_exec(&block)
25
25
  Statistics.register_step(user: user.name, step_name: name)
26
+ rescue SuccessfulStep, SuccessfulUser => error
27
+ Statistics.register_step(user: user.name, step_name: name)
28
+ throw :stop_user if error.is_a? SuccessfulUser
26
29
  rescue IrrecoverableError => error
27
30
  Statistics.register_step(user: user.name, step_name: name, failure: error.message)
28
- throw :failure
31
+ throw :stop_user
29
32
  rescue => error
33
+ puts "Exception in #{user.name}.#{name} - #{error.class}: #{error.message}"
30
34
  Statistics.register_step(user: user.name, step_name: name, failure: error.message)
31
35
  end
32
36
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'lavin/error'
4
+
5
+ module Lavin
6
+ module Success
7
+ def success
8
+ raise SuccessfulStep
9
+ end
10
+
11
+ def success!
12
+ raise SuccessfulUser
13
+ end
14
+ end
15
+ end
data/lib/lavin/user.rb CHANGED
@@ -5,6 +5,7 @@ require "lavin/user_config"
5
5
  require "lavin/worker"
6
6
  require "lavin/http_client"
7
7
  require "lavin/failure"
8
+ require "lavin/success"
8
9
 
9
10
  module Lavin
10
11
  class User
@@ -14,6 +15,7 @@ module Lavin
14
15
  subclass.include Worker
15
16
  subclass.include HttpClient
16
17
  subclass.include Failure
18
+ subclass.include Success
17
19
  all_personas << subclass
18
20
  end
19
21
 
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.3.0"
4
+ VERSION = "0.5.0"
5
5
  end
data/lib/lavin/worker.rb CHANGED
@@ -40,13 +40,13 @@ module Lavin
40
40
  end
41
41
 
42
42
  def run
43
- catch(:failure) do
43
+ catch(:stop_user) do
44
44
  self.class.before.run(context: self).then { Runner.yield } if self.class.before
45
45
 
46
46
  run_step until finished?
47
47
  end
48
48
 
49
- catch(:failure) do
49
+ catch(:stop_user) do
50
50
  self.class.after.run(context: self).then { Runner.yield } if self.class.after
51
51
  end
52
52
  end
data/views/edit.erb ADDED
@@ -0,0 +1,25 @@
1
+ <div class="flex flex-col items-center">
2
+ <h1 class="mt-32 text-center text-2xl">Edit <%= persona.name %></h1>
3
+ <div class="w-1/5 bg-white dark:bg-slate-800 rounded-lg mt-8 px-6 py-4 shadow-slate-900 shadow-lg">
4
+ <form action="/update_config" method="post" class="mt-16">
5
+ <% persona.config.each do |key, value| %>
6
+ <input type="hidden" name="persona" value="<%= persona.name %>">
7
+ <% if value == true || value == false %>
8
+ <div class="my-4">
9
+ <label for="<%= key %>" class="text-slate-500 dark:text-slate-300"><%= key.to_s.capitalize %></label>
10
+ <input type="checkbox" id="<%= key %>" name="<%= key %>" class="float-right" <%= "checked" if value %>></br>
11
+ </div>
12
+ <% else %>
13
+ <div class="mt-2">
14
+ <label for="<%= key %>" class="text-slate-500 dark:text-slate-300"><%= key.to_s.capitalize %></label></br>
15
+ <input type="<%= input_type_for(value) %>" id="<%= key %>" name="<%= key %>" class="rounded p-2 w-full" value="<%= value %>"></br>
16
+ </div>
17
+ <% end %>
18
+ <% end %>
19
+ <div class="mt-8 flex flex-row gap-x-4">
20
+ <a href="/" class="p-2 grow bg-slate-300 hover:bg-slate-400 dark:bg-slate-500 dark:hover:bg-slate-600 shadow-slate-900 shadow-lg rounded text-center">Cancel</a>
21
+ <input type=submit value="Update" class="p-2 grow bg-indigo-400 hover:bg-indigo-500 dark:bg-indigo-500 dark:hover:bg-indigo-600 shadow-slate-900 shadow-lg rounded text-center">
22
+ </div>
23
+ </form>
24
+ </div>
25
+ </div>
@@ -0,0 +1,62 @@
1
+ <div class="mt-16 h-full flex-grow flex flex-col items-center">
2
+ <div class="flex flex-col w-full h-full bg-white dark:bg-slate-800 px-16 pt-16 pb-8 text-slate-500 dark:text-slate-300">
3
+ <div class="flex flex-row items-center">
4
+ <div class="flex-grow">
5
+ <p>Duration: <%= format("%.3fs", stats.duration) %></p>
6
+ <p>Total requests: <%= stats.total_requests%></p>
7
+ <p>Rate: <%= stats.rate%> rps</p>
8
+ </div>
9
+ <% if running %>
10
+ <div class="">
11
+ <span class="text-amber-700 text-xl animate-pulse">Running</span>
12
+ </div>
13
+ <div class="ml-8 w-1/12">
14
+ <form action="/stop" method="post" class="mb-0">
15
+ <input type=submit value="Stop" class="px-4 py-2 shadow-slate-900 shadow-lg rounded bg-amber-700 hover:bg-amber-800 text-xl text-center w-full">
16
+ </form>
17
+ </div>
18
+ <% end %>
19
+ </div>
20
+ <div class="w-full h-full overflow-auto mt-8">
21
+ <table class="w-1/4 table-auto text-slate-500 dark:text-slate-300">
22
+ <thead>
23
+ <tr>
24
+ <th class="text-left">Steps</th>
25
+ <th class="text-right">Success</th>
26
+ <th class="text-right">Failure</th>
27
+ </tr>
28
+ </thead>
29
+ <% stats.each_step do |(user, step), step_stats| %>
30
+ <tr class="border-b border-dashed hover:border-solid border-slate-700">
31
+ <td class="text-left text-sm"><%= "#{user} - #{step}" %></td>
32
+ <td class="text-right text-sm"><%= step_stats[:success] %></td>
33
+ <td class="text-right text-sm"><%= step_stats[:failure] %></td>
34
+ </tr>
35
+ <% end %>
36
+ </table>
37
+ <table class="mt-8 w-1/2 table-auto text-slate-500 dark:text-slate-300">
38
+ <thead>
39
+ <tr>
40
+ <th class="text-left">Failure</th>
41
+ <th class="text-left">Count</th>
42
+ </tr>
43
+ </thead>
44
+ <% stats.each_failure do |message, count| %>
45
+ <tr class="border-b border-dashed hover:border-solid border-slate-700">
46
+ <td class="text-left text-sm"><%= message %></td>
47
+ <td class="text-left text-sm"><%= count%></td>
48
+ </tr>
49
+ <% end %>
50
+ </table>
51
+ </div>
52
+ </div>
53
+ <div class="w-full h-1/6 text-center py-10 object-center">
54
+ <a href="/" class="bg-slate-500 p-2 shadow-slate-900 shadow-lg rounded hover:bg-slate-600">Back to start</a>
55
+ <a href="/statistics" class="ml-4 bg-slate-500 p-2 shadow-slate-900 shadow-lg rounded hover:bg-slate-600">Statistics</a>
56
+ </div>
57
+ </div>
58
+ <% if running %>
59
+ <script>
60
+ window.setTimeout(function() {window.location.reload();}, 2000);
61
+ </script>
62
+ <% end %>
data/views/index.erb ADDED
@@ -0,0 +1,19 @@
1
+ <div class="mt-32 flex flex-col items-center">
2
+ <% if personas.empty? %>
3
+ <p class="text-lg">No configration found please restart the server with a path to a directory containing the configuration!</p>
4
+ <% else %>
5
+ <div class="w-1/5">
6
+ <form action="/start" method="post">
7
+ <input type=submit value="Start" class="py-3 shadow-slate-900 shadow-lg rounded bg-amber-700 hover:bg-amber-800 text-xl text-center w-full">
8
+ </form>
9
+ </div>
10
+ <h2 class="mt-16 text-2xl">Configuration</h2>
11
+ <div class="w-5/6 flex flex-row flex-wrap gap-x-8 gap-y-4 justify-center">
12
+ <% personas.each do |persona| %>
13
+ <div class="w-1/4">
14
+ <%= erb :user_config, locals: {persona: persona} %>
15
+ </div>
16
+ <% end %>
17
+ </div>
18
+ <% end %>
19
+ </div>
data/views/layout.erb ADDED
@@ -0,0 +1,14 @@
1
+ <head>
2
+ <meta charset="UTF-8">
3
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
4
+ <title>Lavin load testing</title>
5
+ <script src="https://cdn.tailwindcss.com"></script>
6
+ </head>
7
+ <body class="bg-cyan-800">
8
+ <div class="h-screen flex flex-col">
9
+ <div>
10
+ <h1 class="mt-16 text-center text-4xl"><strong class="text-6xl">Lavin</strong> load testing</h1>
11
+ </div>
12
+ <%= yield %>
13
+ </div>
14
+ </body>
@@ -0,0 +1,4 @@
1
+ <div class="flex flex-col items-center">
2
+ <h1 class="mt-16 text-2xl text-center">Sorry, this page does not exist!</h1>
3
+ <a href="/" class="mt-8 bg-slate-300 hover:bg-slate-400 dark:bg-slate-500 dark:hover:bg-slate-600 p-2 shadow-slate-900 shadow-lg rounded">Back to start</a>
4
+ </div>
@@ -0,0 +1,72 @@
1
+ <div class="mt-16 h-full flex-grow flex flex-col items-center">
2
+ <div class="flex flex-col w-full h-full bg-white dark:bg-slate-800 px-16 pt-16 pb-8 text-slate-500 dark:text-slate-300">
3
+ <div class="flex flex-row items-center">
4
+ <div class="flex-grow">
5
+ <p>Duration: <%= format("%.3fs", stats.duration) %></p>
6
+ <p>Total requests: <%= stats.total_requests%></p>
7
+ <p>Rate: <%= stats.rate%> rps</p>
8
+ </div>
9
+ <% if running %>
10
+ <div class="">
11
+ <span class="text-amber-700 text-xl animate-pulse">Running</span>
12
+ </div>
13
+ <div class="ml-8 w-1/12">
14
+ <form action="/stop" method="post" class="mb-0">
15
+ <input type=submit value="Stop" class="px-4 py-2 shadow-slate-900 shadow-lg rounded bg-amber-700 hover:bg-amber-800 text-xl text-center w-full">
16
+ </form>
17
+ </div>
18
+ <% end %>
19
+ </div>
20
+ <div class="w-full h-full overflow-auto mt-8">
21
+ <table class="w-1/4 table-auto text-slate-500 dark:text-slate-300">
22
+ <thead>
23
+ <tr>
24
+ <th class="text-left">Steps</th>
25
+ <th class="text-right">Success</th>
26
+ <th class="text-right">Failure</th>
27
+ </tr>
28
+ </thead>
29
+ <% stats.each_step do |(user, step), step_stats| %>
30
+ <tr class="border-b border-dashed hover:border-solid border-slate-700">
31
+ <td class="text-left text-sm"><%= "#{user} - #{step}" %></td>
32
+ <td class="text-right text-sm"><%= step_stats[:success] %></td>
33
+ <td class="text-right text-sm"><%= step_stats[:failure] %></td>
34
+ </tr>
35
+ <% end %>
36
+ </table>
37
+ <table class="mt-8 w-full table-auto text-slate-500 dark:text-slate-300">
38
+ <thead>
39
+ <tr>
40
+ <th class="text-left">Method</th>
41
+ <th class="text-left">URL</th>
42
+ <th class="text-right">Requests</th>
43
+ <th class="text-right">Failed requests</th>
44
+ <th class="text-right">Avg duration</th>
45
+ <th class="text-right">Min duration</th>
46
+ <th class="text-right">Max duration</th>
47
+ </tr>
48
+ </thead>
49
+ <% stats.each_request do |request_stats| %>
50
+ <tr class="border-b border-dashed hover:border-solid border-slate-700">
51
+ <td class="text-left text-sm"><%= request_stats[:method] %></td>
52
+ <td class="text-left text-sm"><%= request_stats[:url]%></td>
53
+ <td class="text-right text-sm"><%= request_stats[:requests]%></td>
54
+ <td class="text-right text-sm"><%= request_stats[:failed_requests]%></td>
55
+ <td class="text-right text-sm"><%= format("%8fs", request_stats[:avg_duration]) %></td>
56
+ <td class="text-right text-sm"><%= format("%8fs", request_stats[:min_duration]) %></td>
57
+ <td class="text-right text-sm"><%= format("%8fs", request_stats[:max_duration]) %></td>
58
+ </tr>
59
+ <% end %>
60
+ </table>
61
+ </div>
62
+ </div>
63
+ <div class="w-full h-1/6 text-center py-10 object-center">
64
+ <a href="/" class="bg-slate-500 p-2 shadow-slate-900 shadow-lg rounded hover:bg-slate-600">Back to start</a>
65
+ <a href="/failures" class="ml-4 bg-slate-500 p-2 shadow-slate-900 shadow-lg rounded hover:bg-slate-600">Failures</a>
66
+ </div>
67
+ </div>
68
+ <% if running %>
69
+ <script>
70
+ window.setTimeout(function() {window.location.reload();}, 2000);
71
+ </script>
72
+ <% end %>
@@ -0,0 +1,15 @@
1
+ <div class="mt-8 px-6 py-8 bg-white dark:bg-slate-800 rounded-lg shadow-slate-900 shadow-lg">
2
+ <h3 class="text-center text-slate-900 dark:text-white text-2xl"><%= persona.name %></h3>
3
+ <p class="text-center truncate text-slate-500 dark:text-slate-400 mt-2 text-sm"><%= persona.description %></p>
4
+ <ul class="mt-8">
5
+ <% persona.config.each do |key, value| %>
6
+ <li>
7
+ <span class="text-slate-500 dark:text-slate-300"><%= key %></span>
8
+ <span class="text-slate-500 dark:text-slate-300 float-right"><%= value%></span>
9
+ </li>
10
+ <% end %>
11
+ </ul>
12
+ <div class="mt-8 flex flex-row justify-end">
13
+ <a href="/edit?persona=<%= persona.name %>" class="mt-4 text-sm bg-slate-300 hover:bg-slate-400 dark:bg-slate-500 dark:hover:bg-slate-600 p-2 shadow-slate-900 shadow-4xl rounded">Edit</a>
14
+ </div>
15
+ </div>
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.3.0
4
+ version: 0.5.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-11-02 00:00:00.000000000 Z
32
+ date: 2022-11-04 00:00:00.000000000 Z
33
33
  dependencies:
34
34
  - !ruby/object:Gem::Dependency
35
35
  name: async
@@ -120,11 +120,19 @@ files:
120
120
  - lib/lavin/statistics.rb
121
121
  - lib/lavin/stats.rb
122
122
  - lib/lavin/step.rb
123
+ - lib/lavin/success.rb
123
124
  - lib/lavin/user.rb
124
125
  - lib/lavin/user_config.rb
125
126
  - lib/lavin/version.rb
126
127
  - lib/lavin/web_server.rb
127
128
  - lib/lavin/worker.rb
129
+ - views/edit.erb
130
+ - views/failures.erb
131
+ - views/index.erb
132
+ - views/layout.erb
133
+ - views/not_found.erb
134
+ - views/statistics.erb
135
+ - views/user_config.erb
128
136
  homepage: https://github.com/sammyhenningsson/lavin
129
137
  licenses:
130
138
  - MIT
metadata.gz.sig CHANGED
Binary file