cloud-crowd 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'cloud-crowd'
3
- s.version = '0.4.1' # Keep version in sync with cloud-cloud.rb
4
- s.date = '2010-04-22'
3
+ s.version = '0.5.0' # Keep version in sync with cloud-cloud.rb
4
+ s.date = '2010-06-22'
5
5
 
6
6
  s.homepage = "http://wiki.github.com/documentcloud/cloud-crowd"
7
7
  s.summary = "Parallel Processing for the Rest of Us"
@@ -1,68 +1,7 @@
1
- # The URL where you're planning on running the central server/queue/database.
2
- :central_server: http://localhost:9173
1
+ # This file configures your CloudCrowd installation, and should be consistent
2
+ # between your server and all of your nodes. For more information, see:
3
+ # http://wiki.github.com/documentcloud/cloud-crowd/the-configuration-folder
3
4
 
4
- # The following settings allow you to control the number of workers that can run
5
- # on a given node, to prevent the node from becoming overloaded. 'max_workers'
6
- # is a simple cap on the maximum number of workers a node is allowed to run
7
- # concurrently. 'max_load' is the maximum (one-minute) load average, above which
8
- # a node will refuse to take new work. 'min_free_memory' is the minimum amount
9
- # of free RAM (in megabytes) a node is allowed to have, below which no new
10
- # workers are run. These settings may be used in any combination.
11
- :max_workers: 5
12
- # :max_load: 5.0
13
- # :min_free_memory: 150
14
-
15
- # The storage back-end that you'd like to use for intermediate and final results
16
- # of processing. 's3', 'filesystem', and 'cloudfiles' are supported.
17
- # 'filesystem' should only be used in development, on single-machine installations,
18
- # or networked drives. If you *are* developing an action, filesystem is certainly
19
- # faster and easier.
20
- :storage: s3
21
-
22
- # Please provide your AWS credentials for S3 storage of job output.
23
- :aws_access_key: [your AWS access key]
24
- :aws_secret_key: [your AWS secret access key]
25
-
26
- # Choose an S3 bucket to store all CloudCrowd output, and decide if you'd like
27
- # to keep all resulting files on S3 private. If so, you'll receive authenticated
28
- # S3 URLs as job output, good for 24 hours. If left public, you'll get the
29
- # straight URLs to the files on S3.
30
- :s3_bucket: [your CloudCrowd bucket]
31
- :s3_authentication: no
32
-
33
- # Cloudfiles
34
- :cloudfiles_username: [your Rackspace Cloud Files username]
35
- :cloudfiles_api_key: [your Rackspace Cloud Files API key]
36
- :cloudfiles_container: [your Rackspace Cloud Files container]
37
-
38
- # The following settings configure local paths. 'local_storage_path' is the
39
- # directory in which all files will be saved if you're using the 'filesystem'
40
- # storage. 'log_path' and 'pid_path' are the directories in which daemonized
41
- # servers and nodes will store their process ids and log files. The default
42
- # values are listed.
43
- # :local_storage_path: /tmp/cloud_crowd_storage
44
- # :log_path: log
45
- # :pid_path: tmp/pids
46
-
47
- # Use HTTP Basic Auth for all requests? (Includes all internal worker requests
48
- # to the central server). If yes, specify the login and password that all
49
- # requests must provide for authentication.
50
- :http_authentication: no
51
- :login: [your login name]
52
- :password: [your password]
53
-
54
- # Disable all the default built-in actions
55
- # :disable_default_actions: true
56
-
57
- # Disable specific actions for the node
58
- # Use this if you want to disable a limited number of actions
59
- # :disabled_actions: ['word_count']
60
-
61
- # By default, CloudCrowd looks for installed actions inside the 'actions'
62
- # subdirectory of this configuration folder. 'actions_path' allows you to load
63
- # additional actions from a location of your choice.
64
- # :actions_path: /path/to/actions
65
-
66
- # The number of separate attempts that will be made to process an individual
67
- # work unit, before marking it as having failed.
68
- :work_unit_retries: 3
5
+ :central_server: http://localhost:9173
6
+ :max_workers: 5
7
+ :storage: filesystem
@@ -26,6 +26,7 @@ autoload :YAML, 'yaml'
26
26
 
