cloud-crowd 0.6.2 → 0.7.0.pre

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b642c04c5f924a808fb7e8877db3f784f4150345
4
+ data.tar.gz: ca7630f054708dc5ed088eb36019cd2587047cb0
5
+ SHA512:
6
+ metadata.gz: 440f76dc31892df07de7549ac985a4bd9fbca89b656a66340979a7fd9469685112f73a807fd1b256ec773a15c12798bf78c9d73f660e4d7f9c705a892153410c
7
+ data.tar.gz: 0b92287c1c6aa436dafd1a4f38e9a9bbe312c12967b67dfd08d272bafc16277696715ea3d46c2e8d22500e6087cc07b693e40338950d5c7da9f887cfa8063d42
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'cloud-crowd'
3
- s.version = '0.6.2' # Keep version in sync with cloud-cloud.rb
4
- s.date = '2011-04-14'
3
+ s.version = '0.7.0.pre' # Keep version in sync with cloud-cloud.rb
4
+ s.date = '2014-03-08'
5
5
 
6
6
  s.homepage = "http://wiki.github.com/documentcloud/cloud-crowd"
7
7
  s.summary = "Parallel Processing for the Rest of Us"
@@ -12,9 +12,11 @@ Gem::Specification.new do |s|
12
12
  everywhere is black with people and more come streaming from all sides as though
13
13
  streets had only one direction.
14
14
  EOS
15
+
16
+ s.license = "MIT"
15
17
 
16
- s.authors = ['Jeremy Ashkenas']
17
- s.email = 'jeremy@documentcloud.org'
18
+ s.authors = ['Jeremy Ashkenas', 'Ted Han']
19
+ s.email = 'opensource@documentcloud.org'
18
20
  s.rubyforge_project = 'cloud-crowd'
19
21
 
20
22
  s.require_paths = ['lib']
@@ -26,20 +28,6 @@ Gem::Specification.new do |s|
26
28
  '--main' << 'README' <<
27
29
  '--all'
28
30
 
29
- s.add_dependency 'sinatra', ['~> 0.9']
30
- s.add_dependency 'activerecord', ['~> 2.3']
31
- s.add_dependency 'json', ['>= 1.1.7']
32
- s.add_dependency 'rest-client', ['>= 1.4']
33
- s.add_dependency 'thin', ['>= 1.2.4']
34
-
35
- if s.respond_to?(:add_development_dependency)
36
- s.add_development_dependency 'faker', ['>= 0.3.1']
37
- s.add_development_dependency 'thoughtbot-shoulda', ['>= 2.10.2']
38
- s.add_development_dependency 'notahat-machinist', ['>= 1.0.3']
39
- s.add_development_dependency 'rack-test', ['>= 0.4.1']
40
- s.add_development_dependency 'mocha', ['>= 0.9.7']
41
- end
42
-
43
31
  s.files = %w(
44
32
  actions/graphics_magick.rb
45
33
  actions/process_pdfs.rb
@@ -4,9 +4,8 @@ $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__))
4
4
 
5
5
  # Common Gems:
6
6
  require 'rubygems'
7
- gem 'activerecord', '~> 2.0'
7
+ gem 'activerecord'
8
8
  gem 'json'
9
- gem 'rest-client'
10
9
  gem 'sinatra'
11
10
  gem 'thin'
12
11
 
@@ -17,7 +16,6 @@ autoload :Digest, 'digest'
17
16
  autoload :ERB, 'erb'
18
17
  autoload :FileUtils, 'fileutils'
19
18
  autoload :JSON, 'json'
20
- autoload :RestClient, 'rest_client'
21
19
  autoload :RightAws, 'right_aws'
22
20
  autoload :CloudFiles, 'cloudfiles'
23
21
  autoload :Sinatra, 'sinatra'
@@ -28,6 +26,10 @@ autoload :YAML, 'yaml'
28
26
  require 'socket'
29
27
  require 'net/http'
30
28
  require 'cloud_crowd/exceptions'
29
+ require 'rest_client'
30
+
31
+ require 'active_model_serializers'
32
+ ActiveModel::Serializer.root = false
31
33
 
32
34
  module CloudCrowd
33
35
 
@@ -45,7 +47,7 @@ module CloudCrowd
45
47
  autoload :WorkUnit, 'cloud_crowd/models'
46
48
 
47
49
  # Keep this version in sync with the gemspec.
48
- VERSION = '0.6.2'
50
+ VERSION = '0.7.0'
49
51
 
50
52
  # Increment the schema version when there's a backwards incompatible change.
51
53
  SCHEMA_VERSION = 4
@@ -7,7 +7,7 @@ module CloudCrowd
7
7
  def json(obj)
8
8
  content_type :json
9
9
  return status(204) && '' if obj.nil?
