lavin 0.3.0 → 0.5.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 +4 -4
- checksums.yaml.gz.sig +2 -3
- data/lib/lavin/error.rb +4 -0
- data/lib/lavin/hook.rb +6 -4
- data/lib/lavin/step.rb +5 -1
- data/lib/lavin/success.rb +15 -0
- data/lib/lavin/user.rb +2 -0
- data/lib/lavin/version.rb +1 -1
- data/lib/lavin/worker.rb +2 -2
- data/views/edit.erb +25 -0
- data/views/failures.erb +62 -0
- data/views/index.erb +19 -0
- data/views/layout.erb +14 -0
- data/views/not_found.erb +4 -0
- data/views/statistics.erb +72 -0
- data/views/user_config.erb +15 -0
- data.tar.gz.sig +0 -0
- metadata +10 -2
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f992df4f0b4f330811a5c440e4f2cc0f2d514c6adc93520851b5a3f37c1807d0
|
4
|
+
data.tar.gz: 1ab740ad5a07113568023f7a46e2d36a722422ad4c3ea75dbcd7974dd79db570
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '07319fe5d1f1cdfbd5cd86519ce6b273f773397ff11707cef85bda11c65a1b77a27fc5a739c7c1aa3c61f20726103a08d9d45afd0d1d811849c30820717d0d1b'
|
7
|
+
data.tar.gz: 3049f57b36562110c1bc09ffe0a7bfe7648cb8134c9cff73f9d74c6e66590749177158999d2c4f7f41cd0d8ad7e712d90410a05b56dc36222d878ab3a8879f0e
|
checksums.yaml.gz.sig
CHANGED
@@ -1,3 +1,2 @@
|
|
1
|
-
|
2
|
-
|
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
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 "
|
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 :
|
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
|
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
data/lib/lavin/worker.rb
CHANGED
@@ -40,13 +40,13 @@ module Lavin
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def run
|
43
|
-
catch(:
|
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(:
|
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>
|
data/views/failures.erb
ADDED
@@ -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>
|
data/views/not_found.erb
ADDED
@@ -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.
|
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-
|
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
|