27
27
  # Common code which should really be required in every circumstance.
28
28
  require 'socket'
29
+ require 'net/http'
29
30
  require 'cloud_crowd/exceptions'
30
31
 
31
32
  module CloudCrowd
@@ -44,10 +45,10 @@ module CloudCrowd
44
45
  autoload :WorkUnit, 'cloud_crowd/models'
45
46
 
46
47
  # Keep this version in sync with the gemspec.
47
- VERSION = '0.4.1'
48
+ VERSION = '0.5.0'
48
49
 
49
50
  # Increment the schema version when there's a backwards incompatible change.
50
- SCHEMA_VERSION = 3
51
+ SCHEMA_VERSION = 4
51
52
 
52
53
  # Root directory of the CloudCrowd gem.
53
54
  ROOT = File.expand_path(File.dirname(__FILE__) + '/..')
@@ -92,14 +93,14 @@ module CloudCrowd
92
93
  # Configure CloudCrowd by passing in the path to <tt>config.yml</tt>.
93
94
  def configure(config_path)
94
95
  @config_path = File.expand_path(File.dirname(config_path))
95
- @config = YAML.load_file(config_path)
96
+ @config = YAML.load(ERB.new(File.read(config_path)).result)
96
97
  end
97
98
 
98
99
  # Configure the CloudCrowd central database (and connect to it), by passing
99
100
  # in a path to <tt>database.yml</tt>. The file should use the standard
100
101
  # ActiveRecord connection format.
101
102
  def configure_database(config_path, validate_schema=true)
102
- configuration = YAML.load_file(config_path)
103
+ configuration = YAML.load(ERB.new(File.read(config_path)).result)
103
104
  ActiveRecord::Base.establish_connection(configuration)
104
105
  if validate_schema
105
106
  version = ActiveRecord::Base.connection.select_values('select max(version) from schema_migrations').first.to_i
@@ -42,19 +42,18 @@ module CloudCrowd
42
42
 
43
43
  # Download a file to the specified path.
44
44
  def download(url, path)
45
- `curl -s "#{url}" > "#{path}"`
46
- return path
47
- # The previous implementation is below, and, although it would be
48
- # wonderful not to shell out, RestClient wasn't handling URLs with encoded
49
- # entities (%20, for example), and doesn't let you download to a given
50
- # location. Getting a RestClient patch in would be ideal.
51
- #
52
- # if url.match(FILE_URL)
53
- # FileUtils.cp(url.sub(FILE_URL, ''), path)
54
- # else
55
- # resp = RestClient::Request.execute(:url => url, :method => :get, :raw_response => true)
56
- # FileUtils.mv resp.file.path, path
57
- # end
45
+ if url.match(FILE_URL)
46
+ FileUtils.cp(url.sub(FILE_URL, ''), path)
47
+ else
48
+ File.open(path, 'w+') do |file|
49
+ Net::HTTP.get_response(URI(url)) do |response|
50
+ response.read_body do |chunk|
51
+ file.write chunk
52
+ end
53
+ end
54
+ end
55
+ end
56
+ path
58
57
  end
59
58
 
60
59
  # Takes a local filesystem path, saves the file to S3, and returns the
@@ -84,7 +83,7 @@ module CloudCrowd
84
83
 
85
84
  # Convert an unsafe URL into a filesystem-friendly filename.
86
85
  def safe_filename(url)
87
- url.sub!(/\?.*\Z/, '')
86
+ url = url.sub(/\?.*\Z/, '')
88
87
  ext = File.extname(url)
