specwrk 0.5.0 → 0.6.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: 331e0982599a516c3c862c4a5c33a825c71256f5f95e6d1656c0ad410541df06
4
- data.tar.gz: c7d93bf3add6e6de08cad22f8036ef89b01752b0e6dfe42615035d9e301ecff5
3
+ metadata.gz: bf78cf2d1c82bc0878e1e89777eb8de0ab04af441e210c64a15c2bad1277c1fa
4
+ data.tar.gz: 3701d6f676e4c31c3fb787f4ca59a8aaa7aa412118371470b069471da4e6c933
5
5
  SHA512:
6
- metadata.gz: 9daa901f8a7b7f453079f766d09e47fb621cf85e1cdb6111303e1f8b17cc3091312b2128ca141328f1c8a28216151b991f431cbb4550445ce137349dcb30f3c5
7
- data.tar.gz: f0ae841735759d62e9ad6607065ca7bc8747a9d85e8906dea19019af7c63183df26b82cce51bc2a8c453cf4e1bb7d3d0b0c900c917cf689730cdac6028efaae5
6
+ metadata.gz: debda5ab7128ae03e74652196da8783b4d78ddf3648ccfd2c3e62104fe8a3fb87b98abbc68deb7d66565d66474a504a8d778ca0de44eef311e14188a4258f856
7
+ data.tar.gz: 1a4089b567a0840f91a133fef5580b6c5bd3c43190eb7cd1156fe3439e042f727b62bdf69ee1624815ac741f738907e43c92559be1f4c4d55268b2db1625b074
@@ -11,7 +11,10 @@ require "rspec/core/formatters/console_codes"
11
11
  module Specwrk
12
12
  class CLIReporter
13
13
  def report
14
- return 1 unless Client.connect?
14
+ unless Client.connect?
15
+ puts colorizer.wrap("\nCannot connect to server to generate report. Assuming failure.", :red)
16
+ return 1
17
+ end
15
18
 
16
19
  puts "\nFinished in #{total_duration} " \
17
20
  "(total execution time of #{total_run_time})\n"
@@ -28,8 +31,11 @@ module Specwrk
28
31
  puts colorizer.wrap(totals_line, :green)
29
32
  0
30
33
  end
31
- rescue Specwrk::UnhandledResponseError
32
- puts colorizer.wrap("No examples run.", :red)
34
+ rescue Specwrk::UnhandledResponseError => e
35
+ puts colorizer.wrap("\nCannot report, #{e.message}.", :red)
36
+
37
+ client.shutdown
38
+
33
39
  1
34
40
  end
35
41
 
@@ -43,28 +49,28 @@ module Specwrk
43
49
  summary
44
50
  end
45
51
 
46
- def stats
47
- @stats ||= client.stats
52
+ def report_data
53
+ @report_data ||= client.report
48
54
  end
49
55
 
50
56
  def total_duration
51
- Time.parse(stats.dig(:completed, :meta, :last_finished_at)) - Time.parse(stats.dig(:completed, :meta, :first_started_at))
57
+ Time.parse(report_data.dig(:meta, :last_finished_at)) - Time.parse(report_data.dig(:meta, :first_started_at))
52
58
  end
53
59
 
54
60
  def total_run_time
55
- stats.dig(:completed, :meta, :total_run_time)
61
+ report_data.dig(:meta, :total_run_time)
56
62
  end
57
63
 
58
64
  def failure_count
59
- stats.dig(:completed, :meta, :failures)
65
+ report_data.dig(:meta, :failures)
60
66
  end
61
67
 
62
68
  def pending_count
63
- stats.dig(:completed, :meta, :pending)
69
+ report_data.dig(:meta, :pending)
64
70
  end
65
71
 
66
72
  def example_count
67
- stats.dig(:completed, :examples).length
73
+ report_data.dig(:examples).length
68
74
  end
69
75
 
70
76
  def client
@@ -62,8 +62,8 @@ module Specwrk
62
62
  response.code == "200"
63
63
  end
64
64
 
65
- def stats
66
- response = get "/stats"
65
+ def report
66
+ response = get "/report"
67
67
 
68
68
  if response.code == "200"
69
69
  JSON.parse(response.body, symbolize_names: true)
data/lib/specwrk/queue.rb CHANGED
@@ -6,7 +6,11 @@ require "json"
6
6
  module Specwrk
