summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristoph Helma <helma@in-silico.ch>2012-02-23 16:20:39 +0000
committerChristoph Helma <helma@in-silico.ch>2012-02-23 16:20:39 +0000
commitb651c4d199a7b4d6a06cdefb281601bddd2fc885 (patch)
tree52e4ec4bfb303472ef74713f828a3146869bd2e5
parentb6134b992fde8784c3556fbca32925e721700d32 (diff)
integrated features and tests from feature/typhoeus, tests pass reliably (as opposed to feature/typhoeus)
-rw-r--r--lib/opentox.rb100
-rw-r--r--lib/otlogger.rb2
-rw-r--r--lib/task.rb67
-rw-r--r--test/task.rb27
4 files changed, 100 insertions, 96 deletions
diff --git a/lib/opentox.rb b/lib/opentox.rb
index 01de3e7..2fbf9dc 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -2,66 +2,46 @@
RDF::OT = RDF::Vocabulary.new 'http://www.opentox.org/api/1.2#'
RDF::OT1 = RDF::Vocabulary.new 'http://www.opentox.org/api/1.1#'
RDF::OTA = RDF::Vocabulary.new 'http://www.opentox.org/algorithmTypes.owl#'
-SERVICES = ["Compound", "Feature", "Dataset", "Algorithm", "Model", "Validation", "Task"]
+SERVICES = ["Compound", "Feature", "Dataset", "Algorithm", "Model", "Validation", "Task", "Investigation"]
-# not working
-RestClient.add_before_execution_proc do |req, params|
- params[:subjectid] = @subjectid
+class String
+ def underscore
+ self.gsub(/::/, '/').
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
+ tr("-", "_").
+ downcase
+ end
end
-class String
- def to_object
- # TODO: fix, this is unsafe
- self =~ /dataset/ ? uri = File.join(self.chomp,"metadata") : uri = self.chomp
- #raise "#{uri} is not a valid URI." unless RDF::URI.new(uri).uri?
- raise "#{uri} is not a valid URI." unless uri.uri?
- RDF::Reader.open(uri) do |reader|
- reader.each_statement do |statement|
- if statement.predicate == RDF.type and statement.subject == uri
- klass = "OpenTox::#{statement.object.to_s.split("#").last}"
- object = eval "#{klass}.new \"#{uri}\""
- end
- end
- end
- # fallback: guess class from uri
- # TODO: fix services and remove
- unless object
- case uri
- when /compound/
- object = OpenTox::Compound.new uri
- when /feature/
- object = OpenTox::Feature.new uri
- when /dataset/
- object = OpenTox::Dataset.new uri.sub(/\/metadata/,'')
- when /algorithm/
- object = OpenTox::Algorithm.new uri
- when /model/
- object = OpenTox::Model.new uri
- when /validation/
- object = OpenTox::Validation.new uri
- when /task/
- object = OpenTox::Task.new uri
- else
- raise "Class for #{uri} not found."
- end
- end
- if object.class == Task # wait for tasks
- object.wait_for_completion
- object = object.result_uri.to_s.to_object
- end
- object
+module URI
+
+ def self.task? uri
+ uri =~ /task/ and URI.valid? uri
+ end
+
+ def self.dataset? uri, subjectid=nil
+ uri =~ /dataset/ and URI.accessible? uri, subjectid=nil
+ end
+
+ def self.model? uri, subjectid=nil
+ uri =~ /model/ and URI.accessible? uri, subjectid=nil
end
- def uri?
- begin
- Net::HTTP.get_response(URI.parse(self))
- true
- rescue
- false
- end
+ def self.accessible? uri, subjectid=nil
+ Net::HTTP.get_response(URI.parse(uri))
+ true
+ rescue
+ false
end
-end
+ def self.valid? uri
+ u = URI::parse(uri)
+ u.scheme!=nil and u.host!=nil
+ rescue URI::InvalidURIError
+ false
+ end
+end
# defaults to stderr, may be changed to file output
$logger = OTLogger.new(STDERR) # no rotation
@@ -79,21 +59,19 @@ module OpenTox
# Ruby interface
+
+ # override to read all error codes
def metadata reload=true
if reload
@metadata = {}
- begin
- #puts self.class
- #self.kind_of?(OpenTox::Dataset) ? uri = URI.join(@uri,"metadata") : uri = @uri
- #$logger.debug uri
- RDF::Reader.open(uri) do |reader|
+ # ignore error codes from Task services (may contain eg 500 which causes exceptions in RestClient and RDF::Reader
+ RestClient.get(@uri) do |response, request, result, &block|
+ $logger.warn "#{@uri} returned #{result}" unless response.code == 200 or response.code == 202 or URI.task? @uri
+ RDF::Reader.for(:rdfxml).new(response) do |reader|
reader.each_statement do |statement|
@metadata[statement.predicate] = statement.object if statement.subject == @uri
end
end
- rescue
- $logger.error "Cannot read RDF metadata from #{@uri}: #{$!}.\n#{$!.backtrace.join("\n")}"
- raise
end
end
@metadata
diff --git a/lib/otlogger.rb b/lib/otlogger.rb
index 295d0c1..e9fbc4d 100644
--- a/lib/otlogger.rb
+++ b/lib/otlogger.rb
@@ -12,7 +12,7 @@ class OTLogger < Logger
n = 2
line = lines[n]
- while (line =~ /spork.rb/ or line =~ /create/ or line =~ /overwrite.rb/)
+ while (line =~ /spork.rb/ or line =~ /create/ or line =~ /#{File.basename(__FILE__)}/)
n += 1
line = lines[n]
end
diff --git a/lib/task.rb b/lib/task.rb
index 582f592..9aaee04 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -5,13 +5,13 @@ module OpenTox
# Class for handling asynchronous tasks
class Task
- attr_accessor :pid
+ attr_accessor :pid, :observer_pid
def self.create service_uri, params={}
task = Task.new RestClient.post(service_uri,params).chomp
pid = fork do
begin
result_uri = yield
- if result_uri.uri?
+ if URI.accessible?(result_uri)
task.completed result_uri
else
raise "#{result_uri} is not a valid URI"
@@ -26,14 +26,25 @@ module OpenTox
end
Process.detach(pid)
task.pid = pid
+
+ # watch if task has been cancelled
+ observer_pid = fork do
+ task.wait_for_completion
+ begin
+ Process.kill(9,task.pid) if task.cancelled?
+ rescue
+ $logger.warn "Could not kill process of task #{task.uri}, pid: #{task.pid}"
+ end
+ end
+ Process.detach(observer_pid)
+ task.observer_pid = observer_pid
task
end
def kill
- begin
- Process.kill(9,pid)
- rescue
- end
+ Process.kill(9,@pid)
+ Process.kill(9,@observer_pid)
+ rescue # no need to raise an aexeption if processes are not running
end
def description
@@ -46,15 +57,17 @@ module OpenTox
end
def completed(uri)
+ #TODO: subjectid?
+ #TODO: error code
+ raise "\"#{uri}\" does not exist." unless URI.accessible? uri
RestClient.put(File.join(@uri,'Completed'),{:resultURI => uri})
end
def error error
$logger.error self if $logger
- kill
report = ErrorReport.create(error,"http://localhost")
RestClient.put(File.join(@uri,'Error'),{:errorReport => report})
- #RestClient.put(File.join(@uri,'Error'),{:message => error, :backtrace => error.backtrace})
+ kill
end
# waits for a task, unless time exceeds or state is no longer running
@@ -69,6 +82,23 @@ module OpenTox
end
+ # get only header for ststus requests
+ def running?
+ RestClient.head(@uri){ |response, request, result| result.code.to_i == 202 }
+ end
+
+ def cancelled?
+ RestClient.head(@uri){ |response, request, result| result.code.to_i == 503 }
+ end
+
+ def completed?
+ RestClient.head(@uri){ |response, request, result| result.code.to_i == 200 }
+ end
+
+ def error?
+ RestClient.head(@uri){ |response, request, result| result.code.to_i == 500 }
+ end
+
def method_missing(method,*args)
method = method.to_s
begin
@@ -76,8 +106,8 @@ module OpenTox
when /=/
res = RestClient.put(File.join(@uri,method.sub(/=/,'')),{})
super unless res.code == 200
- when /\?/
- return hasStatus == method.sub(/\?/,'').capitalize
+ #when /\?/
+ #return hasStatus == method.sub(/\?/,'').capitalize
else
response = metadata[RDF::OT[method]].to_s
response = metadata[RDF::OT1[method]].to_s #if response.empty? # API 1.1 compatibility
@@ -93,23 +123,6 @@ module OpenTox
end
end
- # override to read all error codes
- def metadata reload=true
- if reload
- @metadata = {}
- # ignore error codes from Task services (may contain eg 500 which causes exceptions in RestClient and RDF::Reader
- RestClient.get(@uri) do |response, request, result, &block|
- $logger.warn "#{@uri} returned #{result}" unless response.code == 200 or response.code == 202
- RDF::Reader.for(:rdfxml).new(response) do |reader|
- reader.each_statement do |statement|
- @metadata[statement.predicate] = statement.object if statement.subject == @uri
- end
- end
- end
- end
- @metadata
- end
-
#TODO: subtasks
end
diff --git a/test/task.rb b/test/task.rb
index b217ec2..56b21cf 100644
--- a/test/task.rb
+++ b/test/task.rb
@@ -11,9 +11,11 @@ class TaskTest < Test::Unit::TestCase
def test_all
- t = OpenTox::Task.all(TASK_SERVICE_URI)
- assert_equal Array, t.class
- assert_equal RDF::OT1.Task, t.last.metadata[RDF.type]
+ all = OpenTox::Task.all(TASK_SERVICE_URI)
+ assert_equal Array, all.class
+ t = all.last
+ assert_equal OpenTox::Task, t.class
+ assert_equal RDF::OT1.Task, t.metadata[RDF.type]
end
def test_create_and_complete
@@ -21,16 +23,23 @@ class TaskTest < Test::Unit::TestCase
sleep 1
TASK_SERVICE_URI
end
+ assert task.running?
assert_equal "Running", task.hasStatus
task.wait_for_completion
+ assert task.completed?
assert_equal "Completed", task.hasStatus
assert_equal TASK_SERVICE_URI, task.resultURI
end
- def test_rdf
- task = OpenTox::Task.all(TASK_SERVICE_URI).last
- assert_equal OpenTox::Task, task.class
- #validate_owl(task.uri)
+
+ def test_create_and_cancel
+ task = OpenTox::Task.create TASK_SERVICE_URI do
+ sleep 2
+ TASK_SERVICE_URI
+ end
+ assert task.running?
+ task.cancel
+ assert task.cancelled?
end
def test_create_and_fail
@@ -38,8 +47,10 @@ class TaskTest < Test::Unit::TestCase
sleep 1
raise "an error occured"
end
+ assert task.running?
assert_equal "Running", task.hasStatus
task.wait_for_completion
+ assert task.error?
assert_equal "Error", task.hasStatus
end
@@ -48,8 +59,10 @@ class TaskTest < Test::Unit::TestCase
sleep 1
"Asasadasd"
end
+ assert task.running?
assert_equal "Running", task.hasStatus
task.wait_for_completion
+ assert task.error?
assert_equal "Error", task.hasStatus
end