89
88
  name = URI.unescape(File.basename(url)).gsub(/[^a-zA-Z0-9_\-.]/, '-').gsub(/-+/, '-')
90
89
  File.basename(name, ext).gsub('.', '-') + ext
@@ -27,13 +27,13 @@ module CloudCrowd
27
27
 
28
28
  # Remove all of a Job's resulting files from Cloud Files, both intermediate and finished.
29
29
  def cleanup(job)
30
- @container.objects(:prefix => "#{job.action}/job_#{job.id}").each do |object|
31
- begin
32
- @container.delete_object object
33
- rescue
34
- log "failed to delete #{job.action}/job_#{job.id}"
35
- end
30
+ @container.objects(:prefix => "#{job.action}/job_#{job.id}").each do |object|
31
+ begin
32
+ @container.delete_object object
33
+ rescue
34
+ log "failed to delete #{job.action}/job_#{job.id}"
36
35
  end
36
+ end
37
37
  end
38
38
  end
39
39
 
@@ -2,13 +2,13 @@ require 'optparse'
2
2
 
3
3
  module CloudCrowd
4
4
  class CommandLine
5
-
5
+
6
6
  # Configuration files required for the `crowd` command to function.
7
7
  CONFIG_FILES = ['config.yml', 'config.ru', 'database.yml']
8
-
8
+
9
9
  # Reference the absolute path to the root.
10
10
  CC_ROOT = File.expand_path(File.dirname(__FILE__) + '/../..')
11
-
11
+
12
12
  # Command-line banner for the usage message.
13
13
  BANNER = <<-EOS
14
14
  CloudCrowd is a MapReduce-inspired Parallel Processing System for Ruby.
@@ -25,13 +25,13 @@ Commands:
25
25
  console Launch a CloudCrowd console, connected to the central database
26
26
  load_schema Load the schema into the database specified by database.yml
27
27
  cleanup Removes jobs that were finished over --days (7 by default) ago
28
-
28
+
29
29
  server -d [start | stop | restart] Servers and nodes can be launched as
30
30
  node -d [start | stop | restart] daemons, then stopped or restarted.
31
31
 
32
32
  Options:
33
33
  EOS
34
-
34
+
35
35
  # Creating a CloudCrowd::CommandLine runs from the contents of ARGV.
36
36
  def initialize
37
37
  parse_options
@@ -47,7 +47,7 @@ Options:
47
47
  else usage
48
48
  end
49
49
  end
50
-
50
+
51
51
  # Spin up an IRB session with the CloudCrowd code loaded in, and a database
52
52
  # connection established. The equivalent of Rails' `script/console`.
53
53
  def run_console
@@ -60,7 +60,7 @@ Options:
60
60
  Object.send(:include, CloudCrowd)
61
61
  IRB.start
62
62
  end
63
-
63
+
64
64
  # `crowd server` can either 'start', 'stop', or 'restart'.
65
65
  def run_server(subcommand)
66
66
  load_code
@@ -71,7 +71,7 @@ Options:
71
71
  when 'restart' then restart_server
72
72
  end
73
73
  end
74
-
74
+
75
75
  # Convenience command for quickly spinning up the central server. More
76
76
  # sophisticated deployments, load-balancing across multiple app servers,
77
77
  # should use the config.ru rackup file directly. This method will start
@@ -86,19 +86,19 @@ Options:
86
86
  puts "Starting CloudCrowd Central Server on port #{port}..."
87
87
  exec "thin -e #{@options[:environment]} -p #{port} #{daemonize} --tag cloud-crowd-server --log #{log_path} --pid #{pid_path} -R #{rackup_path} start"
88
88
  end
89
-
89
+
90
90
  # Stop the daemonized central server, if it exists.
91
91
  def stop_server
92
92
  Thin::Server.kill(CloudCrowd.pid_path('server.pid'), 0)
93
93
  end
94
-
94
+
95
95
  # Restart the daemonized central server.
96
96
  def restart_server