10
- obj.to_json
10
+ (obj.respond_to?(:as_json) ? obj.as_json : obj).to_json
11
11
  end
12
12
 
13
13
  # Lazy-fetch the job specified by <tt>job_id</tt>.
@@ -8,13 +8,13 @@ module CloudCrowd
8
8
 
9
9
  klass.class_eval do
10
10
  # Note that COMPLETE and INCOMPLETE are unions of other states.
11
- named_scope 'processing', :conditions => {:status => PROCESSING}
12
- named_scope 'succeeded', :conditions => {:status => SUCCEEDED}
13
- named_scope 'failed', :conditions => {:status => FAILED}
14
- named_scope 'splitting', :conditions => {:status => SPLITTING}
15
- named_scope 'merging', :conditions => {:status => MERGING}
16
- named_scope 'complete', :conditions => {:status => COMPLETE}
17
- named_scope 'incomplete', :conditions => {:status => INCOMPLETE}
11
+ scope 'processing', -> { where( :status => PROCESSING )}
12
+ scope 'succeeded', -> { where( :status => SUCCEEDED )}
13
+ scope 'failed', -> { where( :status => FAILED )}
14
+ scope 'splitting', -> { where( :status => SPLITTING )}
15
+ scope 'merging', -> { where( :status => MERGING )}
16
+ scope 'complete', -> { where( :status => COMPLETE )}
17
+ scope 'incomplete', -> { where( :status => INCOMPLETE )}
18
18
  end
19
19
 
20
20
  end
@@ -13,12 +13,17 @@ module CloudCrowd
13
13
 
14
14
  validates_presence_of :status, :inputs, :action, :options
15
15
 
16
- before_validation_on_create :set_initial_status
16
+ # Set initial status
17
+ # A Job starts out either splitting or processing, depending on its action.
18
+ before_validation(:on => :create) do
19
+ self.status = self.splittable? ? SPLITTING : PROCESSING
20
+ end
21
+
17
22
  after_create :queue_for_workers
18
23
  before_destroy :cleanup_assets
19
24
 
20
25
  # Jobs that were last updated more than N days ago.
21
- named_scope :older_than, lambda {|num| {:conditions => ['updated_at < ?', num.days.ago]} }
26
+ scope :older_than, lambda {|num| {:conditions => ['updated_at < ?', num.days.ago]} }
22
27
 
23
28
  # Create a Job from an incoming JSON request, and add it to the queue.
24
29
  def self.create_from_request(h)
@@ -86,7 +91,7 @@ module CloudCrowd
86
91
  # separate thread to get out of the transaction's way.
87
92
  # TODO: Convert this into a 'cleanup' work unit that gets run by a worker.
88
93
  def cleanup_assets
89
- AssetStore.new.cleanup(self)
94
+ # AssetStore.new.cleanup(self)
90
95
  end
91
96
 
92
97
  # Have all of the WorkUnits finished?
@@ -147,7 +152,7 @@ module CloudCrowd
147
152
 
148
153
  # A JSON representation of this job includes the statuses of its component
149
154
  # WorkUnits, as well as any completed outputs.
150
- def to_json(opts={})
155
+ def as_json(opts={})
151
156
  atts = {
152
157
  'id' => id,
153
158
  'color' => color,
@@ -158,7 +163,7 @@ module CloudCrowd
158
163
  }
159
164
  atts['outputs'] = JSON.parse(outputs) if outputs
160
165
  atts['email'] = email if email
161
- atts.to_json
166
+ atts
162
167
  end
163
168
 
164
169
 
@@ -182,10 +187,5 @@ module CloudCrowd
182
187
  self
183
188
  end
184
189
 
185
- # A Job starts out either splitting or processing, depending on its action.
186
- def set_initial_status
187
- self.status = self.splittable? ? SPLITTING : PROCESSING
188
- end
189
-
190
190
  end
191
191
  end
@@ -12,9 +12,9 @@ module CloudCrowd
12
12
  after_destroy :redistribute_work_units
13
13
 
14
14
  # Available Nodes haven't used up their maxiumum number of workers yet.
15
- named_scope :available, {
16
- :conditions => ['(max_workers is null or (select count(*) from work_units where node_record_id = node_records.id) < max_workers)'],
17
- :order => 'updated_at asc'
15
+ scope :available, -> {
16
+ where('(max_workers is null or (select count(*) from work_units where node_record_id = node_records.id) < max_workers)').
17
+ order('updated_at asc')
18
18
  }
19
19
 
20
20
  # Extract the port number from the host id.
@@ -32,7 +32,7 @@ module CloudCrowd
32
32
  :max_workers => params[:max_workers],
33
33
  :enabled_actions => params[:enabled_actions]
34
34
  }
35
- self.find_or_create_by_host(params[:host]).update_attributes!(attrs)
35
+ self.find_or_create_by(:host => params[:host]).update_attributes!(attrs)
36
36
  end
