From a3c5fac3f7849cab38bedd313b522b994be17b15 Mon Sep 17 00:00:00 2001 From: radhika chippada Date: Tue, 22 Apr 2014 00:20:56 -0400 Subject: [PATCH] 2352: Add state to pipeline_instance. Db migration and unit testing. --- services/api/app/models/pipeline_instance.rb | 86 +++++++++++++++ .../20140422011506_pipeline_instance_state.rb | 85 +++++++++++++++ services/api/db/schema.rb | 8 +- .../api/test/fixtures/pipeline_instances.yml | 3 + .../api/test/unit/pipeline_instance_test.rb | 100 +++++++++++++++++- 5 files changed, 276 insertions(+), 6 deletions(-) create mode 100644 services/api/db/migrate/20140422011506_pipeline_instance_state.rb create mode 100644 services/api/test/fixtures/pipeline_instances.yml diff --git a/services/api/app/models/pipeline_instance.rb b/services/api/app/models/pipeline_instance.rb index b16769cb3c..5c60178438 100644 --- a/services/api/app/models/pipeline_instance.rb +++ b/services/api/app/models/pipeline_instance.rb @@ -4,10 +4,13 @@ class PipelineInstance < ArvadosModel include CommonApiTemplate serialize :components, Hash serialize :properties, Hash + serialize :components_summary, Hash belongs_to :pipeline_template, :foreign_key => :pipeline_template_uuid, :primary_key => :uuid before_validation :bootstrap_components before_validation :update_success + before_create :verify_status + before_save :verify_status api_accessible :user, extend: :common do |t| t.add :pipeline_template_uuid @@ -18,12 +21,46 @@ class PipelineInstance < ArvadosModel t.add :active t.add :dependencies t.add :properties + t.add :state + t.add :components_summary end + # Supported states for a pipeline instance + New = 'New' + Ready = 'Ready' + RunningOnServer = 'RunningOnServer' + RunningOnClient = 'RunningOnClient' + Paused = 'Paused' + Failed = 'Failed' + Complete = 'Complete' + def dependencies dependency_search(self.components).keys end + # if all components have input, the pipeline is Ready + def self.is_ready components + if !components || components.empty? # is this correct? + return true + end + + all_components_have_input = true + components.each do |name, component| + component['script_parameters'].each do |parametername, parameter| + parameter = { 'value' => parameter } unless parameter.is_a? Hash + if parameter['value'].nil? and + ![false,'false',0,'0'].index parameter['required'] + if parameter['output_of'] + next + end + all_components_have_input = false + break + end + end + end + return all_components_have_input + end + def progress_table begin # v0 pipeline format @@ -100,4 +137,53 @@ class PipelineInstance < ArvadosModel {} end end + + def verify_status + if active_changed? + if self.active + self.state = RunningOnServer + else + if PipelineInstance.is_ready self.components + self.state = Ready + else + self.state = New + end + end + elsif success_changed? + if self.success + self.active = false + self.state = Complete + else + self.active = false + self.state = Failed + end + elsif state_changed? + case self.state + when New, Ready + self.active = false + self.success = nil + when RunningOnServer + self.active = true + self.success = nil + when RunningOnClient + self.active = false + self.success = nil + when Failed + self.active = false + self.success = false + when Complete + self.active = false + self.success = true + end + else # new object create or save + if !self.state || self.state == New || !self.active + if PipelineInstance.is_ready self.components + self.state = Ready + else + self.state = New + end + end + end + end + end diff --git a/services/api/db/migrate/20140422011506_pipeline_instance_state.rb b/services/api/db/migrate/20140422011506_pipeline_instance_state.rb new file mode 100644 index 0000000000..a3bc7fe9af --- /dev/null +++ b/services/api/db/migrate/20140422011506_pipeline_instance_state.rb @@ -0,0 +1,85 @@ +class PipelineInstanceState < ActiveRecord::Migration + include CurrentApiClient + + def up + if !column_exists?(:pipeline_instances, :state) + add_column :pipeline_instances, :state, :string + end + + if !column_exists?(:pipeline_instances, :components_summary) + add_column :pipeline_instances, :components_summary, :text + end + + act_as_system_user do + PipelineInstance.all.each do |pi| + pi.state = PipelineInstance::New + + if !pi.attribute_present? :success # success is nil + if pi[:active] == true + pi.state = PipelineInstance::RunningOnServer + else + if PipelineInstance.is_ready pi.components + pi.state = PipelineInstance::Ready + else + pi.state = PipelineInstance::New + end + end + elsif pi[:success] == true + pi.state = PipelineInstance::Complete + else + pi.state = PipelineInstance::Failed + end + + pi.save! + end + end + +=begin + if column_exists?(:pipeline_instances, :active) + remove_column :pipeline_instances, :active + end + + if column_exists?(:pipeline_instances, :success) + remove_column :pipeline_instances, :success + end +=end + end + + def down +=begin + add_column :pipeline_instances, :success, :boolean, :null => true + add_column :pipeline_instances, :active, :boolean, :default => false + + act_as_system_user do + PipelineInstance.all.each do |pi| + case pi.state + when PipelineInstance::New, PipelineInstance::Ready + pi.active = false + pi.success = nil + when PipelineInstance::RunningOnServer + pi.active = true + pi.success = nil + when PipelineInstance::RunningOnClient + pi.active = false + pi.success = nil + when PipelineInstance::Failed + pi.active = false + pi.success = false + when PipelineInstance::Complete + pi.active = false + pi.success = true + end + pi.save! + end + end +=end + + if column_exists?(:pipeline_instances, :components_summary) + remove_column :pipeline_instances, :components_summary + end + + if column_exists?(:pipeline_instances, :state) + remove_column :pipeline_instances, :state + end + end +end diff --git a/services/api/db/schema.rb b/services/api/db/schema.rb index e2301e5be9..ab39901db4 100644 --- a/services/api/db/schema.rb +++ b/services/api/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20140407184311) do +ActiveRecord::Schema.define(:version => 20140422011506) do create_table "api_client_authorizations", :force => true do |t| t.string "api_token", :null => false @@ -311,10 +311,12 @@ ActiveRecord::Schema.define(:version => 20140407184311) do t.string "pipeline_template_uuid" t.string "name" t.text "components" - t.boolean "success" - t.boolean "active", :default => false t.datetime "updated_at" t.text "properties" + t.boolean "active" + t.boolean "success" + t.string "state" + t.text "components_summary" end add_index "pipeline_instances", ["created_at"], :name => "index_pipeline_instances_on_created_at" diff --git a/services/api/test/fixtures/pipeline_instances.yml b/services/api/test/fixtures/pipeline_instances.yml new file mode 100644 index 0000000000..931eb68f60 --- /dev/null +++ b/services/api/test/fixtures/pipeline_instances.yml @@ -0,0 +1,3 @@ +new_pipeline: + uuid: zzzzz-xxxxx-f4gneyn6br1xize + owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz diff --git a/services/api/test/unit/pipeline_instance_test.rb b/services/api/test/unit/pipeline_instance_test.rb index 9b4c7c3787..0eb3ff9920 100644 --- a/services/api/test/unit/pipeline_instance_test.rb +++ b/services/api/test/unit/pipeline_instance_test.rb @@ -1,7 +1,101 @@ require 'test_helper' class PipelineInstanceTest < ActiveSupport::TestCase - # test "the truth" do - # assert true - # end + + test "check active and success for a pipeline in new state" do + pi = pipeline_instances :new_pipeline + + assert !pi.active, 'expected active to be false for a new pipeline' + assert !pi.success, 'expected success to be false for a new pipeline' + assert !pi.state, 'expected state to be nil because the fixture had no state specified' + + # save the pipeline and expect state to be New + pi.save + pi = PipelineInstance.find_by_uuid 'zzzzz-xxxxx-f4gneyn6br1xize' + assert_equal PipelineInstance::Ready, pi.state, 'expected state to be New for new pipeline' + assert !pi.active, 'expected active to be false for a new pipeline' + assert !pi.success, 'expected success to be false for a new pipeline' + end + + test "update attributes for pipeline" do + pi = pipeline_instances :new_pipeline + + # add a component with no input and expect state to be New + component = {'script_parameters' => {"input_not_provided" => {"required" => "true"}}} + pi.components['first'] = component + components = pi.components + pi.update_attribute 'components', pi.components + pi = PipelineInstance.find_by_uuid 'zzzzz-xxxxx-f4gneyn6br1xize' + assert_equal PipelineInstance::New, pi.state, 'expected state to be New after adding component with input' + assert_equal pi.components.size, 1, 'expected one component' + assert !pi.active, 'expected active to be false after update' + assert !pi.success, 'expected success to be false for a new pipeline' + + # add a component with input and expect state to become Ready + component = {'script_parameters' => {"input" => "yyyad4b39ca5a924e481008009d94e32+210"}} + pi.components['first'] = component + components = pi.components + pi.update_attribute 'components', pi.components + pi = PipelineInstance.find_by_uuid 'zzzzz-xxxxx-f4gneyn6br1xize' + assert_equal PipelineInstance::Ready, pi.state, 'expected state to be Ready after adding component with input' + assert_equal pi.components.size, 1, 'expected one component' + assert !pi.active, 'expected active to be false after update' + assert !pi.success, 'expected success to be false for a new pipeline' + + pi.active = true + pi.save + pi = PipelineInstance.find_by_uuid 'zzzzz-xxxxx-f4gneyn6br1xize' + assert_equal PipelineInstance::RunningOnServer, pi.state, 'expected state to be RunningOnServer after updating active to true' + assert pi.active, 'expected active to be true after update' + assert !pi.success, 'expected success to be false for a new pipeline' + + pi.success = false + pi.save + pi = PipelineInstance.find_by_uuid 'zzzzz-xxxxx-f4gneyn6br1xize' + assert_equal PipelineInstance::Failed, pi.state, 'expected state to be Failed after updating success to false' + assert !pi.active, 'expected active to be false after update' + assert !pi.success, 'expected success to be false for a new pipeline' + + pi.success = true + pi.save + pi = PipelineInstance.find_by_uuid 'zzzzz-xxxxx-f4gneyn6br1xize' + assert_equal PipelineInstance::Complete, pi.state, 'expected state to be Complete after updating success to true' + assert !pi.active, 'expected active to be false after update' + assert pi.success, 'expected success to be true after update' + + pi.update_attribute 'active', true + pi = PipelineInstance.find_by_uuid 'zzzzz-xxxxx-f4gneyn6br1xize' + assert_equal PipelineInstance::RunningOnServer, pi.state, 'expected state to be RunningOnServer after updating active to true' + assert pi.active, 'expected active to be true after update' + + pi.update_attribute 'success', false + pi = PipelineInstance.find_by_uuid 'zzzzz-xxxxx-f4gneyn6br1xize' + assert_equal PipelineInstance::Failed, pi.state, 'expected state to be Failed after updating success to false' + assert !pi.active, 'expected active to be false after update' + assert !pi.success, 'expected success to be false for a new pipeline' + + pi.update_attribute 'success', true + pi = PipelineInstance.find_by_uuid 'zzzzz-xxxxx-f4gneyn6br1xize' + assert_equal PipelineInstance::Complete, pi.state, 'expected state to be Complete after updating success to true' + assert !pi.active, 'expected active to be false after update' + assert pi.success, 'expected success to be true after update' + end + + test "update attributes for pipeline with two components" do + pi = pipeline_instances :new_pipeline + + # add two components, one with input and one with no input and expect state to be New + component1 = {'script_parameters' => {"something" => "xxxad4b39ca5a924e481008009d94e32+210", "input" => "c1bad4b39ca5a924e481008009d94e32+210"}} + component2 = {'script_parameters' => {"something_else" => "xxxad4b39ca5a924e481008009d94e32+210", "input_missing" => {"required" => "true"}}} + pi.components['first'] = component1 + pi.components['second'] = component2 + components = pi.components + pi.update_attribute 'components', pi.components + pi = PipelineInstance.find_by_uuid 'zzzzz-xxxxx-f4gneyn6br1xize' + assert_equal PipelineInstance::New, pi.state, 'expected state to be New after adding component with input' + assert_equal pi.components.size, 2, 'expected two components' + assert !pi.active, 'expected active to be false after update' + assert !pi.success, 'expected success to be false for a new pipeline' + end + end -- 2.30.2