97
97
  stop_server
98
98
  sleep 1
99
99
  start_server
100
100
  end
101
-
101
+
102
102
  # `crowd node` can either 'start', 'stop', or 'restart'.
103
103
  def run_node(subcommand)
104
104
  load_code
@@ -109,34 +109,34 @@ Options:
109
109
  when 'restart' then restart_node
110
110
  end
111
111
  end
112
-
112
+
113
113
  # Launch a Node. Please only run a single node per machine. The Node process
114
114
  # will be long-lived, although its workers will come and go.
115
115
  def start_node
116
- port = @options[:port] || Node::DEFAULT_PORT
117
- puts "Starting CloudCrowd Node on port #{port}..."
118
- Node.new(port, @options[:daemonize])
116
+ @options[:port] ||= Node::DEFAULT_PORT
117
+ puts "Starting CloudCrowd Node on port #{@options[:port]}..."
118
+ Node.new(@options)
119
119
  end
120
-
120
+
121
121
  # If the daemonized Node is running, stop it.
122
122
  def stop_node
123
123
  Thin::Server.kill CloudCrowd.pid_path('node.pid')
124
124
  end
125
-
125
+
126
126
  # Restart the daemonized Node, if it exists.
127
127
  def restart_node
128
128
  stop_node
129
129
  sleep 1
130
130
  start_node
131
131
  end
132
-
132
+
133
133
  # Load in the database schema to the database specified in 'database.yml'.
134
134
  def run_load_schema
135
135
  load_code
136
136
  connect_to_database(false)
137
137
  require 'cloud_crowd/schema.rb'
138
138
  end
139
-
139
+
140
140
  # Install the required CloudCrowd configuration files into the specified
141
141
  # directory, or the current one.
142
142
  def run_install(install_path)
@@ -148,22 +148,22 @@ Options:
148
148
  install_file "#{CC_ROOT}/config/database.example.yml", "#{install_path}/database.yml"
149
149
  install_file "#{CC_ROOT}/actions", "#{install_path}/actions", true
150
150
  end
151
-
151
+
152
152
  # Clean up all Jobs in the CloudCrowd database older than --days old.
153
153
  def run_cleanup
154
154
  load_code
155
155
  connect_to_database(true)
156
156
  Job.cleanup_all(:days => @options[:days])
157
157
  end
158
-
158
+
159
159
  # Print `crowd` usage.
160
160
  def usage
161
161
  puts "\n#{@option_parser}\n"
162
162
  end
163
-
164
-
163
+
164
+
165
165
  private
166
-
166
+
167
167
  # Check for configuration files, either in the current directory, or in
168
168
  # the CLOUD_CROWD_CONFIG environment variable. Exit if they're not found.
169
169
  def ensure_config
@@ -171,9 +171,9 @@ Options:
171
171
  found = CONFIG_FILES.all? {|f| File.exists? "#{@options[:config_path]}/#{f}" }
172
172
  found ? @config_dir = true : config_not_found
173
173
  end
174
-
174
+
175
175
  # Parse all options for all commands.
176
- # Valid options are: --config --port --environment --daemonize --days.
176
+ # Valid options are: --config --port --environment --tag --daemonize --days.
177
177
  def parse_options
