probedock-ruby 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d941395e464c62eab491d4939d4a8a64096cbac6
4
+ data.tar.gz: 4e35bc79a67d9f0cf1460ea0f167f5b7061a34a7
5
+ SHA512:
6
+ metadata.gz: e7b22566142e31593d73930d26ef56eefc3f1e491a0deb1f22c5a1960806d07d3e82d2510706fc92f5086dd1fa1eddccb94e89db091525211d2dfb1c05a38998
7
+ data.tar.gz: b05d2128a07ae016a8a7616a7651b0fa4d9b1d21d08a8a6ba4cf8c6a057d7da0d486540bd9990090910dbfd4fe7208598ef10480cdb1fc769360f3728a28b8b9
data/Gemfile ADDED
@@ -0,0 +1,22 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ gem 'oj', '~> 2.1'
7
+ gem 'httparty', '~> 0.13'
8
+ gem 'paint', '~> 1.0'
9
+ gem 'rake', '~> 10.1'
10
+
11
+ # Add dependencies to develop your gem here.
12
+ # Include everything needed to run rake, tests, features, etc.
13
+ group :development do
14
+ gem 'jeweler', '~> 2.0'
15
+ gem 'rake-version', '~> 0.4'
16
+ gem 'simplecov', '~> 0.10', require: false
17
+ gem 'fakefs', '~> 0.6', require: 'fakefs/safe'
18
+ gem 'rspec', '~> 3.1'
19
+ gem 'rspec-its', '~> 1.2'
20
+ gem 'rspec-collection_matchers', '~> 1.1'
21
+ gem 'coveralls', '~> 0.8', require: false
22
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2015 Probe Dock
2
+ Copyright (c) 2012-2013 Lotaris SA
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,36 @@
1
+ # Probe Dock Ruby Library
2
+
3
+ **Ruby library to develop new probes for [Probe Dock](https://github.com/probedock/probedock).**
4
+
5
+ [![Gem Version](https://badge.fury.io/rb/probedock-ruby.svg)](http://badge.fury.io/rb/probedock-ruby)
6
+ [![Dependency Status](https://gemnasium.com/probedock/probedock-ruby.svg)](https://gemnasium.com/probedock/probedock-ruby)
7
+ [![Build Status](https://secure.travis-ci.org/probedock/probedock-ruby.svg)](http://travis-ci.org/probedock/probedock-ruby)
8
+ [![Coverage Status](https://coveralls.io/repos/probedock/probedock-ruby/badge.svg)](https://coveralls.io/r/probedock/probedock-ruby?branch=master)
9
+ [![License](https://img.shields.io/github/license/probedock/probedock-ruby.svg)](LICENSE.txt)
10
+
11
+ ## Requirements
12
+
13
+ * Ruby 2+
14
+
15
+ ## Installation
16
+
17
+ Add it to your Gemfile:
18
+
19
+ ```rb
20
+ gem 'probedock-ruby', '~> 0.1.0'
21
+ ```
22
+
23
+ Run `bundle install`.
24
+
25
+ ## Contributing
26
+
27
+ * [Fork](https://help.github.com/articles/fork-a-repo)
28
+ * Create a topic branch - `git checkout -b my_feature`
29
+ * Push to your branch - `git push origin my_feature`
30
+ * Create a [pull request](http://help.github.com/pull-requests/) from your branch
31
+
32
+ Please add a [changelog](CHANGELOG.md) entry with your name for new features and bug fixes.
33
+
34
+ ## License
35
+
36
+ Probe Dock RSpec is licensed under the [MIT License](http://opensource.org/licenses/MIT).
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,9 @@
1
+ # encoding: UTF-8
2
+ module ProbeDockProbe
3
+ VERSION = '0.1.0'
4
+
5
+ class Error < StandardError; end
6
+ class PayloadError < Error; end
7
+ end
8
+
9
+ Dir[File.join File.dirname(__FILE__), File.basename(__FILE__, '.*'), '*.rb'].each{ |lib| require lib }
@@ -0,0 +1,101 @@
1
+ module ProbeDockProbe
2
+
3
+ class Client
4
+
5
+ def initialize server, options = {}
6
+
7
+ @server = server
8
+ @publish, @local_mode, @workspace = options[:publish], options[:local_mode], options[:workspace]
9
+ @print_payload, @save_payload = options[:print_payload], options[:save_payload]
10
+
11
+ @uid = UID.new workspace: @workspace
12
+ end
13
+
14
+ def process test_run
15
+
16
+ return fail "No server to publish results to" if !@server
17
+
18
+ test_run.uid = @uid.load_uid
19
+
20
+ payload_options = {}
21
+ return false unless payload = build_payload(test_run, payload_options)
22
+
23
+ published = if !@publish
24
+ puts Paint["Probe Dock - Publishing disabled", :yellow]
25
+ false
26
+ elsif publish_payload payload
27
+ true
28
+ else
29
+ false
30
+ end
31
+
32
+ save_payload payload if @save_payload
33
+ print_payload payload if @print_payload
34
+
35
+ puts
36
+
37
+ published
38
+ end
39
+
40
+ private
41
+
42
+ def build_payload test_run, options = {}
43
+ begin
44
+ TestPayload.new(test_run).to_h options
45
+ rescue PayloadError => e
46
+ fail e.message
47
+ end
48
+ end
49
+
50
+ def fail msg, type = :error
51
+ styles = { warning: [ :yellow ], error: [ :bold, :red ] }
52
+ warn Paint["Probe Dock - #{msg}", *styles[type]]
53
+ false
54
+ end
55
+
56
+ def print_payload payload
57
+ puts Paint['Probe Dock - Printing payload...', :yellow]
58
+ begin
59
+ puts JSON.pretty_generate(payload)
60
+ rescue
61
+ puts payload.inspect
62
+ end
63
+ end
64
+
65
+ def save_payload payload
66
+
67
+ missing = { "workspace" => @workspace, "server" => @server }.inject([]){ |memo,(k,v)| !v ? memo << k : memo }
68
+ return fail "Cannot save payload without a #{missing.join ' and '}" if missing.any?
69
+
70
+ FileUtils.mkdir_p File.dirname(payload_file)
71
+ File.open(payload_file, 'w'){ |f| f.write Oj.dump(payload, mode: :strict) }
72
+ end
73
+
74
+ def payload_file
75
+ @payload_file ||= File.join(@workspace, 'rspec', 'servers', @server.name, 'payload.json')
76
+ end
77
+
78
+ def publish_payload payload
79
+
80
+ puts Paint["Probe Dock - Sending payload to #{@server.api_url}...", :magenta]
81
+
82
+ begin
83
+ if @local_mode
84
+ puts Paint['Probe Dock - LOCAL MODE: not actually sending payload.', :yellow]
85
+ else
86
+ @server.upload payload
87
+ end
88
+ puts Paint["Probe Dock - Done!", :green]
89
+ true
90
+ rescue Server::Error => e
91
+ warn Paint["Probe Dock - Upload failed!", :red, :bold]
92
+ warn Paint["Probe Dock - #{e.message}", :red, :bold]
93
+ if e.response
94
+ warn Paint["Probe Dock - Dumping response body...", :red, :bold]
95
+ warn e.response.body
96
+ end
97
+ false
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,187 @@
1
+ require 'yaml'
2
+
3
+ # Utilities to send test results to Probe Dock.
4
+ module ProbeDockProbe
5
+
6
+ def self.config
7
+ @config ||= Config.new.tap(&:load!)
8
+ end
9
+
10
+ def self.configure options = {}
11
+
12
+ yield config if block_given?
13
+
14
+ config.check!
15
+ config.load_warnings.each{ |w| warn Paint["Probe Dock - #{w}", :yellow] }
16
+
17
+ config
18
+ end
19
+
20
+ class Config
21
+ # TODO: add silent/verbose option(s)
22
+ class Error < ProbeDockProbe::Error; end
23
+ attr_writer :publish, :local_mode, :print_payload, :save_payload
24
+ attr_reader :project, :server, :workspace, :load_warnings
25
+
26
+ def initialize
27
+ @servers = []
28
+ @server = Server.new
29
+ @project = Project.new
30
+ @publish, @local_mode, @print_payload, @save_payload = false, false, false, false
31
+ @load_warnings = []
32
+ end
33
+
34
+ def workspace= dir
35
+ @workspace = dir ? File.expand_path(dir) : nil
36
+ end
37
+
38
+ def servers
39
+ @servers.dup
40
+ end
41
+
42
+ %w(publish local_mode print_payload save_payload).each do |name|
43
+ define_method("#{name}?"){ instance_variable_get("@#{name}") }
44
+ end
45
+
46
+ def client_options
47
+ {
48
+ publish: @publish,
49
+ local_mode: @local_mode,
50
+ workspace: @workspace,
51
+ print_payload: @print_payload,
52
+ save_payload: @save_payload
53
+ }.select{ |k,v| !v.nil? }
54
+ end
55
+
56
+ def load!
57
+
58
+ @server.clear
59
+ @servers.clear
60
+
61
+ @load_warnings = []
62
+ return unless config = load_config_files
63
+
64
+ @publish = parse_env_flag :publish, !!config[:publish]
65
+ @server_name = parse_env_option(:server) || config[:server]
66
+ @local_mode = parse_env_flag(:local) || !!config[:local]
67
+
68
+ self.workspace = parse_env_option(:workspace) || config[:workspace]
69
+ @print_payload = parse_env_flag :print_payload, !!config[:payload][:print]
70
+ @save_payload = parse_env_flag :save_payload, !!config[:payload][:save]
71
+
72
+ @servers, server = build_servers config
73
+
74
+ if server
75
+ @server = server
76
+ else
77
+ @server.name = @server_name
78
+ end
79
+
80
+ {
81
+ api_url: parse_env_option(:server_api_url),
82
+ api_token: parse_env_option(:server_api_token),
83
+ project_api_id: parse_env_option(:server_project_api_id)
84
+ }.each{ |k,v| @server.send "#{k}=", v if v }
85
+
86
+ project_options = config[:project]
87
+ project_options.merge! api_id: @server.project_api_id if @server and @server.project_api_id
88
+ @project.update project_options
89
+
90
+ self
91
+ end
92
+
93
+ def check!
94
+
95
+ configs = [ home_config_file, working_config_file ]
96
+ actual_configs = configs.select{ |f| File.exists? f }
97
+
98
+ if actual_configs.empty?
99
+ @load_warnings << %|no config file found, looking for:\n #{configs.join "\n "}|
100
+ end
101
+
102
+ if @servers.empty?
103
+ @load_warnings << "No server defined"
104
+ elsif !@server_name && !@server.name
105
+ @load_warnings << "No server name given"
106
+ end
107
+ end
108
+
109
+ private
110
+
111
+ def build_servers config
112
+
113
+ default_server_options = { project_api_id: config[:project][:api_id] }
114
+ servers = config[:servers].inject({}) do |memo,(name, options)|
115
+ memo[name] = Server.new default_server_options.merge(options).merge(name: name)
116
+ memo
117
+ end
118
+
119
+ [ servers.values, servers[@server_name.to_s.strip] ]
120
+ end
121
+
122
+ def load_config_files
123
+
124
+ configs = [ home_config_file, working_config_file ]
125
+ actual_configs = configs.select{ |f| File.exists? f }
126
+ return false if actual_configs.empty?
127
+
128
+ actual_configs.collect!{ |f| YAML.load_file f }
129
+
130
+ actual_configs.inject({ servers: {} }) do |memo,yml|
131
+ memo.merge! parse_general_options(yml)
132
+
133
+ if yml['servers'].kind_of? Hash
134
+ yml['servers'].each_pair do |k,v|
135
+ if v.kind_of? Hash
136
+ memo[:servers][k] = (memo[:servers][k] || {}).merge(parse_server_options(v))
137
+ end
138
+ end
139
+ end
140
+
141
+ memo[:payload] = (memo[:payload] || {}).merge parse_payload_options(yml['payload'])
142
+ memo[:project] = (memo[:project] || {}).merge parse_project_options(yml['project'])
143
+
144
+ memo
145
+ end
146
+ end
147
+
148
+ def home_config_file
149
+ File.join File.expand_path('~'), '.probedock', 'config.yml'
150
+ end
151
+
152
+ def working_config_file
153
+ File.expand_path ENV['PROBE_DOCK_CONFIG'] || 'probedock.yml', Dir.pwd
154
+ end
155
+
156
+ def parse_env_flag name, default = false
157
+ val = parse_env_option name
158
+ val ? !!val.to_s.strip.match(/\A(1|y|yes|t|true)\Z/i) : default
159
+ end
160
+
161
+ def parse_env_option name
162
+ var = "PROBE_DOCK_#{name.upcase}"
163
+ ENV.key?(var) ? ENV[var] : nil
164
+ end
165
+
166
+ def parse_general_options h
167
+ parse_options h, %w(publish server local workspace)
168
+ end
169
+
170
+ def parse_server_options h
171
+ parse_options h, %w(name apiUrl apiToken apiVersion projectApiId)
172
+ end
173
+
174
+ def parse_payload_options h
175
+ parse_options h, %w(save print)
176
+ end
177
+
178
+ def parse_project_options h
179
+ parse_options h, %w(version apiId category tags tickets)
180
+ end
181
+
182
+ def parse_options h, keys
183
+ return {} unless h.kind_of? Hash
184
+ keys.inject({}){ |memo,k| memo[k.gsub(/(.)([A-Z])/, '\1_\2').downcase.to_sym] = h[k] if h.key?(k); memo }
185
+ end
186
+ end
187
+ end
@@ -0,0 +1,30 @@
1
+ module ProbeDockProbe
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
@@ -0,0 +1,59 @@
1
+ require 'oj'
2
+ require 'httparty'
3
+
4
+ module ProbeDockProbe
5
+
6
+ class Server
7
+ attr_accessor :name, :api_url, :api_token, :project_api_id
8
+
9
+ class Error < ProbeDockProbe::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
@@ -0,0 +1,62 @@
1
+ require 'fileutils'
2
+ require 'rake/tasklib'
3
+
4
+ module ProbeDockProbe
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 Probe Dock (stored in an environment variable)"
15
+ task :uid do
16
+ trace do
17
+ uid = uid_manager.generate_uid_to_env
18
+ puts Paint["Probe Dock - 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 Probe Dock (stored in a file)"
25
+ task :file do
26
+ trace do
27
+ uid = uid_manager.generate_uid_to_file
28
+ puts Paint["Probe Dock - 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["Probe Dock - 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["Probe Dock - #{e.message}", :red]
54
+ end
55
+ end
56
+ end
57
+
58
+ def uid_manager
59
+ UID.new ProbeDockProbe.config.client_options
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,18 @@
1
+ require 'fileutils'
2
+ require 'digest/sha2'
3
+
4
+ module ProbeDockProbe
5
+
6
+ class TestPayload
7
+
8
+ class Error < ProbeDockProbe::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
@@ -0,0 +1,112 @@
1
+ module ProbeDockProbe
2
+ class TestResult
3
+ attr_reader :key, :name, :category, :tags, :tickets, :data, :duration, :message
4
+
5
+ def initialize project, example, groups = [], options = {}
6
+
7
+ @category = project.category
8
+ @tags = project.tags
9
+ @tickets = project.tickets
10
+
11
+ @grouped = extract_grouped example, groups
12
+
13
+ [ :key, :name, :category, :tags, :tickets, :data ].each do |attr|
14
+ instance_variable_set "@#{attr}".to_sym, send("extract_#{attr}".to_sym, example, groups)
15
+ end
16
+
17
+ @passed = !!options[:passed]
18
+ @duration = options[:duration]
19
+ @message = options[:message]
20
+ end
21
+
22
+ def passed?
23
+ @passed
24
+ end
25
+
26
+ def grouped?
27
+ @grouped
28
+ end
29
+
30
+ def update options = {}
31
+ @passed &&= options[:passed]
32
+ @duration += options[:duration]
33
+ @message = [ @message, options[:message] ].select{ |m| m }.join("\n\n") if options[:message]
34
+ end
35
+
36
+ def to_h options = {}
37
+ {
38
+ 'p' => @passed,
39
+ 'd' => @duration
40
+ }.tap do |h|
41
+ h['k'] = @key if @key
42
+ h['m'] = @message if @message
43
+ h['n'] = @name
44
+ h['c'] = @category
45
+ h['g'] = @tags
46
+ h['t'] = @tickets
47
+ h['a'] = @data
48
+ end
49
+ end
50
+
51
+ def self.extract_grouped example, groups = []
52
+ !!groups.collect{ |g| meta(g)[:grouped] }.compact.last
53
+ end
54
+
55
+ def self.extract_key example, groups = []
56
+ (groups.collect{ |g| meta(g)[:key] } << meta(example)[:key]).compact.reject{ |k| k.strip.empty? }.last
57
+ end
58
+
59
+ def self.meta holder
60
+ meta = holder.metadata[:probe_dock] || {}
61
+ if meta.kind_of? String
62
+ { key: meta }
63
+ elsif meta.kind_of? Hash
64
+ meta
65
+ else
66
+ {}
67
+ end
68
+ end
69
+
70
+ private
71
+
72
+ def meta *args
73
+ self.class.meta *args
74
+ end
75
+
76
+ def extract_grouped *args
77
+ self.class.extract_grouped *args
78
+ end
79
+
80
+ def extract_key *args
81
+ self.class.extract_key *args
82
+ end
83
+
84
+ def extract_name example, groups = []
85
+ parts = groups.dup
86
+ parts = parts[0, parts.index{ |p| meta(p)[:grouped] } + 1] if @grouped
87
+ parts << example unless @grouped
88
+ parts.collect{ |p| p.description.strip }.join ' '
89
+ end
90
+
91
+ def extract_category example, groups = []
92
+ cat = (groups.collect{ |g| meta(g)[:category] }.unshift(@category) << meta(example)[:category]).compact.last
93
+ cat ? cat.to_s : nil
94
+ end
95
+
96
+ def extract_tags example, groups = []
97
+ (wrap(@tags) + groups.collect{ |g| wrap meta(g)[:tags] } + (wrap meta(example)[:tags])).flatten.compact.uniq.collect(&:to_s)
98
+ end
99
+
100
+ def extract_tickets example, groups = []
101
+ (wrap(@tickets) + groups.collect{ |g| wrap meta(g)[:tickets] } + (wrap meta(example)[:tickets])).flatten.compact.uniq.collect(&:to_s)
102
+ end
103
+
104
+ def extract_data example, groups = []
105
+ meta(example)[:data] || {}
106
+ end
107
+
108
+ def wrap a
109
+ a.kind_of?(Array) ? a : [ a ]
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,84 @@
1
+ module ProbeDockProbe
2
+
3
+ class TestRun
4
+ attr_reader :results, :project
5
+ attr_accessor :duration, :uid
6
+
7
+ def initialize project
8
+ @results = []
9
+ @project = project
10
+ end
11
+
12
+ def add_result example, groups = [], options = {}
13
+ if TestResult.extract_grouped(example, groups) and (existing_result = @results.find{ |r| r.grouped? && r.key == TestResult.extract_key(example, groups) })
14
+ existing_result.update options
15
+ else
16
+ @results << TestResult.new(@project, example, groups, options)
17
+ end
18
+ end
19
+
20
+ def results_without_key
21
+ @results.select{ |r| !r.key or r.key.to_s.strip.empty? }
22
+ end
23
+
24
+ def results_by_key
25
+ @results.inject({}) do |memo,r|
26
+ (memo[r.key] ||= []) << r unless !r.key or r.key.to_s.strip.empty?
27
+ memo
28
+ end
29
+ end
30
+
31
+ def to_h options = {}
32
+ validate!
33
+
34
+ {
35
+ 'projectId' => @project.api_id,
36
+ 'version' => @project.version,
37
+ 'duration' => @duration,
38
+ 'results' => @results.collect{ |r| r.to_h options }
39
+ }.tap do |h|
40
+ h['reports'] = [ { 'uid' => @uid } ] if @uid
41
+ end
42
+ end
43
+
44
+ private
45
+
46
+ def validate!
47
+ # TODO: validate duration
48
+
49
+ raise PayloadError.new("Missing project") if !@project
50
+ @project.validate!
51
+
52
+ # FIXME: log info/warnings
53
+ #validate_no_results_without_key
54
+ #validate_no_duplicate_keys
55
+ end
56
+
57
+ def validate_no_duplicate_keys
58
+
59
+ results_with_duplicate_key = results_by_key.select{ |k,r| r.length >= 2 }
60
+ return if results_with_duplicate_key.none?
61
+
62
+ msg = "the following keys are used by multiple test results".tap do |s|
63
+ results_with_duplicate_key.each_pair do |key,results|
64
+ s << "\n - #{key}"
65
+ results.each{ |r| s << "\n - #{r.name}" }
66
+ end
67
+ end
68
+
69
+ raise PayloadError.new(msg)
70
+ end
71
+
72
+ def validate_no_results_without_key
73
+
74
+ keyless = results_without_key
75
+ return if keyless.empty?
76
+
77
+ msg = "the following test results are missing a key".tap do |s|
78
+ keyless.each{ |r| s << "\n - #{r.name}" }
79
+ end
80
+
81
+ raise PayloadError.new(msg)
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,60 @@
1
+ require 'securerandom'
2
+
3
+ module ProbeDockProbe
4
+
5
+ class UID
6
+ ENVIRONMENT_VARIABLE = 'PROBE_DOCK_TEST_REPORT_UID'
7
+
8
+ class Error < ProbeDockProbe::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
@@ -0,0 +1 @@
1
+ require 'probe_dock_ruby'
metadata ADDED
@@ -0,0 +1,230 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: probedock-ruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Simon Oulevay (Alpha Hydrae)
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-07-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: oj
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: httparty
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.13'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.13'
41
+ - !ruby/object:Gem::Dependency
42
+ name: paint
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.1'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.1'
69
+ - !ruby/object:Gem::Dependency
70
+ name: jeweler
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '2.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '2.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake-version
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.4'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.4'
97
+ - !ruby/object:Gem::Dependency
98
+ name: simplecov
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.10'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.10'
111
+ - !ruby/object:Gem::Dependency
112
+ name: fakefs
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '0.6'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '0.6'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rspec
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '3.1'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '3.1'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rspec-its
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '1.2'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '1.2'
153
+ - !ruby/object:Gem::Dependency
154
+ name: rspec-collection_matchers
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '1.1'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '1.1'
167
+ - !ruby/object:Gem::Dependency
168
+ name: coveralls
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - "~>"
172
+ - !ruby/object:Gem::Version
173
+ version: '0.8'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: '0.8'
181
+ description: Ruby library to develop new probes for Probe Dock. It can parse Probe
182
+ Dock configuration files, collect test results and publish them to a Probe Dock
183
+ server.
184
+ email: devops@probedock.io
185
+ executables: []
186
+ extensions: []
187
+ extra_rdoc_files:
188
+ - LICENSE.txt
189
+ - README.md
190
+ files:
191
+ - Gemfile
192
+ - LICENSE.txt
193
+ - README.md
194
+ - VERSION
195
+ - lib/probe_dock_ruby.rb
196
+ - lib/probe_dock_ruby/client.rb
197
+ - lib/probe_dock_ruby/config.rb
198
+ - lib/probe_dock_ruby/project.rb
199
+ - lib/probe_dock_ruby/server.rb
200
+ - lib/probe_dock_ruby/tasks.rb
201
+ - lib/probe_dock_ruby/test_payload.rb
202
+ - lib/probe_dock_ruby/test_result.rb
203
+ - lib/probe_dock_ruby/test_run.rb
204
+ - lib/probe_dock_ruby/uid.rb
205
+ - lib/probedock-ruby.rb
206
+ homepage: https://github.com/probedock/probedock-ruby
207
+ licenses:
208
+ - MIT
209
+ metadata: {}
210
+ post_install_message:
211
+ rdoc_options: []
212
+ require_paths:
213
+ - lib
214
+ required_ruby_version: !ruby/object:Gem::Requirement
215
+ requirements:
216
+ - - ">="
217
+ - !ruby/object:Gem::Version
218
+ version: '0'
219
+ required_rubygems_version: !ruby/object:Gem::Requirement
220
+ requirements:
221
+ - - ">="
222
+ - !ruby/object:Gem::Version
223
+ version: '0'
224
+ requirements: []
225
+ rubyforge_project:
226
+ rubygems_version: 2.4.8
227
+ signing_key:
228
+ specification_version: 4
229
+ summary: Ruby library to develop new probes for Probe Dock.
230
+ test_files: []