korinthenkacker 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rspec +3 -0
- data/README.md +12 -0
- data/Rakefile +5 -1
- data/korinthenkacker.gemspec +1 -0
- data/lib/korinthenkacker/cli.rb +45 -40
- data/lib/korinthenkacker/filters/failed.rb +9 -0
- data/lib/korinthenkacker/filters/flaky.rb +12 -0
- data/lib/korinthenkacker/job_info.rb +4 -1
- data/lib/korinthenkacker/reporters/simple.rb +25 -0
- data/lib/korinthenkacker/reporters/verbose.rb +33 -0
- data/lib/korinthenkacker/test_case.rb +26 -2
- data/lib/korinthenkacker/test_report.rb +10 -12
- data/lib/korinthenkacker/version.rb +1 -1
- data/spec/filters/failed_spec.rb +33 -0
- data/spec/filters/flaky_spec.rb +33 -0
- data/spec/fixtures/test_cases.json +170 -0
- data/spec/spec_helper.rb +89 -0
- data/spec/test_case_spec.rb +85 -0
- metadata +33 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c8b03b372dfb50d7134c8f789c824613e22ab5fd
|
4
|
+
data.tar.gz: 8613ab7127a2595676f1f6d25723f25f385518dc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3c1957868677c50eb69b66c5945fe941adbcf6dedecff57609ed15460e7c25386e3e3a3d580304da2a434e413eeb5cbaaf6fa4542c4e31e65a2affd00daefcba
|
7
|
+
data.tar.gz: 2bfcb6c65bd58565879b52cb724a581f60a5b8bada1402ef539b3cf5fe2a71a4bb2b225450087749ad3fd1b516d0863630460aca85e6d9582809c14a4e205dd4
|
data/.rspec
ADDED
data/README.md
CHANGED
@@ -4,6 +4,10 @@ Know your Jenkins
|
|
4
4
|
|
5
5
|
## Setup
|
6
6
|
|
7
|
+
```
|
8
|
+
gem install korinthenkacker
|
9
|
+
```
|
10
|
+
|
7
11
|
Add a `.korinthenkacker.yml` containing the jenkins url:
|
8
12
|
|
9
13
|
```
|
@@ -60,6 +64,14 @@ $> korinthenkacker failed_scenarios soundcloud_rac_acceptance_tests_0 47
|
|
60
64
|
47 80.93447 When a follow request fails, display unfollowed state
|
61
65
|
```
|
62
66
|
|
67
|
+
```
|
68
|
+
$> korinthenkacker flaky_scenarios soundcloud_rac_acceptance_tests -l 20
|
69
|
+
# duration scenario name
|
70
|
+
228 63.409763 'Player.Foreground playback with server errors'
|
71
|
+
225 3.24821 'Player shortcut (Mini waveform).Mini waveform stops animating on track error'
|
72
|
+
223 30.674717 'Player Audio Ads Playback.Going back after playing ad does not show ad again'
|
73
|
+
```
|
74
|
+
|
63
75
|
```
|
64
76
|
$> korinthenkacker report soundcloud_rac_acceptance_tests_{0,1,2,3,4} -l 5
|
65
77
|
soundcloud_rac_acceptance_tests_0
|
data/Rakefile
CHANGED
data/korinthenkacker.gemspec
CHANGED
data/lib/korinthenkacker/cli.rb
CHANGED
@@ -3,79 +3,84 @@ require 'thor'
|
|
3
3
|
require_relative 'api'
|
4
4
|
require_relative 'configuration'
|
5
5
|
require_relative 'test_report'
|
6
|
+
require_relative 'reporters/verbose'
|
7
|
+
require_relative 'reporters/simple'
|
6
8
|
require_relative 'job_info'
|
9
|
+
require_relative 'filters/failed'
|
10
|
+
require_relative 'filters/flaky'
|
7
11
|
|
8
12
|
module Korinthenkacker
|
9
13
|
class CLI < Thor
|
10
14
|
package_name 'korinthenkacker'
|
11
15
|
|
12
16
|
desc 'jobs', 'Show all jobs'
|
17
|
+
method_option :simple, aliases: '-s', type: :boolean, desc: 'simple output formatting'
|
13
18
|
def jobs
|
14
|
-
|
19
|
+
jobs = api.jobs['jobs'].map { |job| JobInfo.new(job) }
|
20
|
+
reporter(options.simple).print_jobs_report(jobs)
|
15
21
|
end
|
16
22
|
|
17
23
|
desc 'builds JOBNAME', 'Display JOBNAME builds and their status'
|
18
|
-
method_option :limit, :
|
24
|
+
method_option :limit, aliases: '-l', type: :numeric
|
25
|
+
method_option :simple, aliases: '-s', type: :boolean, desc: 'simple output formatting'
|
19
26
|
def builds(jobname)
|
20
27
|
reports = test_reports(jobname, options.limit)
|
21
|
-
|
22
|
-
output << "#\tsuccess\tduration"
|
23
|
-
reports.each{ |report|
|
24
|
-
output << "#{report.build}\t#{report.success?}\t#{report.duration}"
|
25
|
-
}
|
26
|
-
puts output.join("\n")
|
28
|
+
reporter(options.simple).print_builds_report(reports)
|
27
29
|
end
|
28
30
|
|
29
31
|
desc 'failed_scenarios JOBNAME [BUILD]', 'Display JOBNAME failing scenarios'
|
30
|
-
method_option :limit, :
|
32
|
+
method_option :limit, aliases: '-l', type: :numeric
|
33
|
+
method_option :simple, aliases: '-s', type: :boolean, desc: 'simple output formatting'
|
31
34
|
def failed_scenarios(jobname, build=nil)
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
report.failed_cases.each{ |failed_case|
|
44
|
-
print_scenario_report(report.build, failed_case)
|
45
|
-
}
|
46
|
-
}
|
47
|
-
end
|
35
|
+
failed_cases = failed_cases_for(jobname, build)
|
36
|
+
reporter(options.simple).print_scenario_reports(failed_cases)
|
37
|
+
end
|
38
|
+
|
39
|
+
desc 'flaky_scenarios JOBNAME', 'Display JOBNAME flaky scenarios'
|
40
|
+
method_option :limit, aliases: '-l', type: :numeric
|
41
|
+
method_option :simple, aliases: '-s', type: :boolean, desc: 'simple output formatting'
|
42
|
+
def flaky_scenarios(jobname)
|
43
|
+
failed_cases = failed_cases_for(jobname)
|
44
|
+
flaky_cases = flaky_filter.filter(failed_cases)
|
45
|
+
reporter(options.simple).print_scenario_reports(flaky_cases)
|
48
46
|
end
|
49
47
|
|
50
48
|
desc 'report [JOBS...]', 'Display failing scenario for jobs'
|
51
|
-
method_option :limit, :
|
49
|
+
method_option :limit, aliases: '-l', type: :numeric
|
52
50
|
def report(*jobs)
|
53
|
-
jobs.each
|
51
|
+
jobs.each do |job|
|
54
52
|
puts job
|
55
53
|
failed_scenarios(job, nil)
|
56
|
-
|
54
|
+
end
|
57
55
|
end
|
58
56
|
|
59
57
|
private
|
60
58
|
|
61
|
-
def
|
62
|
-
|
59
|
+
def failed_cases_for(jobname, build=nil)
|
60
|
+
test_reports = build.nil? ? test_reports(jobname, options.limit) : [test_report(jobname, build)]
|
61
|
+
failed_filter.filter(test_reports.map(&:cases).flatten)
|
63
62
|
end
|
64
63
|
|
65
|
-
def
|
66
|
-
|
64
|
+
def test_report(jobname, build)
|
65
|
+
TestReport.new(jobname, build, api.test_report(jobname, build))
|
67
66
|
end
|
68
67
|
|
69
68
|
def test_reports(jobname, limit=nil)
|
70
69
|
job_info = JobInfo.new(api.job(jobname))
|
71
|
-
builds =
|
72
|
-
builds.map{ |build|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
70
|
+
builds = limit ? job_info.build_numbers.first(limit) : job_info.build_numbers
|
71
|
+
builds.map { |build| test_report(jobname, build) rescue nil }.compact # TODO: proper catching
|
72
|
+
end
|
73
|
+
|
74
|
+
def reporter(simple=false)
|
75
|
+
@reporter ||= simple ? Reporters::Simple.new : Reporters::Verbose.new
|
76
|
+
end
|
77
|
+
|
78
|
+
def failed_filter
|
79
|
+
@failed_filter ||= Filters::Failed.new
|
80
|
+
end
|
81
|
+
|
82
|
+
def flaky_filter
|
83
|
+
@flaky_filter ||= Filters::Flaky.new
|
79
84
|
end
|
80
85
|
|
81
86
|
def api
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Korinthenkacker
|
2
|
+
module Reporters
|
3
|
+
class Simple
|
4
|
+
def print_jobs_report(jobs)
|
5
|
+
puts jobs.map(&:name)
|
6
|
+
end
|
7
|
+
|
8
|
+
def print_builds_report(reports)
|
9
|
+
reports.map do |report|
|
10
|
+
"#{report.build}\t#{report.success?}\t#{report.duration}"
|
11
|
+
end.join("\n")
|
12
|
+
end
|
13
|
+
|
14
|
+
def print_scenario_reports(test_cases)
|
15
|
+
test_cases.each { |test_case| print_scenario_report(test_case) }
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def print_scenario_report(scenario)
|
21
|
+
printf("%s\t%s\t'%s'\n", scenario.build, scenario.duration, scenario.full_name)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Korinthenkacker
|
2
|
+
module Reporters
|
3
|
+
class Verbose
|
4
|
+
def print_jobs_report(jobs)
|
5
|
+
puts jobs.map(&:name)
|
6
|
+
end
|
7
|
+
|
8
|
+
def print_builds_report(reports)
|
9
|
+
output = ["#\tsuccess\tduration"]
|
10
|
+
reports.each do |report|
|
11
|
+
output << "#{report.build}\t#{report.success?}\t#{report.duration}"
|
12
|
+
end
|
13
|
+
puts output.join("\n")
|
14
|
+
end
|
15
|
+
|
16
|
+
def print_scenario_reports(test_cases)
|
17
|
+
print_table_header unless test_cases.empty?
|
18
|
+
|
19
|
+
test_cases.each { |test_case| print_scenario_report(test_case) }
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def print_table_header
|
25
|
+
printf("%s\t%-15s\t%s\n", '#', 'duration', 'scenario name')
|
26
|
+
end
|
27
|
+
|
28
|
+
def print_scenario_report(scenario)
|
29
|
+
printf("%s\t%-15s\t'%s'\n", scenario.build, scenario.duration, scenario.full_name)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -1,18 +1,42 @@
|
|
1
1
|
module Korinthenkacker
|
2
2
|
class TestCase
|
3
|
-
attr_reader :name, :duration, :failed_since, :status
|
3
|
+
attr_reader :name, :class_name, :duration, :failed_since, :status, :build
|
4
4
|
|
5
|
-
def initialize(json)
|
5
|
+
def initialize(json, build)
|
6
6
|
@name = json['name']
|
7
|
+
@class_name = json['className']
|
7
8
|
@duration = json['duration']
|
8
9
|
@failed_since = json['duration']
|
9
10
|
@status = json['status']
|
11
|
+
@failed_since = json['failedSince']
|
12
|
+
@build = build
|
13
|
+
end
|
14
|
+
|
15
|
+
def full_name
|
16
|
+
[class_name, name].join('. ')
|
10
17
|
end
|
11
18
|
|
12
19
|
def success?
|
13
20
|
!(status == 'REGRESSION' || status == 'FAILED')
|
14
21
|
end
|
15
22
|
|
23
|
+
def failure?
|
24
|
+
!success?
|
25
|
+
end
|
26
|
+
|
27
|
+
def sibling?(other)
|
28
|
+
other == self && other.failed_since != self.failed_since
|
29
|
+
end
|
30
|
+
|
31
|
+
def ==(other)
|
32
|
+
other.class == self.class && other.full_name == self.full_name
|
33
|
+
end
|
34
|
+
alias_method :eql?, :==
|
35
|
+
|
36
|
+
def hash
|
37
|
+
full_name.hash
|
38
|
+
end
|
39
|
+
|
16
40
|
private
|
17
41
|
|
18
42
|
def status_with_json(json)
|
@@ -2,7 +2,7 @@ require_relative 'test_case'
|
|
2
2
|
|
3
3
|
module Korinthenkacker
|
4
4
|
class TestReport
|
5
|
-
attr_reader :jobname, :build
|
5
|
+
attr_reader :jobname, :build, :json
|
6
6
|
|
7
7
|
def initialize(jobname, build, json)
|
8
8
|
@jobname = jobname
|
@@ -11,36 +11,34 @@ module Korinthenkacker
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def duration
|
14
|
-
|
14
|
+
json['duration']
|
15
15
|
end
|
16
16
|
|
17
17
|
def fail_count
|
18
|
-
|
18
|
+
json['failCount']
|
19
19
|
end
|
20
20
|
|
21
21
|
def pass_count
|
22
|
-
|
22
|
+
json['passCount']
|
23
23
|
end
|
24
24
|
|
25
25
|
def skip_count
|
26
|
-
|
26
|
+
json['skipCount']
|
27
27
|
end
|
28
28
|
|
29
29
|
def success?
|
30
30
|
fail_count == 0 && skip_count == 0
|
31
31
|
end
|
32
32
|
|
33
|
-
def
|
34
|
-
|
33
|
+
def failure?
|
34
|
+
!success?
|
35
35
|
end
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
def all_cases
|
40
|
-
@json['suites']
|
37
|
+
def cases
|
38
|
+
json['suites']
|
41
39
|
.map { |suite| suite['cases'] }
|
42
40
|
.flatten
|
43
|
-
.map { |my_case| TestCase.new(my_case) }
|
41
|
+
.map { |my_case| TestCase.new(my_case, build) }
|
44
42
|
end
|
45
43
|
end
|
46
44
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'korinthenkacker/filters/failed'
|
3
|
+
require 'korinthenkacker/test_case'
|
4
|
+
|
5
|
+
module Korinthenkacker
|
6
|
+
module Filters
|
7
|
+
describe Failed do
|
8
|
+
describe '#filter' do
|
9
|
+
let(:report_json_path) { File.expand_path('../../fixtures/test_cases.json', __FILE__) }
|
10
|
+
let(:report_json_fixture) { JSON.parse(File.read(report_json_path)) }
|
11
|
+
let(:test_cases) { report_json_fixture.map { |json_case| TestCase.new(json_case, 1) } }
|
12
|
+
|
13
|
+
context 'with empty TestCases' do
|
14
|
+
let(:test_cases) { [] }
|
15
|
+
|
16
|
+
it 'returns and empty array' do
|
17
|
+
expect(subject.filter([])).to be_empty
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'with non-empty cases' do
|
22
|
+
it 'returns the correct amount of TestCases' do
|
23
|
+
expect(subject.filter(test_cases).count).to eql(8)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'returns only failed TestCases' do
|
27
|
+
expect(subject.filter(test_cases).all?(&:failure?)).to be_truthy
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'korinthenkacker/filters/flaky'
|
3
|
+
require 'korinthenkacker/test_case'
|
4
|
+
|
5
|
+
module Korinthenkacker
|
6
|
+
module Filters
|
7
|
+
describe Flaky do
|
8
|
+
let(:json_fixture_path) { File.expand_path('../../fixtures/test_cases.json', __FILE__) }
|
9
|
+
let(:json_fixture) { JSON.parse(File.read(json_fixture_path)) }
|
10
|
+
let(:test_cases) { json_fixture.map { |json_case| TestCase.new(json_case, 1) } }
|
11
|
+
|
12
|
+
context 'with empty TestCases' do
|
13
|
+
let(:test_cases) { [] }
|
14
|
+
|
15
|
+
it 'returns and empty array' do
|
16
|
+
expect(subject.filter([])).to be_empty
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'with non-empty cases' do
|
21
|
+
it 'returns the correct number of flaky TestCases' do
|
22
|
+
expect(subject.filter(test_cases).count).to eql(2)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'returns only the flaky TestCases' do
|
26
|
+
flaky_test_case_names = subject.filter(test_cases).map(&:class_name)
|
27
|
+
expect(flaky_test_case_names).to include('Flaky Spec A')
|
28
|
+
expect(flaky_test_case_names).to include('Flaky Spec B')
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,170 @@
|
|
1
|
+
[
|
2
|
+
{
|
3
|
+
"age": 1,
|
4
|
+
"className": "Player",
|
5
|
+
"duration": 63.409763,
|
6
|
+
"errorDetails": "failed Foreground playback with server errors",
|
7
|
+
"errorStackTrace": "\n Scenario: Foreground playback with server errors\n\nGiven explore and player and waveform datasets are loaded\nGiven that the app is started\nAnd that \"Media\" endpoint returns status code 404\nAnd I go to \"Trending Music Track 1\" player_page\nThen I am in error state\n\nMessage:\n\n wait_for_page_animations_to_finish (elapsed time: 15.000691, time 2014-09-25 00:41:27 +0200) (RuntimeError)\n./features/lib/helpers/wait_until.rb:28:in `rescue in wait_until'\n./features/lib/helpers/wait_until.rb:15:in `wait_until'\n./features/lib/helpers/waiter.rb:154:in `wait_for_animations'\n./features/lib/helpers/waiter.rb:94:in `wait_for_page_animations_to_finish'\n./features/step_definitions/player_page_steps.rb:175:in `/^I am in error state$/'\nfeatures/acceptance/player/player.feature:56:in `Then I am in error state'\n ",
|
8
|
+
"failedSince": 228,
|
9
|
+
"name": "Foreground playback with server errors",
|
10
|
+
"skipped": false,
|
11
|
+
"skippedMessage": null,
|
12
|
+
"status": "REGRESSION",
|
13
|
+
"stderr": "",
|
14
|
+
"stdout": ""
|
15
|
+
},
|
16
|
+
{
|
17
|
+
"age": 0,
|
18
|
+
"className": "Playlist deeplinks",
|
19
|
+
"duration": 31.45592,
|
20
|
+
"errorDetails": null,
|
21
|
+
"errorStackTrace": null,
|
22
|
+
"failedSince": 0,
|
23
|
+
"name": "Splash screen is visible while loading",
|
24
|
+
"skipped": false,
|
25
|
+
"skippedMessage": null,
|
26
|
+
"status": "PASSED",
|
27
|
+
"stderr": "",
|
28
|
+
"stdout": ""
|
29
|
+
},
|
30
|
+
{
|
31
|
+
"age": 1,
|
32
|
+
"className": "Liking a track in player",
|
33
|
+
"duration": 86.92972,
|
34
|
+
"errorDetails": "failed Liking an unliked track",
|
35
|
+
"errorStackTrace": "\n Scenario: Liking an unliked track\n\nGiven explore and player and signin and waveform and stream datasets are loaded\nAnd that the app is started\nGiven I am signed in\nAnd I am on feed_picker_page\nAnd I tap on \"Trending Music\" stream_cell\nAnd track_list loaded items\nAnd I go to \"Trending Music Track 1\" player_page\nAnd I tap the player\nWhen I tap the player like button\nThen after a while I should see the player unlike button\n\nMessage:\n\n couldn't open player from feed (RuntimeError)\n./features/lib/page/explore.rb:38:in `block in touch_track_with_title_and_wait_for_player'\n./features/lib/page/explore.rb:57:in `call'\n./features/lib/page/explore.rb:57:in `track_with_title'\n./features/lib/page/explore.rb:24:in `touch_track_with_title_and_wait_for_player'\n./features/step_definitions/explore_page_steps.rb:54:in `/^I tap on track titled \"(.*)\"$/'\n./features/step_definitions/player_page_steps.rb:4:in `/^I go to \"(.*)\" player_page$/'\nfeatures/acceptance/player/player_like.feature:42:in `And I go to \"Trending Music Track 1\" player_page'\n ",
|
36
|
+
"failedSince": 225,
|
37
|
+
"name": "Liking an unliked track",
|
38
|
+
"skipped": false,
|
39
|
+
"skippedMessage": null,
|
40
|
+
"status": "FAILED",
|
41
|
+
"stderr": "",
|
42
|
+
"stdout": ""
|
43
|
+
},
|
44
|
+
{
|
45
|
+
"age": 1,
|
46
|
+
"className": "Flaky Spec A",
|
47
|
+
"duration": 3.24821,
|
48
|
+
"errorDetails": "failed Mini waveform stops animating on track error",
|
49
|
+
"errorStackTrace": "\n Scenario: Mini waveform stops animating on track error\n\nGiven explore and player and waveform datasets are loaded\nAnd that the app is started\nAnd I am on explore_page\nAnd track_list loaded items\nWhen I go to \"Trending Music Track 1\" player_page\nThen I am in play state\nGiven that the network is unreachable\nThen offline_bar should be in unreachable state\nAnd I tap the next_player_page_button until I'm on \"Trending Music Track 3\" player_page\nThen I am in error state\nWhen I close the player\nThen mini waveform view should not be animating\n\nMessage:\n\n expected visible? to return true, got false (RSpec::Expectations::ExpectationNotMetError)\n./features/step_definitions/player_page_steps.rb:192:in `/^I should see the player error retry button$/'\n./features/step_definitions/player_page_steps.rb:177:in `/^I am in error state$/'\nfeatures/acceptance/player/player_shortcut.feature:43:in `Then I am in error state'\n ",
|
50
|
+
"failedSince": 225,
|
51
|
+
"name": "Mini waveform stops animating on track error",
|
52
|
+
"skipped": false,
|
53
|
+
"skippedMessage": null,
|
54
|
+
"status": "REGRESSION",
|
55
|
+
"stderr": "",
|
56
|
+
"stdout": ""
|
57
|
+
},
|
58
|
+
{
|
59
|
+
"age": 1,
|
60
|
+
"className": "Flaky Spec B",
|
61
|
+
"duration": 30.674717,
|
62
|
+
"errorDetails": "failed Going back after playing ad does not show ad again",
|
63
|
+
"errorStackTrace": "\n Scenario: Going back after playing ad does not show ad again\n\nGiven explore and player and waveform and audio_ad datasets are loaded\nAnd that the app is started\nAnd I am on explore_page\nGiven I go to \"Trending Music Track 1\" player_page\nAnd audio ad has loaded after \"Trending Music Track 1\"\nWhen I tap the next_player_page_button\nThen I should be on audio ad page\nAnd I should hear the audio ad \"MONEYZZZZ\"\nGiven I really want to wait for 4 seconds\nWhen I tap the next_player_page_button\nThen I should be on \"Trending Music Track 2\" player_page\nAnd I should hear music for track \"Trending Music Track 2\"\nAnd I should see the leave_behind\nWhen I tap the leave_behind close button\nThen I should not see the leave_behind\nWhen I tap the previous_player_page_button\nThen I should be on \"Trending Music Track 1\" player_page\n\nMessage:\n\n timed out waiting: timeout = 15, poll_sleep = 0.5 (elapsed time: 15.001166, time 2014-09-24 21:18:19 +0200) (RuntimeError)\n./features/lib/helpers/wait_until.rb:28:in `rescue in wait_until'\n./features/lib/helpers/wait_until.rb:15:in `wait_until'\n./features/step_definitions/player_page_steps.rb:63:in `/^I should be on \"(.*)\" player_page$/'\nfeatures/acceptance/player/player_audio_ad_playback.feature:52:in `Then I should be on \"Trending Music Track 1\" player_page'\n ",
|
64
|
+
"failedSince": 223,
|
65
|
+
"name": "Going back after playing ad does not show ad again",
|
66
|
+
"skipped": false,
|
67
|
+
"skippedMessage": null,
|
68
|
+
"status": "REGRESSION",
|
69
|
+
"stderr": "",
|
70
|
+
"stdout": ""
|
71
|
+
},
|
72
|
+
{
|
73
|
+
"age": 0,
|
74
|
+
"className": "Playlist deeplinks",
|
75
|
+
"duration": 32.77258,
|
76
|
+
"errorDetails": null,
|
77
|
+
"errorStackTrace": null,
|
78
|
+
"failedSince": 0,
|
79
|
+
"name": "Opening a valid playlist url (outline example : | soundcloud:playlists:1 |)",
|
80
|
+
"skipped": false,
|
81
|
+
"skippedMessage": null,
|
82
|
+
"status": "PASSED",
|
83
|
+
"stderr": "",
|
84
|
+
"stdout": ""
|
85
|
+
},
|
86
|
+
{
|
87
|
+
"age": 0,
|
88
|
+
"className": "Playlist deeplinks",
|
89
|
+
"duration": 32.77258,
|
90
|
+
"errorDetails": null,
|
91
|
+
"errorStackTrace": null,
|
92
|
+
"failedSince": 0,
|
93
|
+
"name": "Opening a valid playlist url (outline example : | soundcloud:playlists:1 |)",
|
94
|
+
"skipped": false,
|
95
|
+
"skippedMessage": null,
|
96
|
+
"status": "PASSED",
|
97
|
+
"stderr": "",
|
98
|
+
"stdout": ""
|
99
|
+
},
|
100
|
+
{
|
101
|
+
"age": 1,
|
102
|
+
"className": "Liking a track in player",
|
103
|
+
"duration": 86.88021,
|
104
|
+
"errorDetails": "failed When a user is offline and likes a track, display liked state and sync when online again",
|
105
|
+
"errorStackTrace": "\n Scenario: When a user is offline and likes a track, display liked state and sync when online again\n\nGiven explore and player and signin and waveform and stream datasets are loaded\nAnd that the app is started\nGiven I am signed in\nAnd I am on feed_picker_page\nAnd I tap on \"Trending Music\" stream_cell\nAnd track_list loaded items\nAnd I go to \"Trending Music Track 1\" player_page\nAnd I tap the player\nAnd that the network is unreachable\nThen offline_bar should be in unreachable state\nWhen I tap the player like button\nThen I should see the unlike button on player\nWhen that the network is reachable\n\nMessage:\n\n couldn't open player from feed (RuntimeError)\n./features/lib/page/explore.rb:38:in `block in touch_track_with_title_and_wait_for_player'\n./features/lib/page/explore.rb:57:in `call'\n./features/lib/page/explore.rb:57:in `track_with_title'\n./features/lib/page/explore.rb:24:in `touch_track_with_title_and_wait_for_player'\n./features/step_definitions/explore_page_steps.rb:54:in `/^I tap on track titled \"(.*)\"$/'\n./features/step_definitions/player_page_steps.rb:4:in `/^I go to \"(.*)\" player_page$/'\nfeatures/acceptance/player/player_like.feature:66:in `And I go to \"Trending Music Track 1\" player_page'\n ",
|
106
|
+
"failedSince": 223,
|
107
|
+
"name": "When a user is offline and likes a track, display liked state and sync when online again",
|
108
|
+
"skipped": false,
|
109
|
+
"skippedMessage": null,
|
110
|
+
"status": "REGRESSION",
|
111
|
+
"stderr": "",
|
112
|
+
"stdout": ""
|
113
|
+
},
|
114
|
+
{
|
115
|
+
"age": 7,
|
116
|
+
"className": "Search",
|
117
|
+
"duration": 26.78047,
|
118
|
+
"errorDetails": "failed ErrorView should not be shown when clearing search results",
|
119
|
+
"errorStackTrace": "\n Scenario: ErrorView should not be shown when clearing search results\n\nGiven explore and signin and search datasets are loaded\nAnd that the app is started\nAnd I am on search_page\nGiven that \"Search 0\" endpoint returns status code 404\nWhen I search for \"skrillex rulez\"\nThen I should not see any results\nAnd I should see the server_error_view\nAnd I should not see header_logo_view\nGiven search dataset is loaded\nWhen I clear the search box\nWhen I search for \"skrillex rulez\"\nAnd search results are loaded\nWhen I clear the search box\nThen I should not see the server_error_view\nAnd I should not see header_logo_view\n\nMessage:\n\n Error View is visible but it should not be (elapsed time: 15.001035, time 2014-09-24 21:21:04 +0200) (RuntimeError)\n./features/lib/helpers/wait_until.rb:28:in `rescue in wait_until'\n./features/lib/helpers/wait_until.rb:15:in `wait_until'\n./features/lib/helpers/waiter.rb:148:in `perform_until'\n./features/lib/helpers/waiter.rb:144:in `perform_until_after_delay'\n./features/step_definitions/search_page_steps.rb:78:in `/^I should not see the server_error_view$/'\nfeatures/acceptance/search/search.feature:121:in `Then I should not see the server_error_view'\n ",
|
120
|
+
"failedSince": 217,
|
121
|
+
"name": "ErrorView should not be shown when clearing search results",
|
122
|
+
"skipped": false,
|
123
|
+
"skippedMessage": null,
|
124
|
+
"status": "FAILED",
|
125
|
+
"stderr": "",
|
126
|
+
"stdout": ""
|
127
|
+
},
|
128
|
+
{
|
129
|
+
"age": 2,
|
130
|
+
"className": "Flaky Spec A",
|
131
|
+
"duration": 2.83868,
|
132
|
+
"errorDetails": "failed Mini waveform stops animating on track error",
|
133
|
+
"errorStackTrace": "\n Scenario: Mini waveform stops animating on track error\n\nGiven explore and player and waveform datasets are loaded\nAnd that the app is started\nAnd I am on explore_page\nAnd track_list loaded items\nWhen I go to \"Trending Music Track 1\" player_page\nThen I am in play state\nGiven that the network is unreachable\nThen offline_bar should be in unreachable state\nAnd I tap the next_player_page_button until I'm on \"Trending Music Track 3\" player_page\nThen I am in error state\nWhen I close the player\nThen mini waveform view should not be animating\n\nMessage:\n\n expected visible? to return true, got false (RSpec::Expectations::ExpectationNotMetError)\n./features/step_definitions/player_page_steps.rb:192:in `/^I should see the player error retry button$/'\n./features/step_definitions/player_page_steps.rb:177:in `/^I am in error state$/'\nfeatures/acceptance/player/player_shortcut.feature:43:in `Then I am in error state'\n ",
|
134
|
+
"failedSince": 221,
|
135
|
+
"name": "Mini waveform stops animating on track error",
|
136
|
+
"skipped": false,
|
137
|
+
"skippedMessage": null,
|
138
|
+
"status": "FAILED",
|
139
|
+
"stderr": "",
|
140
|
+
"stdout": ""
|
141
|
+
},
|
142
|
+
{
|
143
|
+
"age": 6,
|
144
|
+
"className": "Search",
|
145
|
+
"duration": 26.590137,
|
146
|
+
"errorDetails": "failed ErrorView should not be shown when clearing search results",
|
147
|
+
"errorStackTrace": "\n Scenario: ErrorView should not be shown when clearing search results\n\nGiven explore and signin and search datasets are loaded\nAnd that the app is started\nAnd I am on search_page\nGiven that \"Search 0\" endpoint returns status code 404\nWhen I search for \"skrillex rulez\"\nThen I should not see any results\nAnd I should see the server_error_view\nAnd I should not see header_logo_view\nGiven search dataset is loaded\nWhen I clear the search box\nWhen I search for \"skrillex rulez\"\nAnd search results are loaded\nWhen I clear the search box\nThen I should not see the server_error_view\nAnd I should not see header_logo_view\n\nMessage:\n\n Error View is visible but it should not be (elapsed time: 15.001807, time 2014-09-24 21:12:29 +0200) (RuntimeError)\n./features/lib/helpers/wait_until.rb:28:in `rescue in wait_until'\n./features/lib/helpers/wait_until.rb:15:in `wait_until'\n./features/lib/helpers/waiter.rb:148:in `perform_until'\n./features/lib/helpers/waiter.rb:144:in `perform_until_after_delay'\n./features/step_definitions/search_page_steps.rb:78:in `/^I should not see the server_error_view$/'\nfeatures/acceptance/search/search.feature:121:in `Then I should not see the server_error_view'\n ",
|
148
|
+
"failedSince": 217,
|
149
|
+
"name": "ErrorView should not be shown when clearing search results",
|
150
|
+
"skipped": false,
|
151
|
+
"skippedMessage": null,
|
152
|
+
"status": "FAILED",
|
153
|
+
"stderr": "",
|
154
|
+
"stdout": ""
|
155
|
+
},
|
156
|
+
{
|
157
|
+
"age": 1,
|
158
|
+
"className": "Flaky Spec B",
|
159
|
+
"duration": 30.674717,
|
160
|
+
"errorDetails": "failed Going back after playing ad does not show ad again",
|
161
|
+
"errorStackTrace": "\n Scenario: Going back after playing ad does not show ad again\n\nGiven explore and player and waveform and audio_ad datasets are loaded\nAnd that the app is started\nAnd I am on explore_page\nGiven I go to \"Trending Music Track 1\" player_page\nAnd audio ad has loaded after \"Trending Music Track 1\"\nWhen I tap the next_player_page_button\nThen I should be on audio ad page\nAnd I should hear the audio ad \"MONEYZZZZ\"\nGiven I really want to wait for 4 seconds\nWhen I tap the next_player_page_button\nThen I should be on \"Trending Music Track 2\" player_page\nAnd I should hear music for track \"Trending Music Track 2\"\nAnd I should see the leave_behind\nWhen I tap the leave_behind close button\nThen I should not see the leave_behind\nWhen I tap the previous_player_page_button\nThen I should be on \"Trending Music Track 1\" player_page\n\nMessage:\n\n timed out waiting: timeout = 15, poll_sleep = 0.5 (elapsed time: 15.001166, time 2014-09-24 21:18:19 +0200) (RuntimeError)\n./features/lib/helpers/wait_until.rb:28:in `rescue in wait_until'\n./features/lib/helpers/wait_until.rb:15:in `wait_until'\n./features/step_definitions/player_page_steps.rb:63:in `/^I should be on \"(.*)\" player_page$/'\nfeatures/acceptance/player/player_audio_ad_playback.feature:52:in `Then I should be on \"Trending Music Track 1\" player_page'\n ",
|
162
|
+
"failedSince": 220,
|
163
|
+
"name": "Going back after playing ad does not show ad again",
|
164
|
+
"skipped": false,
|
165
|
+
"skippedMessage": null,
|
166
|
+
"status": "FAILED",
|
167
|
+
"stderr": "",
|
168
|
+
"stdout": ""
|
169
|
+
}
|
170
|
+
]
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
2
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
|
+
# The generated `.rspec` file contains `--require spec_helper` which will cause this
|
4
|
+
# file to always be loaded, without a need to explicitly require it in any files.
|
5
|
+
#
|
6
|
+
# Given that it is always loaded, you are encouraged to keep this file as
|
7
|
+
# light-weight as possible. Requiring heavyweight dependencies from this file
|
8
|
+
# will add to the boot time of your test suite on EVERY test run, even for an
|
9
|
+
# individual file that may not need all of that loaded. Instead, consider making
|
10
|
+
# a separate helper file that requires the additional dependencies and performs
|
11
|
+
# the additional setup, and require it from the spec files that actually need it.
|
12
|
+
#
|
13
|
+
# The `.rspec` file also contains a few flags that are not defaults but that
|
14
|
+
# users commonly want.
|
15
|
+
#
|
16
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
17
|
+
RSpec.configure do |config|
|
18
|
+
# rspec-expectations config goes here. You can use an alternate
|
19
|
+
# assertion/expectation library such as wrong or the stdlib/minitest
|
20
|
+
# assertions if you prefer.
|
21
|
+
config.expect_with :rspec do |expectations|
|
22
|
+
# This option will default to `true` in RSpec 4. It makes the `description`
|
23
|
+
# and `failure_message` of custom matchers include text for helper methods
|
24
|
+
# defined using `chain`, e.g.:
|
25
|
+
# be_bigger_than(2).and_smaller_than(4).description
|
26
|
+
# # => "be bigger than 2 and smaller than 4"
|
27
|
+
# ...rather than:
|
28
|
+
# # => "be bigger than 2"
|
29
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
30
|
+
end
|
31
|
+
|
32
|
+
# rspec-mocks config goes here. You can use an alternate test double
|
33
|
+
# library (such as bogus or mocha) by changing the `mock_with` option here.
|
34
|
+
config.mock_with :rspec do |mocks|
|
35
|
+
# Prevents you from mocking or stubbing a method that does not exist on
|
36
|
+
# a real object. This is generally recommended, and will default to
|
37
|
+
# `true` in RSpec 4.
|
38
|
+
mocks.verify_partial_doubles = true
|
39
|
+
end
|
40
|
+
|
41
|
+
# The settings below are suggested to provide a good initial experience
|
42
|
+
# with RSpec, but feel free to customize to your heart's content.
|
43
|
+
=begin
|
44
|
+
# These two settings work together to allow you to limit a spec run
|
45
|
+
# to individual examples or groups you care about by tagging them with
|
46
|
+
# `:focus` metadata. When nothing is tagged with `:focus`, all examples
|
47
|
+
# get run.
|
48
|
+
config.filter_run :focus
|
49
|
+
config.run_all_when_everything_filtered = true
|
50
|
+
|
51
|
+
# Limits the available syntax to the non-monkey patched syntax that is recommended.
|
52
|
+
# For more details, see:
|
53
|
+
# - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
|
54
|
+
# - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
|
55
|
+
# - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
|
56
|
+
config.disable_monkey_patching!
|
57
|
+
|
58
|
+
# This setting enables warnings. It's recommended, but in some cases may
|
59
|
+
# be too noisy due to issues in dependencies.
|
60
|
+
config.warnings = true
|
61
|
+
|
62
|
+
# Many RSpec users commonly either run the entire suite or an individual
|
63
|
+
# file, and it's useful to allow more verbose output when running an
|
64
|
+
# individual spec file.
|
65
|
+
if config.files_to_run.one?
|
66
|
+
# Use the documentation formatter for detailed output,
|
67
|
+
# unless a formatter has already been configured
|
68
|
+
# (e.g. via a command-line flag).
|
69
|
+
config.default_formatter = 'doc'
|
70
|
+
end
|
71
|
+
|
72
|
+
# Print the 10 slowest examples and example groups at the
|
73
|
+
# end of the spec run, to help surface which specs are running
|
74
|
+
# particularly slow.
|
75
|
+
config.profile_examples = 10
|
76
|
+
|
77
|
+
# Run specs in random order to surface order dependencies. If you find an
|
78
|
+
# order dependency and want to debug it, you can fix the order by providing
|
79
|
+
# the seed, which is printed after each run.
|
80
|
+
# --seed 1234
|
81
|
+
config.order = :random
|
82
|
+
|
83
|
+
# Seed global randomization in this process using the `--seed` CLI option.
|
84
|
+
# Setting this allows you to use `--seed` to deterministically reproduce
|
85
|
+
# test failures related to randomization by passing the same `--seed` value
|
86
|
+
# as the one that triggered the failure.
|
87
|
+
Kernel.srand config.seed
|
88
|
+
=end
|
89
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'korinthenkacker/test_case'
|
3
|
+
|
4
|
+
module Korinthenkacker
|
5
|
+
describe TestCase do
|
6
|
+
let(:test_case_a) { TestCase.new(json_a, 1) }
|
7
|
+
let(:test_case_b) { TestCase.new(json_b, 2) }
|
8
|
+
|
9
|
+
describe '#==' do
|
10
|
+
context 'with same name and same class name' do
|
11
|
+
let(:json_a) { {'name' => 'name', 'className' => 'class_name'} }
|
12
|
+
let(:json_b) { {'name' => 'name', 'className' => 'class_name'} }
|
13
|
+
|
14
|
+
it 'is considered equal' do
|
15
|
+
expect(test_case_a).to eql(test_case_b)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'with same name but different class name' do
|
20
|
+
let(:json_a) { {'name' => 'name', 'className' => 'class_name_a'} }
|
21
|
+
let(:json_b) { {'name' => 'name', 'className' => 'class_name_b'} }
|
22
|
+
|
23
|
+
it 'is NOT considered equal' do
|
24
|
+
expect(test_case_a).to_not eql(test_case_b)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'with different name but same class name' do
|
29
|
+
let(:json_a) { {'name' => 'name_a', 'className' => 'class_name'} }
|
30
|
+
let(:json_b) { {'name' => 'name_b', 'className' => 'class_name'} }
|
31
|
+
|
32
|
+
it 'is NOT considered equal' do
|
33
|
+
expect(test_case_a).to_not eql(test_case_b)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'with different name and different class name' do
|
38
|
+
let(:json_a) { {'name' => 'name_a', 'className' => 'class_name_a'} }
|
39
|
+
let(:json_b) { {'name' => 'name_b', 'className' => 'class_name_b'} }
|
40
|
+
|
41
|
+
it 'is NOT considered equal' do
|
42
|
+
expect(test_case_a).to_not eql(test_case_b)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe '#sibling?' do
|
48
|
+
context 'when equal and same failed_since' do
|
49
|
+
let(:json_a) { {'name' => 'name', 'className' => 'class_name', 'failedSince' => 42} }
|
50
|
+
let(:json_b) { {'name' => 'name', 'className' => 'class_name', 'failedSince' => 42} }
|
51
|
+
|
52
|
+
it 'returns false' do
|
53
|
+
expect(test_case_a.sibling?(test_case_b)).to be_falsy
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'when equal but different failed_since' do
|
58
|
+
let(:json_a) { {'name' => 'name', 'className' => 'class_name', 'failedSince' => 1} }
|
59
|
+
let(:json_b) { {'name' => 'name', 'className' => 'class_name', 'failedSince' => 42} }
|
60
|
+
|
61
|
+
it 'returns false' do
|
62
|
+
expect(test_case_a.sibling?(test_case_b)).to be_truthy
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'when not equal and same failed_since' do
|
67
|
+
let(:json_a) { {'name' => 'nameA', 'className' => 'class_nameA', 'failedSince' => 42} }
|
68
|
+
let(:json_b) { {'name' => 'nameB', 'className' => 'class_nameB', 'failedSince' => 42} }
|
69
|
+
|
70
|
+
it 'returns false' do
|
71
|
+
expect(test_case_a.sibling?(test_case_b)).to be_falsy
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'when not equal and different failed_since' do
|
76
|
+
let(:json_a) { {'name' => 'nameA', 'className' => 'class_nameA', 'failedSince' => 1} }
|
77
|
+
let(:json_b) { {'name' => 'nameB', 'className' => 'class_nameB', 'failedSince' => 42} }
|
78
|
+
|
79
|
+
it 'returns false' do
|
80
|
+
expect(test_case_a.sibling?(test_case_b)).to be_falsy
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: korinthenkacker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vincent Garrigues
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-09-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - '>='
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
55
69
|
description: Find out what the fuck is going on with those tests
|
56
70
|
email:
|
57
71
|
- vincent@soundcloud.com
|
@@ -61,6 +75,7 @@ extensions: []
|
|
61
75
|
extra_rdoc_files: []
|
62
76
|
files:
|
63
77
|
- .gitignore
|
78
|
+
- .rspec
|
64
79
|
- .rvmrc
|
65
80
|
- Gemfile
|
66
81
|
- LICENSE.txt
|
@@ -72,10 +87,19 @@ files:
|
|
72
87
|
- lib/korinthenkacker/api.rb
|
73
88
|
- lib/korinthenkacker/cli.rb
|
74
89
|
- lib/korinthenkacker/configuration.rb
|
90
|
+
- lib/korinthenkacker/filters/failed.rb
|
91
|
+
- lib/korinthenkacker/filters/flaky.rb
|
75
92
|
- lib/korinthenkacker/job_info.rb
|
93
|
+
- lib/korinthenkacker/reporters/simple.rb
|
94
|
+
- lib/korinthenkacker/reporters/verbose.rb
|
76
95
|
- lib/korinthenkacker/test_case.rb
|
77
96
|
- lib/korinthenkacker/test_report.rb
|
78
97
|
- lib/korinthenkacker/version.rb
|
98
|
+
- spec/filters/failed_spec.rb
|
99
|
+
- spec/filters/flaky_spec.rb
|
100
|
+
- spec/fixtures/test_cases.json
|
101
|
+
- spec/spec_helper.rb
|
102
|
+
- spec/test_case_spec.rb
|
79
103
|
homepage: ''
|
80
104
|
licenses:
|
81
105
|
- MIT
|
@@ -96,8 +120,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
96
120
|
version: '0'
|
97
121
|
requirements: []
|
98
122
|
rubyforge_project:
|
99
|
-
rubygems_version: 2.
|
123
|
+
rubygems_version: 2.2.1
|
100
124
|
signing_key:
|
101
125
|
specification_version: 4
|
102
126
|
summary: Seriously Jenkins?
|
103
|
-
test_files:
|
127
|
+
test_files:
|
128
|
+
- spec/filters/failed_spec.rb
|
129
|
+
- spec/filters/flaky_spec.rb
|
130
|
+
- spec/fixtures/test_cases.json
|
131
|
+
- spec/spec_helper.rb
|
132
|
+
- spec/test_case_spec.rb
|