178
178
  @options = {
179
179
  :environment => 'production',
@@ -190,6 +190,9 @@ Options:
190
190
  opts.on('-e', '--environment ENV', 'server environment (defaults to production)') do |env|
191
191
  @options[:environment] = env
192
192
  end
193
+ opts.on('-t', '--tag TAG', 'tag a node with a name') do |tag|
194
+ @options[:tag] = tag
195
+ end
193
196
  opts.on('-d', '--daemonize', 'run as a background daemon') do |daemonize|
194
197
  @options[:daemonize] = daemonize
195
198
  end
@@ -205,7 +208,7 @@ Options:
205
208
  @option_parser.banner = BANNER
206
209
  @option_parser.parse!(ARGV)
207
210
  end
208
-
211
+
209
212
  # Load in the CloudCrowd module code, dependencies, lib files and models.
210
213
  # Not all commands require this.
211
214
  def load_code
@@ -213,21 +216,21 @@ Options:
213
216
  require "#{CC_ROOT}/lib/cloud-crowd"
214
217
  CloudCrowd.configure("#{@options[:config_path]}/config.yml")
215
218
  end
216
-
219
+
217
220
  # Establish a connection to the central server's database. Not all commands
218
221
  # require this.
219
222
  def connect_to_database(validate_schema)
220
223
  require 'cloud_crowd/models'
221
224
  CloudCrowd.configure_database("#{@options[:config_path]}/database.yml", validate_schema)
222
225
  end
223
-
226
+
224
227
  # Exit with an explanation if the configuration files couldn't be found.
225
228
  def config_not_found
226
229
  puts "`crowd` can't find the CloudCrowd configuration directory. Please use `crowd -c path/to/config`, or run `crowd` from inside of the configuration directory itself."
227
230
  exit(1)
228
231
  end
229
-
230
- # Install a file and log the installation. If we're overwriting a file,
232
+
233
+ # Install a file and log the installation. If we're overwriting a file,
231
234
  # offer a chance to back out.
232
235
  def install_file(source, dest, is_dir=false)
233
236
  if File.exists?(dest)
@@ -237,6 +240,6 @@ Options:
237
240
  is_dir ? FileUtils.cp_r(source, dest) : FileUtils.cp(source, dest)
238
241
  puts "installed #{dest}" unless ENV['RACK_ENV'] == 'test'
239
242
  end
240
-
243
+
241
244
  end
242
245
  end
@@ -48,7 +48,7 @@ module CloudCrowd
48
48
  return queue_for_workers([outs]) if merging?
49
49
  if complete?
50
50
  update_attributes(:outputs => outs, :time => time_taken)
51
- puts "Job ##{id} (#{action}) #{display_status}."
51
+ puts "Job ##{id} (#{action}) #{display_status}." unless ENV['RACK_ENV'] == 'test'
52
52
  Thread.new { fire_callback } if callback_url
53
53
  end
54
54
  self
@@ -28,6 +28,7 @@ module CloudCrowd
28
28
  :ip_address => request.ip,
29
29
  :port => params[:host].match(PORT)[1].to_i,
30
30
  :busy => params[:busy],
31
+ :tag => params[:tag],
31
32
  :max_workers => params[:max_workers],
32
33
  :enabled_actions => params[:enabled_actions]
33
34
  }
@@ -93,7 +94,8 @@ module CloudCrowd
93
94
  def to_json(opts={})
94
95
  { 'host' => host,
95
96
  'workers' => worker_pids,
96
- 'status' => display_status
97
+ 'status' => display_status,
98
+ 'tag' => tag
97
99
  }.to_json
98
100
  end
99
101
 
@@ -39,8 +39,9 @@ module CloudCrowd
39
39
  # action in question disabled.
40
40
  def self.distribute_to_nodes
41
41
  reservation = nil
42
+ filter = {}
42
43
  loop do
43
- return unless reservation = WorkUnit.reserve_available(:limit => RESERVATION_LIMIT)
44
+ return unless reservation = WorkUnit.reserve_available(:limit => RESERVATION_LIMIT, :conditions => filter)
44
45
  work_units = WorkUnit.reserved(reservation)
45
46
  available_nodes = NodeRecord.available
46
47
  while node = available_nodes.shift and unit = work_units.shift do
@@ -54,6 +55,10 @@ module CloudCrowd
54
55
  end
55
56
  work_units.push(unit)
56
57
  end
58
+ if work_units.any? && available_nodes.any?
59
+ filter = {:action => available_nodes.map {|node| node.actions }.flatten.uniq }
60
+ next
61
+ end
57
62
  return if work_units.any? || available_nodes.empty?
