rspec2db 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.project +12 -0
- data/.rspec +2 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +57 -0
- data/README.md +139 -0
- data/bin/rspec2db +118 -0
- data/config/rspec2db.yml +13 -0
- data/config/rspec_db.rb +44 -0
- data/lib/rspec2db/db/build_execution_stats.rb +60 -0
- data/lib/rspec2db/db/migrations/2_add_test_case_screenshots.rb +10 -0
- data/lib/rspec2db/db/schema.rb +53 -0
- data/lib/rspec2db/models/test_case.rb +3 -0
- data/lib/rspec2db/models/test_run.rb +4 -0
- data/lib/rspec2db/models/test_suite.rb +3 -0
- data/lib/rspec2db/utils/db_utils.rb +99 -0
- data/lib/rspec2db/utils/rspec_configuration_helper.rb +127 -0
- data/lib/rspec2db.rb +106 -0
- data/rspec2db.gemspec +18 -0
- data/spec/spec_spec.rb +19 -0
- metadata +125 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 46aed6e716b94e2dffdba843c02777e90583f97e
|
4
|
+
data.tar.gz: c75c5d8efa246d8b7c6f8878087df2c8397e6a61
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b5cc9b7c8f0ce9c459375c55d6ecc5c88a25b492c023158838e071e00b580bec846b694f38a6b3eb8438ee54f7676cf4692405ab09c66db150203351a08ff262
|
7
|
+
data.tar.gz: af16bda7290716021632416ab48cda8eef50a09176575d539b0ea4d35a91ab332e13f27f0cf6716f8e9736fa5b6748247c1d267b8ed72159b2c5ede5c51b8139
|
data/.gitignore
ADDED
data/.project
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<projectDescription>
|
3
|
+
<name>rspec2db git</name>
|
4
|
+
<comment></comment>
|
5
|
+
<projects>
|
6
|
+
</projects>
|
7
|
+
<buildSpec>
|
8
|
+
</buildSpec>
|
9
|
+
<natures>
|
10
|
+
<nature>com.aptana.ruby.core.rubynature</nature>
|
11
|
+
</natures>
|
12
|
+
</projectDescription>
|
data/.rspec
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
rspec2db (1.2.0)
|
5
|
+
activerecord (~> 5.1)
|
6
|
+
activerecord-postgresql-adapter
|
7
|
+
pg (~> 0.21)
|
8
|
+
rspec (>= 3.0)
|
9
|
+
|
10
|
+
GEM
|
11
|
+
remote: http://rubygems.org/
|
12
|
+
specs:
|
13
|
+
activemodel (5.2.0)
|
14
|
+
activesupport (= 5.2.0)
|
15
|
+
activerecord (5.2.0)
|
16
|
+
activemodel (= 5.2.0)
|
17
|
+
activesupport (= 5.2.0)
|
18
|
+
arel (>= 9.0)
|
19
|
+
activerecord-postgresql-adapter (0.0.1)
|
20
|
+
pg
|
21
|
+
activesupport (5.2.0)
|
22
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
23
|
+
i18n (>= 0.7, < 2)
|
24
|
+
minitest (~> 5.1)
|
25
|
+
tzinfo (~> 1.1)
|
26
|
+
arel (9.0.0)
|
27
|
+
concurrent-ruby (1.0.5)
|
28
|
+
diff-lcs (1.3)
|
29
|
+
i18n (1.0.1)
|
30
|
+
concurrent-ruby (~> 1.0)
|
31
|
+
minitest (5.11.3)
|
32
|
+
pg (0.21.0)
|
33
|
+
rspec (3.7.0)
|
34
|
+
rspec-core (~> 3.7.0)
|
35
|
+
rspec-expectations (~> 3.7.0)
|
36
|
+
rspec-mocks (~> 3.7.0)
|
37
|
+
rspec-core (3.7.1)
|
38
|
+
rspec-support (~> 3.7.0)
|
39
|
+
rspec-expectations (3.7.0)
|
40
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
41
|
+
rspec-support (~> 3.7.0)
|
42
|
+
rspec-mocks (3.7.0)
|
43
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
44
|
+
rspec-support (~> 3.7.0)
|
45
|
+
rspec-support (3.7.1)
|
46
|
+
thread_safe (0.3.6)
|
47
|
+
tzinfo (1.2.5)
|
48
|
+
thread_safe (~> 0.1)
|
49
|
+
|
50
|
+
PLATFORMS
|
51
|
+
ruby
|
52
|
+
|
53
|
+
DEPENDENCIES
|
54
|
+
rspec2db!
|
55
|
+
|
56
|
+
BUNDLED WITH
|
57
|
+
1.16.1
|
data/README.md
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
rspec2db: RSpec DB Formatter
|
2
|
+
============================
|
3
|
+
|
4
|
+
|
5
|
+
## Description
|
6
|
+
rspec2db is a Ruby gem used for storing rspec test execution results to a database. This gem extends RSpec formatter and has to be required in `.rspec` (which is done by rspec2db init command described below). Once added, the gem will handle storing all test related informations (test suites, test cases, test steps) into the database. By default, rspec2db supports writing to postgresql database but can be easily adjusted to write results into other relational databases as well since it uses ActiveRecord for persisting data.
|
7
|
+
|
8
|
+
The gem also provides a CLI tool meant for bootstrapping rspec2db configuration files.
|
9
|
+
|
10
|
+
|
11
|
+
## Rspec2DB CLI
|
12
|
+
|
13
|
+
Rspec2db provides a CLI tool that helps users with bootstraping by generating configuration files.
|
14
|
+
|
15
|
+
```
|
16
|
+
$ rspec2db
|
17
|
+
Loading default rspec2db configuration.
|
18
|
+
Using project config file
|
19
|
+
No command provided
|
20
|
+
Usage: rspec2db [options] <command>
|
21
|
+
|
22
|
+
init - initialize rspec2db config file (~/rspec2db.yaml)
|
23
|
+
create - creates rspec2db database
|
24
|
+
migrate - migrates rspec2db database
|
25
|
+
build-stats - extracts test run execution based on test run id
|
26
|
+
|
27
|
+
Options:
|
28
|
+
-H, --host=h rspec2db database host
|
29
|
+
-p, --port=port rspec2db database port
|
30
|
+
-d, --database=db rspec2db database name
|
31
|
+
-u, --username=u rspec2db database username
|
32
|
+
-w, --password=pw rspec2db database user password
|
33
|
+
-a, --adapter=ad rspec2db database adapter
|
34
|
+
-h, --help rspec2db help
|
35
|
+
```
|
36
|
+
### Usage
|
37
|
+
The tool provides number of options for onboarding:
|
38
|
+
1. `init` - Initialization of a global configuration file (stored in the home directory) with predefined configuration that can be modified (ie. values in `~/rspec2db.yaml` should be changed to appropriate values). This will also add Rspec2db formater to your spec `.rspec` file.
|
39
|
+
2. `create` - Rake-like task that will create and seed the db.
|
40
|
+
3. `migrate` - Rake-like task that will migrate latest changes to the db
|
41
|
+
3. `build-stats` - Export of Test execution results and statistics for a Test build
|
42
|
+
|
43
|
+
### Example
|
44
|
+
|
45
|
+
```
|
46
|
+
$ rspec2db init
|
47
|
+
Loading default rspec2db configuration.
|
48
|
+
Using project config file
|
49
|
+
No rspec2db config specified in .rspec
|
50
|
+
Loading default rspec2db options (/Users/user/rspec2db.yaml)
|
51
|
+
Creating default rspec2db config file (/Users/user/rspec2db.yaml)
|
52
|
+
Adding rspec2db options and formatter to .rspec
|
53
|
+
```
|
54
|
+
|
55
|
+
```
|
56
|
+
# Edit ~/rspec2db.yaml to use your PG database. Database has to exist before running create task.
|
57
|
+
$ rspec2db create
|
58
|
+
Loading default rspec2db configuration.
|
59
|
+
No project file detected. Looking for local config file
|
60
|
+
-- create_table(:test_suites, {:force=>:cascade})
|
61
|
+
-> 0.1380s
|
62
|
+
-- create_table(:test_runs, {:force=>:cascade})
|
63
|
+
-> 0.0513s
|
64
|
+
-- create_table(:test_cases, {:force=>:cascade})
|
65
|
+
-> 0.0425s
|
66
|
+
```
|
67
|
+
|
68
|
+
```
|
69
|
+
# Migrate changes
|
70
|
+
$ rspec2db migrate
|
71
|
+
Loading default rspec2db configuration.
|
72
|
+
No project file detected. Looking for local config file
|
73
|
+
```
|
74
|
+
|
75
|
+
This flow will result in a configured PG Database and a configuration file that can be used among different projects.
|
76
|
+
|
77
|
+
|
78
|
+
To reuse the existing configuration file in a separate rspec spec project, simply run `rspec init`. This will configure your `.rspec` file:
|
79
|
+
`
|
80
|
+
```$ rspec2db init
|
81
|
+
bundle exec rspec2db init
|
82
|
+
Loading default rspec2db configuration.
|
83
|
+
No project file detected. Looking for local config file
|
84
|
+
No rspec2db config specified in .rspec
|
85
|
+
Loading default rspec2db options (/Users/user/rspec2db.yaml)
|
86
|
+
Default config file exists, override with default? (Y/N)
|
87
|
+
N
|
88
|
+
Adding rspec2db options and formatter to .rspec
|
89
|
+
```
|
90
|
+
|
91
|
+
## Other
|
92
|
+
Rspec2DB CLI commands load the rspec2db configuration file that is either defined in the `.rspec` file in your spec directory, or loads the default configuration file in your home directory.
|
93
|
+
Default configuration (from the `rspec2db.yaml`) can be overriden using the provided CLI options for targeting a specific DB (ie. by providing host, port, db credentials and similar).
|
94
|
+
|
95
|
+
### Using the formatter
|
96
|
+
`rspec2db init` will add `rspec2db` formatter to `.rspec` file, resulting in every spec that is ran by `rspec spec/*` to be written to the database (in the format of test suites, test cases and test steps).
|
97
|
+
|
98
|
+
#### Retrieve results from database
|
99
|
+
|
100
|
+
To retrieve test results from the database, you can use RSpec2DB CLI command `build-stats`.
|
101
|
+
To execute the script, run the following command:
|
102
|
+
```
|
103
|
+
$ rspec2db build-stats --help
|
104
|
+
Loading default rspec2db configuration.
|
105
|
+
No project file detected. Looking for local config file
|
106
|
+
Usage: rspec2db [options]
|
107
|
+
-i, --id=id rspec2db test build id
|
108
|
+
-o, --output file rspec2db extract output file
|
109
|
+
-l, --limit [LIMIT] rspec2db number of extracted test runs
|
110
|
+
-s, --suite suite rspec2db test suite
|
111
|
+
-U [url]--URL [url] Test Reporter (www.github.com/ATLANTBH/owl) url link
|
112
|
+
|
113
|
+
```
|
114
|
+
|
115
|
+
|
116
|
+
To execute the script with all optional parameters, run the following command:
|
117
|
+
|
118
|
+
```
|
119
|
+
rspec2db build-stats -i <build_number> -l <limit> -o <output_file> -s <test_suite> -U <reporter_url>
|
120
|
+
```
|
121
|
+
|
122
|
+
- build_number is a user specified value which needs to be the same like the one found in rspec2db.yml configuration file
|
123
|
+
- output_file is name of the file in which results are written
|
124
|
+
- limit (optional) determines if the statistics will be calculated for a single run with same build_number or for all runs with same build_number:
|
125
|
+
- not specified - results for only one run (the first one) will be in the results file
|
126
|
+
- all - results for all runs will be in the results file
|
127
|
+
- test_suite is the name of the suite from which we want to query results
|
128
|
+
- reporter_url (optional) is the url of the Test Reporter tool which can be used in conjunction with rspec2db gem. If you use this parameter, you need to specify base url of your Test Reporter instance (for example: http://testreporter:8080). Based on this url, script will generate exact url path to this specific run which contains list of tests that have been executed
|
129
|
+
- suite_name - name of the test suite that was specified in `rspec2db.yml` file and for which the stats are calculated
|
130
|
+
|
131
|
+
|
132
|
+
### Updating Rspec2DB gem version
|
133
|
+
|
134
|
+
If you are updating Rspec2DB gem from a to a newer version, running `rspec2db migrate` is required. This command will migrate the database so that it satisfies the Rspec2DB model, if it was changed.
|
135
|
+
|
136
|
+
```
|
137
|
+
$ bundle update rspec2db
|
138
|
+
$ bundle exec rspec2db migrate
|
139
|
+
```
|
data/bin/rspec2db
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'optparse'
|
3
|
+
require 'yaml'
|
4
|
+
require 'fileutils'
|
5
|
+
require_relative '../lib/rspec2db/utils/db_utils'
|
6
|
+
require_relative '../lib/rspec2db/utils/rspec_configuration_helper'
|
7
|
+
|
8
|
+
def check_required_options(required_options, options)
|
9
|
+
missing_options = required_options - options.keys.map { |k| k.to_s }
|
10
|
+
abort 'Missing required options: ' + missing_options.reduce { |m, k| m + ', ' + k } unless missing_options.empty?
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse_extract_command
|
14
|
+
options = {}
|
15
|
+
required_options = ['id', 'file', 'suite']
|
16
|
+
extract_options = OptionParser.new do |opts|
|
17
|
+
opts.on('-i id', '--id=id', 'rspec2db test build id') do |id|
|
18
|
+
options[:id] = id
|
19
|
+
end
|
20
|
+
|
21
|
+
opts.on('-o file', '--output file', 'rspec2db extract output file') do |f|
|
22
|
+
options[:file] = f
|
23
|
+
end
|
24
|
+
|
25
|
+
opts.on('-l [LIMIT]', '--limit [LIMIT]', 'rspec2db number of extracted test runs') do |l|
|
26
|
+
options[:limit] = l || nil
|
27
|
+
end
|
28
|
+
|
29
|
+
opts.on('-s suite', '--suite suite', 'rspec2db test suite') do |suite|
|
30
|
+
options[:suite] = suite
|
31
|
+
end
|
32
|
+
|
33
|
+
opts.on('-U [url]' '--URL [url]', 'Test Reporter (www.github.com/ATLANTBH/owl) url link') do |url|
|
34
|
+
options[:url] = url
|
35
|
+
end
|
36
|
+
end
|
37
|
+
extract_options.parse!
|
38
|
+
check_required_options(required_options, options)
|
39
|
+
[options, extract_options]
|
40
|
+
end
|
41
|
+
|
42
|
+
def parse_options(load_local = true)
|
43
|
+
options = {}
|
44
|
+
required_options = ['username', 'password', 'host', 'port', 'database']
|
45
|
+
|
46
|
+
option_parser = OptionParser.new do |opts|
|
47
|
+
opts.banner = "Usage: rspec2db [options] <command>\n" + \
|
48
|
+
"\ninit - initialize rspec2db config file (" + ENV['PWD'] + "/rspec2db.yaml)" \
|
49
|
+
"\ncreate - creates rspec2db database" + \
|
50
|
+
"\nmigrate - migrates rspec2db database" + \
|
51
|
+
"\nbuild-stats - extracts test run execution based on test run id" + \
|
52
|
+
"\n\nOptions:"
|
53
|
+
|
54
|
+
opts.on('-H h', '--host=h', 'rspec2db database host') do |h|
|
55
|
+
options[:host] = h
|
56
|
+
end
|
57
|
+
|
58
|
+
opts.on('-p port', '--port=port', 'rspec2db database port') do |port|
|
59
|
+
options[:port] = port
|
60
|
+
end
|
61
|
+
|
62
|
+
opts.on('-d db', '--database=db', 'rspec2db database name') do |db|
|
63
|
+
options[:database] = db
|
64
|
+
end
|
65
|
+
|
66
|
+
opts.on('-u u', '--username=u', 'rspec2db database username') do |u|
|
67
|
+
options[:username] = u
|
68
|
+
end
|
69
|
+
|
70
|
+
opts.on('-w pw', '--password=pw', 'rspec2db database user password') do |pw|
|
71
|
+
options[:password] = pw
|
72
|
+
end
|
73
|
+
|
74
|
+
opts.on('-a ad', '--adapter=ad', 'rspec2db database adapter') do |ad|
|
75
|
+
options[:adapter] = ad
|
76
|
+
end
|
77
|
+
|
78
|
+
opts.on('-h', '--help', 'rspec2db help') do |h|
|
79
|
+
options[:help] = h
|
80
|
+
end
|
81
|
+
end
|
82
|
+
option_parser.order!
|
83
|
+
return [options, option_parser] unless options.empty?
|
84
|
+
|
85
|
+
if options.empty?
|
86
|
+
puts 'Loading rspec2db configuration.'
|
87
|
+
options = RSpecConfigurationHelper.load_local_config
|
88
|
+
end
|
89
|
+
|
90
|
+
check_required_options(required_options, options)
|
91
|
+
options[:adapter] = 'postgresql' if options[:adapter].nil?
|
92
|
+
|
93
|
+
[options, option_parser]
|
94
|
+
end
|
95
|
+
|
96
|
+
options, option_parser = parse_options
|
97
|
+
command = ARGV[0]
|
98
|
+
case command
|
99
|
+
when 'init'
|
100
|
+
puts 'No .rspec file found in working directory' if options.nil?
|
101
|
+
when 'create'
|
102
|
+
DBUtils.create_rspec_db options
|
103
|
+
when 'migrate'
|
104
|
+
DBUtils.migrate_rspec_db options
|
105
|
+
when 'build-stats'
|
106
|
+
build_options, extract_option_parser = parse_extract_command
|
107
|
+
if build_options.empty?
|
108
|
+
puts extract_option_parser
|
109
|
+
else
|
110
|
+
DBUtils.build_stats build_options[:id], build_options[:file], build_options[:limit], build_options[:suite], options, build_options[:url]
|
111
|
+
end
|
112
|
+
when nil
|
113
|
+
puts 'No command provided'
|
114
|
+
puts option_parser
|
115
|
+
else
|
116
|
+
puts 'Command unknown.'
|
117
|
+
puts option_parser
|
118
|
+
end
|
data/config/rspec2db.yml
ADDED
data/config/rspec_db.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'yaml'
|
3
|
+
require 'active_record'
|
4
|
+
|
5
|
+
dbconfig = YAML::load(File.open('./rspec2db.yml'))
|
6
|
+
ActiveRecord::Base.establish_connection(dbconfig["dbconnection"])
|
7
|
+
|
8
|
+
ActiveRecord::Base.transaction do
|
9
|
+
|
10
|
+
ActiveRecord::Migration.create_table :test_suites do |t|
|
11
|
+
t.string :suite
|
12
|
+
t.timestamps
|
13
|
+
end
|
14
|
+
|
15
|
+
ActiveRecord::Migration.create_table :test_runs do |t|
|
16
|
+
t.float :duration
|
17
|
+
t.integer :example_count
|
18
|
+
t.integer :failure_count
|
19
|
+
t.integer :pending_count
|
20
|
+
t.string :build
|
21
|
+
t.string :computer_name
|
22
|
+
t.string :environment
|
23
|
+
t.string :git_hash
|
24
|
+
t.string :git_branch
|
25
|
+
t.timestamps
|
26
|
+
t.references :test_suites
|
27
|
+
end
|
28
|
+
|
29
|
+
ActiveRecord::Migration.create_table :test_cases do |t|
|
30
|
+
t.string :test_group
|
31
|
+
t.string :context
|
32
|
+
t.string :description
|
33
|
+
t.string :execution_result
|
34
|
+
t.string :screenshot_path
|
35
|
+
t.string :screenshot_url
|
36
|
+
t.text :exception
|
37
|
+
t.string :pending_message
|
38
|
+
t.float :duration
|
39
|
+
t.text :backtrace
|
40
|
+
t.text :metadata
|
41
|
+
t.timestamps
|
42
|
+
t.references :test_runs
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'yaml'
|
3
|
+
require 'active_record'
|
4
|
+
|
5
|
+
module DBUtils
|
6
|
+
def self.build_stats(build_id, file_name, limit, suite, config, reporter_url = 'http://localhost/')
|
7
|
+
ActiveRecord::Base.establish_connection(config)
|
8
|
+
if limit == nil
|
9
|
+
@query = "select tr.* from test_runs tr, test_suites ts where ts.id = tr.test_suites_id and tr.build LIKE '#{build_id}' and ts.suite LIKE '#{suite}' order by tr.created_at desc limit 1"
|
10
|
+
elsif limit == 'all'
|
11
|
+
@query = "select tr.* from test_runs tr, test_suites ts where ts.id = tr.test_suites_id and tr.build LIKE '#{build_id}' and ts.suite LIKE '#{suite}' order by tr.created_at desc"
|
12
|
+
else
|
13
|
+
raise Exception, 'Invalid parameter value.'
|
14
|
+
end
|
15
|
+
|
16
|
+
report = "Execution stats:\n"
|
17
|
+
report << "----------------\n"
|
18
|
+
|
19
|
+
@build = ""
|
20
|
+
@success_rate = []
|
21
|
+
@test_steps_count = 0
|
22
|
+
@test_steps_pass_count = 0
|
23
|
+
@test_steps_failed_count = 0
|
24
|
+
@duration = 0
|
25
|
+
@test_run_id = 0
|
26
|
+
|
27
|
+
@test_runs = TestRun.find_by_sql(@query)
|
28
|
+
@test_runs.each do |test_run|
|
29
|
+
@success_rate << ((test_run.example_count.to_i - test_run.failure_count.to_i).to_f / test_run.example_count.to_f) * 100
|
30
|
+
@test_steps_count = @test_steps_count + test_run.example_count
|
31
|
+
@test_steps_pass_count = @test_steps_pass_count + (test_run.example_count.to_i - test_run.failure_count.to_i)
|
32
|
+
@test_steps_failed_count = @test_steps_failed_count + test_run.failure_count
|
33
|
+
if test_run.duration>@duration
|
34
|
+
@duration = test_run.duration
|
35
|
+
end
|
36
|
+
@build = test_run.build
|
37
|
+
@test_run_id = test_run.id
|
38
|
+
end
|
39
|
+
|
40
|
+
@rate = ( @test_steps_pass_count.to_f / @test_steps_count.to_f ) * 100
|
41
|
+
@formatted_rate = sprintf('%.2f', @rate.to_f)
|
42
|
+
@formatted_duration = sprintf('%.2f', @duration.to_f)
|
43
|
+
|
44
|
+
if reporter_url == nil
|
45
|
+
File.open(file_name, 'w') { |f| f.write("#{report}Build name: #{@build}\nDuration: #{@formatted_duration}s\nSuccess rate: #{@formatted_rate}%\nTest steps count: #{@test_steps_count}\nTest steps passed: #{@test_steps_pass_count}\nTest steps failed: #{@test_steps_failed_count}\n") }
|
46
|
+
else
|
47
|
+
File.open(file_name, 'w') { |f| f.write("#{report}Build name: #{@build}\nDuration: #{@formatted_duration}s\nSuccess rate: #{@formatted_rate}%\nTest steps count: #{@test_steps_count}\nTest steps passed: #{@test_steps_pass_count}\nTest steps failed: #{@test_steps_failed_count}\nTest reporter page: #{reporter_url}/test-runs/#{@test_run_id}/test-cases\n") }
|
48
|
+
end
|
49
|
+
|
50
|
+
sql = "select count(tc.test_group) from test_suites ts, test_runs tr, test_cases tc where ts.id=tr.test_suites_id and tr.id=tc.test_runs_id and tr.build='#{build_id}' and ts.suite='#{suite}' group by tc.test_group"
|
51
|
+
number_of_scripts = TestRun.find_by_sql(sql)
|
52
|
+
|
53
|
+
File.open(file_name, 'a') { |f| f.puts "Number of test scripts: #{number_of_scripts.count}"}
|
54
|
+
|
55
|
+
sql_failed="select count(tc.test_group) from test_suites ts, test_runs tr, test_cases tc where ts.id=tr.test_suites_id and tr.id=tc.test_runs_id and tr.build='#{build_id}' and ts.suite='#{suite}' and tc.execution_result='failed' group by tc.test_group"
|
56
|
+
|
57
|
+
number_of_failed_scripts=TestRun.find_by_sql(sql_failed)
|
58
|
+
File.open(file_name, 'a') { |f| f.puts "Number of failed scripts: #{number_of_failed_scripts.count}"}
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require "active_record"
|
3
|
+
|
4
|
+
class AddTestCaseScreenshots < ActiveRecord::Migration[5.2]
|
5
|
+
def self.up
|
6
|
+
add_column :test_cases, :screenshot_path, :string
|
7
|
+
add_column :test_cases, :screenshot_url, :string
|
8
|
+
add_column :test_runs, :environment, :string
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'yaml'
|
3
|
+
require 'active_record'
|
4
|
+
|
5
|
+
module DBUtils
|
6
|
+
def self.create_rspec_db(dbconfig)
|
7
|
+
ActiveRecord::Base.establish_connection(dbconfig)
|
8
|
+
|
9
|
+
ActiveRecord::Schema.define(version: 1) do
|
10
|
+
create_table :test_suites, force: :cascade do |t|
|
11
|
+
t.string :suite
|
12
|
+
t.timestamps
|
13
|
+
end
|
14
|
+
|
15
|
+
create_table :test_runs, force: :cascade do |t|
|
16
|
+
t.float :duration
|
17
|
+
t.integer :example_count
|
18
|
+
t.integer :failure_count
|
19
|
+
t.integer :pending_count
|
20
|
+
t.string :build
|
21
|
+
t.string :computer_name
|
22
|
+
t.string :environment
|
23
|
+
t.string :git_hash
|
24
|
+
t.string :git_branch
|
25
|
+
t.timestamps
|
26
|
+
t.references :test_suites
|
27
|
+
end
|
28
|
+
|
29
|
+
create_table :test_cases, force: :cascade do |t|
|
30
|
+
t.string :test_group
|
31
|
+
t.string :context
|
32
|
+
t.string :description
|
33
|
+
t.string :execution_result
|
34
|
+
t.string :screenshot_path
|
35
|
+
t.string :screenshot_url
|
36
|
+
t.text :exception
|
37
|
+
t.string :pending_message
|
38
|
+
t.float :duration
|
39
|
+
t.text :backtrace
|
40
|
+
t.text :metadata
|
41
|
+
t.timestamps
|
42
|
+
t.references :test_runs
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.migrate_rspec_db(dbconfig)
|
48
|
+
ActiveRecord::Base.establish_connection(dbconfig)
|
49
|
+
migrations_path = Bundler.rubygems.find_name('rspec2db').first.full_gem_path + '/lib/rspec2db/db/migrations'
|
50
|
+
migration_context = ActiveRecord::MigrationContext.new(migrations_path)
|
51
|
+
migration_context.migrate
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require_relative 'rspec_configuration_helper'
|
3
|
+
require_relative '../db/schema.rb'
|
4
|
+
require_relative '../db/build_execution_stats'
|
5
|
+
require_relative '../models/test_case'
|
6
|
+
require_relative '../models/test_run'
|
7
|
+
require_relative '../models/test_suite'
|
8
|
+
|
9
|
+
module DBUtils
|
10
|
+
include RSpecConfigurationHelper
|
11
|
+
|
12
|
+
def connect_to_db(config)
|
13
|
+
ActiveRecord::Base.establish_connection(config['dbconnection'])
|
14
|
+
ActiveRecord::Base.default_timezone = :local
|
15
|
+
end
|
16
|
+
|
17
|
+
def create_test_suite(config)
|
18
|
+
begin
|
19
|
+
test_suite = TestSuite.find_or_create_by(suite: config['options']['suite'])
|
20
|
+
rescue ActiveRecord::RecordNotUnique => active_record_error
|
21
|
+
puts active_record_error
|
22
|
+
test_suite = TestSuite.find_by(suite: config['options']['suite'])
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def create_test_run(test_suite, config, global_file_lock = '/tmp/.rspec2db.yaml')
|
27
|
+
test_run_hash = {
|
28
|
+
build: config['options']['build'],
|
29
|
+
test_suites_id: test_suite.id,
|
30
|
+
git_hash: config['options']['git_commit'],
|
31
|
+
git_branch: config['options']['git_branch'],
|
32
|
+
environment: config['options']['environment']
|
33
|
+
}
|
34
|
+
global_lock = File.new(global_file_lock, File::CREAT | File::TRUNC)
|
35
|
+
|
36
|
+
begin
|
37
|
+
global_lock.flock(File::LOCK_EX)
|
38
|
+
test_run = TestRun.where(test_run_hash).first || TestRun.create(test_run_hash)
|
39
|
+
global_lock.flock(File::LOCK_UN)
|
40
|
+
rescue Exception => e
|
41
|
+
puts e.message
|
42
|
+
puts e.backtrace
|
43
|
+
ensure
|
44
|
+
global_lock.flock(File::LOCK_UN)
|
45
|
+
end
|
46
|
+
test_run
|
47
|
+
end
|
48
|
+
|
49
|
+
def create_test_case(test_run, example_group, example, backtrace = nil, screenshot_event = nil)
|
50
|
+
example
|
51
|
+
test_case = TestCase.create(
|
52
|
+
test_runs_id: test_run.id,
|
53
|
+
test_group: example_group.top_level_description,
|
54
|
+
description: example.description,
|
55
|
+
execution_result: example.execution_result.status,
|
56
|
+
duration: example.execution_result.run_time,
|
57
|
+
pending_message: example.execution_result.pending_message.to_s,
|
58
|
+
exception: example.execution_result.exception.to_s)
|
59
|
+
|
60
|
+
if backtrace && !example.execution_result.exception.nil? && !example.execution_result.exception.backtrace.nil?
|
61
|
+
File.open('/tmp/output', 'w'){ |w| w.write(example.execution_result.exception.backtrace) }
|
62
|
+
test_case.update_attributes(
|
63
|
+
backtrace: example.execution_result.exception.backtrace.join('\n'),
|
64
|
+
metadata: print_example_failed_content(example)
|
65
|
+
)
|
66
|
+
end
|
67
|
+
|
68
|
+
if !example_group.top_level? # check for detecting Context (as opposed to Describe group)
|
69
|
+
test_case.update_attributes(
|
70
|
+
context: example_group.description
|
71
|
+
)
|
72
|
+
end
|
73
|
+
if screenshot_event[:example] && screenshot_event[:example] == example.description
|
74
|
+
screenshot_event.delete :example
|
75
|
+
test_case.update_attributes screenshot_event
|
76
|
+
screenshot_event = {}
|
77
|
+
end
|
78
|
+
test_case
|
79
|
+
end
|
80
|
+
|
81
|
+
def update_test_run(test_run, summary, global_file_lock = nil)
|
82
|
+
global_lock = File.new(global_file_lock, File::CREAT | File::TRUNC)
|
83
|
+
begin
|
84
|
+
global_lock.flock(File::LOCK_EX)
|
85
|
+
test_run.reload
|
86
|
+
test_run.increment(:example_count, summary.example_count)
|
87
|
+
.increment(:failure_count, summary.failure_count)
|
88
|
+
.increment(:pending_count, summary.pending_count)
|
89
|
+
.increment(:duration, summary.duration)
|
90
|
+
.save!
|
91
|
+
global_lock.flock(File::LOCK_UN)
|
92
|
+
rescue Exception => e
|
93
|
+
puts e.message
|
94
|
+
puts e.backtrace
|
95
|
+
ensure
|
96
|
+
global_lock.flock(File::LOCK_UN)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
module RSpecConfigurationHelper
|
2
|
+
def self.load_config(failsafe = true)
|
3
|
+
rspec_file = '.rspec'
|
4
|
+
file_path = nil
|
5
|
+
File.open(rspec_file).each do |line|
|
6
|
+
file_path = line.split('--options ').last.strip if line.match '--options\s?.+ya?ml'
|
7
|
+
end
|
8
|
+
|
9
|
+
if file_path.nil?
|
10
|
+
puts 'No rspec2db config specified in .rspec'
|
11
|
+
return nil
|
12
|
+
elsif !File.exists?(file_path)
|
13
|
+
puts 'could not find the config file at the following location: ' + file_path
|
14
|
+
abort 'exiting... please check your config file' if failsafe
|
15
|
+
nil
|
16
|
+
else
|
17
|
+
config = YAML::load(File.open(file_path))
|
18
|
+
config['file_path'] = file_path
|
19
|
+
config
|
20
|
+
end
|
21
|
+
# Bakir: disabled override by environment variables because it can cause unwanted side-effects
|
22
|
+
#(for example: env variable defined by specific name like BUILD can override what user defined in rspec2db.yaml)
|
23
|
+
#override_default_config config
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.generate_local_config(rspec2db_config_file)
|
27
|
+
if File.exist?(rspec2db_config_file)
|
28
|
+
puts 'Default config file exists, override with default? (Y/N)'
|
29
|
+
override = STDIN.gets.chomp
|
30
|
+
return if override == 'N' || override == 'n'
|
31
|
+
end
|
32
|
+
|
33
|
+
puts 'Creating default rspec2db config file (' + rspec2db_config_file + ')'
|
34
|
+
rspec2db_bundler_path = Bundler.rubygems.find_name('rspec2db').first.full_gem_path
|
35
|
+
rspec2db_config_src = rspec2db_bundler_path + '/config/rspec2db.yml'
|
36
|
+
FileUtils.cp rspec2db_config_src, rspec2db_config_file
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.load_local_config
|
40
|
+
rspec2db_default_config_file = './rspec2db.yaml'
|
41
|
+
rspec2db_project_config = RSpecConfigurationHelper.load_config
|
42
|
+
rspec_options_file = '.rspec'
|
43
|
+
unless rspec2db_project_config.nil?
|
44
|
+
puts 'Using project config file'
|
45
|
+
else
|
46
|
+
puts 'No project file specified in .rspec. Looking for default rspec2db.yaml file'
|
47
|
+
if File.exists? rspec2db_default_config_file
|
48
|
+
rspec2db_project_config = YAML::load(File.open(rspec2db_default_config_file))
|
49
|
+
else
|
50
|
+
puts 'File not found, generating a default rpsec2db.yaml'
|
51
|
+
RSpecConfigurationHelper.generate_local_config(rspec2db_default_config_file)
|
52
|
+
rspec2db_project_config = YAML::load(File.open(rspec2db_default_config_file))
|
53
|
+
end
|
54
|
+
RSpecConfigurationHelper.insert_rspec2db_formatter rspec_options_file, rspec2db_default_config_file
|
55
|
+
end
|
56
|
+
|
57
|
+
Hash[rspec2db_project_config['dbconnection'].map { |k, v| [k.to_sym, v] }]
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.insert_rspec2db_formatter(rspec_file, rspec2db_config_file)
|
61
|
+
rspec2db_formatter = "--format Rspec2db\n--options #{rspec2db_config_file}"
|
62
|
+
puts 'Adding rspec2db options and formatter to ' + rspec_file
|
63
|
+
File.open(rspec_file, 'a') do |f|
|
64
|
+
f.puts rspec2db_formatter
|
65
|
+
f.flush
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.override_default_config(config)
|
70
|
+
config["options"].each do |key, value|
|
71
|
+
config["options"][key] = ENV[key.upcase] unless ENV[key.upcase].nil?
|
72
|
+
end
|
73
|
+
|
74
|
+
config["dbconnection"].each do |key, value|
|
75
|
+
config["dbconnection"][key] = ENV[key.upcase] unless ENV[key.upcase].nil?
|
76
|
+
end
|
77
|
+
config
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.check_rspec_options
|
81
|
+
rspec_options_file = '.rspec'
|
82
|
+
rspec2db_config_file = './rspec2db.yaml'
|
83
|
+
|
84
|
+
return nil unless File.exist?(rspec_options_file)
|
85
|
+
config = RSpecConfigurationHelper.load_config(false)
|
86
|
+
if config.nil?
|
87
|
+
puts 'Creating rspec2db config file (' + rspec2db_config_file + ')'
|
88
|
+
RSpecConfigurationHelper.generate_local_config rspec2db_config_file
|
89
|
+
RSpecConfigurationHelper.insert_rspec2db_formatter rspec_options_file, rspec2db_config_file
|
90
|
+
return RSpecConfigurationHelper.load_config
|
91
|
+
end
|
92
|
+
puts 'rspec2db config file already exists (' + config['file_path'] + ')'
|
93
|
+
config['dbconnection']
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
def extract_rspec_core_version
|
98
|
+
Gem.loaded_specs['rspec-core'].version.to_s.split('.').map { |v| v.to_i }
|
99
|
+
end
|
100
|
+
|
101
|
+
def load_snippet_extractor
|
102
|
+
major_version, minor_version = @rspec_core_version
|
103
|
+
|
104
|
+
if major_version == 3 && minor_version < 4
|
105
|
+
require 'rspec/core/formatters/snippet_extractor'
|
106
|
+
RSpec::Core::Formatters::SnippetExtractor.new
|
107
|
+
elsif major_version == 3 && minor_version >= 4
|
108
|
+
require 'rspec/core/formatters/html_snippet_extractor'
|
109
|
+
RSpec::Core::Formatters::HtmlSnippetExtractor.new
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def print_example_failed_content(example)
|
114
|
+
print_content = ''
|
115
|
+
exception = example.execution_result.exception
|
116
|
+
return print_content if exception.backtrace.nil?
|
117
|
+
|
118
|
+
backtrace_content = exception.backtrace.map { |line| RSpec::Core::BacktraceFormatter.new.backtrace_line(line) }
|
119
|
+
backtrace_content.compact!
|
120
|
+
snippet_extractor ||= load_snippet_extractor
|
121
|
+
|
122
|
+
snippet_content = snippet_extractor.snippet(backtrace_content)
|
123
|
+
snippet_content = snippet_content.sub( "class=\"offending\"", "class=\"offending\" style=\"background-color: red;\"" )
|
124
|
+
print_content = " <pre class=\"ruby\" style=\"background-color: #E6E6E6; border: 1px solid;\"><code>#{snippet_content}</code></pre>"
|
125
|
+
print_content
|
126
|
+
end
|
127
|
+
end
|
data/lib/rspec2db.rb
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'rspec/core/formatters/base_text_formatter'
|
2
|
+
require 'active_record'
|
3
|
+
require 'yaml'
|
4
|
+
require_relative './rspec2db/utils/db_utils'
|
5
|
+
require_relative './rspec2db/utils/rspec_configuration_helper'
|
6
|
+
|
7
|
+
|
8
|
+
class Rspec2db < RSpec::Core::Formatters::BaseTextFormatter
|
9
|
+
include DBUtils
|
10
|
+
include RSpecConfigurationHelper
|
11
|
+
|
12
|
+
RSpec::Core::Formatters.register self, :start,
|
13
|
+
:example_group_started,
|
14
|
+
:example_started,
|
15
|
+
:example_passed,
|
16
|
+
:example_pending,
|
17
|
+
:example_failed,
|
18
|
+
:dump_failures,
|
19
|
+
:dump_pending,
|
20
|
+
:dump_summary,
|
21
|
+
:dump_profile,
|
22
|
+
:screenshot_saved,
|
23
|
+
:screenshot_uploaded
|
24
|
+
|
25
|
+
attr_reader :output,
|
26
|
+
:results,
|
27
|
+
:config,
|
28
|
+
:example_group,
|
29
|
+
:global_file_lock,
|
30
|
+
:test_run,
|
31
|
+
:test_suite
|
32
|
+
|
33
|
+
|
34
|
+
def initialize(output)
|
35
|
+
@output = output || StringIO.new
|
36
|
+
@global_file_lock = '/tmp/rspec2db.lock'
|
37
|
+
@config = RSpecConfigurationHelper.load_config
|
38
|
+
connect_to_db @config
|
39
|
+
@test_suite = create_test_suite(@config)
|
40
|
+
@test_run = create_test_run(@test_suite, @config)
|
41
|
+
@screenshot_event = {}
|
42
|
+
end
|
43
|
+
|
44
|
+
def start(notification)
|
45
|
+
end
|
46
|
+
|
47
|
+
def example_group_started(notification)
|
48
|
+
@example_group = notification.group
|
49
|
+
end
|
50
|
+
|
51
|
+
def example_group_finished(notification)
|
52
|
+
end
|
53
|
+
|
54
|
+
def example_started(example)
|
55
|
+
end
|
56
|
+
|
57
|
+
def example_passed(notification)
|
58
|
+
|
59
|
+
@current_test_case = create_test_case(@test_run, @example_group, notification.example, @config['options']['backtrace'], @screenshot_event)
|
60
|
+
end
|
61
|
+
|
62
|
+
def example_pending(notification)
|
63
|
+
@current_test_case = create_test_case(@test_run, @example_group, notification.example, @config['options']['backtrace'], @screenshot_event)
|
64
|
+
end
|
65
|
+
|
66
|
+
def example_failed(notification)
|
67
|
+
@current_test_case = create_test_case(@test_run, @example_group, notification.example, @config['options']['backtrace'], @screenshot_event)
|
68
|
+
end
|
69
|
+
|
70
|
+
def message(notification)
|
71
|
+
end
|
72
|
+
|
73
|
+
def start_dump(notification)
|
74
|
+
end
|
75
|
+
|
76
|
+
def dump_pending(notification)
|
77
|
+
end
|
78
|
+
|
79
|
+
def dump_profile(notification)
|
80
|
+
end
|
81
|
+
|
82
|
+
def dump_failures(notification)
|
83
|
+
end
|
84
|
+
|
85
|
+
def screenshot_saved(notification)
|
86
|
+
@screenshot_event.merge!(
|
87
|
+
screenshot_path: notification[:screenshot_path],
|
88
|
+
example: notification[:example]
|
89
|
+
)
|
90
|
+
end
|
91
|
+
|
92
|
+
def screenshot_uploaded(notification)
|
93
|
+
@screenshot_event.merge!(
|
94
|
+
screenshot_url: notification[:screenshot_url],
|
95
|
+
example: notification[:example]
|
96
|
+
)
|
97
|
+
end
|
98
|
+
|
99
|
+
def dump_summary(notification)
|
100
|
+
update_test_run(@test_run, notification, @global_file_lock)
|
101
|
+
end
|
102
|
+
|
103
|
+
def seed(seed)
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
data/rspec2db.gemspec
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'rspec2db'
|
3
|
+
s.version = '1.2.0'
|
4
|
+
s.date = '2018-01-01'
|
5
|
+
s.summary = 'Save your RSpec test results to a database'
|
6
|
+
s.description = 'A simple RSpec formatter to enable writing RSpec test results to any database using ActiveRecord. Specify DB connection in a yml file and put path to that file as --options PATH in your .rspec file'
|
7
|
+
s.authors = ['Nermin Caluk', 'Bakir Jusufbegovic', 'Adnan Muslija']
|
8
|
+
s.email = ['bakir@atlantbh.com', 'adnan.muslija@atlantbh.com']
|
9
|
+
s.files = ['lib/rspec2db.rb', 'bin/rspec2db', 'config/rspec2db.yml']
|
10
|
+
s.executables = ['rspec2db']
|
11
|
+
s.files = `git ls-files`.split("\n")
|
12
|
+
s.homepage = 'https://github.com/ATLANTBH/rspec'
|
13
|
+
|
14
|
+
s.add_dependency 'activerecord', '~>5.1'
|
15
|
+
s.add_dependency 'pg', '~>0.21'
|
16
|
+
s.add_dependency 'activerecord-postgresql-adapter'
|
17
|
+
s.add_dependency 'rspec', '>= 3.0'
|
18
|
+
end
|
data/spec/spec_spec.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
describe "Dummy describe" do # this spec file is just for test / demo purposes
|
2
|
+
context "CoNtExT" do
|
3
|
+
it "does nothing, within context" do
|
4
|
+
1.should eql(1)
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
it "does nothing again" do
|
9
|
+
1.should eql(1)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "raises" do
|
13
|
+
raise "oh no"
|
14
|
+
end
|
15
|
+
|
16
|
+
it "pends" do pending
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
metadata
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rspec2db
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.2.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nermin Caluk
|
8
|
+
- Bakir Jusufbegovic
|
9
|
+
- Adnan Muslija
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2018-01-01 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: activerecord
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
requirements:
|
19
|
+
- - "~>"
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '5.1'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - "~>"
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
version: '5.1'
|
29
|
+
- !ruby/object:Gem::Dependency
|
30
|
+
name: pg
|
31
|
+
requirement: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - "~>"
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '0.21'
|
36
|
+
type: :runtime
|
37
|
+
prerelease: false
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - "~>"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '0.21'
|
43
|
+
- !ruby/object:Gem::Dependency
|
44
|
+
name: activerecord-postgresql-adapter
|
45
|
+
requirement: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0'
|
50
|
+
type: :runtime
|
51
|
+
prerelease: false
|
52
|
+
version_requirements: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
57
|
+
- !ruby/object:Gem::Dependency
|
58
|
+
name: rspec
|
59
|
+
requirement: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '3.0'
|
64
|
+
type: :runtime
|
65
|
+
prerelease: false
|
66
|
+
version_requirements: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '3.0'
|
71
|
+
description: A simple RSpec formatter to enable writing RSpec test results to any
|
72
|
+
database using ActiveRecord. Specify DB connection in a yml file and put path to
|
73
|
+
that file as --options PATH in your .rspec file
|
74
|
+
email:
|
75
|
+
- bakir@atlantbh.com
|
76
|
+
- adnan.muslija@atlantbh.com
|
77
|
+
executables:
|
78
|
+
- rspec2db
|
79
|
+
extensions: []
|
80
|
+
extra_rdoc_files: []
|
81
|
+
files:
|
82
|
+
- ".gitignore"
|
83
|
+
- ".project"
|
84
|
+
- ".rspec"
|
85
|
+
- Gemfile
|
86
|
+
- Gemfile.lock
|
87
|
+
- README.md
|
88
|
+
- bin/rspec2db
|
89
|
+
- config/rspec2db.yml
|
90
|
+
- config/rspec_db.rb
|
91
|
+
- lib/rspec2db.rb
|
92
|
+
- lib/rspec2db/db/build_execution_stats.rb
|
93
|
+
- lib/rspec2db/db/migrations/2_add_test_case_screenshots.rb
|
94
|
+
- lib/rspec2db/db/schema.rb
|
95
|
+
- lib/rspec2db/models/test_case.rb
|
96
|
+
- lib/rspec2db/models/test_run.rb
|
97
|
+
- lib/rspec2db/models/test_suite.rb
|
98
|
+
- lib/rspec2db/utils/db_utils.rb
|
99
|
+
- lib/rspec2db/utils/rspec_configuration_helper.rb
|
100
|
+
- rspec2db.gemspec
|
101
|
+
- spec/spec_spec.rb
|
102
|
+
homepage: https://github.com/ATLANTBH/rspec
|
103
|
+
licenses: []
|
104
|
+
metadata: {}
|
105
|
+
post_install_message:
|
106
|
+
rdoc_options: []
|
107
|
+
require_paths:
|
108
|
+
- lib
|
109
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '0'
|
114
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
requirements: []
|
120
|
+
rubyforge_project:
|
121
|
+
rubygems_version: 2.4.8
|
122
|
+
signing_key:
|
123
|
+
specification_version: 4
|
124
|
+
summary: Save your RSpec test results to a database
|
125
|
+
test_files: []
|