rrrspec-client 0.2.0

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/lib/rrrspec.rb ADDED
@@ -0,0 +1,103 @@
1
+ require 'redis'
2
+ require 'active_support/core_ext'
3
+ require 'active_support/time'
4
+ require 'socket'
5
+ require 'logger'
6
+ Time.zone_default = Time.find_zone('UTC')
7
+
8
+ require 'rrrspec/configuration'
9
+ require 'rrrspec/redis_models'
10
+
11
+ module RRRSpec
12
+ module_function
13
+
14
+ def configuration
15
+ @configuration
16
+ end
17
+
18
+ def configuration=(configuration)
19
+ @configuration = configuration
20
+ end
21
+
22
+ def configure(type=nil)
23
+ if type == nil || type == configuration.type
24
+ yield configuration
25
+ end
26
+ end
27
+
28
+ def redis
29
+ # After the process is daemonized, the redis instance is in invalid state.
30
+ # We avoid using such instance by checking the PID.
31
+ if not Thread.current[:pid] or Thread.current[:pid] != Process.pid
32
+ Thread.current[:redis] = nil
33
+ Thread.current[:pid] = Process.pid
34
+ end
35
+
36
+ # It is probable that if two other threads shares one redis connection
37
+ # one thread blocks the other thread. We avoid this by using separate
38
+ # connections.
39
+ Thread.current[:redis] ||= begin
40
+ configuration.redis.dup
41
+ end
42
+ end
43
+
44
+ def flushredis
45
+ Thread.list.each do |thread|
46
+ thread[:redis] = nil
47
+ thread[:pid] = nil
48
+ end
49
+ end
50
+
51
+ def make_key(*args)
52
+ args.join(':')
53
+ end
54
+
55
+ def hostname
56
+ @hostname ||= Socket.gethostname
57
+ end
58
+
59
+ def hostname=(hostname)
60
+ @hostname = hostname
61
+ end
62
+
63
+ def pacemaker(obj, time, margin)
64
+ loop do
65
+ obj.heartbeat(time)
66
+ sleep time - margin
67
+ end
68
+ end
69
+
70
+ DEFAULT_CONFIG_FILES = [
71
+ File.expand_path('~/.rrrspec'),
72
+ '.rrrspec',
73
+ '.rrrspec-local'
74
+ ]
75
+
76
+ def setup(configuration, config_files)
77
+ RRRSpec.configuration = configuration
78
+ files = config_files
79
+ files += ENV['RRRSPEC_CONFIG_FILES'].split(':') if ENV['RRRSPEC_CONFIG_FILES']
80
+ files += DEFAULT_CONFIG_FILES if files.empty?
81
+ RRRSpec.configuration.load_files(files)
82
+ exit 1 unless RRRSpec.configuration.check_validity
83
+ end
84
+
85
+ def logger
86
+ @logger ||= Logger.new(STDERR)
87
+ end
88
+
89
+ def logger=(logger)
90
+ @logger = logger
91
+ end
92
+
93
+ class TimedLogger
94
+ def initialize(obj)
95
+ @obj = obj
96
+ end
97
+
98
+ def write(string)
99
+ now = Time.zone.now
100
+ @obj.append_log(now.strftime("%F %T ") + string + "\n")
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,37 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'rrrspec/client/version'
5
+ require 'pathname'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = "rrrspec-client"
9
+ spec.version = RRRSpec::Client::VERSION
10
+ spec.authors = ["Masaya Suzuki"]
11
+ spec.email = ["draftcode@gmail.com"]
12
+ spec.description = "Execute RSpec in a distributed manner"
13
+ spec.summary = "Execute RSpec in a distributed manner"
14
+ spec.homepage = ""
15
+ spec.license = "MIT"
16
+
17
+ gemspec_dir = File.expand_path('..', __FILE__)
18
+ spec.files = `git ls-files`.split($/).
19
+ map { |f| File.absolute_path(f) }.
20
+ select { |f| f.start_with?(gemspec_dir) }.
21
+ map { |f| Pathname(f).relative_path_from(Pathname(gemspec_dir)).to_s }
22
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
23
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
24
+ spec.require_paths = ["lib"]
25
+
26
+ spec.add_development_dependency "bundler", "~> 1.4"
27
+ spec.add_development_dependency "rake"
28
+ spec.add_dependency "activesupport"
29
+ spec.add_dependency "extreme_timeout"
30
+ spec.add_dependency "facter"
31
+ spec.add_dependency "launchy"
32
+ spec.add_dependency "redis"
33
+ spec.add_dependency "rspec", ">= 2.14.1"
34
+ spec.add_dependency "thor"
35
+ spec.add_dependency "uuidtools"
36
+ spec.add_dependency "tzinfo"
37
+ end
data/spec/fixture.rb ADDED
@@ -0,0 +1,32 @@
1
+ module RRRSpec
2
+ def self.finished_fullset
3
+ worker = Worker.create('default')
4
+ taskset = Taskset.create(
5
+ 'testuser', 'echo 1', 'echo 2', 'default', 'default', 3, 3, 5, 5
6
+ )
7
+ task = Task.create(taskset, 10, 'spec/test_spec.rb')
8
+ taskset.add_task(task)
9
+ taskset.enqueue_task(task)
10
+ ActiveTaskset.add(taskset)
11
+ worker_log = WorkerLog.create(worker, taskset)
12
+ worker_log.set_rsync_finished_time
13
+ worker_log.append_log('worker_log log body')
14
+ worker_log.set_setup_finished_time
15
+ slave = Slave.create
16
+ taskset.add_slave(slave)
17
+ slave.append_log('slave log body')
18
+ trial = Trial.create(task, slave)
19
+ trial.start
20
+ trial.finish('pending', 'stdout body', 'stderr body', 10, 2, 0)
21
+ task.update_status('pending')
22
+ taskset.incr_succeeded_count
23
+ taskset.finish_task(task)
24
+ taskset.update_status('succeeded')
25
+ taskset.set_finished_time
26
+ ActiveTaskset.remove(taskset)
27
+ slave.update_status('normal_exit')
28
+ worker_log.set_finished_time
29
+
30
+ return worker, taskset, task, worker_log, slave, trial
31
+ end
32
+ end
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+ require 'rrrspec/client/cli'
3
+
4
+ module RRRSpec
5
+ module Client
6
+ describe CLI do
7
+ before do
8
+ RRRSpec.configuration = Configuration.new
9
+ RRRSpec.configuration.redis = @redis
10
+ described_class.class_eval do
11
+ no_commands do
12
+ def setup(arg)
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ describe '#cancelall' do
19
+ let!(:taskset1) do
20
+ Taskset.create('rsync_name', '', '', 'default', 'nothing', 3, 3, 3, 3)
21
+ end
22
+ let!(:taskset2) do
23
+ Taskset.create('rsync_name', '', '', 'default', 'nothing', 3, 3, 3, 3)
24
+ end
25
+ let!(:taskset3) do
26
+ Taskset.create('another_rsync_name', '', '', 'default', 'nothing', 3, 3, 3, 3)
27
+ end
28
+
29
+ before do
30
+ ActiveTaskset.add(taskset1)
31
+ ActiveTaskset.add(taskset2)
32
+ ActiveTaskset.add(taskset3)
33
+ end
34
+
35
+ it 'cancels all tasksets' do
36
+ subject.cancelall('rsync_name')
37
+ Timeout.timeout(3) do
38
+ expect(ArbiterQueue.dequeue).to eq(['cancel', taskset1])
39
+ expect(ArbiterQueue.dequeue).to eq(['cancel', taskset2])
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+
3
+ module RRRSpec
4
+ describe Taskset do
5
+ before do
6
+ RRRSpec.configuration = Configuration.new
7
+ RRRSpec.configuration.redis = @redis
8
+ end
9
+
10
+ before do
11
+ @worker, @taskset, @task, @worker_log, @slave, @trial =
12
+ RRRSpec.finished_fullset
13
+ end
14
+
15
+ describe '#expire' do
16
+ it 'expires all keys' do
17
+ @taskset.expire(60)
18
+ expect(@redis.ttl(@taskset.key)).to be >= 0
19
+ expect(@redis.ttl("#{@taskset.key}:rrrspec:worker:testhostname")).to be >= 0
20
+ expect(@redis.ttl("#{@taskset.key}:rrrspec:worker:testhostname:log")).to be >= 0
21
+ expect(@redis.ttl("#{@taskset.key}:slave")).to be >= 0
22
+ expect(@redis.ttl("#{@taskset.key}:task:spec/test_spec.rb")).to be >= 0
23
+ expect(@redis.ttl("#{@taskset.key}:task:spec/test_spec.rb:trial")).to be >= 0
24
+ expect(@redis.ttl(@task.trials[0].key)).to be >= 0
25
+ expect(@redis.ttl("#{@taskset.key}:task_queue")).to be >= 0
26
+ expect(@redis.ttl("#{@taskset.key}:tasks")).to be >= 0
27
+ expect(@redis.ttl("#{@taskset.key}:worker_log")).to be >= 0
28
+ expect(@redis.ttl(@slave.key)).to be >= 0
29
+ expect(@redis.ttl("#{@slave.key}:log")).to be >= 0
30
+ expect(@redis.ttl("#{@slave.key}:trial")).to be >= 0
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,54 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+ require 'rrrspec/client'
8
+ require 'fixture'
9
+
10
+ RSpec.configure do |config|
11
+ config.treat_symbols_as_metadata_keys_with_true_values = true
12
+ config.run_all_when_everything_filtered = true
13
+ config.filter_run :focus
14
+
15
+ # Run specs in random order to surface order dependencies. If you find an
16
+ # order dependency and want to debug it, you can fix the order by providing
17
+ # the seed, which is printed after each run.
18
+ # --seed 1234
19
+ config.order = 'random'
20
+
21
+ pid = nil
22
+ config.before(:suite) do
23
+ pid = Kernel.spawn("redis-server --port 9999 --save ''",
24
+ in: '/dev/null', out: '/dev/null', err: '/dev/null')
25
+ redis = Redis.new(port: 9999)
26
+ retry_count = 1
27
+ loop do
28
+ begin
29
+ redis.client.connect
30
+ break
31
+ rescue Redis::CannotConnectError
32
+ if retry_count < 10
33
+ retry_count += 1
34
+ sleep 0.01
35
+ retry
36
+ end
37
+ raise
38
+ end
39
+ end
40
+ end
41
+
42
+ config.before(:each) do
43
+ @redis = Redis.new(port: 9999)
44
+ @redis.flushall
45
+
46
+ RRRSpec.configuration = nil
47
+ RRRSpec.flushredis
48
+ RRRSpec.hostname = 'testhostname'
49
+ end
50
+
51
+ config.after(:suite) do
52
+ Process.kill('KILL', pid) if pid
53
+ end
54
+ end
metadata ADDED
@@ -0,0 +1,225 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rrrspec-client
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Masaya Suzuki
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-02-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.4'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.4'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: activesupport
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: extreme_timeout
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: facter
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: launchy
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: redis
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rspec
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - '>='
116
+ - !ruby/object:Gem::Version
117
+ version: 2.14.1
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '>='
123
+ - !ruby/object:Gem::Version
124
+ version: 2.14.1
125
+ - !ruby/object:Gem::Dependency
126
+ name: thor
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - '>='
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - '>='
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: uuidtools
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - '>='
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :runtime
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - '>='
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: tzinfo
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - '>='
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :runtime
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - '>='
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ description: Execute RSpec in a distributed manner
168
+ email:
169
+ - draftcode@gmail.com
170
+ executables:
171
+ - rrrspec
172
+ - rrrspec-client
173
+ extensions: []
174
+ extra_rdoc_files: []
175
+ files:
176
+ - .rspec
177
+ - .ruby-version
178
+ - Gemfile
179
+ - Rakefile
180
+ - bin/rrrspec
181
+ - bin/rrrspec-client
182
+ - lib/rrrspec.rb
183
+ - lib/rrrspec/client.rb
184
+ - lib/rrrspec/client/cli.rb
185
+ - lib/rrrspec/client/configuration.rb
186
+ - lib/rrrspec/client/rspec_runner.rb
187
+ - lib/rrrspec/client/slave_runner.rb
188
+ - lib/rrrspec/client/support.rb
189
+ - lib/rrrspec/client/version.rb
190
+ - lib/rrrspec/configuration.rb
191
+ - lib/rrrspec/redis_models.rb
192
+ - rrrspec-client.gemspec
193
+ - spec/fixture.rb
194
+ - spec/rrrspec/client/cli_spec.rb
195
+ - spec/rrrspec/redis_models_spec.rb
196
+ - spec/spec_helper.rb
197
+ homepage: ''
198
+ licenses:
199
+ - MIT
200
+ metadata: {}
201
+ post_install_message:
202
+ rdoc_options: []
203
+ require_paths:
204
+ - lib
205
+ required_ruby_version: !ruby/object:Gem::Requirement
206
+ requirements:
207
+ - - '>='
208
+ - !ruby/object:Gem::Version
209
+ version: '0'
210
+ required_rubygems_version: !ruby/object:Gem::Requirement
211
+ requirements:
212
+ - - '>='
213
+ - !ruby/object:Gem::Version
214
+ version: '0'
215
+ requirements: []
216
+ rubyforge_project:
217
+ rubygems_version: 2.0.3
218
+ signing_key:
219
+ specification_version: 4
220
+ summary: Execute RSpec in a distributed manner
221
+ test_files:
222
+ - spec/fixture.rb
223
+ - spec/rrrspec/client/cli_spec.rb
224
+ - spec/rrrspec/redis_models_spec.rb
225
+ - spec/spec_helper.rb