37
37
 
38
38
  # Dispatch a WorkUnit to this node. Places the node at back at the end of
@@ -82,23 +82,33 @@ module CloudCrowd
82
82
 
83
83
  # A list of the process ids of the workers currently being run by the Node.
84
84
  def worker_pids
85
- work_units.all(:select => 'worker_pid').map(&:worker_pid)
85
+ work_units.pluck('worker_pid')
86
86
  end
87
87
 
88
88
  # Release all of this Node's WorkUnits for other nodes to take.
89
89
  def release_work_units
90
- WorkUnit.update_all('node_record_id = null, worker_pid = null', "node_record_id = #{id}")
90
+ WorkUnit.where("node_record_id = #{id}").update_all('node_record_id = null, worker_pid = null')
91
91
  end
92
92
 
93
93
  # The JSON representation of a NodeRecord includes its worker_pids.
94
- def to_json(opts={})
95
- { 'host' => host,
96
- 'workers' => worker_pids,
97
- 'status' => display_status,
98
- 'tag' => tag
99
- }.to_json
94
+
95
+ class Serializer < ActiveModel::Serializer
96
+ attributes :host, :tag, :workers, :status
97
+
98
+ def workers
99
+ object.worker_pids
100
+ end
101
+
102
+ def status
103
+ object.display_status
104
+ end
100
105
  end
106
+
107
+ def active_model_serializer; Serializer; end
101
108
 
109
+ def to_json
110
+ Serializer.new(self).to_json
111
+ end
102
112
 
103
113
  private
104
114
 
@@ -6,7 +6,7 @@ module CloudCrowd
6
6
  # are each run as a single WorkUnit.
7
7
  class WorkUnit < ActiveRecord::Base
8
8
  include ModelStatus
9
-
9
+
10
10
  # We use a random number in (0...MAX_RESERVATION) to reserve work units.
11
11
  # The size of the maximum signed integer in MySQL -- SQLite has no limit.
12
12
  MAX_RESERVATION = 2147483647
@@ -21,11 +21,9 @@ module CloudCrowd
21
21
  validates_presence_of :job_id, :status, :input, :action
22
22
 
23
23
  # Available WorkUnits are waiting to be distributed to Nodes for processing.
24
- named_scope :available, {:conditions => {:reservation => nil, :worker_pid => nil, :status => INCOMPLETE}}
24
+ scope :available, -> { where(:reservation => nil, :worker_pid => nil, :status => INCOMPLETE) }
25
25
  # Reserved WorkUnits have been marked for distribution by a central server process.
26
- named_scope :reserved, lambda {|reservation|
27
- {:conditions => {:reservation => reservation}, :order => 'updated_at asc'}
28
- }
26
+ scope :reserved, ->(reservation) { where(:reservation => reservation).order('updated_at asc') }
29
27
 
30
28
  # Attempt to send a list of WorkUnits to nodes with available capacity.
31
29
  # A single central server process stops the same WorkUnit from being
@@ -43,27 +41,25 @@ module CloudCrowd
43
41
 
44
42
  # Find the available nodes, and determine what actions we're capable
45
43
  # of running at the moment.
46
- available_nodes = NodeRecord.available
44
+ available_nodes = NodeRecord.available.to_a
47
45
  available_actions = available_nodes.map {|node| node.actions }.flatten.uniq
48
46
  filter = "action in (#{available_actions.map{|a| "'#{a}'"}.join(',')})"
49
47
 
50
48
  # Reserve a handful of available work units.
51
49
  WorkUnit.cancel_reservations(reservation) if reservation
52
50
  return unless reservation = WorkUnit.reserve_available(:limit => RESERVATION_LIMIT, :conditions => filter)
53
- work_units = WorkUnit.reserved(reservation)
51
+ work_units = WorkUnit.reserved(reservation).to_a
54
52
 
55
53
  # Round robin through the nodes and units, sending the unit if the node
56
54
  # is able to process it.
57
- work_units.each do |unit|
58
- available_nodes.each do |node|
59
- if node.actions.include? unit.action
60
- if node.send_work_unit unit
61
- work_units.delete unit
62
- available_nodes.delete node if node.busy?
63
- break
64
- end
55
+ while (unit = work_units.shift) and available_nodes.any? do
56
+ while node = available_nodes.shift do
57
+ if node.actions.include?(unit.action) and node.send_work_unit(unit)
58
+ available_nodes.push(node) unless node.busy?
59
+ break
65
60
  end
66
61
  end
62
+ work_units.push(unit) unless unit.assigned?
67
63
  end
68
64
 
69
65
  # If we still have units at this point, or we're fresh out of nodes,
@@ -77,9 +73,11 @@ module CloudCrowd
77
73
  # Reserves all available WorkUnits for this process. Returns false if there
