probedock-rspec 0.5.3 → 0.5.4

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
  SHA1:
3
- metadata.gz: 8085834c08513ed1483ffe926f80cf4ebd331652
4
- data.tar.gz: f31f332aea49f4e204f426f502684a3552a6d334
3
+ metadata.gz: 6ba3723d851863c76fd9c4e1b073b20c78d5d0cb
4
+ data.tar.gz: dda7e8ca57d12c7ee6da40a09e50e1e527bc9ef9
5
5
  SHA512:
6
- metadata.gz: 056f30e646719712bd6975d7486882c534a67755af7ae2f4d4184252359f32924b1edc3f262be7e7de5a3157a5b622b155fadb30dcba4d27c7ae8d9605be7ccc
7
- data.tar.gz: 03bfe700e0990b6f8da525f5b191d937acc38794bb715e96a246075635a21e2e2cdde830fbfdfefd1cd7c9d393abf96c8e3a14910a2f28247a15c4b6bd3ca0be
6
+ metadata.gz: d10c9793f2364be0cd064a6283d2fd77834676a090d7add0eda3d537ce716e174d611c53be761f73e32658530c0a266a98c681e5551c8037431cea6a04856ca4
7
+ data.tar.gz: 9c6e27cb99f6ecd5679d68d7a138bf8691156c2c682b5dd70758ea3709f7db2afb2d91eeaa6f012a008401332ba679fbe4f68f92ab792c203df75e04b0603fb0
data/Gemfile CHANGED
@@ -4,10 +4,7 @@ source "http://rubygems.org"
4
4
  # gem "activesupport", ">= 2.3.5"
5
5
 
6
6
  gem 'rspec', '~> 3.1'
7
- gem 'oj', '~> 2.1'
8
- gem 'httparty', '~> 0.13'
9
- gem 'paint', '~> 1.0'
10
- gem 'rake', '~> 10.1'
7
+ gem 'probedock-ruby', '~> 0.1'
11
8
 
12
9
  # Add dependencies to develop your gem here.
13
10
  # Include everything needed to run rake, tests, features, etc.
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2015 ProbeDock
1
+ Copyright (c) 2015 Probe Dock
2
2
  Copyright (c) 2012-2013 Lotaris SA
3
3
 
4
4
  Permission is hereby granted, free of charge, to any person obtaining
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
- # ProbeDock RSpec
1
+ # Probe Dock RSpec
2
2
 
