UNPKG

pimatic

Version:

A home automation server and framework for the Raspberry PI running on node.js

1,242 lines (1,125 loc) 35.2 kB
cassert = require "cassert" assert = require "assert" Promise = require 'bluebird' S = require 'string' util = require 'util' events = require 'events' env = require('../startup').env describe "RuleManager", -> rulesAst = require '../lib/rules-ast-builder' before -> env.logger.winston.transports.taggedConsoleLogger.level = 'error' ruleManager = null getTime = -> new Date().getTime() class DummyPredicateHandler extends env.predicates.PredicateHandler constructor: -> getValue: -> Promise.resolve(false) destroy: -> getType: -> 'state' class DummyPredicateProvider extends env.predicates.PredicateProvider type: 'unknown' name: 'test' parsePredicate: (input, context) -> cassert S(input).startsWith("predicate 1") return { token: "predicate 1" nextInput: S(input).chompLeft("predicate 1").s predicateHandler: new DummyPredicateHandler() } class DummyActionHandler extends env.actions.ActionHandler executeAction: (simulate) => return Promise.resolve "action 1 executed" hasRestoreAction: => yes executeRestoreAction: (simulate) => return Promise.resolve "restore action 1 executed" class DummyActionProvider parseAction: (input, context) -> cassert S(input).startsWith("action 1") return { token: "action 1" nextInput: S(input).chompLeft("action 1").s actionHandler: new DummyActionHandler() } predProvider = new DummyPredicateProvider() frameworkDummy = new events.EventEmitter() frameworkDummy.variableManager = new env.variables.VariableManager(frameworkDummy, []) frameworkDummy.variableManager.init() ruleManager = new env.rules.RuleManager(frameworkDummy, []) ruleManager.addPredicateProvider predProvider actionProvider = new DummyActionProvider() ruleManager.actionProviders = [actionProvider] describe '#parseRuleCondition', -> context = null beforeEach -> context = ruleManager._createParseContext() testCases = [ { input: "predicate 1" result: { predicates: [ { id: 'prd-test1-0', token: 'predicate 1', handler: {}, for: null justTrigger: false, justCondition: false } ] tokens: [ 'predicate', '(', 0, ')' ] } } { input: "predicate 1 for 10 seconds" result: { predicates: [ { id: 'prd-test1-0', token: 'predicate 1', handler: {}, for: token: '10 seconds' exprTokens: ['10'] unit: 'seconds' justTrigger: false, justCondition: false } ] tokens: [ 'predicate', '(', 0, ')' ] } } { input: "predicate 1 for 2 hours" result: { predicates: [ { id: 'prd-test1-0', token: 'predicate 1', handler: {}, for: token: '2 hours' exprTokens: ['2'] unit: 'hours' justTrigger: false, justCondition: false } ] tokens: [ 'predicate', '(', 0, ')' ] } } { input: "predicate 1 and predicate 1" result: { predicates: [ { id: 'prd-test1-0', token: 'predicate 1', handler: {}, for: null justTrigger: false, justCondition: false } { id: 'prd-test1-1', token: 'predicate 1', handler: {}, for: null justTrigger: false, justCondition: false } ] tokens: [ 'predicate', '(', 0, ')', 'and', 'predicate', '(', 1, ')' ] } } { input: "[predicate 1 and predicate 1]" result: { predicates: [ { id: 'prd-test1-0', token: 'predicate 1', handler: {}, for: null justTrigger: false, justCondition: false } { id: 'prd-test1-1', token: 'predicate 1', handler: {}, for: null justTrigger: false, justCondition: false } ] tokens: [ '[', 'predicate', '(', 0, ')', 'and', 'predicate', '(', 1, ')', ']' ] } } { input: "predicate 1 and [predicate 1]" result: { predicates: [ { id: 'prd-test1-0', token: 'predicate 1', handler: {}, for: null justTrigger: false, justCondition: false } { id: 'prd-test1-1', token: 'predicate 1', handler: {}, for: null justTrigger: false, justCondition: false } ] tokens: [ 'predicate', '(', 0, ')', 'and', '[', 'predicate', '(', 1, ')', ']' ] } } { input: "predicate 1 or predicate 1" result: { predicates: [ { id: 'prd-test1-0', token: 'predicate 1', handler: {}, for: null justTrigger: false, justCondition: false } { id: 'prd-test1-1', token: 'predicate 1', handler: {}, for: null justTrigger: false, justCondition: false } ] tokens: [ 'predicate', '(', 0, ')', 'or', 'predicate', '(', 1, ')' ] } } { input: "predicate 1 for 2 hours or predicate 1" result: { predicates: [ { id: 'prd-test1-0', token: 'predicate 1', handler: {}, for: token: '2 hours' exprTokens: [ '2'] unit: 'hours' justTrigger: false, justCondition: false } { id: 'prd-test1-1', token: 'predicate 1', handler: {}, for: null justTrigger: false, justCondition: false } ] tokens: [ 'predicate', '(', 0, ')', 'or', 'predicate', '(', 1, ')' ] } } { input: "predicate 1 and [predicate 1 or predicate 1]" result: { predicates: [ { id: 'prd-test1-0', token: 'predicate 1', handler: {}, for: null justTrigger: false, justCondition: false } { id: 'prd-test1-1', token: 'predicate 1', handler: {}, for: null justTrigger: false, justCondition: false } { id: 'prd-test1-2', token: 'predicate 1', handler: {}, for: null justTrigger: false, justCondition: false } ] tokens: [ 'predicate', '(', 0, ')', 'and', '[', 'predicate', '(', 1, ')', 'or', 'predicate', '(', 2, ')', ']' ] } } ] for tc in testCases do (tc) -> it "it should parse \"#{tc.input}\"", -> result = ruleManager._parseRuleCondition("test1", tc.input, context, null, false) assert.deepEqual result, tc.result describe '#parseRuleActions', -> context = null beforeEach -> context = ruleManager._createParseContext() testCases = [ { input: "action 1" result: { actions: [ { id: 'act-test1-0', token: 'action 1', handler: {} # should be the dummyHandler after: null for: null } ], tokens: [ 'action', '(', 0, ')' ] } } { input: "action 1 and action 1" result: { actions: [ { id: 'act-test1-0', token: 'action 1', handler: {} # should be the dummyHandler after: null for: null } { id: 'act-test1-1', token: 'action 1', handler: {} # should be the dummyHandler after: null for: null } ], tokens: [ 'action', '(', 0, ')', 'and', 'action', '(', 1, ')' ] } } { input: "after 1 minute action 1" result: { actions: [ { id: 'act-test1-0', token: 'action 1', handler: {} # should be the dummyHandler after: token: '1 minute' exprTokens: [ 1 ] unit: 'minute' for: null } ], tokens: [ 'action', '(', 0, ')' ] } } { input: "action 1 after 1 minute" result: { actions: [ { id: 'act-test1-0', token: 'action 1', handler: {} # should be the dummyHandler after: token: '1 minute' exprTokens: [ 1 ] unit: 'minute' for: null } ], tokens: [ 'action', '(', 0, ')' ] } } { input: "after 2 minutes action 1 and after 1 hour action 1" result: { actions: [ { id: 'act-test1-0', token: 'action 1', handler: {} # should be the dummyHandler after: token: '2 minutes', exprTokens: [ 2], unit: 'minutes' for: null } { id: 'act-test1-1', token: 'action 1', handler: {} # should be the dummyHandler after: token: '1 hour', exprTokens: [ 1 ], unit: 'hour' for: null } ], tokens: [ 'action', '(', 0, ')', 'and', 'action', '(', 1, ')' ] } } { input: "action 1 after 2 minutes and action 1 after 1 hour" result: { actions: [ { id: 'act-test1-0', token: 'action 1', handler: {} # should be the dummyHandler after: token: '2 minutes', exprTokens: [ 2 ], unit: 'minutes' for: null } { id: 'act-test1-1', token: 'action 1', handler: {} # should be the dummyHandler after: token: '1 hour', exprTokens: [ 1 ], unit: 'hour' for: null } ], tokens: [ 'action', '(', 0, ')', 'and', 'action', '(', 1, ')' ] } } { input: "action 1 for 1 minute" result: { actions: [ { id: 'act-test1-0', token: 'action 1', handler: {} # should be the dummyHandler after: null for: token: '1 minute', exprTokens: [ 1 ], unit: 'minute' } ], tokens: [ 'action', '(', 0, ')' ] } } ] for tc in testCases do (tc) -> it "it should parse \"#{tc.input}\"", -> result = ruleManager._parseRuleActions("test1", tc.input, context) assert result? for action in result.actions assert action.handler instanceof env.actions.ActionHandler action.handler = {} assert(not context.hasErrors()) assert.deepEqual result, tc.result describe '#parseRuleString()', -> context = null beforeEach -> context = ruleManager._createParseContext() it 'should parse: "when predicate 1 then action 1"', (finish) -> ruleManager._parseRuleString("test1", "test1", "when predicate 1 then action 1", context) .then( (rule) -> cassert rule.id is 'test1' cassert rule.conditionToken is 'predicate 1' cassert rule.tokens.length > 0 cassert rule.predicates.length is 1 cassert rule.actionsToken is 'action 1' cassert rule.string is 'when predicate 1 then action 1' finish() ).catch(finish).done() ruleWithForSuffix = 'when predicate 1 for 10 seconds then action 1' it """should parse rule with for "10 seconds" suffix: #{ruleWithForSuffix}'""", (finish) -> ruleManager._parseRuleString("test1", "test1", ruleWithForSuffix, context) .then( (rule) -> cassert rule.id is 'test1' cassert rule.conditionToken is 'predicate 1 for 10 seconds' cassert rule.tokens.length > 0 cassert rule.predicates.length is 1 cassert rule.predicates[0].for.token is '10 seconds' assert.deepEqual rule.predicates[0].for.exprTokens, ['10'] cassert rule.actionsToken is 'action 1' cassert rule.string is 'when predicate 1 for 10 seconds then action 1' finish() ).catch(finish).done() ruleWithHoursSuffix = "when predicate 1 for 2 hours then action 1" it """should parse rule with for "2 hours" suffix: #{ruleWithHoursSuffix}""", (finish) -> ruleManager._parseRuleString("test1", "test1", ruleWithHoursSuffix, context) .then( (rule) -> cassert rule.id is 'test1' cassert rule.conditionToken is 'predicate 1 for 2 hours' cassert rule.tokens.length > 0 cassert rule.predicates.length is 1 cassert rule.predicates[0].for.token is '2 hours' assert.deepEqual rule.predicates[0].for.exprTokens, ['2'] cassert rule.actionsToken is 'action 1' cassert rule.string is 'when predicate 1 for 2 hours then action 1' finish() ).catch(finish).done() it 'should not detect for "42 foo" as for suffix', (finish) -> ruleManager._parseRuleString( "test1", "test1", "when predicate 1 for 42 foo then action 1", context ).then( (rule) -> cassert rule.id is 'test1' cassert rule.conditionToken is 'predicate 1 for 42 foo' cassert rule.tokens.length > 0 cassert rule.predicates.length is 1 cassert rule.predicates[0].for is null cassert rule.actionsToken is 'action 1' cassert rule.string is 'when predicate 1 for 42 foo then action 1' finish() ).catch(finish).done() it 'should reject wrong rule format', (finish) -> # Missing `then`: ruleManager._parseRuleString("test2", "test1", "when predicate 1 and action 1", context) .then( -> finish new Error 'Accepted invalid rule' ).catch( (error) -> cassert error? cassert error.message is 'The rule must start with "when" and contain a "then" part!' finish() ).done() it 'should reject unknown predicate', (finish) -> canDecideCalled = false predProvider.parsePredicate = (input, context) -> cassert input is "predicate 2" canDecideCalled = true return null ruleManager._parseRuleString('test3', "test1", 'when predicate 2 then action 1', context) .then( -> cassert context.hasErrors() cassert context.errors.length is 1 errorMsg = context.errors[0] cassert( errorMsg is 'Could not find an provider that decides next predicate of "predicate 2".' ) cassert canDecideCalled finish() ).catch(finish) return it 'should reject unknown action', (finish) -> canDecideCalled = false predProvider.parsePredicate = (input, context) -> cassert input is "predicate 1" canDecideCalled = true return { token: "predicate 1" nextInput: S(input).chompLeft("predicate 1").s predicateHandler: new DummyPredicateHandler() } parseActionCalled = false actionProvider.parseAction = (input) => cassert input is "action 2" parseActionCalled = true return null ruleManager._parseRuleString('test4', "test1", 'when predicate 1 then action 2', context) .then( -> cassert context.hasErrors() cassert context.errors.length is 1 errorMsg = context.errors[0] cassert( errorMsg is 'Could not find an provider that provides the next action of "action 2".' ) cassert parseActionCalled finish() ).catch(finish) return notifyId = null # ###Tests for `addRuleByString()` describe '#addRuleByString()', -> changeHandler = null before -> predProvider.parsePredicate = (input, context) -> cassert S(input).startsWith("predicate 1") predHandler = new DummyPredicateHandler() predHandler.on = (event, handler) -> if event is 'change' cassert event is 'change' changeHandler = handler return { token: "predicate 1" nextInput: S(input).chompLeft("predicate 1").s predicateHandler: predHandler } it 'should add the rule', (finish) -> parseActionCallCount = 0 actionProvider.parseAction = (input) => cassert input is "action 1" parseActionCallCount++ return { token: "action 1" nextInput: S(input).chompLeft("action 1").s actionHandler: new DummyActionHandler() } ruleManager.addRuleByString('test5', { name: "test5", ruleString: 'when predicate 1 then action 1' }).then( -> cassert changeHandler? cassert parseActionCallCount is 1 cassert ruleManager.rules['test5']? finish() ).catch(finish).done() it 'should react to notifies', (finish) -> this.timeout 3000 ruleManager.rules['test5'].actions[0].handler.executeAction = (simulate) => cassert not simulate finish() return Promise.resolve "execute action" setTimeout((-> changeHandler('event')), 2001) # ###Tests for `updateRuleByString()` describe '#doesRuleCondtionHold', -> predHandler1 = null predHandler2 = null beforeEach -> predHandler1 = new DummyPredicateHandler() predHandler1.on = (event, listener) -> cassert event is 'change' predHandler1.getValue = => Promise.resolve true predHandler1.getType = => "state" predHandler2 = new DummyPredicateHandler() predHandler2.on = (event, listener) -> cassert event is 'change' predHandler2.getValue = => Promise.resolve true predHandler2.getType = => "state" it 'should decide predicate 1', (finish)-> rule = id: "test1" orgCondition: "predicate 1" predicates: [ id: "test1," token: "predicate 1" type: "state" handler: predHandler1 for: null ] tokens: [ "predicate" "(" 0 ")" ] action: "action 1" string: "when predicate 1 then action 1" rule.conditionExprTree = (new rulesAst.BoolExpressionTreeBuilder()) .build(rule.tokens, rule.predicates) ruleManager._evaluateConditionOfRule(rule).then( (isTrue) -> cassert isTrue is true ).then( -> predHandler1.getValue = => Promise.resolve false ).then( -> ruleManager._evaluateConditionOfRule rule).then( (isTrue) -> cassert isTrue is false finish() ).catch(finish).done() it 'should decide trigger: predicate 1', (finish)-> rule = id: "test1" orgCondition: "predicate 1" predicates: [ id: "test1," token: "trigger: predicate 1" type: "state" handler: predHandler1 for: null justTrigger: yes ] tokens: [ "predicate" "(" 0 ")" ] action: "action 1" string: "when trigger: predicate 1 then action 1" predHandler1.getValue = => Promise.resolve true rule.conditionExprTree = (new rulesAst.BoolExpressionTreeBuilder()) .build(rule.tokens, rule.predicates) ruleManager._evaluateConditionOfRule(rule).then( (isTrue) -> cassert isTrue is false ).then( -> knownPredicates = { test1: true } return ruleManager._evaluateConditionOfRule(rule, knownPredicates).then( (isTrue) -> cassert isTrue is false finish() ) ).done() it 'should decide predicate 1 and predicate 2', (finish)-> rule = id: "test1" orgCondition: "predicate 1 and predicate 2" predicates: [ { id: "test1," token: "predicate 1" type: "state" handler: predHandler1 for: null } { id: "test2," token: "predicate 2" type: "state" handler: predHandler2 for: null } ] tokens: [ "predicate" "(" 0 ")" "and" "predicate" "(" 1 ")" ] action: "action 1" string: "when predicate 1 and predicate 2 then action 1" rule.conditionExprTree = (new rulesAst.BoolExpressionTreeBuilder()) .build(rule.tokens, rule.predicates) ruleManager._evaluateConditionOfRule(rule).then( (isTrue) -> cassert isTrue is true ).then( -> predHandler1.getValue = => Promise.resolve true predHandler2.getValue = => Promise.resolve false ).then( -> ruleManager._evaluateConditionOfRule rule ).then( (isTrue) -> cassert isTrue is false finish() ).catch(finish).done() it 'should decide predicate 1 or predicate 2', (finish)-> rule = id: "test1" orgCondition: "predicate 1 or predicate 2" predicates: [ { id: "test1," token: "predicate 1" type: "state" handler: predHandler1 for: null } { id: "test2," token: "predicate 2" type: "state" handler: predHandler2 for: null } ] tokens: [ "predicate" "(" 0 ")" "or" "predicate" "(" 1 ")" ] action: "action 1" string: "when predicate 1 or predicate 2 then action 1" rule.conditionExprTree = (new rulesAst.BoolExpressionTreeBuilder()) .build(rule.tokens, rule.predicates) ruleManager._evaluateConditionOfRule(rule).then( (isTrue) -> cassert isTrue is true ).then( -> predHandler1.getValue = => Promise.resolve true predHandler2.getValue = => Promise.resolve false ).then( -> ruleManager._evaluateConditionOfRule rule ).then( (isTrue) -> cassert isTrue is true finish() ).catch(finish).done() it 'should decide predicate 1 for 1 second (holds)', (finish)-> this.timeout 2000 start = getTime() rule = id: "test1" orgCondition: "predicate 1 for 1 second" predicates: [ id: "test1," token: "predicate 1" type: "state" handler: predHandler1 for: token: '1 second' exprTokens: [ 1 ] unit: 'second' lastChange: start timeAchived: false ] tokens: [ "predicate" "(" 0 ")" ] action: "action 1" string: "when predicate 1 for 1 second then action 1" rule.conditionExprTree = (new rulesAst.BoolExpressionTreeBuilder()) .build(rule.tokens, rule.predicates) ruleManager._evaluateConditionOfRule(rule).then( (isTrue) -> cassert isTrue is false rule.predicates[0].timeAchived = true return ruleManager._evaluateConditionOfRule(rule).then( (isTrue) -> cassert isTrue is true finish() ) ).done() it 'should decide predicate 1 for 1 second (does not hold)', (finish) -> this.timeout 2000 start = getTime() predHandler1.on = (event, listener) -> cassert event is 'change' setTimeout -> listener false , 500 rule = id: "test1" orgCondition: "predicate 1 for 1 second" predicates: [ id: "test1," token: "predicate 1" type: "state" handler: predHandler1 for: token: '1 second' exprTokens: [ 1 ] unit: 'second' lastChange: start timeAchived: false ] tokens: [ "predicate" "(" 0 ")" ] action: "action 1" string: "when predicate 1 for 1 second then action 1" rule.conditionExprTree = (new rulesAst.BoolExpressionTreeBuilder()) .build(rule.tokens, rule.predicates) ruleManager._evaluateConditionOfRule(rule).then( (isTrue) -> cassert isTrue is false finish() ).done() it 'should decide predicate 1 for 1 second and predicate 2 for 2 seconds (holds)', (finish)-> this.timeout 3000 start = getTime() rule = id: "test1" orgCondition: "predicate 1 for 1 second and predicate 2 for 2 seconds" predicates: [ { id: "test1" token: "predicate 1" type: "state" handler: predHandler1 for: token: '1 second' exprTokens: [ 1 ] unit: 'second' lastChange: start timeAchived: true } { id: "test2" token: "predicate 2" type: "state" handler: predHandler2 for: token: '2 seconds' exprTokens: [ 2 ] unit: 'seconds' lastChange: start timeAchived: true } ] tokens: [ "predicate" "(" 0 ")" "and" "predicate" "(" 1 ")" ] action: "action 1" string: "when predicate 1 for 1 second and predicate 2 for 2 seconds then action 1" rule.conditionExprTree = (new rulesAst.BoolExpressionTreeBuilder()) .build(rule.tokens, rule.predicates) ruleManager._evaluateConditionOfRule(rule).then( (isTrue) -> cassert isTrue is true finish() ).done() it 'should decide predicate 1 for 1 second and predicate 2 for 2 seconds (does not holds)', (finish)-> this.timeout 3000 start = getTime() predHandler2.on = (event, listener) -> cassert event is 'change' setTimeout -> listener false , 500 rule = id: "test1" orgCondition: "predicate 1 for 1 second and predicate 2 for 2 seconds" predicates: [ { id: "test1" token: "predicate 1" type: "state" handler: predHandler1 for: token: '1 second' exprTokens: [ 1 ] unit: 'second' lastChange: start timeAchived: true } { id: "test2" token: "predicate 2" type: "state" handler: predHandler2 for: token: '2 seconds' exprTokens: [ 2 ] unit: 'seconds' lastChange: start timeAchived: false } ] tokens: [ "predicate" "(" 0 ")" "and" "predicate" "(" 1 ")" ] action: "action 1" string: "when predicate 1 for 1 second and predicate 2 for 2 seconds then action 1" rule.conditionExprTree = (new rulesAst.BoolExpressionTreeBuilder()) .build(rule.tokens, rule.predicates) ruleManager._evaluateConditionOfRule(rule).then( (isTrue) -> cassert isTrue is false finish() ).done() it 'should decide predicate 1 for 1 second or predicate 2 for 2 seconds (holds)', (finish)-> this.timeout 3000 start = getTime() predHandler1.getValue = => Promise.resolve true predHandler2.getValue = => Promise.resolve true predHandler2.on = (event, listener) -> cassert event is 'change' setTimeout -> listener false , 500 rule = id: "test1" orgCondition: "predicate 1 for 1 second or predicate 2 for 2 seconds" predicates: [ { id: "test1" token: "predicate 1" type: "state" handler: predHandler1 for: token: '1 second' exprTokens: [ 1 ] unit: 'second' lastChange: start timeAchived: true } { id: "test2" token: "predicate 2" type: "state" handler: predHandler2 for: token: '2 seconds' exprTokens: [ 2 ] unit: 'seconds' lastChange: start timeAchived: true } ] tokens: [ "predicate" "(" 0 ")" "or" "predicate" "(" 1 ")" ] action: "action 1" string: "when predicate 1 for 1 second or predicate 2 for 2 seconds then action 1" rule.conditionExprTree = (new rulesAst.BoolExpressionTreeBuilder()) .build(rule.tokens, rule.predicates) ruleManager._evaluateConditionOfRule(rule).then( (isTrue) -> cassert isTrue is true finish() ).done() it 'should decide predicate 1 for 1 second or predicate 2 for 2 seconds (does not holds)', (finish)-> this.timeout 3000 start = getTime() predHandler1.getValue = => Promise.resolve true predHandler2.getValue = => Promise.resolve true predHandler1.on = (event, listener) -> cassert event is 'change' setTimeout -> console.log "emit1" listener false , 500 predHandler2.on = (event, listener) -> cassert event is 'change' setTimeout -> console.log "emit2" listener false , 500 rule = id: "test1" orgCondition: "predicate 1 for 1 second or predicate 2 for 2 seconds" predicates: [ { id: "test1" token: "predicate 1" type: "state" handler: predHandler1 for: token: '1 second' exprTokens: [ 1 ] unit: 'second' lastChange: start timeAchived: false } { id: "test2" token: "predicate 2" type: "state" handler: predHandler2 for: token: '2 seconds' exprTokens: [ 2 ] unit: 'seconds' lastChange: start timeAchived: false } ] tokens: [ "predicate" "(" 0 ")" "or" "predicate" "(" 1 ")" ] action: "action 1" string: "when predicate 1 for 1 second or predicate 2 for 2 seconds then action 1" rule.conditionExprTree = (new rulesAst.BoolExpressionTreeBuilder()) .build(rule.tokens, rule.predicates) ruleManager._evaluateConditionOfRule(rule).then( (isTrue) -> cassert isTrue is false finish() ).done() predHandler = null actHandler = null # ###Tests for `updateRuleByString()` describe '#updateRuleByString()', -> changeListener = null i = 1 it 'should update the rule', (finish) -> parsePredicateCalled = false onCalled = false predProvider.parsePredicate = (input, context) -> cassert S(input).startsWith("predicate 2") parsePredicateCalled = i i++ predHandler = new DummyPredicateHandler() predHandler.on = (event, listener) -> if event is 'change' changeListener = listener onCalled = i i++ predHandler.getVale = => Promise.resolve true predHandler.getType => 'event' return { token: "predicate 2" nextInput: S(input).chompLeft("predicate 2").s predicateHandler: predHandler } actionProvider.parseAction = (input, context) -> cassert S(input).startsWith("action 1") actHandler = new DummyActionHandler() actHandler.executeAction = (simulate) => Promise.resolve "execute action" return { token: "action 1" nextInput: S(input).chompLeft("action 1").s actionHandler: actHandler } ruleManager.updateRuleByString('test5', { name: 'test5' ruleString: 'when predicate 2 then action 1' }).then( -> cassert parsePredicateCalled is 1 cassert onCalled is 2 cassert ruleManager.rules['test5']? cassert ruleManager.rules['test5'].string is 'when predicate 2 then action 1' finish() ).catch(finish).done() it 'should react to notifies', (finish) -> this.timeout 3000 actHandler.executeAction = (simulate) => cassert not simulate finish() return Promise.resolve "execute action" setTimeout( -> changeListener('event') , 2001 ) # ###Tests for `removeRule()` describe '#removeRule()', -> it 'should remove the rule', -> removeListenerCalled = false predHandler.removeListener = (event, listener) -> cassert event is "change" removeListenerCalled = true return true ruleManager.removeRule 'test5' cassert not ruleManager.rules['test5']? cassert removeListenerCalled