diff --git a/ironic_ui/static/dashboard/admin/ironic/base-node/base-node.service.js b/ironic_ui/static/dashboard/admin/ironic/base-node/base-node.service.js index c5f7e0fe..38186ed3 100644 --- a/ironic_ui/static/dashboard/admin/ironic/base-node/base-node.service.js +++ b/ironic_ui/static/dashboard/admin/ironic/base-node/base-node.service.js @@ -25,160 +25,11 @@ function baseNodeService() { var service = { - PostfixExpr: PostfixExpr, driverPropertyGroupHasRequired: driverPropertyGroupHasRequired, driverPropertyGroupsToString: driverPropertyGroupsToString, compareDriverPropertyGroups: compareDriverPropertyGroups }; - /** - * PostFixExpr is a class primarily developed to support the - * evaluation of boolean expressions that determine whether a - * particular property is active. - * - * The expression is stored as a postfix sequence of operands and - * operators. Operands are currently limited to the literal values - * and the values of properties in a specified set. Currently - * supported operands are ==, or, and. - * - * @return {void} - */ - function PostfixExpr() { - this.elem = []; - } - - PostfixExpr.op = { - EQ: "==", - AND: "and", - OR: "or" - }; - - PostfixExpr.UNDEFINED = undefined; - - PostfixExpr.status = { - OK: 0, - ERROR: 1, - BAD_ARG: 2, - UNKNOWN_OP: 3, - MALFORMED: 4 - }; - - /** - * @description Add a property to the expression - * - * @param {string} propertyName - Property name - * - * @return {void} - */ - PostfixExpr.prototype.addProperty = function(propertyName) { - this.elem.push({name: propertyName}); - }; - - /** - * @description Add a value to the expression - * - * @param {object} value - value - * - * @return {void} - */ - PostfixExpr.prototype.addValue = function(value) { - this.elem.push({value: value}); - }; - - /** - * @description Add an operator to the expression - * - * @param {PostfixExpr.op} opId - operator - * - * @return {void} - */ - PostfixExpr.prototype.addOperator = function(opId) { - this.elem.push({op: opId}); - }; - - /** - * @description Get a list of property names referenced by this - * expression - * - * @return {object} An object each property of which corresponds to - * a property in the expression - */ - PostfixExpr.prototype.getProperties = function() { - var properties = {}; - angular.forEach(this.elem, function(elem) { - if (angular.isDefined(elem.name)) { - properties[elem.name] = true; - } - }); - return properties; - }; - - /** - * @description Evaluate a boolean binary operation - * - * @param {array} valStack - Stack of values to operate on - * @param {string} opId - operator id - * - * @return {integer} Return code - */ - function _evaluateBoolBinaryOp(valStack, opId) { - var retCode = PostfixExpr.status.OK; - var val1 = valStack.pop(); - var val2 = valStack.pop(); - if (typeof val1 === "boolean" && - typeof val2 === "boolean") { - switch (opId) { - case PostfixExpr.op.AND: - valStack.push(val1 && val2); - break; - case PostfixExpr.op.OR: - valStack.push(val1 || val2); - break; - default: - retCode = PostfixExpr.status.UNKNOWN_OP; - } - } else { - retCode = PostfixExpr.status.BAD_ARG; - } - return retCode; - } - - /** - * @description Evaluate the experssion using property values from - * a specified set - * - * @param {object} propertySet - Dictionary of DriverProperty instances - * - * @return {array} Return code and Value of the expression - */ - PostfixExpr.prototype.evaluate = function(propertySet) { - var resultStack = []; - for (var i = 0, len = this.elem.length; i < len; i++) { - var elem = this.elem[i]; - if (elem.hasOwnProperty("name")) { - resultStack.push(propertySet[elem.name].getInputValue()); - } else if (elem.hasOwnProperty("value")) { - resultStack.push(elem.value); - } else if (elem.hasOwnProperty("op")) { - if (elem.op === PostfixExpr.op.EQ) { - var val1 = resultStack.pop(); - var val2 = resultStack.pop(); - resultStack.push(val1 === val2); - } else { - var ret = _evaluateBoolBinaryOp(resultStack, elem.op); - if (ret !== PostfixExpr.status.OK) { - return [ret, PostfixExpr.UNDEFINED]; - } - } - } else { - return [PostfixExpr.status.UNKNOWN_ELEMENT, PostfixExpr.UNDEFINED]; - } - } - return resultStack.length === 1 - ? [PostfixExpr.status.OK, resultStack.pop()] - : [PostfixExpr.status.MALFORMED, PostfixExpr.UNDEFINED]; - }; - /** * @description Check whether a group contains required properties * diff --git a/ironic_ui/static/dashboard/admin/ironic/base-node/base-node.spec.js b/ironic_ui/static/dashboard/admin/ironic/base-node/base-node.spec.js index ba6b8302..66c105f8 100644 --- a/ironic_ui/static/dashboard/admin/ironic/base-node/base-node.spec.js +++ b/ironic_ui/static/dashboard/admin/ironic/base-node/base-node.spec.js @@ -36,123 +36,6 @@ expect(service).toBeDefined(); }); - describe('PostfixExpr', function() { - it('Base construction', function() { - var expr = new service.PostfixExpr(); - var ret = expr.evaluate({}); - expect(ret[0]).toBe(service.PostfixExpr.status.MALFORMED); - expect(ret[1]).toBe(service.PostfixExpr.UNDEFINED); - }); - - function evalBinary(val1, val2, op) { - var propertySet = {}; - var prop1 = - new driverPropertyService.DriverProperty("prop1", "", propertySet); - propertySet.prop1 = prop1; - var prop2 = - new driverPropertyService.DriverProperty("prop2", "", propertySet); - propertySet.prop2 = prop2; - - var expr = new service.PostfixExpr(); - expr.addProperty("prop1"); - expr.addProperty("prop2"); - prop1.inputValue = val1; - prop2.inputValue = val2; - expr.addOperator(op); - return expr.evaluate(propertySet); - } - - it('T and T', function() { - var ret = evalBinary(true, true, service.PostfixExpr.op.AND); - expect(ret[0]).toBe(service.PostfixExpr.status.OK); - expect(ret[1]).toBe(true); - }); - - it('T and F', function() { - var ret = evalBinary(true, false, service.PostfixExpr.op.AND); - expect(ret[0]).toBe(service.PostfixExpr.status.OK); - expect(ret[1]).toBe(false); - }); - - it('F and T', function() { - var ret = evalBinary(false, true, service.PostfixExpr.op.AND); - expect(ret[0]).toBe(service.PostfixExpr.status.OK); - expect(ret[1]).toBe(false); - }); - - it('F and F', function() { - var ret = evalBinary(false, false, service.PostfixExpr.op.AND); - expect(ret[0]).toBe(service.PostfixExpr.status.OK); - expect(ret[1]).toBe(false); - }); - - it('T or T', function() { - var ret = evalBinary(true, true, service.PostfixExpr.op.OR); - expect(ret[0]).toBe(service.PostfixExpr.status.OK); - expect(ret[1]).toBe(true); - }); - - it('T or F', function() { - var ret = evalBinary(true, false, service.PostfixExpr.op.OR); - expect(ret[0]).toBe(service.PostfixExpr.status.OK); - expect(ret[1]).toBe(true); - }); - - it('F or T', function() { - var ret = evalBinary(false, true, service.PostfixExpr.op.OR); - expect(ret[0]).toBe(service.PostfixExpr.status.OK); - expect(ret[1]).toBe(true); - }); - - it('F or F', function() { - var ret = evalBinary(false, false, service.PostfixExpr.op.OR); - expect(ret[0]).toBe(service.PostfixExpr.status.OK); - expect(ret[1]).toBe(false); - }); - - it('T eq T', function() { - var ret = evalBinary(true, true, service.PostfixExpr.op.EQ); - expect(ret[0]).toBe(service.PostfixExpr.status.OK); - expect(ret[1]).toBe(true); - }); - - it('T eq F', function() { - var ret = evalBinary(true, false, service.PostfixExpr.op.EQ); - expect(ret[0]).toBe(service.PostfixExpr.status.OK); - expect(ret[1]).toBe(false); - }); - - it('F eq T', function() { - var ret = evalBinary(false, true, service.PostfixExpr.op.EQ); - expect(ret[0]).toBe(service.PostfixExpr.status.OK); - expect(ret[1]).toBe(false); - }); - - it('F eq F', function() { - var ret = evalBinary(false, false, service.PostfixExpr.op.EQ); - expect(ret[0]).toBe(service.PostfixExpr.status.OK); - expect(ret[1]).toBe(true); - }); - - it('1 eq 1', function() { - var ret = evalBinary(1, 1, service.PostfixExpr.op.EQ); - expect(ret[0]).toBe(service.PostfixExpr.status.OK); - expect(ret[1]).toBe(true); - }); - - it('1 eq 0', function() { - var ret = evalBinary(1, 0, service.PostfixExpr.op.EQ); - expect(ret[0]).toBe(service.PostfixExpr.status.OK); - expect(ret[1]).toBe(false); - }); - - it('"1" eq 1', function() { - var ret = evalBinary('1', 1, service.PostfixExpr.op.EQ); - expect(ret[0]).toBe(service.PostfixExpr.status.OK); - expect(ret[1]).toBe(false); - }); - }); - describe('DriverPropertyGroup', function() { it('driverPropertyGroupHasRequired', function () { var dp1 = diff --git a/ironic_ui/static/dashboard/admin/ironic/driver-property.service.js b/ironic_ui/static/dashboard/admin/ironic/driver-property.service.js index 63018729..92174d19 100644 --- a/ironic_ui/static/dashboard/admin/ironic/driver-property.service.js +++ b/ironic_ui/static/dashboard/admin/ironic/driver-property.service.js @@ -52,13 +52,13 @@ driverPropertyService.$inject = [ '$log', - 'horizon.dashboard.admin.ironic.base-node.service', + 'horizon.dashboard.admin.ironic.postfix-expr.service', 'horizon.dashboard.admin.ironic.validHostNamePattern', 'horizon.dashboard.admin.ironic.validUuidPattern' ]; function driverPropertyService($log, - baseNodeService, + postfixExprService, validHostNamePattern, validUuidPattern) { var service = { @@ -219,7 +219,7 @@ return true; } var ret = this.isActiveExpr.evaluate(this.propertySet); - return ret[0] === baseNodeService.PostfixExpr.status.OK && + return ret[0] === postfixExprService.PostfixExpr.status.OK && typeof ret[1] === "boolean" ? ret[1] : true; }; @@ -344,7 +344,7 @@ // Build logical expression to describe under what conditions this // property is active - var expr = new baseNodeService.PostfixExpr(); + var expr = new postfixExprService.PostfixExpr(); var numAdds = 0; var i = NOT_INSIDE_MATCH; @@ -360,10 +360,10 @@ } else { expr.addProperty(match[2]); expr.addValue(this.desc.substring(i, j)); - expr.addOperator(baseNodeService.PostfixExpr.op.EQ); + expr.addOperator(postfixExprService.PostfixExpr.op.EQ); numAdds++; if (numAdds > 1) { - expr.addOperator(baseNodeService.PostfixExpr.op.OR); + expr.addOperator(postfixExprService.PostfixExpr.op.OR); } i = NOT_INSIDE_MATCH; } @@ -385,19 +385,19 @@ // Build logical expression to describe under what conditions this // property is active - var expr = new baseNodeService.PostfixExpr(); + var expr = new postfixExprService.PostfixExpr(); var parts = match[1].split(", or "); expr.addProperty(parts[1]); expr.addValue(undefined); - expr.addOperator(baseNodeService.PostfixExpr.op.EQ); + expr.addOperator(postfixExprService.PostfixExpr.op.EQ); parts = parts[0].split(", "); for (var i = 0; i < parts.length; i++) { expr.addProperty(parts[i]); expr.addValue(undefined); - expr.addOperator(baseNodeService.PostfixExpr.op.EQ); - expr.addOperator(baseNodeService.PostfixExpr.op.AND); + expr.addOperator(postfixExprService.PostfixExpr.op.EQ); + expr.addOperator(postfixExprService.PostfixExpr.op.AND); } $log.debug("_analyzeOneOfDependencies | " + this.desc + " | " + diff --git a/ironic_ui/static/dashboard/admin/ironic/postfix-expr.service.js b/ironic_ui/static/dashboard/admin/ironic/postfix-expr.service.js new file mode 100644 index 00000000..72ae0497 --- /dev/null +++ b/ironic_ui/static/dashboard/admin/ironic/postfix-expr.service.js @@ -0,0 +1,181 @@ +/* + * Copyright 2017 Cray Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +(function() { + 'use strict'; + + angular + .module('horizon.dashboard.admin.ironic') + .factory('horizon.dashboard.admin.ironic.postfix-expr.service', + postfixExprService); + + postfixExprService.$inject = []; + + function postfixExprService() { + var service = { + PostfixExpr: PostfixExpr + }; + + /** + * PostfixExpr is a class primarily developed to support the + * evaluation of boolean expressions that determine whether a + * particular property is active. + * + * The expression is stored as a postfix sequence of operands and + * operators. Operands are currently limited to the literal values + * and the values of properties in a specified set. Currently + * supported operands are ==, or, and. + * + * @return {void} + */ + function PostfixExpr() { + this.elem = []; + } + + PostfixExpr.op = { + EQ: "==", + AND: "and", + OR: "or" + }; + + PostfixExpr.UNDEFINED = undefined; + + PostfixExpr.status = { + OK: 0, + ERROR: 1, + BAD_ARG: 2, + UNKNOWN_OP: 3, + MALFORMED: 4 + }; + + /** + * @description Add a property to the expression + * + * @param {string} propertyName - Property name + * + * @return {void} + */ + PostfixExpr.prototype.addProperty = function(propertyName) { + this.elem.push({name: propertyName}); + }; + + /** + * @description Add a value to the expression + * + * @param {object} value - value + * + * @return {void} + */ + PostfixExpr.prototype.addValue = function(value) { + this.elem.push({value: value}); + }; + + /** + * @description Add an operator to the expression + * + * @param {PostfixExpr.op} opId - operator + * + * @return {void} + */ + PostfixExpr.prototype.addOperator = function(opId) { + this.elem.push({op: opId}); + }; + + /** + * @description Get a list of property names referenced by this + * expression + * + * @return {object} An object each property of which corresponds to + * a property in the expression + */ + PostfixExpr.prototype.getProperties = function() { + var properties = {}; + angular.forEach(this.elem, function(elem) { + if (angular.isDefined(elem.name)) { + properties[elem.name] = true; + } + }); + return properties; + }; + + /** + * @description Evaluate a boolean binary operation + * + * @param {array} valStack - Stack of values to operate on + * @param {string} opId - operator id + * + * @return {integer} Return code + */ + function _evaluateBoolBinaryOp(valStack, opId) { + var retCode = PostfixExpr.status.OK; + var val1 = valStack.pop(); + var val2 = valStack.pop(); + if (typeof val1 === "boolean" && + typeof val2 === "boolean") { + switch (opId) { + case PostfixExpr.op.AND: + valStack.push(val1 && val2); + break; + case PostfixExpr.op.OR: + valStack.push(val1 || val2); + break; + default: + retCode = PostfixExpr.status.UNKNOWN_OP; + } + } else { + retCode = PostfixExpr.status.BAD_ARG; + } + return retCode; + } + + /** + * @description Evaluate the experssion using property values from + * a specified set + * + * @param {object} propertySet - Dictionary of DriverProperty instances + * + * @return {array} Return code and Value of the expression + */ + PostfixExpr.prototype.evaluate = function(propertySet) { + var resultStack = []; + for (var i = 0, len = this.elem.length; i < len; i++) { + var elem = this.elem[i]; + if (elem.hasOwnProperty("name")) { + resultStack.push(propertySet[elem.name].getInputValue()); + } else if (elem.hasOwnProperty("value")) { + resultStack.push(elem.value); + } else if (elem.hasOwnProperty("op")) { + if (elem.op === PostfixExpr.op.EQ) { + var val1 = resultStack.pop(); + var val2 = resultStack.pop(); + resultStack.push(val1 === val2); + } else { + var ret = _evaluateBoolBinaryOp(resultStack, elem.op); + if (ret !== PostfixExpr.status.OK) { + return [ret, PostfixExpr.UNDEFINED]; + } + } + } else { + return [PostfixExpr.status.UNKNOWN_ELEMENT, PostfixExpr.UNDEFINED]; + } + } + return resultStack.length === 1 + ? [PostfixExpr.status.OK, resultStack.pop()] + : [PostfixExpr.status.MALFORMED, PostfixExpr.UNDEFINED]; + }; + + return service; + } +})(); diff --git a/ironic_ui/static/dashboard/admin/ironic/postfix-expr.service.spec.js b/ironic_ui/static/dashboard/admin/ironic/postfix-expr.service.spec.js new file mode 100644 index 00000000..e4721ee6 --- /dev/null +++ b/ironic_ui/static/dashboard/admin/ironic/postfix-expr.service.spec.js @@ -0,0 +1,155 @@ +/** + * Copyright 2017 Cray Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +(function() { + "use strict"; + + describe( + 'horizon.dashboard.admin.ironic.postfix-expr.service', + function() { + var service, driverPropertyService; + + beforeEach(module('horizon.dashboard.admin.ironic')); + + beforeEach(inject(function($injector) { + service = $injector.get( + 'horizon.dashboard.admin.ironic.postfix-expr.service'); + driverPropertyService = $injector.get( + 'horizon.dashboard.admin.ironic.driver-property.service'); + })); + + it('defines the service', function() { + expect(service).toBeDefined(); + }); + + describe('PostfixExpr', function() { + it('Base construction', function() { + var expr = new service.PostfixExpr(); + var ret = expr.evaluate({}); + expect(ret[0]).toBe(service.PostfixExpr.status.MALFORMED); + expect(ret[1]).toBe(service.PostfixExpr.UNDEFINED); + }); + + function evalBinary(val1, val2, op) { + var propertySet = {}; + var prop1 = + new driverPropertyService.DriverProperty("prop1", "", propertySet); + propertySet.prop1 = prop1; + var prop2 = + new driverPropertyService.DriverProperty("prop2", "", propertySet); + propertySet.prop2 = prop2; + + var expr = new service.PostfixExpr(); + expr.addProperty("prop1"); + expr.addProperty("prop2"); + prop1.inputValue = val1; + prop2.inputValue = val2; + expr.addOperator(op); + return expr.evaluate(propertySet); + } + + it('T and T', function() { + var ret = evalBinary(true, true, service.PostfixExpr.op.AND); + expect(ret[0]).toBe(service.PostfixExpr.status.OK); + expect(ret[1]).toBe(true); + }); + + it('T and F', function() { + var ret = evalBinary(true, false, service.PostfixExpr.op.AND); + expect(ret[0]).toBe(service.PostfixExpr.status.OK); + expect(ret[1]).toBe(false); + }); + + it('F and T', function() { + var ret = evalBinary(false, true, service.PostfixExpr.op.AND); + expect(ret[0]).toBe(service.PostfixExpr.status.OK); + expect(ret[1]).toBe(false); + }); + + it('F and F', function() { + var ret = evalBinary(false, false, service.PostfixExpr.op.AND); + expect(ret[0]).toBe(service.PostfixExpr.status.OK); + expect(ret[1]).toBe(false); + }); + + it('T or T', function() { + var ret = evalBinary(true, true, service.PostfixExpr.op.OR); + expect(ret[0]).toBe(service.PostfixExpr.status.OK); + expect(ret[1]).toBe(true); + }); + + it('T or F', function() { + var ret = evalBinary(true, false, service.PostfixExpr.op.OR); + expect(ret[0]).toBe(service.PostfixExpr.status.OK); + expect(ret[1]).toBe(true); + }); + + it('F or T', function() { + var ret = evalBinary(false, true, service.PostfixExpr.op.OR); + expect(ret[0]).toBe(service.PostfixExpr.status.OK); + expect(ret[1]).toBe(true); + }); + + it('F or F', function() { + var ret = evalBinary(false, false, service.PostfixExpr.op.OR); + expect(ret[0]).toBe(service.PostfixExpr.status.OK); + expect(ret[1]).toBe(false); + }); + + it('T eq T', function() { + var ret = evalBinary(true, true, service.PostfixExpr.op.EQ); + expect(ret[0]).toBe(service.PostfixExpr.status.OK); + expect(ret[1]).toBe(true); + }); + + it('T eq F', function() { + var ret = evalBinary(true, false, service.PostfixExpr.op.EQ); + expect(ret[0]).toBe(service.PostfixExpr.status.OK); + expect(ret[1]).toBe(false); + }); + + it('F eq T', function() { + var ret = evalBinary(false, true, service.PostfixExpr.op.EQ); + expect(ret[0]).toBe(service.PostfixExpr.status.OK); + expect(ret[1]).toBe(false); + }); + + it('F eq F', function() { + var ret = evalBinary(false, false, service.PostfixExpr.op.EQ); + expect(ret[0]).toBe(service.PostfixExpr.status.OK); + expect(ret[1]).toBe(true); + }); + + it('1 eq 1', function() { + var ret = evalBinary(1, 1, service.PostfixExpr.op.EQ); + expect(ret[0]).toBe(service.PostfixExpr.status.OK); + expect(ret[1]).toBe(true); + }); + + it('1 eq 0', function() { + var ret = evalBinary(1, 0, service.PostfixExpr.op.EQ); + expect(ret[0]).toBe(service.PostfixExpr.status.OK); + expect(ret[1]).toBe(false); + }); + + it('"1" eq 1', function() { + var ret = evalBinary('1', 1, service.PostfixExpr.op.EQ); + expect(ret[0]).toBe(service.PostfixExpr.status.OK); + expect(ret[1]).toBe(false); + }); + }); + }); +})();