78
74
  # were none available.
79
75
  def self.reserve_available(options={})
80
- reservation = ActiveSupport::SecureRandom.random_number(MAX_RESERVATION)
76
+ reservation = SecureRandom.random_number(MAX_RESERVATION)
81
77
  conditions = "reservation is null and node_record_id is null and status in (#{INCOMPLETE.join(',')}) and #{options[:conditions]}"
82
- any = WorkUnit.update_all("reservation = #{reservation}", conditions, options) > 0
78
+ query = WorkUnit.where(conditions)
79
+ query.limit(options[:limit]) if options[:limit]
80
+ any = query.update_all("reservation = #{reservation}") > 0
83
81
  any && reservation
84
82
  end
85
83
 
@@ -166,6 +164,10 @@ module CloudCrowd
166
164
  def assign_to(node_record, worker_pid)
167
165
  update_attributes!(:node_record => node_record, :worker_pid => worker_pid)
168
166
  end
167
+
168
+ def assigned?
169
+ !!(node_record_id && worker_pid)
170
+ end
169
171
 
170
172
  # All output needs to be wrapped in a JSON object for consistency
171
173
  # (unfortunately, JSON.parse needs the top-level to be an object or array).
@@ -176,17 +178,15 @@ module CloudCrowd
176
178
 
177
179
  # The JSON representation of a WorkUnit shares the Job's options with all
178
180
  # its cousin WorkUnits.
179
- def to_json
180
- {
181
- 'id' => self.id,
182
- 'job_id' => self.job_id,
183
- 'input' => self.input,
184
- 'attempts' => self.attempts,
185
- 'action' => self.action,
186
- 'options' => JSON.parse(self.job.options),
187
- 'status' => self.status
188
- }.to_json
181
+ class Serializer < ActiveModel::Serializer
182
+ attributes :id, :job_id, :input, :attempts, :action, :options, :status
183
+
184
+ def options; JSON.parse(object.job.options); end
189
185
  end
186
+
187
+ def active_model_serializer; Serializer; end
188
+ def to_json; Serializer.new(self).to_json; end
190
189
 
191
190
  end
192
191
  end
192
+ require 'securerandom'
@@ -7,6 +7,7 @@ module CloudCrowd
7
7
  # [get /heartbeat] Returns 200 OK to let monitoring tools know the server's up.
8
8
  # [post /work] The central server hits <tt>/work</tt> to dispatch a WorkUnit to this Node.
9
9
  class Node < Sinatra::Base
10
+ use ActiveRecord::ConnectionAdapters::ConnectionManagement
10
11
 
11
12
  # A Node's default port. You only run a single node per machine, so they
12
13
  # can all use the same port without any problems.
@@ -76,7 +77,7 @@ module CloudCrowd
76
77
  @overloaded = false
77
78
  @max_load = CloudCrowd.config[:max_load]
78
79
  @min_memory = CloudCrowd.config[:min_free_memory]
79
- start unless test?
80
+ start unless ENV['RACK_ENV'] == 'test'
80
81
  end
81
82
 
82
83
  # Starting up a Node registers with the central server and begins to listen
@@ -18,6 +18,7 @@ module CloudCrowd
18
18
  # [delete /node/:host] Removes a Node from the registry, freeing up any WorkUnits that it had checked out.
19
19
  # [put /work/:unit_id] Mark a finished WorkUnit as completed or failed, with results.
20
20
  class Server < Sinatra::Base
21
+ use ActiveRecord::ConnectionAdapters::ConnectionManagement
21
22
 
22
23
  set :root, ROOT
23
24
  set :authorization_realm, "CloudCrowd"
@@ -42,7 +43,7 @@ module CloudCrowd
42
43
  # larger -- keep it in mind.
43
44
  get '/status' do
44
45
  json(
45
- 'nodes' => NodeRecord.all(:order => 'host desc'),
46
+ 'nodes' => NodeRecord.order('host desc').map{ |node| NodeRecord::Serializer.new(node).as_json },
46
47
  'job_count' => Job.incomplete.count,
47
48
  'work_unit_count' => WorkUnit.incomplete.count
48
49
  )
@@ -12,7 +12,7 @@ class ServerTest < Test::Unit::TestCase
12
12
 
13
13
  setup do
14
14
  Job.destroy_all
15
- 2.times { Job.make }
15
+ 2.times { Job.make! }
16
16
  end
17
17
 
18
18
  should "set the identity of the Ruby instance" do
@@ -1,6 +1,3 @@
1
- Sham.url { Faker::Internet.domain_name + "/" + Faker::Internet.domain_word + ".jpg" }
2
- Sham.host { Faker::Internet.domain_name + '.local' }
3
-
4
1
  CloudCrowd::Job.blueprint do
5
2
  status { CloudCrowd::PROCESSING }
