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 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