dynport_tools 0.2.6 → 0.2.8

Sign up to get free protection for your applications and to get access to all the features.
data/.autotest ADDED
@@ -0,0 +1,4 @@
1
+ Autotest.add_hook :initialize do |at|
2
+ at.add_exception(%r{^\./tmp/.*})
3
+ at.add_exception(".autotest")
4
+ end
data/Gemfile CHANGED
@@ -18,4 +18,5 @@ group :development do
18
18
  gem "autotest"
19
19
  gem "autotest-growl"
20
20
  gem "ruby-debug"
21
+ gem "timecop"
21
22
  end
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.6
1
+ 0.2.8
@@ -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.6"
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-21}
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
@@ -1,4 +1,4 @@
1
1
  module DynportTools
2
2
  end
3
3
 
4
- %w(deep_merger differ jenkins redis_dumper xml_file have_attributes).map { |m| require "dynport_tools/#{m}" }
4
+ %w(deep_merger differ jenkins redis_dumper xml_file have_attributes redis_q eta).map { |m| require "dynport_tools/#{m}" }
@@ -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(:root) { "http://some.url.com:8098" }
7
- let(:jenkins) { DynportTools::Jenkins.new(root) }
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(ROOT.join("spec/fixtures/jenkins_job.xml"))).to_s
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 = ROOT.join("spec/fixtures/file_a.xml")
5
- FILE2 = ROOT.join("spec/fixtures/file_b.xml")
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
- ROOT = Pathname.new(File.expand_path("../../", __FILE__))
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: 27
4
+ hash: 7
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 2
9
- - 6
10
- version: 0.2.6
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-21 00:00:00 +02:00
18
+ date: 2011-08-23 00:00:00 +02:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
- type: :runtime
23
- requirement: &id001 !ruby/object:Gem::Requirement
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: &id002 !ruby/object:Gem::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: &id003 !ruby/object:Gem::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
- name: typhoeus
61
- version_requirements: *id003
62
- prerelease: false
61
+ type: :runtime
62
+ requirement: *id003
63
63
  - !ruby/object:Gem::Dependency
64
- type: :development
65
- requirement: &id004 !ruby/object:Gem::Requirement
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: &id005 !ruby/object:Gem::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: &id006 !ruby/object:Gem::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: &id007 !ruby/object:Gem::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: &id008 !ruby/object:Gem::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: &id009 !ruby/object:Gem::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: &id010 !ruby/object:Gem::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: &id011 !ruby/object:Gem::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
- name: ruby-debug
181
- version_requirements: *id011
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