dynport_tools 0.2.6 → 0.2.8
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.
- data/.autotest +4 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +2 -0
- data/VERSION +1 -1
- data/dynport_tools.gemspec +10 -2
- data/lib/dynport_tools.rb +1 -1
- data/lib/dynport_tools/eta.rb +63 -0
- data/lib/dynport_tools/jenkins.rb +65 -0
- data/lib/dynport_tools/redis_q.rb +75 -0
- data/spec/dynport_tools/eta_spec.rb +114 -0
- data/spec/dynport_tools/jenkins_spec.rb +150 -3
- data/spec/dynport_tools/redis_q_spec.rb +177 -0
- data/spec/dynport_tools/xml_file_spec.rb +2 -3
- data/spec/spec_helper.rb +33 -2
- metadata +77 -58
data/.autotest
ADDED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -33,6 +33,7 @@ GEM
|
|
33
33
|
ruby-debug-base (~> 0.10.4.0)
|
34
34
|
ruby-debug-base (0.10.4)
|
35
35
|
linecache (>= 0.3)
|
36
|
+
timecop (0.3.5)
|
36
37
|
typhoeus (0.2.4)
|
37
38
|
mime-types
|
38
39
|
mime-types
|
@@ -51,4 +52,5 @@ DEPENDENCIES
|
|
51
52
|
redis
|
52
53
|
rspec (~> 2.3.0)
|
53
54
|
ruby-debug
|
55
|
+
timecop
|
54
56
|
typhoeus
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.8
|
data/dynport_tools.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{dynport_tools}
|
8
|
-
s.version = "0.2.
|
8
|
+
s.version = "0.2.8"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Tobias Schwab"]
|
12
|
-
s.date = %q{2011-08-
|
12
|
+
s.date = %q{2011-08-23}
|
13
13
|
s.description = %q{Collection of various tools}
|
14
14
|
s.email = %q{tobias.schwab@dynport.de}
|
15
15
|
s.executables = ["xmldiff", "redis_dumper"]
|
@@ -18,6 +18,7 @@ Gem::Specification.new do |s|
|
|
18
18
|
"README.rdoc"
|
19
19
|
]
|
20
20
|
s.files = [
|
21
|
+
".autotest",
|
21
22
|
".document",
|
22
23
|
".rbenv-version",
|
23
24
|
".rspec",
|
@@ -34,15 +35,19 @@ Gem::Specification.new do |s|
|
|
34
35
|
"lib/dynport_tools.rb",
|
35
36
|
"lib/dynport_tools/deep_merger.rb",
|
36
37
|
"lib/dynport_tools/differ.rb",
|
38
|
+
"lib/dynport_tools/eta.rb",
|
37
39
|
"lib/dynport_tools/have_attributes.rb",
|
38
40
|
"lib/dynport_tools/jenkins.rb",
|
39
41
|
"lib/dynport_tools/redis_dumper.rb",
|
42
|
+
"lib/dynport_tools/redis_q.rb",
|
40
43
|
"lib/dynport_tools/xml_file.rb",
|
41
44
|
"spec/dynport_tools/deep_merger_spec.rb",
|
42
45
|
"spec/dynport_tools/differ_spec.rb",
|
46
|
+
"spec/dynport_tools/eta_spec.rb",
|
43
47
|
"spec/dynport_tools/have_attributes_spec.rb",
|
44
48
|
"spec/dynport_tools/jenkins_spec.rb",
|
45
49
|
"spec/dynport_tools/redis_dumper_spec.rb",
|
50
|
+
"spec/dynport_tools/redis_q_spec.rb",
|
46
51
|
"spec/dynport_tools/xml_file_spec.rb",
|
47
52
|
"spec/dynport_tools_spec.rb",
|
48
53
|
"spec/fixtures/file_a.xml",
|
@@ -71,6 +76,7 @@ Gem::Specification.new do |s|
|
|
71
76
|
s.add_development_dependency(%q<autotest>, [">= 0"])
|
72
77
|
s.add_development_dependency(%q<autotest-growl>, [">= 0"])
|
73
78
|
s.add_development_dependency(%q<ruby-debug>, [">= 0"])
|
79
|
+
s.add_development_dependency(%q<timecop>, [">= 0"])
|
74
80
|
else
|
75
81
|
s.add_dependency(%q<nokogiri>, [">= 0"])
|
76
82
|
s.add_dependency(%q<redis>, [">= 0"])
|
@@ -83,6 +89,7 @@ Gem::Specification.new do |s|
|
|
83
89
|
s.add_dependency(%q<autotest>, [">= 0"])
|
84
90
|
s.add_dependency(%q<autotest-growl>, [">= 0"])
|
85
91
|
s.add_dependency(%q<ruby-debug>, [">= 0"])
|
92
|
+
s.add_dependency(%q<timecop>, [">= 0"])
|
86
93
|
end
|
87
94
|
else
|
88
95
|
s.add_dependency(%q<nokogiri>, [">= 0"])
|
@@ -96,6 +103,7 @@ Gem::Specification.new do |s|
|
|
96
103
|
s.add_dependency(%q<autotest>, [">= 0"])
|
97
104
|
s.add_dependency(%q<autotest-growl>, [">= 0"])
|
98
105
|
s.add_dependency(%q<ruby-debug>, [">= 0"])
|
106
|
+
s.add_dependency(%q<timecop>, [">= 0"])
|
99
107
|
end
|
100
108
|
end
|
101
109
|
|
data/lib/dynport_tools.rb
CHANGED
@@ -0,0 +1,63 @@
|
|
1
|
+
class DynportTools::ETA
|
2
|
+
attr_accessor :total, :current, :started
|
3
|
+
|
4
|
+
def initialize(options = {})
|
5
|
+
options.each do |key, value|
|
6
|
+
self.send(:"#{key}=", value) if self.respond_to?(:"#{key}=")
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def percs
|
11
|
+
raise_error_when_current_or_total_not_set
|
12
|
+
current.to_f / total
|
13
|
+
end
|
14
|
+
|
15
|
+
def pending
|
16
|
+
raise_error_when_current_or_total_not_set
|
17
|
+
total - current
|
18
|
+
end
|
19
|
+
|
20
|
+
def running_for
|
21
|
+
Time.now - started
|
22
|
+
end
|
23
|
+
|
24
|
+
def total_time
|
25
|
+
running_for / percs
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_go
|
29
|
+
total_time - running_for
|
30
|
+
end
|
31
|
+
|
32
|
+
def eta
|
33
|
+
Time.now + to_go
|
34
|
+
end
|
35
|
+
|
36
|
+
def per_second
|
37
|
+
current / running_for
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_s
|
41
|
+
"%.1f%%, %.1f/second, ETA: %s" % [percs * 100, per_second, eta.iso8601]
|
42
|
+
end
|
43
|
+
|
44
|
+
def raise_error_when_current_or_total_not_set
|
45
|
+
raise "current and total must be set" if total.nil? || current.nil?
|
46
|
+
end
|
47
|
+
|
48
|
+
class << self
|
49
|
+
FACTORS = [1, 60, 3600]
|
50
|
+
|
51
|
+
def parse_time_string(string)
|
52
|
+
sum = 0.0
|
53
|
+
string.split(":").map { |s| s.to_i }.reverse.each_with_index do |value, i|
|
54
|
+
sum += value * FACTORS[i]
|
55
|
+
end
|
56
|
+
sum
|
57
|
+
end
|
58
|
+
|
59
|
+
def from_time_string(string, options = {})
|
60
|
+
self.new(options.merge(:started => Time.now - parse_time_string(string)))
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -34,4 +34,69 @@ class DynportTools::Jenkins
|
|
34
34
|
hydra.run
|
35
35
|
jobs
|
36
36
|
end
|
37
|
+
|
38
|
+
class Project
|
39
|
+
attr_accessor :name, :commands, :crontab_pattern, :days_to_keep, :num_to_keep, :node, :child_projects
|
40
|
+
DEFAUL_SCM = "hudson.scm.NullSCM"
|
41
|
+
|
42
|
+
def initialize(name)
|
43
|
+
self.name = name
|
44
|
+
self.commands = []
|
45
|
+
self.child_projects = []
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_xml
|
49
|
+
Nokogiri::XML::Builder.new(:encoding => "UTF-8") do |xml|
|
50
|
+
xml.project do
|
51
|
+
xml.actions
|
52
|
+
xml.description
|
53
|
+
if days_to_keep || num_to_keep
|
54
|
+
xml.logRotator do
|
55
|
+
xml.daysToKeep days_to_keep || -1
|
56
|
+
xml.numToKeep num_to_keep || -1
|
57
|
+
xml.artifactDaysToKeep -1
|
58
|
+
xml.artifactNumToKeep -1
|
59
|
+
end
|
60
|
+
end
|
61
|
+
xml.keepDependencies "false"
|
62
|
+
xml.properties
|
63
|
+
xml.scm(:class => DEFAUL_SCM)
|
64
|
+
xml.assignedNode node if node
|
65
|
+
xml.canRoam "true"
|
66
|
+
xml.disabled "false"
|
67
|
+
xml.blockBuildWhenDownstreamBuilding "false"
|
68
|
+
xml.blockBuildWhenUpstreamBuilding "false"
|
69
|
+
xml.triggers(:class => "vector") do
|
70
|
+
if crontab_pattern
|
71
|
+
xml.send("hudson.triggers.TimerTrigger") do
|
72
|
+
xml.spec crontab_pattern
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
xml.concurrentBuild "false"
|
77
|
+
xml.builders do
|
78
|
+
commands.each do |command|
|
79
|
+
xml.send("hudson.tasks.Shell") do
|
80
|
+
xml.command ["#!/bin/sh", command].join("\n")
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
xml.publishers do
|
85
|
+
if child_projects.any?
|
86
|
+
xml.send("hudson.tasks.BuildTrigger") do
|
87
|
+
xml.childProjects child_projects.map { |c| c.name }.join(",")
|
88
|
+
xml.threshold do
|
89
|
+
xml.name "SUCCESS"
|
90
|
+
xml.ordinal "0"
|
91
|
+
xml.color "BLUE"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
xml.buildWrappers do
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end.to_xml
|
100
|
+
end
|
101
|
+
end
|
37
102
|
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
class DynportTools::RedisQ
|
2
|
+
DEFAULTS = { :retry_count => 3 }
|
3
|
+
attr_accessor :redis_key, :retry_count, :redis
|
4
|
+
|
5
|
+
def initialize(redis_key, options = {})
|
6
|
+
DEFAULTS.merge(options).merge(:redis_key => redis_key).each do |key, value|
|
7
|
+
self.send(:"#{key}=", value) if self.respond_to?(:"#{key}=")
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def push(id, priority = nil, options = {})
|
12
|
+
priority ||= Time.now.to_i * -1
|
13
|
+
if nil_or_lower?(priority_of(id), priority)
|
14
|
+
redis.multi if !options[:no_multi]
|
15
|
+
redis.zrem(failed_key, id) if !options[:failed]
|
16
|
+
redis.zadd(redis_key, priority, id)
|
17
|
+
redis.exec if !options[:no_multi]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def push_many(array, options = {})
|
22
|
+
redis.multi do
|
23
|
+
array.each do | (id, popularity) |
|
24
|
+
push(id, popularity, options.merge(:no_multi => true))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def nil_or_lower?(a, b)
|
30
|
+
a.nil? || a.to_i < b
|
31
|
+
end
|
32
|
+
|
33
|
+
def priority_of(id)
|
34
|
+
redis.zscore(redis_key, id)
|
35
|
+
end
|
36
|
+
|
37
|
+
def count
|
38
|
+
redis.zcard(redis_key)
|
39
|
+
end
|
40
|
+
|
41
|
+
def pop
|
42
|
+
redis.multi do
|
43
|
+
redis.zrevrange(redis_key, 0, 0, :with_scores => true)
|
44
|
+
redis.zremrangebyrank(redis_key, -1, -1)
|
45
|
+
end.first
|
46
|
+
end
|
47
|
+
|
48
|
+
def failed_tries
|
49
|
+
@failed_tries ||= Hash.new(0)
|
50
|
+
end
|
51
|
+
|
52
|
+
def each
|
53
|
+
entries_with_errors = []
|
54
|
+
stats = { :errors => {}, :ok => [] }
|
55
|
+
while (result = pop).any?
|
56
|
+
begin
|
57
|
+
yield(result.first)
|
58
|
+
stats[:ok] << result.first
|
59
|
+
rescue => err
|
60
|
+
stats[:errors][result.first] = ([err.message] + err.backtrace[0,5]).join("\n")
|
61
|
+
entries_with_errors << result if mark_failed(result.first) < retry_count
|
62
|
+
end
|
63
|
+
end
|
64
|
+
push_many(entries_with_errors, :failed => true) if entries_with_errors.any?
|
65
|
+
stats
|
66
|
+
end
|
67
|
+
|
68
|
+
def mark_failed(id)
|
69
|
+
redis.zincrby(failed_key, 1, id).to_i
|
70
|
+
end
|
71
|
+
|
72
|
+
def failed_key
|
73
|
+
"#{redis_key}/failed_counts"
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require "time"
|
3
|
+
|
4
|
+
describe "DynportTools::ETA" do
|
5
|
+
let(:eta) { DynportTools::ETA.new(:current => 17, :total => 100) }
|
6
|
+
let(:time) { Time.parse("2011-02-03 04:50") }
|
7
|
+
|
8
|
+
before(:each) do
|
9
|
+
Timecop.freeze(time)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "can be initialized" do
|
13
|
+
DynportTools::ETA.new
|
14
|
+
end
|
15
|
+
|
16
|
+
it "allows setting of total" do
|
17
|
+
eta.total = 10
|
18
|
+
eta.total.should == 10
|
19
|
+
end
|
20
|
+
|
21
|
+
it "allos_setting of current" do
|
22
|
+
eta.current = 10
|
23
|
+
eta.current.should == 10
|
24
|
+
end
|
25
|
+
|
26
|
+
it "allows setting of started" do
|
27
|
+
eta.started = "some value"
|
28
|
+
eta.started.should == "some value"
|
29
|
+
end
|
30
|
+
|
31
|
+
it "allows setting of all value sthrough initalizer" do
|
32
|
+
eta = DynportTools::ETA.new(:total => 10, :current => 1, :started => "started")
|
33
|
+
eta.should return_values(:total => 10, :current => 1, :started => "started")
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "#parse_time_string" do
|
37
|
+
{
|
38
|
+
"00:15:26" => 926,
|
39
|
+
"00:00:26" => 26,
|
40
|
+
"1:00:26" => 3626,
|
41
|
+
}.each do |from, to|
|
42
|
+
it "returns #{to} for #{from}" do
|
43
|
+
DynportTools::ETA.parse_time_string(from).should == to
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "#percs" do
|
49
|
+
it "returns the correct value for percs" do
|
50
|
+
eta.total = 100
|
51
|
+
eta.current = 62
|
52
|
+
eta.percs.should == 0.62
|
53
|
+
end
|
54
|
+
|
55
|
+
it "raises an error when total is not set" do
|
56
|
+
eta.total = nil
|
57
|
+
eta.current = 10
|
58
|
+
lambda {
|
59
|
+
eta.percs
|
60
|
+
}.should raise_error("current and total must be set")
|
61
|
+
end
|
62
|
+
|
63
|
+
it "raises an error when current is not set" do
|
64
|
+
eta.current = nil
|
65
|
+
eta.total = 10
|
66
|
+
lambda {
|
67
|
+
eta.percs
|
68
|
+
}.should raise_error("current and total must be set")
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "#pending" do
|
73
|
+
it "returns teh correct amount for pending" do
|
74
|
+
eta.pending.should == 83
|
75
|
+
end
|
76
|
+
|
77
|
+
it "calls raise_error_when_current_or_total_not_set" do
|
78
|
+
eta.should_receive(:raise_error_when_current_or_total_not_set)
|
79
|
+
eta.pending
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
it "returns the correct amount for running_for" do
|
84
|
+
DynportTools::ETA.new(:current => 17, :total => 100, :started => time - 99).running_for.should == 99
|
85
|
+
end
|
86
|
+
|
87
|
+
it "returns the correct amount of total time" do
|
88
|
+
DynportTools::ETA.new(:current => 10, :total => 100, :started => time - 10).total_time.should == 100
|
89
|
+
end
|
90
|
+
|
91
|
+
it "returns the correct amount of time to go" do
|
92
|
+
DynportTools::ETA.new(:current => 10, :total => 100, :started => time - 10).to_go.should == 90
|
93
|
+
end
|
94
|
+
|
95
|
+
it "returns the correct eta" do
|
96
|
+
DynportTools::ETA.new(:current => 10, :total => 100, :started => time - 10).eta.should == time + 90
|
97
|
+
end
|
98
|
+
|
99
|
+
it "returns the correct value for per_second" do
|
100
|
+
DynportTools::ETA.new(:current => 10, :total => 100, :started => time - 1).per_second.should == 10
|
101
|
+
end
|
102
|
+
|
103
|
+
it "returns the correct string" do
|
104
|
+
DynportTools::ETA.new(:current => 10, :total => 100, :started => time - 1).to_s.should == "10.0%, 10.0/second, ETA: 2011-02-03T04:50:09+01:00"
|
105
|
+
end
|
106
|
+
|
107
|
+
describe "#from_time_string" do
|
108
|
+
it "sets the correct values" do
|
109
|
+
eta = DynportTools::ETA.from_time_string("00:01:10", :total => 100)
|
110
|
+
eta.should be_kind_of(DynportTools::ETA)
|
111
|
+
eta.should return_values(:started => time - 70, :total => 100)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -3,8 +3,155 @@ require 'spec_helper'
|
|
3
3
|
require "dynport_tools/jenkins"
|
4
4
|
|
5
5
|
describe "DynportTools::Jenkins" do
|
6
|
-
let(:
|
7
|
-
let(:jenkins) { DynportTools::Jenkins.new(
|
6
|
+
let(:url) { "http://some.url.com:8098" }
|
7
|
+
let(:jenkins) { DynportTools::Jenkins.new(url) }
|
8
|
+
|
9
|
+
describe "Project" do
|
10
|
+
let(:job) { DynportTools::Jenkins::Project.new("Some Name") }
|
11
|
+
let(:doc) { Nokogiri::XML(job.to_xml) }
|
12
|
+
|
13
|
+
describe "#initialize" do
|
14
|
+
it "sets the commands to an empty array" do
|
15
|
+
job.commands.should == []
|
16
|
+
end
|
17
|
+
|
18
|
+
it "sets the commands to an empty array" do
|
19
|
+
job.child_projects.should == []
|
20
|
+
end
|
21
|
+
|
22
|
+
it "sets the name" do
|
23
|
+
job.name.should == "Some Name"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "#to_xml" do
|
28
|
+
it "returns a string" do
|
29
|
+
job.to_xml.should be_kind_of(String)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "includes a xml header line" do
|
33
|
+
job.to_xml.should include(%(<?xml version="1.0" encoding="UTF-8"?>))
|
34
|
+
end
|
35
|
+
|
36
|
+
it "includes a project root" do
|
37
|
+
job.to_xml.should include("<project>")
|
38
|
+
job.to_xml.should include("</project>")
|
39
|
+
end
|
40
|
+
|
41
|
+
%w(actions description properties builders publishers buildWrappers).each do |key|
|
42
|
+
it "includes an empty node #{key}" do
|
43
|
+
doc.at("/project/#{key}").children.should be_empty
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
{
|
48
|
+
"keepDependencies" => "false",
|
49
|
+
"canRoam" => "true",
|
50
|
+
"disabled" => "false",
|
51
|
+
"blockBuildWhenDownstreamBuilding" => "false",
|
52
|
+
"blockBuildWhenUpstreamBuilding" => "false",
|
53
|
+
"concurrentBuild" => "false"
|
54
|
+
}.each do |key, value|
|
55
|
+
it "sets #{key} to #{value}" do
|
56
|
+
doc.at("/project/#{key}").inner_text.should == value
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
{ "scm" => "hudson.scm.NullSCM", "triggers" => "vector" }.each do |key, clazz|
|
61
|
+
it "sets the class of #{key} to #{clazz}" do
|
62
|
+
doc.at("/project/#{key}")["class"].should == clazz
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
it "includes all set commands" do
|
67
|
+
job.commands << "hostname"
|
68
|
+
job.commands << "date"
|
69
|
+
shell_tasks = doc.search("project/builders/*")
|
70
|
+
shell_tasks.map(&:name).should == ["hudson.tasks.Shell", "hudson.tasks.Shell"]
|
71
|
+
shell_tasks.map { |node| node.at("command").inner_text }.should == ["#!/bin/sh\nhostname", "#!/bin/sh\ndate"]
|
72
|
+
end
|
73
|
+
|
74
|
+
it "includes crontab like triggers" do
|
75
|
+
pattern = "0 2 * * *"
|
76
|
+
job.crontab_pattern = pattern
|
77
|
+
triggers = doc.search("project/triggers/*")
|
78
|
+
triggers.map(&:name).should == ["hudson.triggers.TimerTrigger"]
|
79
|
+
triggers.first.at("spec").inner_text.should == "0 2 * * *"
|
80
|
+
end
|
81
|
+
|
82
|
+
%w(logRotator assignedNode).each do |key|
|
83
|
+
it "does not include a #{key} node by default" do
|
84
|
+
doc.at("/project/#{key}").should be_nil
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
it "sets assignedNode when node is set" do
|
89
|
+
job.node = "processor"
|
90
|
+
doc.at("/project/assignedNode").inner_text.should == "processor"
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "with days_to_keep set" do
|
94
|
+
before(:each) do
|
95
|
+
job.days_to_keep = 7
|
96
|
+
end
|
97
|
+
|
98
|
+
it "sets days_to_keep to 7" do
|
99
|
+
doc.at("/project/logRotator/daysToKeep").inner_text.should == "7"
|
100
|
+
end
|
101
|
+
|
102
|
+
%w(numToKeep artifactDaysToKeep artifactNumToKeep).each do |key|
|
103
|
+
it "sets #{key} to -1" do
|
104
|
+
doc.at("/project/logRotator/#{key}").inner_text.should == "-1"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
describe "with num_to_keep set" do
|
110
|
+
before(:each) do
|
111
|
+
job.num_to_keep = 30
|
112
|
+
end
|
113
|
+
|
114
|
+
it "sets num_to_keep to 30" do
|
115
|
+
doc.at("/project/logRotator/numToKeep").inner_text.should == "30"
|
116
|
+
end
|
117
|
+
|
118
|
+
%w(daysToKeep artifactDaysToKeep artifactNumToKeep).each do |key|
|
119
|
+
it "sets #{key} to -1" do
|
120
|
+
doc.at("/project/logRotator/#{key}").inner_text.should == "-1"
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
it "sets numToKeep and daysToKeep when both set" do
|
126
|
+
job.num_to_keep = 10
|
127
|
+
job.days_to_keep = 2
|
128
|
+
doc.at("/project/logRotator/numToKeep").inner_text.should == "10"
|
129
|
+
doc.at("/project/logRotator/daysToKeep").inner_text.should == "2"
|
130
|
+
end
|
131
|
+
|
132
|
+
describe "with child projects" do
|
133
|
+
let(:child1) { DynportTools::Jenkins::Project.new("child 1") }
|
134
|
+
let(:child2) { DynportTools::Jenkins::Project.new("child 2") }
|
135
|
+
let(:triggers) { doc.xpath("/project/publishers/hudson.tasks.BuildTrigger") }
|
136
|
+
|
137
|
+
before(:each) do
|
138
|
+
job.child_projects << child2
|
139
|
+
job.child_projects << child1
|
140
|
+
end
|
141
|
+
|
142
|
+
it "includes all child projects" do
|
143
|
+
triggers.count.should == 1
|
144
|
+
triggers.first.at("childProjects").inner_text.should == "child 2,child 1"
|
145
|
+
end
|
146
|
+
|
147
|
+
{ "name" => "SUCCESS", "ordinal" => "0", "color" => "BLUE" }.each do |key, value|
|
148
|
+
it "sets #{key} to #{value} in threshold" do
|
149
|
+
triggers.first.at("threshold/#{key}").inner_text.should == value
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
8
155
|
|
9
156
|
describe "#initialize" do
|
10
157
|
it "sets the root url" do
|
@@ -113,7 +260,7 @@ describe "DynportTools::Jenkins" do
|
|
113
260
|
end
|
114
261
|
}
|
115
262
|
end
|
116
|
-
builder.to_xml.should == Nokogiri::XML(File.read(
|
263
|
+
builder.to_xml.should == Nokogiri::XML(File.read(root.join("spec/fixtures/jenkins_job.xml"))).to_s
|
117
264
|
end
|
118
265
|
end
|
119
266
|
end
|
@@ -0,0 +1,177 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DynportTools::RedisQ do
|
4
|
+
let(:key) { "test/redis_queue" }
|
5
|
+
let(:redis) { Redis.new(:path => root.join("tmp/redis.socket")) }
|
6
|
+
let(:queue) do
|
7
|
+
q = DynportTools::RedisQ.new(key)
|
8
|
+
q.redis = redis
|
9
|
+
q
|
10
|
+
end
|
11
|
+
|
12
|
+
before(:each) do
|
13
|
+
redis.del(key)
|
14
|
+
redis.del("test/redis_queue/failed_counts")
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "#initialize" do
|
18
|
+
it "sets the retry_count to the default value when nil" do
|
19
|
+
DynportTools::RedisQ.new("some/queue").retry_count.should == 3
|
20
|
+
end
|
21
|
+
|
22
|
+
it "sets the retry_count to a custom value when given" do
|
23
|
+
DynportTools::RedisQ.new("some/queue", :retry_count => 2).retry_count.should == 2
|
24
|
+
end
|
25
|
+
|
26
|
+
it "sets the redis_key" do
|
27
|
+
DynportTools::RedisQ.new("some/queue").redis_key.should == "some/queue"
|
28
|
+
end
|
29
|
+
|
30
|
+
it "sets the redis connection" do
|
31
|
+
DynportTools::RedisQ.new("some/queue", :redis => "redis con").redis.should == "redis con"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
it "sets the redis key when initializing" do
|
36
|
+
queue = DynportTools::RedisQ.new("some/queue")
|
37
|
+
queue.redis_key.should == "some/queue"
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "#push" do
|
41
|
+
it "pushes the records with negative timestamps" do
|
42
|
+
Timecop.freeze(Time.at(112233))
|
43
|
+
queue.push(99)
|
44
|
+
Timecop.freeze(Time.at(112235))
|
45
|
+
queue.push(101)
|
46
|
+
redis.zrevrange(key, 0, -1, :with_scores => true).should == ["99", "-112233", "101", "-112235"]
|
47
|
+
end
|
48
|
+
|
49
|
+
it "does not push records when already on the queue" do
|
50
|
+
Timecop.freeze(Time.at(112233))
|
51
|
+
queue.push(99)
|
52
|
+
Timecop.freeze(Time.at(112235))
|
53
|
+
queue.push(99)
|
54
|
+
redis.zrevrange(key, 0, -1, :with_scores => true).should == ["99", "-112233"]
|
55
|
+
end
|
56
|
+
|
57
|
+
it "changes the priority of a member when higher" do
|
58
|
+
queue.push(99, 1)
|
59
|
+
queue.push(99, 2)
|
60
|
+
redis.zrevrange(key, 0, -1, :with_scores => true).should == ["99", "2"]
|
61
|
+
end
|
62
|
+
|
63
|
+
it "uses a custom priority when given" do
|
64
|
+
queue.push(99, 1234)
|
65
|
+
redis.zrevrange(key, 0, -1, :with_scores => true).should == ["99", "1234"]
|
66
|
+
end
|
67
|
+
|
68
|
+
it "removes the key from the failed zset" do
|
69
|
+
queue.mark_failed("99")
|
70
|
+
redis.zrevrange("test/redis_queue/failed_counts", 0, -1, :with_scores => true).should == ["99", "1"]
|
71
|
+
queue.push(99, 1234)
|
72
|
+
redis.zrevrange("test/redis_queue/failed_counts", 0, -1, :with_scores => true).should == []
|
73
|
+
end
|
74
|
+
|
75
|
+
it "does not call redis.multi when no_multi is set to true" do
|
76
|
+
redis.should_not_receive(:multi)
|
77
|
+
queue.push(99, 1234, :no_multi => true)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "does not call redis.zrem when failed is true" do
|
81
|
+
redis.should_not_receive(:zrem)
|
82
|
+
queue.push(99, 1234, :failed => true)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
it "returns the correct number of elements" do
|
87
|
+
queue.count.should == 0
|
88
|
+
queue.push(99, 1234)
|
89
|
+
queue.push(101, 1234)
|
90
|
+
queue.count.should == 2
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "#pop" do
|
94
|
+
before(:each) do
|
95
|
+
queue.push(98, 10)
|
96
|
+
queue.push(99, 1)
|
97
|
+
queue.push(101, 100)
|
98
|
+
end
|
99
|
+
|
100
|
+
it "returns the highest member and rank" do
|
101
|
+
queue.pop.should == ["101", "100"]
|
102
|
+
end
|
103
|
+
|
104
|
+
it "removes the member from the set" do
|
105
|
+
queue.pop
|
106
|
+
redis.zrevrange(key, 0, -1, :with_scores => true).should == ["98", "10", "99", "1"]
|
107
|
+
end
|
108
|
+
|
109
|
+
it "returns an empty array when nothing in the queue" do
|
110
|
+
queue.pop
|
111
|
+
queue.pop
|
112
|
+
queue.pop
|
113
|
+
queue.pop.should == []
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
describe "#each" do
|
118
|
+
it "calls the block with all members in the queue" do
|
119
|
+
queue.push(99, 1)
|
120
|
+
queue.push(100, 9)
|
121
|
+
queue.push(101, 0)
|
122
|
+
ids = []
|
123
|
+
queue.each do |id|
|
124
|
+
ids << id
|
125
|
+
end
|
126
|
+
ids.should == ["100", "99", "101"]
|
127
|
+
redis.zrevrange(key, 0, -1, :with_scores => true).should == []
|
128
|
+
end
|
129
|
+
|
130
|
+
it "readds all ids to the queue which raised errors" do
|
131
|
+
queue.push(99, 1)
|
132
|
+
queue.push(100, 9)
|
133
|
+
queue.push(101, 0)
|
134
|
+
processor = double("processor")
|
135
|
+
processor.should_receive(:process).with("99").and_return true
|
136
|
+
processor.should_receive(:process).with("101").and_return true
|
137
|
+
processor.should_receive(:process).with("100").and_raise("some error")
|
138
|
+
stats = queue.each do |id|
|
139
|
+
processor.process(id)
|
140
|
+
end
|
141
|
+
stats[:ok].should == ["99", "101"]
|
142
|
+
stats[:errors]["100"].should match(/^some error/)
|
143
|
+
redis.zrevrange(key, 0, -1, :with_scores => true).should == ["100", "9"]
|
144
|
+
end
|
145
|
+
|
146
|
+
# change this to n times
|
147
|
+
it "only tries to process one failing id 3 times" do
|
148
|
+
queue.push(100, 9)
|
149
|
+
processor = double("processor")
|
150
|
+
processor.stub(:process).with("100").exactly(3).and_raise("some error")
|
151
|
+
|
152
|
+
stats = queue.each { |id| processor.process(id) }
|
153
|
+
redis.zrevrange(key, 0, -1, :with_scores => true).should == ["100", "9"]
|
154
|
+
redis.zrevrange("test/redis_queue/failed_counts", 0, -1, :with_scores => true).should == ["100", "1"]
|
155
|
+
|
156
|
+
stats = queue.each { |id| processor.process(id) }
|
157
|
+
redis.zrevrange(key, 0, -1, :with_scores => true).should == ["100", "9"]
|
158
|
+
redis.zrevrange("test/redis_queue/failed_counts", 0, -1, :with_scores => true).should == ["100", "2"]
|
159
|
+
|
160
|
+
stats = queue.each { |id| processor.process(id) }
|
161
|
+
redis.zrevrange(key, 0, -1, :with_scores => true).should == []
|
162
|
+
redis.zrevrange("test/redis_queue/failed_counts", 0, -1, :with_scores => true).should == ["100", "3"]
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
describe "#mark_failed" do
|
167
|
+
it "increments the counter in the zset" do
|
168
|
+
queue.mark_failed("100")
|
169
|
+
redis.zrevrange("test/redis_queue/failed_counts", 0, -1, :with_scores => true).should == ["100", "1"]
|
170
|
+
end
|
171
|
+
|
172
|
+
it "returns the new failed count" do
|
173
|
+
queue.mark_failed("100").should == 1
|
174
|
+
queue.mark_failed("100").should == 2
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
@@ -1,9 +1,8 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require "dynport_tools/xml_file"
|
3
3
|
|
4
|
-
FILE1 =
|
5
|
-
FILE2 =
|
6
|
-
|
4
|
+
FILE1 = root.join("spec/fixtures/file_a.xml")
|
5
|
+
FILE2 = root.join("spec/fixtures/file_b.xml")
|
7
6
|
|
8
7
|
describe "DynportTools::XmlFile" do
|
9
8
|
let(:file) { DynportTools::XmlFile.new(FILE1) }
|
data/spec/spec_helper.rb
CHANGED
@@ -2,13 +2,44 @@ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
|
2
2
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
3
|
require 'rspec'
|
4
4
|
require 'dynport_tools'
|
5
|
+
require "timecop"
|
5
6
|
|
6
7
|
# Requires supporting files with custom matchers and macros, etc,
|
7
8
|
# in ./support/ and its subdirectories.
|
8
9
|
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
9
10
|
|
10
11
|
RSpec.configure do |config|
|
11
|
-
|
12
|
+
config.include DynportTools::HaveAttributesMatcher
|
13
|
+
config.after(:each) do
|
14
|
+
Timecop.return
|
15
|
+
end
|
12
16
|
end
|
13
17
|
|
14
|
-
|
18
|
+
def root
|
19
|
+
Pathname.new(File.expand_path("../../", __FILE__))
|
20
|
+
end
|
21
|
+
|
22
|
+
def redis_pidfile
|
23
|
+
root.join("tmp/redis.pid")
|
24
|
+
end
|
25
|
+
|
26
|
+
def redis_socket
|
27
|
+
root.join("tmp/redis.socket")
|
28
|
+
end
|
29
|
+
|
30
|
+
redis_config = [
|
31
|
+
"port 0",
|
32
|
+
"unixsocket #{redis_socket}",
|
33
|
+
"pidfile #{redis_pidfile}",
|
34
|
+
"daemonize yes"
|
35
|
+
].join("\n")
|
36
|
+
|
37
|
+
FileUtils.mkdir_p(File.dirname(redis_pidfile))
|
38
|
+
|
39
|
+
system("echo '#{redis_config}' | redis-server -")
|
40
|
+
|
41
|
+
at_exit do
|
42
|
+
pid = File.read(redis_pidfile).strip
|
43
|
+
system("kill #{pid}")
|
44
|
+
FileUtils.rm_f(redis_socket)
|
45
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dynport_tools
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 7
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 2
|
9
|
-
-
|
10
|
-
version: 0.2.
|
9
|
+
- 8
|
10
|
+
version: 0.2.8
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Tobias Schwab
|
@@ -15,12 +15,13 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-08-
|
18
|
+
date: 2011-08-23 00:00:00 +02:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
22
|
-
|
23
|
-
|
22
|
+
name: nokogiri
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: &id001 !ruby/object:Gem::Requirement
|
24
25
|
none: false
|
25
26
|
requirements:
|
26
27
|
- - ">="
|
@@ -29,12 +30,12 @@ dependencies:
|
|
29
30
|
segments:
|
30
31
|
- 0
|
31
32
|
version: "0"
|
32
|
-
name: nokogiri
|
33
|
-
version_requirements: *id001
|
34
|
-
prerelease: false
|
35
|
-
- !ruby/object:Gem::Dependency
|
36
33
|
type: :runtime
|
37
|
-
requirement:
|
34
|
+
requirement: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: redis
|
37
|
+
prerelease: false
|
38
|
+
version_requirements: &id002 !ruby/object:Gem::Requirement
|
38
39
|
none: false
|
39
40
|
requirements:
|
40
41
|
- - ">="
|
@@ -43,12 +44,12 @@ dependencies:
|
|
43
44
|
segments:
|
44
45
|
- 0
|
45
46
|
version: "0"
|
46
|
-
name: redis
|
47
|
-
version_requirements: *id002
|
48
|
-
prerelease: false
|
49
|
-
- !ruby/object:Gem::Dependency
|
50
47
|
type: :runtime
|
51
|
-
requirement:
|
48
|
+
requirement: *id002
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: typhoeus
|
51
|
+
prerelease: false
|
52
|
+
version_requirements: &id003 !ruby/object:Gem::Requirement
|
52
53
|
none: false
|
53
54
|
requirements:
|
54
55
|
- - ">="
|
@@ -57,12 +58,12 @@ dependencies:
|
|
57
58
|
segments:
|
58
59
|
- 0
|
59
60
|
version: "0"
|
60
|
-
|
61
|
-
|
62
|
-
prerelease: false
|
61
|
+
type: :runtime
|
62
|
+
requirement: *id003
|
63
63
|
- !ruby/object:Gem::Dependency
|
64
|
-
|
65
|
-
|
64
|
+
name: rspec
|
65
|
+
prerelease: false
|
66
|
+
version_requirements: &id004 !ruby/object:Gem::Requirement
|
66
67
|
none: false
|
67
68
|
requirements:
|
68
69
|
- - ~>
|
@@ -73,12 +74,12 @@ dependencies:
|
|
73
74
|
- 3
|
74
75
|
- 0
|
75
76
|
version: 2.3.0
|
76
|
-
name: rspec
|
77
|
-
version_requirements: *id004
|
78
|
-
prerelease: false
|
79
|
-
- !ruby/object:Gem::Dependency
|
80
77
|
type: :development
|
81
|
-
requirement:
|
78
|
+
requirement: *id004
|
79
|
+
- !ruby/object:Gem::Dependency
|
80
|
+
name: bundler
|
81
|
+
prerelease: false
|
82
|
+
version_requirements: &id005 !ruby/object:Gem::Requirement
|
82
83
|
none: false
|
83
84
|
requirements:
|
84
85
|
- - ~>
|
@@ -89,12 +90,12 @@ dependencies:
|
|
89
90
|
- 0
|
90
91
|
- 0
|
91
92
|
version: 1.0.0
|
92
|
-
name: bundler
|
93
|
-
version_requirements: *id005
|
94
|
-
prerelease: false
|
95
|
-
- !ruby/object:Gem::Dependency
|
96
93
|
type: :development
|
97
|
-
requirement:
|
94
|
+
requirement: *id005
|
95
|
+
- !ruby/object:Gem::Dependency
|
96
|
+
name: jeweler
|
97
|
+
prerelease: false
|
98
|
+
version_requirements: &id006 !ruby/object:Gem::Requirement
|
98
99
|
none: false
|
99
100
|
requirements:
|
100
101
|
- - ~>
|
@@ -105,12 +106,12 @@ dependencies:
|
|
105
106
|
- 6
|
106
107
|
- 4
|
107
108
|
version: 1.6.4
|
108
|
-
name: jeweler
|
109
|
-
version_requirements: *id006
|
110
|
-
prerelease: false
|
111
|
-
- !ruby/object:Gem::Dependency
|
112
109
|
type: :development
|
113
|
-
requirement:
|
110
|
+
requirement: *id006
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rcov
|
113
|
+
prerelease: false
|
114
|
+
version_requirements: &id007 !ruby/object:Gem::Requirement
|
114
115
|
none: false
|
115
116
|
requirements:
|
116
117
|
- - ">="
|
@@ -119,12 +120,12 @@ dependencies:
|
|
119
120
|
segments:
|
120
121
|
- 0
|
121
122
|
version: "0"
|
122
|
-
name: rcov
|
123
|
-
version_requirements: *id007
|
124
|
-
prerelease: false
|
125
|
-
- !ruby/object:Gem::Dependency
|
126
123
|
type: :development
|
127
|
-
requirement:
|
124
|
+
requirement: *id007
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: ZenTest
|
127
|
+
prerelease: false
|
128
|
+
version_requirements: &id008 !ruby/object:Gem::Requirement
|
128
129
|
none: false
|
129
130
|
requirements:
|
130
131
|
- - "="
|
@@ -135,12 +136,12 @@ dependencies:
|
|
135
136
|
- 5
|
136
137
|
- 0
|
137
138
|
version: 4.5.0
|
138
|
-
name: ZenTest
|
139
|
-
version_requirements: *id008
|
140
|
-
prerelease: false
|
141
|
-
- !ruby/object:Gem::Dependency
|
142
139
|
type: :development
|
143
|
-
requirement:
|
140
|
+
requirement: *id008
|
141
|
+
- !ruby/object:Gem::Dependency
|
142
|
+
name: autotest
|
143
|
+
prerelease: false
|
144
|
+
version_requirements: &id009 !ruby/object:Gem::Requirement
|
144
145
|
none: false
|
145
146
|
requirements:
|
146
147
|
- - ">="
|
@@ -149,12 +150,12 @@ dependencies:
|
|
149
150
|
segments:
|
150
151
|
- 0
|
151
152
|
version: "0"
|
152
|
-
name: autotest
|
153
|
-
version_requirements: *id009
|
154
|
-
prerelease: false
|
155
|
-
- !ruby/object:Gem::Dependency
|
156
153
|
type: :development
|
157
|
-
requirement:
|
154
|
+
requirement: *id009
|
155
|
+
- !ruby/object:Gem::Dependency
|
156
|
+
name: autotest-growl
|
157
|
+
prerelease: false
|
158
|
+
version_requirements: &id010 !ruby/object:Gem::Requirement
|
158
159
|
none: false
|
159
160
|
requirements:
|
160
161
|
- - ">="
|
@@ -163,12 +164,12 @@ dependencies:
|
|
163
164
|
segments:
|
164
165
|
- 0
|
165
166
|
version: "0"
|
166
|
-
name: autotest-growl
|
167
|
-
version_requirements: *id010
|
168
|
-
prerelease: false
|
169
|
-
- !ruby/object:Gem::Dependency
|
170
167
|
type: :development
|
171
|
-
requirement:
|
168
|
+
requirement: *id010
|
169
|
+
- !ruby/object:Gem::Dependency
|
170
|
+
name: ruby-debug
|
171
|
+
prerelease: false
|
172
|
+
version_requirements: &id011 !ruby/object:Gem::Requirement
|
172
173
|
none: false
|
173
174
|
requirements:
|
174
175
|
- - ">="
|
@@ -177,9 +178,22 @@ dependencies:
|
|
177
178
|
segments:
|
178
179
|
- 0
|
179
180
|
version: "0"
|
180
|
-
|
181
|
-
|
181
|
+
type: :development
|
182
|
+
requirement: *id011
|
183
|
+
- !ruby/object:Gem::Dependency
|
184
|
+
name: timecop
|
182
185
|
prerelease: false
|
186
|
+
version_requirements: &id012 !ruby/object:Gem::Requirement
|
187
|
+
none: false
|
188
|
+
requirements:
|
189
|
+
- - ">="
|
190
|
+
- !ruby/object:Gem::Version
|
191
|
+
hash: 3
|
192
|
+
segments:
|
193
|
+
- 0
|
194
|
+
version: "0"
|
195
|
+
type: :development
|
196
|
+
requirement: *id012
|
183
197
|
description: Collection of various tools
|
184
198
|
email: tobias.schwab@dynport.de
|
185
199
|
executables:
|
@@ -191,6 +205,7 @@ extra_rdoc_files:
|
|
191
205
|
- LICENSE.txt
|
192
206
|
- README.rdoc
|
193
207
|
files:
|
208
|
+
- .autotest
|
194
209
|
- .document
|
195
210
|
- .rbenv-version
|
196
211
|
- .rspec
|
@@ -207,15 +222,19 @@ files:
|
|
207
222
|
- lib/dynport_tools.rb
|
208
223
|
- lib/dynport_tools/deep_merger.rb
|
209
224
|
- lib/dynport_tools/differ.rb
|
225
|
+
- lib/dynport_tools/eta.rb
|
210
226
|
- lib/dynport_tools/have_attributes.rb
|
211
227
|
- lib/dynport_tools/jenkins.rb
|
212
228
|
- lib/dynport_tools/redis_dumper.rb
|
229
|
+
- lib/dynport_tools/redis_q.rb
|
213
230
|
- lib/dynport_tools/xml_file.rb
|
214
231
|
- spec/dynport_tools/deep_merger_spec.rb
|
215
232
|
- spec/dynport_tools/differ_spec.rb
|
233
|
+
- spec/dynport_tools/eta_spec.rb
|
216
234
|
- spec/dynport_tools/have_attributes_spec.rb
|
217
235
|
- spec/dynport_tools/jenkins_spec.rb
|
218
236
|
- spec/dynport_tools/redis_dumper_spec.rb
|
237
|
+
- spec/dynport_tools/redis_q_spec.rb
|
219
238
|
- spec/dynport_tools/xml_file_spec.rb
|
220
239
|
- spec/dynport_tools_spec.rb
|
221
240
|
- spec/fixtures/file_a.xml
|