58
63
  end
59
64
  ensure
@@ -30,7 +30,7 @@ module CloudCrowd
30
30
  # The response sent back when this node is overloaded.
31
31
  OVERLOADED_MESSAGE = 'Node Overloaded'
32
32
 
33
- attr_reader :enabled_actions, :host, :port, :central
33
+ attr_reader :enabled_actions, :host, :port, :tag, :central
34
34
 
35
35
  set :root, ROOT
36
36
  set :authorization_realm, "CloudCrowd"
@@ -63,15 +63,16 @@ module CloudCrowd
63
63
  end
64
64
 
65
65
  # When creating a node, specify the port it should run on.
66
- def initialize(port=nil, daemon=false)
66
+ def initialize(options={})
67
67
  require 'json'
68
68
  CloudCrowd.identity = :node
69
69
  @central = CloudCrowd.central_server
70
70
  @host = Socket.gethostname
71
71
  @enabled_actions = CloudCrowd.actions.keys - (CloudCrowd.config[:disabled_actions] || [])
72
- @port = port || DEFAULT_PORT
72
+ @port = options[:port] || DEFAULT_PORT
73
73
  @id = "#{@host}:#{@port}"
74
- @daemon = daemon
74
+ @daemon = !!options[:daemonize]
75
+ @tag = options[:tag]
75
76
  @overloaded = false
76
77
  @max_load = CloudCrowd.config[:max_load]
77
78
  @min_memory = CloudCrowd.config[:min_free_memory]
@@ -102,6 +103,7 @@ module CloudCrowd
102
103
  def check_in(critical=false)
103
104
  @central["/node/#{@id}"].put(
104
105
  :busy => @overloaded,
106
+ :tag => @tag,
105
107
  :max_workers => CloudCrowd.config[:max_workers],
106
108
  :enabled_actions => @enabled_actions.join(',')
107
109
  )
@@ -18,8 +18,9 @@ ActiveRecord::Schema.define(:version => CloudCrowd::SCHEMA_VERSION) do
18
18
  t.string "host", :null => false
19
19
  t.string "ip_address", :null => false
20
20
  t.integer "port", :null => false
21
- t.string "enabled_actions", :default => '', :null => false
21
+ t.text "enabled_actions", :default => '', :null => false
22
22
  t.boolean "busy", :default => false, :null => false
23
+ t.string "tag"
23
24
  t.integer "max_workers"
24
25
  t.datetime "created_at"
25
26
  t.datetime "updated_at"
@@ -71,7 +71,7 @@ module CloudCrowd
71
71
  post '/jobs' do
72
72
  job = Job.create_from_request(JSON.parse(params[:job]))
73
73
  WorkUnit.distribute_to_nodes
74
- puts "Job ##{job.id} (#{job.action}) started."
74
+ puts "Job ##{job.id} (#{job.action}) started." unless ENV['RACK_ENV'] == 'test'
75
75
  json job
76
76
  end
77
77
 
@@ -126,8 +126,9 @@ body {
126
126
  }
127
127
  #nodes .node {
128
128
  font-size: 11px;
129
- line-height: 22px;
129
+ line-height: 22px; height: 22px;
130
130
  background-image: url(../images/server.png);
131
+ overflow: hidden;
131
132
  }
132
133
  #nodes .node.busy {
133
134
  background-image: url(../images/server_busy.png);
