From b651c4d199a7b4d6a06cdefb281601bddd2fc885 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Thu, 23 Feb 2012 16:20:39 +0000 Subject: integrated features and tests from feature/typhoeus, tests pass reliably (as opposed to feature/typhoeus) --- lib/opentox.rb | 100 ++++++++++++++++++++++---------------------------------- lib/otlogger.rb | 2 +- lib/task.rb | 67 ++++++++++++++++++++++--------------- test/task.rb | 27 +++++++++++---- 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 -- cgit v1.2.3