6
3
  inputs { ['http://www.google.com/intl/en_ALL/images/logo.gif'].to_json }
@@ -10,7 +7,7 @@ CloudCrowd::Job.blueprint do
10
7
  end
11
8
 
12
9
  CloudCrowd::NodeRecord.blueprint do
13
- host
10
+ host { "hostname-#{sn}" }
14
11
  ip_address { '127.0.0.1' }
15
12
  port { 6093 }
16
13
  enabled_actions { 'graphics_magick,word_count' }
@@ -18,7 +15,7 @@ CloudCrowd::NodeRecord.blueprint do
18
15
  end
19
16
 
20
17
  CloudCrowd::WorkUnit.blueprint do
21
- job { CloudCrowd::Job.make }
18
+ job { CloudCrowd::Job.make! }
22
19
  status { CloudCrowd::PROCESSING }
23
20
  input { '{"key":"value"}' }
24
21
  action { 'graphics_magick' }
@@ -1,19 +1,28 @@
1
1
  ENV['RACK_ENV'] = 'test'
2
2
  require 'rubygems'
3
3
 
4
+ require 'pry'
5
+ require 'faker'
6
+ require 'sham'
7
+ require 'rack/test'
8
+ require 'shoulda'
9
+ require 'shoulda/context'
10
+ require 'shoulda/matchers/active_record'
11
+ require 'shoulda/matchers/active_model'
12
+ require 'machinist/active_record'
13
+ require 'mocha/setup'
14
+
4
15
  here = File.dirname(__FILE__)
5
16
  require File.expand_path(here + "/../lib/cloud-crowd")
6
17
  CloudCrowd.configure(here + '/config/config.yml')
7
18
  CloudCrowd.configure_database(here + '/config/database.yml')
8
19
 
9
- require 'faker'
10
- require 'sham'
11
- require 'rack/test'
12
- require 'shoulda/active_record'
13
- require 'machinist/active_record'
14
- require 'mocha'
15
20
  require "#{CloudCrowd::ROOT}/test/blueprints.rb"
16
21
 
17
22
  class Test::Unit::TestCase
18
23
  include CloudCrowd
24
+ include Shoulda::Matchers::ActiveRecord
25
+ extend Shoulda::Matchers::ActiveRecord
26
+ include Shoulda::Matchers::ActiveModel
27
+ extend Shoulda::Matchers::ActiveModel
19
28
  end
@@ -8,11 +8,11 @@ class ConfigurationTest < Test::Unit::TestCase
8
8
 
9
9
  should "have read in config.yml" do
10
10
  assert CloudCrowd.config[:max_workers] == 10
11
- assert CloudCrowd.config[:storage] == 'filesystem'
11
+ #assert CloudCrowd.config[:storage] == 'filesystem'
12
12
  end
13
13
 
14
14
  should "allow config.yml to configure the implementation of AssetStore" do
15
- assert CloudCrowd::AssetStore.ancestors.include?(CloudCrowd::AssetStore::FilesystemStore)
15
+ #assert CloudCrowd::AssetStore.ancestors.include?(CloudCrowd::AssetStore::FilesystemStore)
16
16
  end
17
17
 
18
18
  should "have properly configured the ActiveRecord database" do
@@ -5,15 +5,17 @@ class JobTest < Test::Unit::TestCase
5
5
  context "A CloudCrowd Job" do
6
6
 
7
7
  setup do
8
- @job = Job.make
8
+ @job = Job.make!
9
9
  @unit = @job.work_units.first
10
10
  end
11
11
 
12
12
  subject { @job }
13
13
 
14
- should_have_many :work_units
14
+ should have_many(:work_units)
15
15
 
16
- should_validate_presence_of :status, :inputs, :action, :options
16
+ [:status, :inputs, :action, :options].each do |field|
17
+ should validate_presence_of(field)
18
+ end
17
19
 
18
20
  should "create all of its work units as soon as the job is created" do
19
21
  assert @job.work_units.count >= 1
@@ -87,12 +89,10 @@ class JobTest < Test::Unit::TestCase
87
89
  end
88
90
 
89
91
  should "be able to clean up jobs that have aged beyond their use" do
90
- count = Job.count
91
92
  Job.cleanup_all
92
- assert count == Job.count
93
- Job.record_timestamps = false
94
- @job.update_attributes :status => SUCCEEDED, :updated_at => 10.days.ago
95
- Job.record_timestamps = true
93
+ count = Job.count
94
+ @job.update_attributes({:status => SUCCEEDED, :updated_at => 10.days.ago })
95
+ assert @job.status == SUCCEEDED
96
96
  Job.cleanup_all
97
97
  assert count > Job.count
98
98
  assert !Job.find_by_id(@job.id)
@@ -5,7 +5,7 @@ class NodeUnitTest < Test::Unit::TestCase
5
5
  context "A Node" do
6
6
 
7
7
  setup do
8
- @node = Node.new(:port => 11011, :tag => "nodule").instance_variable_get(:@app)
8
+ @node = Node.new(:port => 11011, :tag => "nodule").instance_variable_get(:@instance)
9
9
  end
10
10
 
11
11
  should "set the identity of the Ruby instance" do
@@ -5,14 +5,16 @@ class NodeRecordTest < Test::Unit::TestCase
5
5
  context "A NodeRecord" do
6
6
 
7
7
  setup do
8
- @node = CloudCrowd::NodeRecord.make
8
+ @node = CloudCrowd::NodeRecord.make!
9
9
  end
10
10
 
11
11
  subject { @node }
12
12
 
13
- should_have_many :work_units
13
+ should have_many :work_units
14
14
 
15
- should_validate_presence_of :host, :ip_address, :port, :enabled_actions
15
+ [:host, :ip_address, :port, :enabled_actions].each do |field|
16
+ should validate_presence_of(field)
17
+ end
16
18
 
17
19
  should "be available" do
18
20
  assert NodeRecord.available.map(&:id).include? @node.id
@@ -26,7 +28,7 @@ class NodeRecordTest < Test::Unit::TestCase
26
28
  should "know if the node is busy" do
27
29
  assert !@node.busy?
28
30
  assert @node.display_status == 'available'
29
- (@node.max_workers + 1).times { WorkUnit.make(:node_record => @node) }
31
+ (@node.max_workers + 1).times { WorkUnit.make!(:node_record => @node) }
30
32
  assert @node.busy?
31
33
  assert @node.display_status == 'busy'
32
34
  @node.release_work_units
@@ -5,15 +5,17 @@ class WorkUnitTest < Test::Unit::TestCase
5
5
  context "A WorkUnit" do
6
6
 
7
7
  setup do
8
- @unit = CloudCrowd::WorkUnit.make
8
+ @unit = CloudCrowd::WorkUnit.make!
9
9
  @job = @unit.job
10
10
  end
11
11
 
12
12
  subject { @unit }
13
13
 
14
- should_belong_to :job
14
+ should belong_to :job
15
15
 
16
- should_validate_presence_of :job_id, :status, :input, :action
16
+ [:job_id, :status, :input, :action].each do |field|
17
+ should validate_presence_of(field)
18
+ end
17
19
 
18
20
  should "know if its done" do
19
21
  assert !@unit.complete?
@@ -24,7 +26,7 @@ class WorkUnitTest < Test::Unit::TestCase
24
26
  end
25
27
 
26
28
  should "have JSON that includes job attributes" do
27
- job = Job.make
29
+ job = Job.make!
28
30
  unit_data = JSON.parse(job.work_units.first.to_json)
29
31
  assert unit_data['job_id'] == job.id
30
32
  assert unit_data['action'] == job.action
@@ -5,8 +5,8 @@ class WorkerTest < Test::Unit::TestCase
5
5
  context "A CloudCrowd::Worker" do
6
6
 
7
7
  setup do
8
- @node = Node.new.instance_variable_get(:@app)
9
- @unit = WorkUnit.make
8
+ @node = Node.new.instance_variable_get(:"@instance")
9
+ @unit = WorkUnit.make!
10
10
  @worker = Worker.new(@node, JSON.parse(@unit.to_json))
11
11
  end
12
12
 
metadata CHANGED
@@ -1,220 +1,63 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: cloud-crowd
3
- version: !ruby/object:Gem::Version
4
- hash: 3
5
- prerelease:
6
- segments:
7
- - 0
8
- - 6
9
- - 2
10
- version: 0.6.2
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.7.0.pre
11
5
  platform: ruby
12
- authors:
6
+ authors:
13
7
  - Jeremy Ashkenas
8
+ - Ted Han
14
9
  autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
-
18
- date: 2011-04-14 00:00:00 Z
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
21
- name: sinatra
22
- prerelease: false
23
- requirement: &id001 !ruby/object:Gem::Requirement
24
- none: false
25
- requirements:
26
- - - ~>
27
- - !ruby/object:Gem::Version
28
- hash: 25
29
- segments:
30
- - 0
31
- - 9
32
- version: "0.9"
33
- type: :runtime
34
- version_requirements: *id001
35
- - !ruby/object:Gem::Dependency
36
- name: activerecord
37
- prerelease: false
38
- requirement: &id002 !ruby/object:Gem::Requirement
39
- none: false
40
- requirements:
41
- - - ~>
42
- - !ruby/object:Gem::Version
43
- hash: 5
44
- segments:
45
- - 2
46
- - 3
47
- version: "2.3"
48
- type: :runtime
49
- version_requirements: *id002
50
- - !ruby/object:Gem::Dependency
51
- name: json
52
- prerelease: false
53
- requirement: &id003 !ruby/object:Gem::Requirement
54
- none: false
55
- requirements:
56
- - - ">="
57
- - !ruby/object:Gem::Version
58
- hash: 29
59
- segments:
60
- - 1
61
- - 1
62
- - 7
63
- version: 1.1.7
64
- type: :runtime
65
- version_requirements: *id003
66
- - !ruby/object:Gem::Dependency
67
- name: rest-client
68
- prerelease: false
69
- requirement: &id004 !ruby/object:Gem::Requirement
70
- none: false
71
- requirements:
72
- - - ">="
73
- - !ruby/object:Gem::Version
74
- hash: 7
75
- segments:
76
- - 1
77
- - 4
78
- version: "1.4"
79
- type: :runtime
80
- version_requirements: *id004
81
- - !ruby/object:Gem::Dependency
82
- name: thin
83
- prerelease: false
84
- requirement: &id005 !ruby/object:Gem::Requirement
85
- none: false
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- hash: 23
90
- segments:
91
- - 1
92
- - 2
93
- - 4
94
- version: 1.2.4
95
- type: :runtime
96
- version_requirements: *id005
97
- - !ruby/object:Gem::Dependency
98
- name: faker
99
- prerelease: false
100
- requirement: &id006 !ruby/object:Gem::Requirement
101
- none: false
102
- requirements:
103
- - - ">="
104
- - !ruby/object:Gem::Version
105
- hash: 17
106
- segments:
107
- - 0
108
- - 3
109
- - 1
110
- version: 0.3.1
111
- type: :development
112
- version_requirements: *id006
113
- - !ruby/object:Gem::Dependency
114
- name: thoughtbot-shoulda
115
- prerelease: false
116
- requirement: &id007 !ruby/object:Gem::Requirement
117
- none: false
118
- requirements:
119
- - - ">="
120
- - !ruby/object:Gem::Version
121
- hash: 35
122
- segments:
123
- - 2
124
- - 10
125
- - 2
126
- version: 2.10.2
127
- type: :development
128
- version_requirements: *id007
129
- - !ruby/object:Gem::Dependency
130
- name: notahat-machinist
131
- prerelease: false
132
- requirement: &id008 !ruby/object:Gem::Requirement
133
- none: false
134
- requirements:
135
- - - ">="
136
- - !ruby/object:Gem::Version
137
- hash: 17
138
- segments:
139
- - 1
140
- - 0
141
- - 3
142
- version: 1.0.3
143
- type: :development
144
- version_requirements: *id008
145
- - !ruby/object:Gem::Dependency
146
- name: rack-test
147
- prerelease: false
148
- requirement: &id009 !ruby/object:Gem::Requirement
149
- none: false
150
- requirements:
151
- - - ">="
152
- - !ruby/object:Gem::Version
153
- hash: 13
154
- segments:
155
- - 0
156
- - 4
157
- - 1
158
- version: 0.4.1
159
- type: :development
160
- version_requirements: *id009
161
- - !ruby/object:Gem::Dependency
162
- name: mocha
163
- prerelease: false
164
- requirement: &id010 !ruby/object:Gem::Requirement
165
- none: false
166
- requirements:
167
- - - ">="
168
- - !ruby/object:Gem::Version
169
- hash: 53
170
- segments:
171
- - 0
172
- - 9
173
- - 7
174
- version: 0.9.7
175
- type: :development
176
- version_requirements: *id010
177
- description: " The crowd, suddenly there where there was nothing before, is a mysterious and\n universal phenomenon. A few people may have been standing together -- five, ten\n or twelve, nor more; nothing has been announced, nothing is expected. Suddenly\n everywhere is black with people and more come streaming from all sides as though\n streets had only one direction.\n"
178
- email: jeremy@documentcloud.org
179
- executables:
12
+ date: 2014-03-08 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: |2
15
+ The crowd, suddenly there where there was nothing before, is a mysterious and
16
+ universal phenomenon. A few people may have been standing together -- five, ten
17
+ or twelve, nor more; nothing has been announced, nothing is expected. Suddenly
18
+ everywhere is black with people and more come streaming from all sides as though
19
+ streets had only one direction.
20
+ email: opensource@documentcloud.org
21
+ executables:
180
22
  - crowd
181
23
  extensions: []
182
-
183
- extra_rdoc_files:
24
+ extra_rdoc_files:
25
+ - README
26
+ files:
27
+ - EPIGRAPHS
28
+ - LICENSE
184
29
  - README
185
- files:
186
30
  - actions/graphics_magick.rb
187
31
  - actions/process_pdfs.rb
188
32
  - actions/word_count.rb
33
+ - bin/crowd
189
34
  - cloud-crowd.gemspec
190
35
  - config/config.example.ru
191
36
  - config/config.example.yml