7
7
  # Thread-safe Hash access
8
8
  class Queue
9
+ attr_reader :created_at
10
+
9
11
  def initialize(hash = {})
12
+ @created_at = Time.now
13
+
10
14
  if block_given?
11
15
  @mutex = Monitor.new # Reentrant locking is required here
12
16
  # It's possible to enter the proc from two threads, so we need to ||= in case
@@ -40,8 +44,6 @@ module Specwrk
40
44
  end
41
45
 
42
46
  class PendingQueue < Queue
43
- attr_reader :previous_run_times
44
-
45
47
  def shift_bucket
46
48
  return bucket_by_file unless previous_run_times
47
49
 
@@ -59,17 +61,22 @@ module Specwrk
59
61
  previous_run_times.dig(:meta, :average_run_time)
60
62
  end
61
63
 
62
- # TODO: move reading the file to the getter method
63
- def previous_run_times_file=(path)
64
- return unless path
65
- return unless File.exist? path
64
+ def previous_run_times
65
+ return unless ENV["SPECWRK_OUT"]
66
66
 
67
- File.open(path, "r") do |file|
68
- file.flock(File::LOCK_EX)
67
+ @previous_run_times ||= begin
68
+ return unless previous_run_times_file_path
69
+ return unless File.exist? previous_run_times_file_path
69
70
 
70
- @previous_run_times = JSON.parse(file.read, symbolize_names: true)
71
+ raw_data = File.open(previous_run_times_file_path, "r") do |file|
72
+ file.flock(File::LOCK_SH)
73
+ file.read
74
+ end
71
75
 
72
- file.flock(File::LOCK_UN)
76
+ @previous_run_times = JSON.parse(raw_data, symbolize_names: true)
77
+ rescue JSON::ParserError => e
78
+ warn "#{e.inspect} in file #{previous_run_times_file_path}"
79
+ nil
73
80
  end
74
81
  end
75
82
 
@@ -84,6 +91,15 @@ module Specwrk
84
91
 
85
92
  private
86
93
 
94
+ # We want the most recently modified run time file
95
+ # report files are prefixed with a timestamp, and Dir.glob should order
96
+ # alphanumericly
97
+ def previous_run_times_file_path
98
+ return unless ENV["SPECWRK_OUT"]
99
+
100
+ @previous_run_times_file_path ||= Dir.glob(File.join(ENV["SPECWRK_OUT"], "*-report-*.json")).last
101
+ end
102
+
87
103
  # Take elements from the hash where the file_path is the same
88
104
  def bucket_by_file
89
105
  bucket = []
@@ -163,7 +179,7 @@ module Specwrk
163
179
  @hash.values.each { |example| calculate(example) }
164
180
 
165
181
  @output[:meta][:total_run_time] = @run_times.sum
166
- @output[:meta][:average_run_time] = @output[:meta][:total_run_time] / @run_times.length.to_f
182
+ @output[:meta][:average_run_time] = @output[:meta][:total_run_time] / [@run_times.length, 1].max.to_f
167
183
  @output[:meta][:first_started_at] = @first_started_at.iso8601(6)
168
184
  @output[:meta][:last_finished_at] = @last_finished_at.iso8601(6)
169
185
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Specwrk
4
- VERSION = "0.5.0"
4
+ VERSION = "0.6.0"
5
5
  end
@@ -52,10 +52,8 @@ module Specwrk
52
52
 
53
53
  def setup!
54
54
  if ENV["SPECWRK_OUT"]
55
-
56
55
  FileUtils.mkdir_p(ENV["SPECWRK_OUT"])
57
56
  ENV["SPECWRK_SRV_LOG"] ||= Pathname.new(File.join(ENV["SPECWRK_OUT"], "server.log")).to_s unless ENV["SPECWRK_SRV_VERBOSE"]
58
- ENV["SPECWRK_SRV_OUTPUT"] ||= Pathname.new(File.join(ENV["SPECWRK_OUT"], "report.json")).expand_path(Dir.pwd).to_s
59
57
  end
60
58
 
61
59
  if ENV["SPECWRK_SRV_LOG"]
@@ -100,8 +98,8 @@ module Specwrk
100
98
  Endpoints::Complete
101
99
  when ["POST", "/seed"]
102
100
  Endpoints::Seed
103
- when ["GET", "/stats"]
104
- Endpoints::Stats
101
+ when ["GET", "/report"]
102
+ Endpoints::Report
105
103
  when ["DELETE", "/shutdown"]
106
104
  Endpoints::Shutdown
107
105
  else
@@ -38,7 +38,7 @@ module Specwrk
38
38
  end
39
39
 
40
40
  def pending_queue
41
- Web::PENDING_QUEUES[request.get_header("HTTP_X_SPECWRK_RUN")]
41
+ Web::PENDING_QUEUES[run_id]
42
42
  end
43
43
 
44
44
  def processing_queue
@@ -56,6 +56,14 @@ module Specwrk
56
56
  def worker
57
57
  workers[request.get_header("HTTP_X_SPECWRK_ID")]
58
58
  end
59
+
60
+ def run_id
61
+ request.get_header("HTTP_X_SPECWRK_RUN")
62
+ end
63
+
64
+ def run_report_file_path
65
+ @run_report_file_path ||= File.join(ENV["SPECWRK_OUT"], "#{completed_queue.created_at.strftime("%Y%m%dT%H%M%S")}-report-#{run_id}.json").to_s
66
+ end
59
67
  end
60
68
 
61
69
  # Base default response is 404
@@ -98,8 +106,8 @@ module Specwrk
98
106
  end
99
107
  end
100
108
 
101
- if pending_queue.length.zero? && processing_queue.length.zero? && completed_queue.length.positive? && ENV["SPECWRK_SRV_OUTPUT"]
102
- completed_queue.dump_and_write(ENV["SPECWRK_SRV_OUTPUT"])
109
+ if pending_queue.length.zero? && processing_queue.length.zero? && completed_queue.length.positive? && ENV["SPECWRK_OUT"]
110
+ completed_queue.dump_and_write(run_report_file_path)
103
111
  end
104
112
 
105
113
  ok
@@ -128,20 +136,32 @@ module Specwrk
128
136
  end
129
137
  end
130
138
 
131
- class Stats < Base
139
+ class Report < Base
132
140
  def response
133
- data = {
134
- pending: {count: pending_queue.length},
135
- processing: {count: processing_queue.length},
136
- completed: completed_queue.dump
137
- }
138
-
139
- if data.dig(:completed, :examples).length.positive?
140
- [200, {"Content-Type" => "application/json"}, [JSON.generate(data)]]
141
+ if data
142
+ [200, {"Content-Type" => "application/json"}, [data]]
141
143
  else
142
- not_found
144
+ [404, {"Content-Type" => "text/plain"}, ["Unable to report on run #{run_id}; no file matching #{"*-report-#{run_id}.json"}"]]
145
+ end
146
+ end
147
+
148
+ private
149
+
150
+ def data
151
+ return @data if defined? @data
152
+
153
+ return unless most_recent_run_report_file
154
+ return unless File.exist?(most_recent_run_report_file)
155
+
156
+ @data = File.open(most_recent_run_report_file, "r") do |file|
157
+ file.flock(File::LOCK_SH)
158
+ file.read
143
159
  end
144
160
  end
161
+
162
+ def most_recent_run_report_file
163
+ @most_recent_run_report_file ||= Dir.glob(File.join(ENV["SPECWRK_OUT"], "*-report-#{run_id}.json")).last
164
+ end
145
165
  end
146
166
 
147
167
  class Shutdown < Base
data/lib/specwrk/web.rb CHANGED
@@ -4,7 +4,7 @@ require "specwrk/queue"
4
4
 
5
5
  module Specwrk
6
6
  class Web
7
- PENDING_QUEUES = Queue.new { |h, key| h[key] = PendingQueue.new.tap { |q| q.previous_run_times_file = ENV["SPECWRK_SRV_OUTPUT"] } }
7
+ PENDING_QUEUES = Queue.new { |h, key| h[key] = PendingQueue.new }
8
8
  PROCESSING_QUEUES = Queue.new { |h, key| h[key] = Queue.new }
9
9
  COMPLETED_QUEUES = Queue.new { |h, key| h[key] = CompletedQueue.new }
10
10
  WORKERS = Hash.new { |h, key| h[key] = Hash.new { |h, key| h[key] = {} } }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: specwrk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Westendorf