3
- **RSpec probe for [ProbeDock](https://github.com/probedock/probedock).**
3
+ **RSpec probe for [Probe Dock](https://github.com/probedock/probedock).**
4
4
 
5
5
  [![Gem Version](https://badge.fury.io/rb/probedock-rspec.svg)](http://badge.fury.io/rb/probedock-rspec)
6
6
  [![Dependency Status](https://gemnasium.com/probedock/probedock-rspec.svg)](https://gemnasium.com/probedock/probedock-rspec)
@@ -17,7 +17,7 @@
17
17
  In your Gemfile:
18
18
 
19
19
  ```rb
20
- gem 'probedock-rspec', '~> 0.4.1'
20
+ gem 'probedock-rspec', '~> 0.5.4'
21
21
  ```
22
22
 
23
23
  Manually:
@@ -28,7 +28,7 @@ Manually:
28
28
 
29
29
  If you haven't done it already, follow the [setup procedure](#setup) below.
30
30
 
31
- To track a test with a ProbeDock test key, use RSpec metadata:
31
+ To track a test with a Probe Dock test key, use RSpec metadata:
32
32
 
33
33
  ```rb
34
34
  it "should work", probe_dock: { key: 'abcdefghijkl' } do
@@ -56,7 +56,7 @@ ProbeDockRSpec.configure do |config|
56
56
  end
57
57
  ```
58
58
 
59
- The next time you run your test suite, the RSpec probe will send the results to your ProbeDock server.
59
+ The next time you run your test suite, the RSpec probe will send the results to your Probe Dock server.
60
60
 
61
61
  ## Contributing
62
62
 
@@ -69,5 +69,5 @@ Please add a [changelog](CHANGELOG.md) entry with your name for new features and
69
69
 
70
70
  ## License
71
71
 
72
- ProbeDock RSpec is licensed under the [MIT License](http://opensource.org/licenses/MIT).
72
+ Probe Dock RSpec is licensed under the [MIT License](http://opensource.org/licenses/MIT).
73
73
  See [LICENSE.txt](LICENSE.txt) for the full license.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.5.3
1
+ 0.5.4
@@ -1,8 +1,9 @@
1
1
  # encoding: UTF-8
2
2
  require 'rspec'
3
+ require 'probedock-ruby'
3
4
 
4
5
  module ProbeDockRSpec
5
- VERSION = '0.5.3'
6
+ VERSION = '0.5.4'
6
7
 
7
8
  class Error < StandardError; end
8
9
  class PayloadError < Error; end
@@ -1,198 +1,19 @@
1
- require 'yaml'
2
-
3
- # Utilities to send test results to ProbeDock.
4
1
  module ProbeDockRSpec
5
2
 
6
- def self.config
7
- @config ||= Config.new.tap(&:load!)
3
+ def self.configure options = {}, &block
4
+ ProbeDockProbe.config.load! &block
5
+ setup! if options.fetch :setup, true
6
+ ProbeDockProbe.config
8
7
  end
9
8
 
10
- def self.configure options = {}
11
-
12
- yield config if block_given?
13
-
14
- config.check!
15
- config.load_warnings.each{ |w| warn Paint["ProbeDock - #{w}", :yellow] }
16
-
17
- config.setup! if options[:setup] != false
18
-
19
- config
20
- end
21
-
22
- class Config
23
- # TODO: add silent/verbose option(s)
24
- class Error < ProbeDockRSpec::Error; end
25
- attr_writer :publish, :local_mode, :cache_payload, :print_payload, :save_payload
26
- attr_reader :project, :server, :workspace, :load_warnings
27
-
28
- def initialize
29
- @servers = []
30
- @server = Server.new
31
- @project = Project.new
32
- @publish, @local_mode, @cache_payload, @print_payload, @save_payload = false, false, false, false, false
33
- @load_warnings = []
34
- end
35
-
36
- def workspace= dir
37
- @workspace = dir ? File.expand_path(dir) : nil
38
- end
9
+ private
39
10
 
40
- def servers
41
- @servers.dup
42
- end
43
-
44
- # Plugs ProbeDock utilities into RSpec.
45
- def setup!
11
+ def self.setup!
12
+ unless @setup
13
+ @setup = true
46
14
  ::RSpec.configure do |c|
47
15
  c.add_formatter Formatter
48
16
  end
49
17
  end
50
-
51
- %w(publish local_mode cache_payload print_payload save_payload).each do |name|
52
- define_method("#{name}?"){ instance_variable_get("@#{name}") }
53
- end
54
-
55
- def client_options
56
- {
57
- publish: @publish,
58
- local_mode: @local_mode,
59
- workspace: @workspace,
60
- cache_payload: @cache_payload,
61
- print_payload: @print_payload,
62
- save_payload: @save_payload
63
- }.select{ |k,v| !v.nil? }
64
- end
65
-
66
- def load!
67
-
68
- @server.clear
69
- @servers.clear
70
-
71
- @load_warnings = []
72
- return unless config = load_config_files
73
-
74
- @publish = parse_env_flag :publish, !!config[:publish]
75
- @server_name = parse_env_option(:server) || config[:server]
76
- @local_mode = parse_env_flag(:local) || !!config[:local]
77
-
78
- self.workspace = parse_env_option(:workspace) || config[:workspace]
79
- @cache_payload = parse_env_flag :cache_payload, !!config[:payload][:cache]
80
- @print_payload = parse_env_flag :print_payload, !!config[:payload][:print]
81
- @save_payload = parse_env_flag :save_payload, !!config[:payload][:save]
82
-
83
- @servers, server = build_servers config
84
-
85
- if server
86
- @server = server
87
- else
88
- @server.name = @server_name
89
- end
90
-
91
- {
92
- api_url: parse_env_option(:server_api_url),
93
- api_token: parse_env_option(:server_api_token),
94
- project_api_id: parse_env_option(:server_project_api_id)
95
- }.each{ |k,v| @server.send "#{k}=", v if v }
96
-
97
- project_options = config[:project]
98
- project_options.merge! api_id: @server.project_api_id if @server and @server.project_api_id
99
- @project.update project_options
100
-
101
- self
102
- end
103
-
104
- def check!
105
-
106
- configs = [ home_config_file, working_config_file ]
107
- actual_configs = configs.select{ |f| File.exists? f }
108
-
109
- if actual_configs.empty?
110
- @load_warnings << %|no config file found, looking for:\n #{configs.join "\n "}|
111
- end
112
-
113
- if @servers.empty?
114
- @load_warnings << "No server defined"
115
- elsif !@server_name && !@server.name
116
- @load_warnings << "No server name given"
117
- end
118
- end
119
-
120
- private
121
-
122
- def build_servers config
123
-
124
- default_server_options = { project_api_id: config[:project][:api_id] }
125
- servers = config[:servers].inject({}) do |memo,(name, options)|
126
- memo[name] = Server.new default_server_options.merge(options).merge(name: name)
127
- memo
128
- end
129
-
130
- [ servers.values, servers[@server_name.to_s.strip] ]
131
- end
132
-
133
- def load_config_files
134
-
135
- configs = [ home_config_file, working_config_file ]
136
- actual_configs = configs.select{ |f| File.exists? f }
137
- return false if actual_configs.empty?
138
-
139
- actual_configs.collect!{ |f| YAML.load_file f }
140
-
141
- actual_configs.inject({ servers: {} }) do |memo,yml|
142
- memo.merge! parse_general_options(yml)
143
-
144
- if yml['servers'].kind_of? Hash
145
- yml['servers'].each_pair do |k,v|
146
- if v.kind_of? Hash
147
- memo[:servers][k] = (memo[:servers][k] || {}).merge(parse_server_options(v))
148
- end
149
- end
150
- end
151
-
152
- memo[:payload] = (memo[:payload] || {}).merge parse_payload_options(yml['payload'])
153
- memo[:project] = (memo[:project] || {}).merge parse_project_options(yml['project'])
154
-
155
- memo
156
- end
157
- end
158
-
159
- def home_config_file
160
- File.join File.expand_path('~'), '.probedock', 'config.yml'
161
- end
162
-
163
- def working_config_file
164
- File.expand_path ENV['PROBE_DOCK_CONFIG'] || 'probedock.yml', Dir.pwd
165
- end
166
-
167
- def parse_env_flag name, default = false
168
- val = parse_env_option name
169
- val ? !!val.to_s.strip.match(/\A(1|y|yes|t|true)\Z/i) : default
170
- end
171
-
172
- def parse_env_option name
173
- var = "PROBE_DOCK_#{name.upcase}"
174
- ENV.key?(var) ? ENV[var] : nil
175
- end
176
-
177
- def parse_general_options h
178
- parse_options h, %w(publish server local workspace)
179
- end
180
-
181
- def parse_server_options h
182
- parse_options h, %w(name apiUrl apiToken apiVersion projectApiId)
183
- end
184
-
185
- def parse_payload_options h
186
- parse_options h, %w(save cache print)
187
- end
188
-
189
- def parse_project_options h
190
- parse_options h, %w(version apiId category tags tickets)
191
- end
192
-
193
- def parse_options h, keys
194
- return {} unless h.kind_of? Hash
195
- keys.inject({}){ |memo,k| memo[k.gsub(/(.)([A-Z])/, '\1_\2').downcase.to_sym] = h[k] if h.key?(k); memo }
196
- end
197
18
  end
198
19
  end
@@ -11,9 +11,9 @@ module ProbeDockRSpec
11
11
 
12
12
  def initialize output
13
13
 
14
- config = ProbeDockRSpec.config
15
- @client = Client.new config.server, config.client_options
16
- @test_run = TestRun.new config.project
14
+ config = ProbeDockProbe.config
15
+ @client = ProbeDockProbe::Client.new config.server, config.client_options
16
+ @test_run = ProbeDockProbe::TestRun.new config.project
17
17
 
18
18
  @groups = []
19
19
  end
@@ -55,14 +55,11 @@ module ProbeDockRSpec
55
55
 
56
56
  def add_result example_notification, successful
57
57
 
58
- options = {
59
- passed: successful,
60
- duration: ((Time.now - @current_time) * 1000).round
61
- }
62
-
58
+ options = MetaParser.parse example_notification.example, @groups
59
+ options.merge! passed: successful, duration: ((Time.now - @current_time) * 1000).round
63
60
  options[:message] = failure_message example_notification unless successful
64
61
 
65
- @test_run.add_result example_notification.example, @groups, options
62
+ @test_run.add_result options
66
63
  end
67
64
 
68
65
  def failure_message example_notification
@@ -74,9 +71,5 @@ module ProbeDockRSpec
74
71
  m << example_notification.formatted_backtrace.collect{ |l| " # #{l}" }.join("\n")
75
72
  end
76
73
  end
77
-
78
- def full_example_name example
79
- (@groups.collect{ |g| g.description.strip } << example.description.strip).join ' '
80
- end
81
74
  end
82
75
  end
@@ -0,0 +1,68 @@
1
+ require 'digest/sha1'
2
+
3
+ module ProbeDockRSpec
4
+ class MetaParser
5
+
6
+ def self.parse example, groups = []
7
+
8
+ options = {}
9
+
10
+ %i(key category tags tickets data).each do |attr|
11
+ options[attr] = send "extract_#{attr}", example, groups
12
+ end
13
+
14
+ name_parts = extract_name_parts example, groups
15
+ options[:name] = name_parts.join ' '
16
+ options[:fingerprint] = Digest::SHA1.hexdigest name_parts.join('|||')
17
+
18
+ # TODO: remove once Probe Dock has been migrated to use fingerprints
19
+ options[:data][:fingerprint] = options[:fingerprint]
20
+
21
+ options
22
+ end
23
+
24
+ private
25
+
26
+ def self.extract_key example, groups = []
27
+ (groups.collect{ |g| meta(g)[:key] } << meta(example)[:key]).compact.reject{ |k| k.strip.empty? }.last
28
+ end
29
+
30
+ def self.meta holder
31
+
32
+ meta = holder.metadata[:probe_dock] || {}
33
+
34
+ if meta.kind_of? String
35
+ { key: meta }
36
+ elsif meta.kind_of? Hash
37
+ meta
38
+ else
39
+ {}
40
+ end
41
+ end
42
+
43
+ def self.extract_name_parts example, groups = []
44
+ (groups.collect(&:description) << example.description).compact.collect(&:strip).reject{ |p| p.empty? }
45
+ end
46
+
47
+ def self.extract_category example, groups = []
48
+ cat = (groups.collect{ |g| meta(g)[:category] } << meta(example)[:category]).compact.last
49
+ cat ? cat.to_s : nil
50
+ end
51
+
52
+ def self.extract_tags example, groups = []
53
+ (groups.collect{ |g| wrap meta(g)[:tags] } + (wrap meta(example)[:tags])).flatten.compact.uniq.collect(&:to_s)
54
+ end
55
+
56
+ def self.extract_tickets example, groups = []
57
+ (groups.collect{ |g| wrap meta(g)[:tickets] } + (wrap meta(example)[:tickets])).flatten.compact.uniq.collect(&:to_s)
58
+ end
59
+
60
+ def self.extract_data example, groups = []
61
+ meta(example)[:data] || {}
62
+ end
63
+
64
+ def self.wrap a
65
+ a.kind_of?(Array) ? a : [ a ]
66
+ end
67
+ end
68
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: probedock-rspec
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.3
4
+ version: 0.5.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Simon Oulevay (Alpha Hydrae)
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-27 00:00:00.000000000 Z
11
+ date: 2015-07-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -25,61 +25,19 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '3.1'
27
27
  - !ruby/object:Gem::Dependency
28
- name: oj
28
+ name: probedock-ruby
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '2.1'
33
+ version: '0.1'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '2.1'
41
- - !ruby/object:Gem::Dependency
42
- name: httparty
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '0.13'
48
- type: :runtime
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '0.13'
55
- - !ruby/object:Gem::Dependency
56
- name: paint
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: '1.0'
62
- type: :runtime
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: '1.0'
69
- - !ruby/object:Gem::Dependency
70
- name: rake
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: '10.1'
76
- type: :runtime
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: '10.1'
40
+ version: '0.1'
83
41
  - !ruby/object:Gem::Dependency
84
42
  name: jeweler
85
43
  requirement: !ruby/object:Gem::Requirement
@@ -178,33 +136,23 @@ dependencies:
178
136
  - - "~>"
179
137
  - !ruby/object:Gem::Version
180
138
  version: '0.8'
181
- description: RSpec client to publish test results to ProbeDock, a test tracking and
139
+ description: RSpec client to publish test results to Probe Dock, a test tracking and
182
140
  analysis server.
183
141
  email: simon.oulevay@gmail.com
184
142
  executables: []
185
143
  extensions: []
186
144
  extra_rdoc_files:
187
- - CHANGELOG.md
188
145
  - LICENSE.txt
189
146
  - README.md
190
147
  files:
191
- - CHANGELOG.md
192
148
  - Gemfile
193
149
  - LICENSE.txt
194
150
  - README.md
195
151
  - VERSION
196
152
  - lib/probe_dock_rspec.rb
197
- - lib/probe_dock_rspec/cache.rb
198
- - lib/probe_dock_rspec/client.rb
199
153
  - lib/probe_dock_rspec/config.rb
200
154
  - lib/probe_dock_rspec/formatter.rb
201
- - lib/probe_dock_rspec/project.rb
202
- - lib/probe_dock_rspec/server.rb
203
- - lib/probe_dock_rspec/tasks.rb
204
- - lib/probe_dock_rspec/test_payload.rb
205
- - lib/probe_dock_rspec/test_result.rb
206
- - lib/probe_dock_rspec/test_run.rb
207
- - lib/probe_dock_rspec/uid.rb
155
+ - lib/probe_dock_rspec/meta_parser.rb
208
156
  - lib/probedock-rspec.rb
209
157
  homepage: https://github.com/probedock/probedock-rspec
210
158
  licenses:
@@ -226,8 +174,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
226
174
  version: '0'
227
175
  requirements: []
228
176
  rubyforge_project:
229
- rubygems_version: 2.4.6
177
+ rubygems_version: 2.4.8
230
178
  signing_key:
231
179
  specification_version: 4
232
- summary: RSpec client to publish test results to ProbeDock.
180
+ summary: RSpec client to publish test results to Probe Dock.
233
181
  test_files: []
data/CHANGELOG.md DELETED
@@ -1,13 +0,0 @@
1
- # Changelog
2
-
3
- ## v0.4.0 - September 11, 2014
4
-
5
- * Upgraded to RSpec 3.1.
6
-
7
- ## v0.3.1 - December 13, 2013
8
-
9
- * The `servers` key in the YAML configuration file is now a hash instead of an array.
10
-
11
- ## v0.3.0 - October 25, 2013
12
-
13
- * First open source version.
@@ -1,61 +0,0 @@
1
-
2
- module ProbeDockRSpec
3
-
4
- class Cache
5
-
6
- class Error < ProbeDockRSpec::Error; end
7
-
8
- def initialize options = {}
9
- @tests = {}
10
- @workspace, @server_name, @project_api_id = options[:workspace], options[:server_name], options[:project_api_id]
11
- end
12
-
13
- def save test_run
14
- validate!
15
-
16
- @tests = { @project_api_id => @tests[@project_api_id] || {} }
17
- test_run.results.select(&:key).each{ |r| @tests[@project_api_id][r.key] = test_result_hash(r) }
18
-
19
- FileUtils.mkdir_p File.dirname(cache_file)
20
- File.open(cache_file, 'w'){ |f| f.write Oj.dump(@tests, mode: :strict) }
21
-
22
- self
23
- end
24
-
25
- def load
26
- validate!
27
-
28
- @tests = if File.exists? cache_file
29
- Oj.load(File.read(cache_file), mode: :strict) rescue {}
30
- else
31
- {}
32
- end
33
-
34
- self
35
- end
36
-
37
- def known? test_result
38
- test_result.key && !!@tests[@project_api_id] && !!@tests[@project_api_id][test_result.key]
39
- end
40
-
41
- def stale? test_result
42
- !!@tests[@project_api_id] && test_result_hash(test_result) != @tests[@project_api_id][test_result.key]
43
- end
44
-
45
- private
46
-
47
- def validate!
48
- required = { "workspace" => @workspace, "server name" => @server_name, "project API identifier" => @project_api_id }
49
- missing = required.keys.select{ |k| !required[k] }
50
- raise Error.new("Missing cache options: #{missing.join ', '}") if missing.any?
51
- end
52
-
53
- def test_result_hash r
54
- Digest::SHA2.hexdigest "#{r.name} || #{r.category} || #{r.tags.collect(&:to_s).sort.join(' ')} || #{r.tickets.collect(&:to_s).sort.join(' ')}"
55
- end
56
-
57
- def cache_file
58
- @cache_file ||= File.join(@workspace, 'rspec', 'servers', @server_name, 'cache.json')
59
- end
60
- end
61
- end
@@ -1,120 +0,0 @@
1
-
2
- module ProbeDockRSpec
3
-
4
- class Client
5
-
6
- def initialize server, options = {}
7
-
8
- @server = server
9
- @publish, @local_mode, @workspace = options[:publish], options[:local_mode], options[:workspace]
10
- @cache_payload, @print_payload, @save_payload = options[:cache_payload], options[:print_payload], options[:save_payload]
11
-
12
- cache_options = { workspace: @workspace }
13
- cache_options.merge! server_name: @server.name, project_api_id: @server.project_api_id if @server
14
- @cache = Cache.new cache_options
15
-
16
- @uid = UID.new workspace: @workspace
17
- end
18
-
19
- def process test_run
20
-
21
- return fail "No server to publish results to" if !@server
22
-
23
- test_run.uid = @uid.load_uid
24
-
25
- payload_options = {}
26
-
27
- cache_enabled = @cache_payload && load_cache
28
- payload_options[:cache] = @cache if cache_enabled
29
-
30
- return false unless payload = build_payload(test_run, payload_options)
31
-
32
- published = if !@publish
33
- puts Paint["ProbeDock - Publishing disabled", :yellow]
34
- false
35
- elsif publish_payload payload
36
- @cache.save test_run if cache_enabled
37
- true
38
- else
39
- false
40
- end
41
-
42
- save_payload payload if @save_payload
43
- print_payload payload if @print_payload
44
-
45
- puts
46
-
47
- published
48
- end
49
-
50
- private
51
-
52
- def build_payload test_run, options = {}
53
- begin
54
- TestPayload.new(test_run).to_h options
55
- rescue PayloadError => e
56
- fail e.message
57
- end
58
- end
59
-
60
- def fail msg, type = :error
61
- styles = { warning: [ :yellow ], error: [ :bold, :red ] }
62
- warn Paint["ProbeDock - #{msg}", *styles[type]]
63
- false
64
- end
65
-
66
- def load_cache
67
- begin
68
- @cache.load
69
- rescue Cache::Error => e
70
- warn Paint["ProbeDock - #{e.message}", :yellow]
71
- false
72
- end
73
- end
74
-
75
- def print_payload payload
76
- puts Paint['ProbeDock - Printing payload...', :yellow]
77
- begin
78
- puts JSON.pretty_generate(payload)
79
- rescue
80
- puts payload.inspect
81
- end
82
- end
83
-
84
- def save_payload payload
85
-
86
- missing = { "workspace" => @workspace, "server" => @server }.inject([]){ |memo,(k,v)| !v ? memo << k : memo }
87
- return fail "Cannot save payload without a #{missing.join ' and '}" if missing.any?
88
-
89
- FileUtils.mkdir_p File.dirname(payload_file)
90
- File.open(payload_file, 'w'){ |f| f.write Oj.dump(payload, mode: :strict) }
91
- end
92
-
93
- def payload_file
94
- @payload_file ||= File.join(@workspace, 'rspec', 'servers', @server.name, 'payload.json')
95
- end
96
-
97
- def publish_payload payload
98
-
99
- puts Paint["ProbeDock - Sending payload to #{@server.api_url}...", :magenta]
100
-
101
- begin
102
- if @local_mode
103
- puts Paint['ProbeDock - LOCAL MODE: not actually sending payload.', :yellow]
104
- else
105
- @server.upload payload
106
- end
107
- puts Paint["ProbeDock - Done!", :green]
108
- true
109
- rescue Server::Error => e
110
- warn Paint["ProbeDock - Upload failed!", :red, :bold]
111
- warn Paint["ProbeDock - #{e.message}", :red, :bold]
112
- if e.response
113
- warn Paint["ProbeDock - Dumping response body...", :red, :bold]
114
- warn e.response.body
115
- end
116
- false
117
- end
118
- end
119
- end
120
- end
@@ -1,30 +0,0 @@
1
- module ProbeDockRSpec
2
-
3
- class Project
4
- attr_accessor :version, :api_id, :category, :tags, :tickets
5
-
6
- def initialize options = {}
7
- update options
8
- end
9
-
10
- def update options = {}
11
- %w(version api_id category).each do |k|
12
- instance_variable_set "@#{k}", options[k.to_sym] ? options[k.to_sym].to_s : nil if options.key? k.to_sym
13
- end
14
- @tags = wrap(options[:tags]).compact if options.key? :tags
15
- @tickets = wrap(options[:tickets]).compact if options.key? :tickets
16
- end
17
-
18
- def validate!
19
- required = { "version" => @version, "API identifier" => @api_id }
20
- missing = required.inject([]){ |memo,(k,v)| v.to_s.strip.length <= 0 ? memo << k : memo }
21
- raise PayloadError.new("Missing project options: #{missing.join ', '}") if missing.any?
22
- end
23
-
24
- private
25
-
26
- def wrap a
27
- a.kind_of?(Array) ? a : [ a ]
28
- end
29
- end
30
- end
@@ -1,59 +0,0 @@
1
- require 'oj'
2
- require 'httparty'
3
-
4
- module ProbeDockRSpec
5
-
6
- class Server
7
- attr_accessor :name, :api_url, :api_token, :project_api_id
8
-
9
- class Error < ProbeDockRSpec::Error
10
- attr_reader :response
11
-
12
- def initialize msg, response = nil
13
- super msg
14
- @response = response
15
- end
16
- end
17
-
18
- def initialize options = {}
19
- @name = options[:name].to_s.strip if options[:name]
20
- @api_url = options[:api_url].to_s if options[:api_url]
21
- @api_token = options[:api_token].to_s if options[:api_token]
22
- @project_api_id = options[:project_api_id].to_s if options[:project_api_id]
23
- end
24
-
25
- def clear
26
- @name = nil
27
- @api_url = nil
28
- @api_token = nil
29
- @project_api_id = nil
30
- end
31
-
32
- def upload payload
33
- validate!
34
-
35
- body = Oj.dump payload, mode: :strict
36
- res = HTTParty.post payload_uri, body: body, headers: payload_headers
37
-
38
- if res.code != 202
39
- raise Error.new("Expected HTTP 202 Accepted when submitting payload, got #{res.code}", res)
40
- end
41
- end
42
-
43
- private
44
-
45
- def validate!
46
- required = { "name" => @name, "apiUrl" => @api_url, "apiToken" => @api_token }
47
- missing = required.inject([]){ |memo,(k,v)| v.to_s.strip.length <= 0 ? memo << k : memo }
48
- raise Error.new("Server #{@name} is missing the following options: #{missing.join ', '}") if missing.any?
49
- end
50
-
51
- def payload_headers
52
- { 'Authorization' => "Bearer #{@api_token}", 'Content-Type' => 'application/vnd.probedock.payload.v1+json' }
53
- end
54
-
55
- def payload_uri
56
- "#{@api_url}/publish"
57
- end
58
- end
59
- end
@@ -1,62 +0,0 @@
1
- require 'fileutils'
2
- require 'rake/tasklib'
3
-
4
- module ProbeDockRSpec
5
-
6
- class Tasks < ::Rake::TaskLib
7
-
8
- def initialize
9
-
10
- namespace :spec do
11
-
12
- namespace 'probedock' do
13
-
14
- desc "Generate a test run UID to group test results in ProbeDock (stored in an environment variable)"
15
- task :uid do
16
- trace do
17
- uid = uid_manager.generate_uid_to_env
18
- puts Paint["ProbeDock - Generated UID for test run: #{uid}", :cyan]
19
- end
20
- end
21
-
22
- namespace :uid do
23
-
24
- desc "Generate a test run UID to group test results in ProbeDock (stored in a file)"
25
- task :file do
26
- trace do
27
- uid = uid_manager.generate_uid_to_file
28
- puts Paint["ProbeDock - Generated UID for test run: #{uid}", :cyan]
29
- end
30
- end
31
-
32
- desc "Clean the test run UID (file and environment variable)"
33
- task :clean do
34
- trace do
35
- uid_manager.clean_uid
36
- puts Paint["ProbeDock - Cleaned test run UID", :cyan]
37
- end
38
- end
39
- end
40
- end
41
- end
42
- end
43
-
44
- private
45
-
46
- def trace &block
47
- if Rake.application.options.trace
48
- block.call
49
- else
50
- begin
51
- block.call
52
- rescue UID::Error => e
53
- warn Paint["ProbeDock - #{e.message}", :red]
54
- end
55
- end
56
- end
57
-
58
- def uid_manager
59
- UID.new ProbeDockRSpec.config.client_options
60
- end
61
- end
62
- end
@@ -1,18 +0,0 @@
1
- require 'fileutils'
2
- require 'digest/sha2'
3
-
4
- module ProbeDockRSpec
5
-
6
- class TestPayload
7
-
8
- class Error < ProbeDockRSpec::Error; end
9
-
10
- def initialize run
11
- @run = run
12
- end
13
-
14
- def to_h options = {}
15
- @run.to_h options
16
- end
17
- end
18
- end
@@ -1,119 +0,0 @@
1
-
2
- module ProbeDockRSpec
3
-
4
- class TestResult
5
- attr_reader :key, :name, :category, :tags, :tickets, :data, :duration, :message
6
-
7
- def initialize project, example, groups = [], options = {}
8
-
9
- @category = project.category
10
- @tags = project.tags
11
- @tickets = project.tickets
12
-
13
- @grouped = extract_grouped example, groups
14
-
15
- [ :key, :name, :category, :tags, :tickets, :data ].each do |attr|
16
- instance_variable_set "@#{attr}".to_sym, send("extract_#{attr}".to_sym, example, groups)
17
- end
18
-
19
- @passed = !!options[:passed]
20
- @duration = options[:duration]
21
- @message = options[:message]
22
- end
23
-
24
- def passed?
25
- @passed
26
- end
27
-
28
- def grouped?
29
- @grouped
30
- end
31
-
32
- def update options = {}
33
- @passed &&= options[:passed]
34
- @duration += options[:duration]
35
- @message = [ @message, options[:message] ].select{ |m| m }.join("\n\n") if options[:message]
36
- end
37
-
38
- def to_h options = {}
39
- {
40
- 'p' => @passed,
41
- 'd' => @duration
42
- }.tap do |h|
43
-
44
- h['k'] = @key if @key
45
- h['m'] = @message if @message
46
-
47
- cache = options[:cache]
48
- first = !cache || !cache.known?(self)
49
- stale = !first && cache.stale?(self)
50
- h['n'] = @name if stale or first
51
- h['c'] = @category if stale or (first and @category)
52
- h['g'] = @tags if stale or (first and !@tags.empty?)
53
- h['t'] = @tickets if stale or (first and !@tickets.empty?)
54
- h['a'] = @data if @data # FIXME: cache custom data
55
- end
56
- end
57
-
58
- def self.extract_grouped example, groups = []
59
- !!groups.collect{ |g| meta(g)[:grouped] }.compact.last
60
- end
61
-
62
- def self.extract_key example, groups = []
63
- (groups.collect{ |g| meta(g)[:key] } << meta(example)[:key]).compact.reject{ |k| k.strip.empty? }.last
64
- end
65
-
66
- def self.meta holder
67
- meta = holder.metadata[:probe_dock] || {}
68
- if meta.kind_of? String
69
- { key: meta }
70
- elsif meta.kind_of? Hash
71
- meta
72
- else
73
- {}
74
- end
75
- end
76
-
77
- private
78
-
79
- def meta *args
80
- self.class.meta *args
81
- end
82
-
83
- def extract_grouped *args
84
- self.class.extract_grouped *args
85
- end
86
-
87
- def extract_key *args
88
- self.class.extract_key *args
89
- end
90
-
91
- def extract_name example, groups = []
92
- parts = groups.dup
93
- parts = parts[0, parts.index{ |p| meta(p)[:grouped] } + 1] if @grouped
94
- parts << example unless @grouped
95
- parts.collect{ |p| p.description.strip }.join ' '
96
- end
97
-
98
- def extract_category example, groups = []
99
- cat = (groups.collect{ |g| meta(g)[:category] }.unshift(@category) << meta(example)[:category]).compact.last
100
- cat ? cat.to_s : nil
101
- end
102
-
103
- def extract_tags example, groups = []
104
- (wrap(@tags) + groups.collect{ |g| wrap meta(g)[:tags] } + (wrap meta(example)[:tags])).flatten.compact.uniq.collect(&:to_s)
105
- end
106
-
107
- def extract_tickets example, groups = []
108
- (wrap(@tickets) + groups.collect{ |g| wrap meta(g)[:tickets] } + (wrap meta(example)[:tickets])).flatten.compact.uniq.collect(&:to_s)
109
- end
110
-
111
- def extract_data example, groups = []
112
- meta(example)[:data]
113
- end
114
-
115
- def wrap a
116
- a.kind_of?(Array) ? a : [ a ]
117
- end
118
- end
119
- end
@@ -1,85 +0,0 @@
1
-
2
- module ProbeDockRSpec
3
-
4
- class TestRun
5
- attr_reader :results, :project
6
- attr_accessor :duration, :uid
7
-
8
- def initialize project
9
- @results = []
10
- @project = project
11
- end
12
-
13
- def add_result example, groups = [], options = {}
14
- if TestResult.extract_grouped(example, groups) and (existing_result = @results.find{ |r| r.grouped? && r.key == TestResult.extract_key(example, groups) })
15
- existing_result.update options
16
- else
17
- @results << TestResult.new(@project, example, groups, options)
18
- end
19
- end
20
-
21
- def results_without_key
22
- @results.select{ |r| !r.key or r.key.to_s.strip.empty? }
23
- end
24
-
25
- def results_by_key
26
- @results.inject({}) do |memo,r|
27
- (memo[r.key] ||= []) << r unless !r.key or r.key.to_s.strip.empty?
28
- memo
29
- end
30
- end
31
-
32
- def to_h options = {}
33
- validate!
34
-
35
- {
36
- 'projectId' => @project.api_id,
37
- 'version' => @project.version,
38
- 'duration' => @duration,
39
- 'results' => @results.collect{ |r| r.to_h options }
40
- }.tap do |h|
41
- h['reports'] = [ { 'uid' => @uid } ] if @uid
42
- end
43
- end
44
-
45
- private
46
-
47
- def validate!
48
- # TODO: validate duration
49
-
50
- raise PayloadError.new("Missing project") if !@project
51
- @project.validate!
52
-
53
- # FIXME: log info/warnings
54
- #validate_no_results_without_key
55
- #validate_no_duplicate_keys
56
- end
57
-
58
- def validate_no_duplicate_keys
59
-
60
- results_with_duplicate_key = results_by_key.select{ |k,r| r.length >= 2 }
61
- return if results_with_duplicate_key.none?
62
-
63
- msg = "the following keys are used by multiple test results".tap do |s|
64
- results_with_duplicate_key.each_pair do |key,results|
65
- s << "\n - #{key}"
66
- results.each{ |r| s << "\n - #{r.name}" }
67
- end
68
- end
69
-
70
- raise PayloadError.new(msg)
71
- end
72
-
73
- def validate_no_results_without_key
74
-
75
- keyless = results_without_key
76
- return if keyless.empty?
77
-
78
- msg = "the following test results are missing a key".tap do |s|
79
- keyless.each{ |r| s << "\n - #{r.name}" }
80
- end
81
-
82
- raise PayloadError.new(msg)
83
- end
84
- end
85
- end
@@ -1,60 +0,0 @@
1
- require 'securerandom'
2
-
3
- module ProbeDockRSpec
4
-
5
- class UID
6
- ENVIRONMENT_VARIABLE = 'PROBE_DOCK_TEST_REPORT_UID'
7
-
8
- class Error < ProbeDockRSpec::Error; end
9
-
10
- def initialize options = {}
11
- @workspace = options[:workspace]
12
- end
13
-
14
- def load_uid
15
- if env_var
16
- return env_var
17
- elsif @workspace
18
- current_uid
19
- end
20
- end
21
-
22
- def generate_uid_to_file
23
- raise Error.new("No workspace specified; cannot save test run UID") if !@workspace
24
- generate_uid.tap{ |uid| save_uid uid }
25
- end
26
-
27
- def generate_uid_to_env
28
- raise Error.new("$PROBE_DOCK_TEST_REPORT_UID is already defined") if env_var
29
- ENV[ENVIRONMENT_VARIABLE] = generate_uid
30
- end
31
-
32
- def clean_uid
33
- ENV.delete ENVIRONMENT_VARIABLE
34
- FileUtils.remove_entry_secure uid_file if @workspace and File.exists?(uid_file)
35
- end
36
-
37
- private
38
-
39
- def save_uid uid
40
- FileUtils.mkdir_p File.dirname(uid_file)
41
- File.open(uid_file, 'w'){ |f| f.write uid }
42
- end
43
-
44
- def env_var
45
- ENV[ENVIRONMENT_VARIABLE]
46
- end
47
-
48
- def current_uid
49
- File.file?(uid_file) ? File.read(uid_file) : nil
50
- end
51
-
52
- def uid_file
53
- @uid_file ||= File.join(@workspace, 'uid')
54
- end
55
-
56
- def generate_uid
57
- "#{Time.now.utc.strftime '%Y%m%d%H%M%S'}-#{SecureRandom.uuid}"
58
- end
59
- end
60
- end