@@ -107,10 +107,11 @@ window.Console = {
107
107
  $('.has_nodes', header).html(nc + " Node" + (nc != 1 ? 's' : '') + " / " + wc + " Worker" + (wc != 1 ? 's' : ''));
108
108
  header.toggleClass('no_nodes', this._nodes.length <= 0);
109
109
  $('#nodes').html($.map(this._nodes, function(node) {
110
- var html = "";
110
+ var html = "";
111
111
  var extra = node.status == 'busy' ? ' <span class="busy">[busy]</span>' : '';
112
- html += '<div class="node ' + node.status + '">' + node.host + extra + '</div>';
113
- html += $.map(node.workers, function(pid) {
112
+ var tag = node.tag ? '[' + node.tag + '] ' : '';
113
+ html += '<div class="node ' + node.status + '">' + tag + node.host + extra + '</div>';
114
+ html += $.map(node.workers, function(pid) {
114
115
  var name = pid + '@' + node.host;
115
116
  return '<div class="worker" rel="' + name + '">' + name + '</div>';
116
117
  }).join('');
@@ -1,4 +1,4 @@
1
- :max_workers: 10
1
+ :max_workers: <%= 5 * 2 %>
2
2
  :work_unit_retries: 3
3
3
 
4
4
  :central_server: http://localhost:9173
@@ -42,8 +42,15 @@ class ActionTest < Test::Unit::TestCase
42
42
  assert name == 'file.pdf'
43
43
  end
44
44
 
45
+ should "not change the original URL when generating a safe filename" do
46
+ url = "http://example.com/file.format?parameter=value"
47
+ path = @action.safe_filename url
48
+ assert url == "http://example.com/file.format?parameter=value"
49
+ assert path == "file.format"
50
+ end
51
+
45
52
  should "be able to count the number of words in this file" do
46
- assert @action.process == 219
53
+ assert @action.process == 274
47
54
  end
48
55
 
49
56
  should "raise an exception when backticks fail" do
@@ -51,6 +58,13 @@ class ActionTest < Test::Unit::TestCase
51
58
  assert_raise(CloudCrowd::Error::CommandFailed) { @action.process }
52
59
  end
53
60
 
61
+ should "be able to download a remote file" do
62
+ path = "temp.txt"
63
+ @action.download('http://example.com', path)
64
+ assert File.read(path).match(/These domain names are reserved for use in documentation/)
65
+ FileUtils.rm path
66
+ end
67
+
54
68
  end
55
69
 
56
70
 
@@ -1,31 +1,32 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class NodeUnitTest < Test::Unit::TestCase
4
-
4
+
5
5
  context "A Node" do
6
-
6
+
7
7
  setup do
8
- @node = Node.new(11011).instance_variable_get(:@app)
8
+ @node = Node.new(:port => 11011, :tag => "nodule").instance_variable_get(:@app)
9
9
  end
10
-
10
+
11
11
  should "set the identity of the Ruby instance" do
12
12
  assert CloudCrowd.node?
13
13
  end
14
-
14
+
15
15
  should "instantiate correctly" do
16
16
  assert @node.central.to_s == "http://localhost:9173"
17
17
  assert @node.port == 11011
18
18
  assert @node.host == Socket.gethostname
19
19
  assert @node.enabled_actions.length > 2
20
20
  assert @node.asset_store.is_a? AssetStore::FilesystemStore
21
+ assert @node.tag == "nodule"
21
22
  end
22
-
23
+
23
24
  should "trap signals and launch a server at start" do
24
25
  Thin::Server.any_instance.expects(:start)
25
26
  @node.expects(:check_in)
26
27
  @node.start
27
28
  end
28
-
29
+
29
30
  should "be able to determine if the node is overloaded" do
30
31
  assert !@node.overloaded?
31
32
  @node.instance_variable_set :@max_load, 0.01
@@ -35,7 +36,7 @@ class NodeUnitTest < Test::Unit::TestCase
35
36
  @node.instance_variable_set :@min_memory, 8000
36
37
  assert @node.overloaded?
37
38
  end
38
-
39
+
39
40
  end
40
-
41
+
41
42
  end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 4
8
- - 1
9
- version: 0.4.1
7
+ - 5
8
+ - 0
9
+ version: 0.5.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Jeremy Ashkenas
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-04-22 00:00:00 -04:00
17
+ date: 2010-06-22 00:00:00 -04:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency