require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') describe ReRule do def valid_attributes { :rule_class_name => "MockRuleClass", :title => "Rule Title", :summary => "Mock Summary", :data => '["Rule Title", ["one", "two"], "start_workflow", "Other Pipeline"]' } end before(:each) do @rule = mock("MockRule", :title => "rule title", :summary => "rule summary", :data => "rule data") @rule.stub!(:title=) @rule.stub!(:summary=) @rule.stub!(:data=) @rule.stub!(:before_create) @rule.stub!(:before_update) @rule.stub!(:before_destroy) @rule.stub!(:expected_outcomes).and_return([]) @rule.stub!(:valid?).and_return(true) @rule_class = mock("MockRuleClass") @rule_class.stub!(:new).and_return(@rule) RulesEngine::Discovery.stub!(:rule_class).and_return(@rule_class) @re_workflow = mock('workflow', :valid? => true) @re_workflow.stub!(:code).and_return('mock code') @re_workflow.stub!(:changed!) end it "should be valid with valid attributes" do ReRule.new(valid_attributes).should be_valid end should_belong_to :re_workflow should_have_many :re_rule_expected_outcomes should_validate_presence_of :rule_class_name describe "validate the rule" do it "should be false if the rule class not found" do re_rule = ReRule.new(valid_attributes) RulesEngine::Discovery.stub!(:rule_class).and_return(nil) re_rule.should_not be_valid re_rule.should have(1).error_on(:rule_class) end it "should be false if the rule is not valid" do re_rule = ReRule.new(valid_attributes) @rule.should_receive(:valid?).and_return(false) re_rule.should_not be_valid # re_rule.should have(1).error_on(:rule) end end describe "loading a rule" do before(:each) do @re_rule = ReRule.new(valid_attributes) end it "should return an instance of the rule" do @re_rule.rule.should == @rule end it "should load the rule from the discovery" do RulesEngine::Discovery.should_receive(:rule_class).with("MockRuleClass") @re_rule.rule end it "should only load the rule once" do RulesEngine::Discovery.should_receive(:rule_class).once @re_rule.rule.should == @rule @re_rule.rule.should == @rule end it "should return nil if the rule class not found" do RulesEngine::Discovery.should_receive(:rule_class).with("MockRuleClass").and_return(nil) @re_rule.rule.should be_nil end it "should create a new instance of the rule class" do @rule_class.should_receive(:new) @re_rule.rule end it "should set the rule data with the model data attribute" do @rule.should_receive(:data=).with(valid_attributes[:data]) @re_rule.rule end end describe "setting the rule attributes" do it "should raise an error if the rule does not exist" do re_rule = ReRule.new(valid_attributes) RulesEngine::Discovery.should_receive(:rule_class).with("MockRuleClass").and_return(nil) lambda { re_rule.rule_attributes={} }.should raise_error('rule class not found') end it "should pass the parameters to the rule" do re_rule = ReRule.new(valid_attributes) @rule.should_receive("attributes=").with({:mock => "param"}) re_rule.rule_attributes = {:mock => "param"} end end describe "saving a re_rule" do before(:each) do @re_rule = ReRule.new(valid_attributes) @re_rule.stub!(:re_workflow).and_return(@re_workflow) end it "should fail if the rule does not exist" do @re_rule.should_receive(:rule).and_return(nil) @re_rule.save.should == false end it "should set tell the workflow the rule has changed" do @re_workflow.should_receive(:changed!) @re_rule.save end describe "a valid rule" do before(:each) do @re_rule.stub(:rule).and_return(@rule) end it "should be successful" do @re_rule.save.should == true end it "should set the re_rule title to the title generated by the rule" do @re_rule.save @re_rule.title.should == "rule title" end it "should set the re_rule summary to the summary generated by the rule" do @re_rule.save @re_rule.summary.should == "rule summary" end it "should set the re_rule data to the data generated by the rule" do @re_rule.save @re_rule.data.should == "rule data" end it "should set the expected outcomes to the expected outcomes generated by the rule" do re_rule_expected_outcome = ReRuleExpectedOutcome.new ReRuleExpectedOutcome.should_receive(:new).with(:outcome => 101, :workflow_code => "one").and_return(re_rule_expected_outcome) ReRuleExpectedOutcome.should_receive(:new).with(:outcome => 202, :workflow_code => "two").and_return(re_rule_expected_outcome) @rule.stub(:expected_outcomes).and_return([{:outcome => 101, :workflow_code => "one"}, {:outcome => 202, :workflow_code => "two"}]) @re_rule.save @re_rule.re_rule_expected_outcomes.should == [re_rule_expected_outcome, re_rule_expected_outcome] end end end describe "after creating a re_rule" do it "should notify the rule" do re_rule = ReRule.new(valid_attributes) re_rule.stub!(:re_workflow).and_return(@re_workflow) @rule.should_receive(:before_create) re_rule.save end end describe "after updating a re_rule" do it "should notify the rule" do re_rule = ReRule.new(valid_attributes) re_rule.stub!(:re_workflow).and_return(@re_workflow) re_rule.save re_rule.title = "New Title" @rule.should_receive(:before_update) re_rule.save end end describe "before destroying a re_rule" do it "should notify the rule" do re_rule = ReRule.new(valid_attributes) re_rule.stub!(:re_workflow).and_return(@re_workflow) @rule.should_receive(:before_destroy) re_rule.destroy end end describe "rule outcomes available" do before(:each) do @re_rule = ReRule.new end it "should return the first outcome that is a OUTCOME_NEXT" do outcome_1 = ReRuleExpectedOutcome.new(:outcome => RulesEngine::Rule::Outcome::NEXT) outcome_2 = ReRuleExpectedOutcome.new(:outcome => RulesEngine::Rule::Outcome::NEXT) @re_rule.re_rule_expected_outcomes << outcome_1 @re_rule.re_rule_expected_outcomes << outcome_2 @re_rule.re_rule_expected_outcome_next.should == outcome_1 end it "should return the first outcome that is a OUTCOME_STOP_SUCCESS" do outcome_1 = ReRuleExpectedOutcome.new(:outcome => RulesEngine::Rule::Outcome::STOP_SUCCESS) outcome_2 = ReRuleExpectedOutcome.new(:outcome => RulesEngine::Rule::Outcome::STOP_SUCCESS) @re_rule.re_rule_expected_outcomes << outcome_1 @re_rule.re_rule_expected_outcomes << outcome_2 @re_rule.re_rule_expected_outcome_success.should == outcome_1 end it "should return the first outcome that is a OUTCOME_STOP_FAILURE" do outcome_1 = ReRuleExpectedOutcome.new(:outcome => RulesEngine::Rule::Outcome::STOP_FAILURE) outcome_2 = ReRuleExpectedOutcome.new(:outcome => RulesEngine::Rule::Outcome::STOP_FAILURE) @re_rule.re_rule_expected_outcomes << outcome_1 @re_rule.re_rule_expected_outcomes << outcome_2 @re_rule.re_rule_expected_outcome_failure.should == outcome_1 end it "should return all outcomes that are a OUTCOME_START_WORKFLOW" do outcome_1 = ReRuleExpectedOutcome.new(:outcome => RulesEngine::Rule::Outcome::START_WORKFLOW) outcome_2 = ReRuleExpectedOutcome.new(:outcome => RulesEngine::Rule::Outcome::START_WORKFLOW) @re_rule.re_rule_expected_outcomes << outcome_1 @re_rule.re_rule_expected_outcomes << outcome_2 @re_rule.re_rule_expected_outcomes_start_workflow.should == [outcome_1, outcome_2] end end describe "checking for rule errors" do before(:each) do @rule = mock("Rule", :valid? => true) @re_rule = ReRule.new(valid_attributes) @re_rule.stub!(:rule).and_return(@rule) end it "should return '[title] class [class] invalid' if the rule is missing" do @re_rule.should_receive(:rule).and_return(nil) @re_rule.rule_error.should == "class MockRuleClass missing" end it "should ignore outcomes where the workflow_code is nil" do re_rule_expected_outcome = mock_model(ReRuleExpectedOutcome, :workflow_code => nil) @re_rule.stub!(:re_rule_expected_outcomes).and_return([re_rule_expected_outcome]) @re_rule.rule_error.should be_nil end it "should validate the workflow is present and activated" do re_rule_expected_outcome = mock_model(ReRuleExpectedOutcome, :workflow_code => "mock_workflow_code", :outcome => RulesEngine::Rule::Outcome::START_WORKFLOW) ReWorkflow.should_receive(:find_by_code).and_return(mock("ReWorkflow", :workflow_error => nil)) @re_rule.stub!(:re_rule_expected_outcomes).and_return([re_rule_expected_outcome]) @re_rule.rule_error.should be_nil end it "should return '[workflow_code] missing' if the required workflow is missing" do re_rule_expected_outcome = mock_model(ReRuleExpectedOutcome, :workflow_code => "mock_workflow_code", :outcome => RulesEngine::Rule::Outcome::START_WORKFLOW) ReWorkflow.should_receive(:find_by_code).and_return(nil) @re_rule.stub!(:re_rule_expected_outcomes).and_return([re_rule_expected_outcome]) @re_rule.rule_error.should == "mock_workflow_code missing" end it "should return '[workflow_code] invalid' if the required workflow has errors" do re_rule_expected_outcome = mock_model(ReRuleExpectedOutcome, :workflow_code => "mock_workflow_code", :outcome => RulesEngine::Rule::Outcome::START_WORKFLOW) ReWorkflow.should_receive(:find_by_code).and_return(mock("ReWorkflow", :workflow_error => "workflow error")) @re_rule.stub!(:re_rule_expected_outcomes).and_return([re_rule_expected_outcome]) @re_rule.rule_error.should == "mock_workflow_code invalid" end end describe "moving items in a list" do it "should move a rule down in the list" do re_workflow = ReWorkflow.create!(:code => "AA-MOCK",:title => "Rule Title") re_rule_1 = ReRule.new(valid_attributes) re_rule_2 = ReRule.new(valid_attributes) re_workflow.re_rules << re_rule_1 re_workflow.re_rules << re_rule_2 re_workflow.reload re_workflow.re_rules.should == [re_rule_1, re_rule_2] re_workflow.re_rules[1].move_higher re_workflow.reload re_workflow.re_rules.should == [re_rule_2, re_rule_1] end end describe "publish" do it "should convert the rule to a hash" do re_rule = ReRule.new(valid_attributes) publish_data = re_rule.publish publish_data["rule_class_name"].should == valid_attributes[:rule_class_name] publish_data["title"].should == valid_attributes[:title] publish_data["summary"].should == valid_attributes[:summary] publish_data["data"].should == valid_attributes[:data] end end describe "revert!" do it "should return self" do re_rule = ReRule.new re_rule.revert!({}).should == re_rule end it "should set the rule based on the data" do re_rule = ReRule.new RulesEngine::Discovery.should_receive(:rule_class).with('mock_rule_class_name').and_return(@rule_class) re_rule.revert!({ "rule_class_name" => 'mock_rule_class_name', "title" => 'mock title', "summary" => 'mock summary', "data" => 'mock data' }) re_rule[:rule_class_name].should == 'mock_rule_class_name' re_rule[:title].should == 'mock title' re_rule[:summary].should == 'mock summary' re_rule[:data].should == 'mock data' end end end