192
37
  - config/database.example.yml
193
- - EPIGRAPHS
194
38
  - examples/graphics_magick_example.rb
195
39
  - examples/process_pdfs_example.rb
196
40
  - examples/word_count_example.rb
197
41
  - lib/cloud-crowd.rb
198
42
  - lib/cloud_crowd/action.rb
43
+ - lib/cloud_crowd/asset_store.rb
44
+ - lib/cloud_crowd/asset_store/cloudfiles_store.rb
199
45
  - lib/cloud_crowd/asset_store/filesystem_store.rb
200
46
  - lib/cloud_crowd/asset_store/s3_store.rb
201
- - lib/cloud_crowd/asset_store/cloudfiles_store.rb
202
- - lib/cloud_crowd/asset_store.rb
203
47
  - lib/cloud_crowd/command_line.rb
204
48
  - lib/cloud_crowd/exceptions.rb
49
+ - lib/cloud_crowd/helpers.rb
205
50
  - lib/cloud_crowd/helpers/authorization.rb
206
51
  - lib/cloud_crowd/helpers/resources.rb
207
- - lib/cloud_crowd/helpers.rb
208
52
  - lib/cloud_crowd/inflector.rb
53
+ - lib/cloud_crowd/models.rb
209
54
  - lib/cloud_crowd/models/job.rb
210
55
  - lib/cloud_crowd/models/node_record.rb
211
56
  - lib/cloud_crowd/models/work_unit.rb
212
- - lib/cloud_crowd/models.rb
213
57
  - lib/cloud_crowd/node.rb
214
58
  - lib/cloud_crowd/schema.rb
215
59
  - lib/cloud_crowd/server.rb
216
60
  - lib/cloud_crowd/worker.rb
217
- - LICENSE
218
61
  - public/css/admin_console.css
219
62
  - public/css/reset.css
220
63
  - public/images/bullet_green.png
@@ -234,64 +77,53 @@ files:
234
77
  - public/js/excanvas.js
235
78
  - public/js/flot.js
236
79
  - public/js/jquery.js
237
- - README
238
- - test/acceptance/test_node.rb
239
80
  - test/acceptance/test_failing_work_units.rb
81
+ - test/acceptance/test_node.rb
240
82
  - test/acceptance/test_server.rb
241
83
  - test/acceptance/test_word_count.rb
242
84
  - test/blueprints.rb
85
+ - test/config/actions/failure_testing.rb
243
86
  - test/config/config.ru
244
87
  - test/config/config.yml
245
88
  - test/config/database.yml
246
- - test/config/actions/failure_testing.rb
247
89
  - test/test_helper.rb
248
90
  - test/unit/test_action.rb
249
91
  - test/unit/test_configuration.rb
92
+ - test/unit/test_job.rb
250
93
  - test/unit/test_node.rb
251
94
  - test/unit/test_node_record.rb
252
- - test/unit/test_job.rb
253
- - test/unit/test_worker.rb
254
95
  - test/unit/test_work_unit.rb
96
+ - test/unit/test_worker.rb
255
97
  - views/operations_center.erb
256
- - bin/crowd
257
98
  homepage: http://wiki.github.com/documentcloud/cloud-crowd
258
- licenses: []
259
-
99
+ licenses:
100
+ - MIT
101
+ metadata: {}
260
102
  post_install_message:
261
- rdoc_options:
262
- - --title
103
+ rdoc_options:
104
+ - "--title"
263
105
  - CloudCrowd | Parallel Processing for the Rest of Us
264
- - --exclude
106
+ - "--exclude"
265
107
  - test
266
- - --main
108
+ - "--main"
267
109
  - README
268
- - --all
269
- require_paths:
110
+ - "--all"
111
+ require_paths:
270
112
  - lib
271
- required_ruby_version: !ruby/object:Gem::Requirement
272
- none: false
273
- requirements:
274
- - - ">="
275
- - !ruby/object:Gem::Version
276
- hash: 3
277
- segments:
278
- - 0
279
- version: "0"
280
- required_rubygems_version: !ruby/object:Gem::Requirement
281
- none: false
282
- requirements:
113
+ required_ruby_version: !ruby/object:Gem::Requirement
114
+ requirements:
283
115
  - - ">="
284
- - !ruby/object:Gem::Version
285
- hash: 3
286
- segments:
287
- - 0
288
- version: "0"
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ required_rubygems_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ">"
121
+ - !ruby/object:Gem::Version
122
+ version: 1.3.1
289
123
  requirements: []
290
-
291
124
  rubyforge_project: cloud-crowd
292
- rubygems_version: 1.7.2
125
+ rubygems_version: 2.2.1
293
126
  signing_key:
294
- specification_version: 3
127
+ specification_version: 4
295
128
  summary: Parallel Processing for the Rest of Us
296
129
  test_files: []
297
-