From 52f2e318ad7a7571c4fc40e09b3cb460609ae2b1 Mon Sep 17 00:00:00 2001 From: Xinni Ge Date: Tue, 24 Oct 2017 16:18:41 +0900 Subject: [PATCH] Add unittests for template generator angular The following changes have been made. - Test cases for common components and individual resources. - Setup karma + jasmine test environment. - Setup eslint environment and rules. - Code style adjustment to satisfiy eslint rules. Change-Id: Icb3e48be11beaebc4e410644c62e0df86b345207 --- .eslintignore | 1 + .eslintrc.js | 265 ++++++++++++++ .gitignore | 4 + .../templates/template_generator/index.html | 22 +- .../_1650_project_template_generator_panel.py | 11 +- .../template_generator/css/hotgen.css | 4 + .../js/components/agent.controller.js | 15 +- .../js/components/agent.controller.spec.js | 100 ++++++ .../js/components/agent.module.js | 8 +- .../js/components/agent.module.spec.js | 82 +++++ .../js/components/compile.directive.spec.js | 29 ++ .../js/components/dependson.directive.spec.js | 51 +++ .../js/components/draggable.directive.js | 22 +- .../js/components/draggable.directive.spec.js | 52 +++ .../js/components/droppable.directive.js | 23 +- .../js/components/droppable.directive.spec.js | 70 ++++ .../js/components/globals.service.spec.js | 126 +++++++ .../js/components/icons.controller.js | 2 +- .../js/components/icons.controller.spec.js | 38 ++ .../js/components/loading.controller.js | 4 +- .../js/components/loading.controller.spec.js | 36 ++ .../js/components/menu.controller.js | 19 +- .../js/components/menu.controller.spec.js | 135 ++++++++ .../js/components/modal-draft.controller.js | 47 +-- .../components/modal-draft.controller.spec.js | 94 +++++ .../js/components/modal-edge.controller.js | 106 +++--- .../components/modal-edge.controller.spec.js | 196 +++++++++++ .../js/components/modal-node.controller.js | 286 +++++++-------- .../components/modal-node.controller.spec.js | 278 +++++++++++++++ .../components/modal-template.controller.js | 281 +++++++-------- .../modal-template.controller.spec.js | 159 +++++++++ .../js/components/states.service.js | 2 +- .../js/components/states.service.spec.js | 123 +++++++ .../template-generator.module.spec.js | 42 +++ .../js/components/utils.module.js | 52 ++- .../js/components/utils.module.spec.js | 327 ++++++++++++++++++ .../js/components/vis-network.controller.js | 9 +- .../components/vis-network.controller.spec.js | 203 +++++++++++ .../os__cinder__volume.spec.js | 83 +++++ .../os__cinder__volumeattachment.spec.js | 78 +++++ .../os__heat__resourcegroup.js | 19 +- .../os__heat__resourcegroup.spec.js | 144 ++++++++ .../os__neutron__floatingip.html | 2 +- .../os__neutron__floatingip.spec.js | 92 +++++ .../os__neutron__floatingassociation.spec.js | 78 +++++ .../os__neutron__floatingipassociation.html | 2 +- .../os__neutron__floatingipassociation.js | 2 +- .../os__neutron__net/os__neutron__net.html | 2 +- .../os__neutron__net/os__neutron__net.spec.js | 61 ++++ .../os__neutron__port/os__neutron__port.html | 2 +- .../os__neutron__port/os__neutron__port.js | 2 +- .../os__neutron__port.spec.js | 146 ++++++++ .../os__neutron__router.html | 2 +- .../os__neutron__router.spec.js | 99 ++++++ .../os__neutron__routerinterface.html | 2 +- .../os__neutron__routerinterface.js | 2 +- .../os__neutron__routerinterface.spec.js | 75 ++++ .../os__neutron__securitygroup.html | 2 +- .../os__neutron__securitygroup.spec.js | 62 ++++ .../os__neutron__subnet.js | 2 +- .../os__neutron__subnet.spec.js | 100 ++++++ .../os__nova__keypair/os__nova__keypair.html | 2 +- .../os__nova__keypair.spec.js | 39 +++ .../os__nova__server/os__nova__server.html | 2 +- .../os__nova__server/os__nova__server.js | 21 +- .../os__nova__server/os__nova__server.spec.js | 308 +++++++++++++++++ .../templates/depends_on.html | 12 +- .../templates/modal_edge.html | 12 +- .../templates/modal_template.html | 22 +- karma.conf.js | 100 ++++++ package.json | 33 ++ 71 files changed, 4447 insertions(+), 487 deletions(-) create mode 100644 .eslintignore create mode 100644 .eslintrc.js create mode 100644 heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/agent.controller.spec.js create mode 100644 heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/agent.module.spec.js create mode 100644 heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/compile.directive.spec.js create mode 100644 heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/dependson.directive.spec.js create mode 100644 heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/draggable.directive.spec.js create mode 100644 heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/droppable.directive.spec.js create mode 100644 heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/globals.service.spec.js create mode 100644 heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/icons.controller.spec.js create mode 100644 heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/loading.controller.spec.js create mode 100644 heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/menu.controller.spec.js create mode 100644 heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/modal-draft.controller.spec.js create mode 100644 heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/modal-edge.controller.spec.js create mode 100644 heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/modal-node.controller.spec.js create mode 100644 heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/modal-template.controller.spec.js create mode 100644 heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/states.service.spec.js create mode 100644 heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/template-generator.module.spec.js create mode 100644 heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/utils.module.spec.js create mode 100644 heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/vis-network.controller.spec.js create mode 100644 heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__cinder__volume/os__cinder__volume.spec.js create mode 100644 heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__cinder__volumeattachment/os__cinder__volumeattachment.spec.js create mode 100644 heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__heat__resourcegroup/os__heat__resourcegroup.spec.js create mode 100644 heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingip/os__neutron__floatingip.spec.js create mode 100644 heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingipassociation/os__neutron__floatingassociation.spec.js create mode 100644 heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__net/os__neutron__net.spec.js create mode 100644 heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__port/os__neutron__port.spec.js create mode 100644 heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__router/os__neutron__router.spec.js create mode 100644 heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__routerinterface/os__neutron__routerinterface.spec.js create mode 100644 heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__securitygroup/os__neutron__securitygroup.spec.js create mode 100644 heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__subnet/os__neutron__subnet.spec.js create mode 100644 heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__keypair/os__nova__keypair.spec.js create mode 100644 heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__server/os__nova__server.spec.js create mode 100644 karma.conf.js create mode 100644 package.json diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000..4b44eae8 --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/vendors/* diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000..b5ac79a4 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,265 @@ +module.exports = { + "env": { + "browser": true, + "jasmine": true, + }, + "plugins": ["jasmine"], + "globals": { + "angular": true, + "module": true, + "inject": true, + "saveAs": true, + "json2yaml": true + }, + "extends": ["eslint:recommended", "plugin:jasmine/recommended"], + "rules": { + "accessor-pairs": "error", + "array-bracket-newline": "off", + "array-bracket-spacing": "off", + "array-callback-return": "error", + "array-element-newline": "off", + "arrow-body-style": "error", + "arrow-parens": "error", + "arrow-spacing": "error", + "block-scoped-var": "off", + "block-spacing": "off", + "brace-style": "off", + "callback-return": "off", + "camelcase": "off", + "capitalized-comments": "off", + "class-methods-use-this": "error", + "comma-dangle": "off", + "comma-spacing": "off", + "comma-style": "off", + "complexity": "off", + "computed-property-spacing": [ + "error", + "never" + ], + "consistent-return": "off", + "consistent-this": "off", + "curly": "off", + "default-case": "off", + "dot-location": [ + "error", + "property" + ], + "dot-notation": "off", + "eol-last": "off", + "eqeqeq": "off", + "for-direction": "error", + "func-call-spacing": "off", + "func-name-matching": "off", + "func-names": "off", + "func-style": "off", + "function-paren-newline": "off", + "generator-star-spacing": "error", + "getter-return": "error", + "global-require": "error", + "guard-for-in": "off", + "handle-callback-err": "error", + "id-blacklist": "error", + "id-length": "off", + "id-match": "error", + "indent": "off", + "indent-legacy": "off", + "init-declarations": "off", + "jasmine/prefer-toHaveBeenCalledWith": "off", + "jsx-quotes": "error", + "key-spacing": "off", + "keyword-spacing": "off", + "line-comment-position": "off", + "linebreak-style": [ + "error", + "unix" + ], + "lines-around-comment": "off", + "lines-around-directive": "off", + "lines-between-class-members": "error", + "max-depth": "off", + "max-len": "off", + "max-lines": "off", + "max-nested-callbacks": "error", + "max-params": "off", + "max-statements": "off", + "max-statements-per-line": "off", + "multiline-comment-style": "off", + "multiline-ternary": "off", + "new-parens": "off", + "newline-after-var": "off", + "newline-before-return": "off", + "newline-per-chained-call": "off", + "no-alert": "off", + "no-array-constructor": "error", + "no-await-in-loop": "error", + "no-bitwise": "off", + "no-buffer-constructor": "error", + "no-caller": "error", + "no-catch-shadow": "off", + "no-confusing-arrow": "error", + "no-continue": "off", + "no-div-regex": "error", + "no-duplicate-imports": "error", + "no-else-return": "off", + "no-empty-function": "off", + "no-eq-null": "off", + "no-eval": "error", + "no-extend-native": "error", + "no-extra-bind": "off", + "no-extra-label": "off", + "no-extra-parens": "off", + "no-floating-decimal": "off", + "no-implicit-coercion": [ + "error", + { + "boolean": false, + "number": false, + "string": false + } + ], + "no-implicit-globals": "off", + "no-implied-eval": "error", + "no-inline-comments": "off", + "no-inner-declarations": [ + "error", + "functions" + ], + "no-invalid-this": "off", + "no-iterator": "error", + "no-label-var": "error", + "no-lone-blocks": "off", + "no-lonely-if": "off", + "no-loop-func": "off", + "no-magic-numbers": "off", + "no-mixed-operators": "off", + "no-mixed-requires": "error", + "no-multi-assign": "off", + "no-multi-spaces": "off", + "no-multi-str": "error", + "no-multiple-empty-lines": "off", + "no-native-reassign": "error", + "no-negated-condition": "off", + "no-negated-in-lhs": "error", + "no-nested-ternary": "off", + "no-new": "error", + "no-new-func": "off", + "no-new-object": "error", + "no-new-require": "error", + "no-new-wrappers": "error", + "no-octal-escape": "error", + "no-param-reassign": "off", + "no-path-concat": "error", + "no-plusplus": "off", + "no-process-env": "error", + "no-process-exit": "error", + "no-proto": "off", + "no-prototype-builtins": "off", + "no-redeclare": "off", + "no-restricted-globals": "error", + "no-restricted-imports": "error", + "no-restricted-modules": "error", + "no-restricted-properties": "error", + "no-restricted-syntax": "error", + "no-return-assign": "off", + "no-return-await": "error", + "no-script-url": "error", + "no-self-compare": "error", + "no-sequences": "off", + "no-shadow": "off", + "no-shadow-restricted-names": "off", + "no-spaced-func": "off", + "no-sync": "error", + "no-tabs": "off", + "no-template-curly-in-string": "error", + "no-ternary": "off", + "no-throw-literal": "off", + "no-trailing-spaces": [ + "error", + { + "ignoreComments": true, + "skipBlankLines": true + } + ], + "no-undef-init": "off", + "no-undefined": "off", + "no-underscore-dangle": "off", + "no-unmodified-loop-condition": "off", + "no-unneeded-ternary": "off", + "no-unused-expressions": "off", + "no-unused-vars": "off", + "no-use-before-define": "off", + "no-useless-call": "off", + "no-useless-computed-key": "error", + "no-useless-concat": "off", + "no-useless-constructor": "error", + "no-useless-rename": "error", + "no-useless-return": "off", + "no-var": "off", + "no-void": "off", + "no-warning-comments": "off", + "no-whitespace-before-property": "error", + "no-with": "error", + "nonblock-statement-body-position": [ + "error", + "any" + ], + "object-curly-newline": "off", + "object-curly-spacing": "off", + "object-property-newline": "off", + "object-shorthand": "off", + "one-var": "off", + "one-var-declaration-per-line": "off", + "operator-assignment": "off", + "operator-linebreak": "off", + "padded-blocks": "off", + "padding-line-between-statements": "error", + "prefer-arrow-callback": "off", + "prefer-const": "error", + "prefer-destructuring": "off", + "prefer-numeric-literals": "error", + "prefer-promise-reject-errors": "error", + "prefer-reflect": "off", + "prefer-rest-params": "off", + "prefer-spread": "off", + "prefer-template": "off", + "quote-props": "off", + "quotes": "off", + "radix": "off", + "require-await": "error", + "require-jsdoc": "off", + "rest-spread-spacing": "error", + "semi": "off", + "semi-spacing": "off", + "semi-style": "off", + "sort-imports": "error", + "sort-keys": "off", + "sort-vars": "off", + "space-before-blocks": "off", + "space-before-function-paren": "off", + "space-in-parens": "off", + "space-infix-ops": "off", + "space-unary-ops": "off", + "spaced-comment": "off", + "strict": "off", + "switch-colon-spacing": "off", + "symbol-description": "error", + "template-curly-spacing": "error", + "template-tag-spacing": "error", + "unicode-bom": [ + "error", + "never" + ], + "valid-jsdoc": "off", + "valid-typeof": [ + "error", + { + "requireStringLiterals": false + } + ], + "vars-on-top": "off", + "wrap-iife": "off", + "wrap-regex": "off", + "yield-star-spacing": "error", + "yoda": "off" + } +}; diff --git a/.gitignore b/.gitignore index 91f4e430..57a43108 100644 --- a/.gitignore +++ b/.gitignore @@ -110,3 +110,7 @@ ENV/ # backup files *.bak + +coverage/* +node_modules/* +package-lock.json diff --git a/heat_dashboard/content/template_generator/templates/template_generator/index.html b/heat_dashboard/content/template_generator/templates/template_generator/index.html index 29b504c2..356c2d3b 100644 --- a/heat_dashboard/content/template_generator/templates/template_generator/index.html +++ b/heat_dashboard/content/template_generator/templates/template_generator/index.html @@ -10,7 +10,7 @@ {% endblock %} {% block main %} -
+
@@ -19,7 +19,7 @@
-
+
@@ -29,16 +29,16 @@
-
+
Generate Template
-
+
Manage Drafts - + @@ -66,7 +66,7 @@
-
+
Clear Canvas @@ -82,7 +82,7 @@ -
+
{$ resobj.name $} @@ -95,7 +95,7 @@
-
+
@@ -104,17 +104,17 @@ -
+
-
+
-
+
diff --git a/heat_dashboard/enabled/_1650_project_template_generator_panel.py b/heat_dashboard/enabled/_1650_project_template_generator_panel.py index c4cb074c..69241c16 100644 --- a/heat_dashboard/enabled/_1650_project_template_generator_panel.py +++ b/heat_dashboard/enabled/_1650_project_template_generator_panel.py @@ -64,9 +64,12 @@ ADD_JS_FILES.extend( 'static'), sub_path='%s/components' % JS_BASE, ext='.js', - trim_base_path=True) if file not in ADD_JS_FILES + trim_base_path=True) + if file not in ADD_JS_FILES and 'spec.js' not in file ]) ADD_JS_FILES.extend( - discover_files(os.path.join(HEAT_DASHBOARD_ROOT, 'static'), - sub_path='%s/resources' % JS_BASE, - ext='.js', trim_base_path=True)) + [file for file in discover_files( + os.path.join(HEAT_DASHBOARD_ROOT, 'static'), + sub_path='%s/resources' % JS_BASE, + ext='.js', trim_base_path=True) if 'spec.js' not in file + ]) diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/hotgen.css b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/hotgen.css index a25bdd5d..21ada364 100644 --- a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/hotgen.css +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/hotgen.css @@ -163,3 +163,7 @@ md-icon.spinner{ color: #fff; } +.div-scroll{ + overflow: auto; + max-height: 500px; +} \ No newline at end of file diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/agent.controller.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/agent.controller.js index 313ec15f..19eb1eb0 100644 --- a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/agent.controller.js +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/agent.controller.js @@ -3,11 +3,11 @@ 'use strict'; angular.module('horizon.dashboard.project.heat_dashboard.template_generator') - .controller('horizon.dashboard.project.heat_dashboard.template_generator.AgentCtrl', [ + .controller('horizon.dashboard.project.heat_dashboard.template_generator.AgentController', [ '$scope','hotgenAgent', 'hotgenGlobals', 'hotgenMessage', function($scope, hotgenAgent, hotgenGlobals, hotgenMessage){ - - var init = function(){ + $scope.template_versions = []; + $scope.init = function(){ /* ********************************************************************* * The following selections should be replaced by OpenStack API response */ @@ -35,10 +35,15 @@ }); }; - init(); + $scope.init(); $scope.update_template_version = function(template_version){ - hotgenGlobals.set_template_version(template_version) + hotgenGlobals.set_template_version(template_version); + return true; + }; + $scope.load_template_version = function(){ + $scope.template_version = hotgenGlobals.get_template_version() } + $scope.$on('update_template_version', $scope.load_template_version); }]) })(); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/agent.controller.spec.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/agent.controller.spec.js new file mode 100644 index 00000000..a30320a5 --- /dev/null +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/agent.controller.spec.js @@ -0,0 +1,100 @@ +(function() { + 'use strict'; + + describe('horizon.dashboard.project.heat_dashboard.template_generator.AgentController', function(){ + beforeEach(module('horizon.dashboard.project.heat_dashboard.template_generator')); + + var $httpBackend, requestHandler; + var $location; + var hotgenGlobals; + + beforeEach(inject(function($injector){ + $location = $injector.get('$location'); + hotgenGlobals = $injector.get('hotgenGlobals'); + spyOn($location, 'absUrl').and.callFake(function (p) { + return 'http://some-url/'; + }); + })); + + beforeEach(inject(function($injector) { + // Set up the mock http service responses + $httpBackend = $injector.get('$httpBackend'); + requestHandler = $httpBackend.when('GET', 'http://some-url/get_resource_options') + .respond(200, { + 'auth': { + 'tenant_id': 'tenant-id', + 'admin': false, + }, + 'template_versions': [ + {'name': 'v1', 'id': 'v1'}, + {'name': 'v2', 'id': 'v2'} + ], + } + ); + + + })); + + var $controller, controller, $scope; + beforeEach(inject(function(_$controller_, $rootScope) { + $controller = _$controller_; + $scope = $rootScope.$new(); + })); + + afterEach(function() { + $httpBackend.verifyNoOutstandingExpectation(); + $httpBackend.verifyNoOutstandingRequest(); + }); + + it('should exist', function(){ + controller = $controller('horizon.dashboard.project.heat_dashboard.template_generator.AgentController', { $scope: $scope,}); + + expect(controller).toBeDefined(); + + $httpBackend.flush(); + }); + + it('should return array with 2 items', function(){ + $httpBackend.expectGET('http://some-url/get_resource_options'); + + controller = $controller('horizon.dashboard.project.heat_dashboard.template_generator.AgentController', { $scope: $scope,}); + $httpBackend.flush(); + + expect($scope.template_versions.length).toEqual(2); + + }); + + it('should return empty array', function(){ + requestHandler.respond(500, ''); + $httpBackend.expectGET('http://some-url/get_resource_options'); + controller = $controller('horizon.dashboard.project.heat_dashboard.template_generator.AgentController', { $scope: $scope,}); + $httpBackend.flush(); + + expect($scope.template_versions.length).toEqual(0); + + }); + + it('should return true', function(){ + $httpBackend.expectGET('http://some-url/get_resource_options'); + + controller = $controller('horizon.dashboard.project.heat_dashboard.template_generator.AgentController', { $scope: $scope,}); + $httpBackend.flush(); + + expect($scope.update_template_version()).toEqual(true); + + }); + + it('should set template version from hotgenGlobals', function(){ + $httpBackend.expectGET('http://some-url/get_resource_options'); + + hotgenGlobals.set_template_version('template_version-1'); + controller = $controller('horizon.dashboard.project.heat_dashboard.template_generator.AgentController', { $scope: $scope,}); + $httpBackend.flush(); + + $scope.load_template_version(); + + expect($scope.template_version).toEqual('template_version-1'); + }); + }); + +})(); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/agent.module.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/agent.module.js index bc8011eb..d322cfc8 100644 --- a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/agent.module.js +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/agent.module.js @@ -4,11 +4,11 @@ angular.module('hotgen-agent', ['hotgen-utils', ]) .factory('hotgenAgent', ['$http', '$location', 'hotgenNotify', function($http, $location, hotgenNotify) { - var static_url = $location.absUrl(); - if (static_url.substr(-1) != '/'){ - static_url += '/'; - } var get_resource_options = function(){ + var static_url = $location.absUrl(); + if (static_url.substr(-1) != '/'){ + static_url += '/'; + } return $http({ method: 'GET', url: static_url+'get_resource_options' diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/agent.module.spec.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/agent.module.spec.js new file mode 100644 index 00000000..2a92e66b --- /dev/null +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/agent.module.spec.js @@ -0,0 +1,82 @@ +(function () { + 'use strict'; + + describe('hotgen-agent module', function () { + it('should be defined', function () { + expect(angular.module('hotgen-agent')).toBeDefined(); + }); + }); + + describe('hotgen-utils.hotgenStates', function(){ + beforeEach(module('hotgen-agent')); + + var hotgenAgent; + + beforeEach(inject(function(_hotgenAgent_){ + hotgenAgent = _hotgenAgent_; + })); + + var $httpBackend, requestHandler; + var $location; + + beforeEach(inject(function($injector){ + $location = $injector.get('$location'); + })); + + beforeEach(inject(function($injector) { + // Set up the mock http service responses + $httpBackend = $injector.get('$httpBackend'); + requestHandler = $httpBackend.when('GET', 'http://some-url/get_resource_options') + .respond(200, { + 'auth': { + 'tenant_id': 'tenant-id', + 'admin': false, + }} + ); + + + })); + + afterEach(function() { + $httpBackend.verifyNoOutstandingExpectation(); + $httpBackend.verifyNoOutstandingRequest(); + }); + + it('should exist', function(){ + expect(hotgenAgent).toBeDefined(); + }); + + it('should return get_resource_options', function(){ + spyOn($location, 'absUrl').and.callFake(function (p) { + return 'http://some-url/'; + }); + $httpBackend.expectGET('http://some-url/get_resource_options'); + var optionsPromise = hotgenAgent.get_resource_options(); + optionsPromise.then(function(options){ + expect(options.auth.tenant_id).toEqual('tenant-id'); + expect(options.auth.admin).toEqual(false); + }); + $httpBackend.flush(); + + }); + + it('should return error', function(){ + spyOn($location, 'absUrl').and.callFake(function (p) { + return 'http://some-url'; + }); + requestHandler.respond(500, ''); + + $httpBackend.expectGET('http://some-url/get_resource_options'); + + var optionsPromise = hotgenAgent.get_resource_options(); + optionsPromise.then(function(options){ + expect(options).toEqual(null); + }); + $httpBackend.flush(); + + }); + + + }); + +})(); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/compile.directive.spec.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/compile.directive.spec.js new file mode 100644 index 00000000..7362e26e --- /dev/null +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/compile.directive.spec.js @@ -0,0 +1,29 @@ +(function() { + 'use strict'; + + describe('hotgen-utils compile directive', function(){ + beforeEach(module('hotgen-utils')); + + var $compile, $rootScope, $scope, $isolateScope, element; + + beforeEach(inject(function($rootScope, $compile) { + $scope = $rootScope.$new(); + + // element will enable you to test your directive's element on the DOM + element = $compile(angular.element('
'))($scope); + + // Digest needs to be called to set any values on the directive's scope + $scope.$digest(); + + // If the directive uses isolate scope, we need to get a reference to it + // explicitly + })); + + + it('Replaces the element with the appropriate content', function() { + expect(element.html()).toContain("Compile Me"); + }); + + }); + +})(); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/dependson.directive.spec.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/dependson.directive.spec.js new file mode 100644 index 00000000..0e24e7b1 --- /dev/null +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/dependson.directive.spec.js @@ -0,0 +1,51 @@ +(function() { + 'use strict'; + + describe('horizon.dashboard.project.heat_dashboard.template_generator dependson directive', function(){ + beforeEach(module('horizon.dashboard.project.heat_dashboard.template_generator')); + + beforeEach(module('appTemplates')); + + var $compile, $rootScope, $scope, $isolateScope, element; + + beforeEach(inject(function($rootScope, $compile) { + $scope = $rootScope.$new(); + $scope.dependson = ['node-id-1111', 'node-id-2222', 'node-id-3333']; + + // element will enable you to test your directive's element on the DOM + element = $compile(angular.element(''))($scope); + + // Digest needs to be called to set any values on the directive's scope + $scope.$digest(); + + // If the directive uses isolate scope, we need to get a reference to it + // explicitly + $isolateScope = element.isolateScope(); + })); + + + it('Replaces the element with the appropriate content', function() { + expect(element.find('label').html()).toContain("Depends on"); + }); + + it('toggle function modifies array', function() { + var array = [0, 1, 2, 3, 4]; + $isolateScope.toggle(5, array); + + expect(array.length).toEqual(6); + + $isolateScope.toggle(0, array); + $isolateScope.toggle(5, array); + + expect(array.length).toEqual(4); + }); + + it('check array item existence ', function() { + var array = [0, 1, 2, 3, 4]; + + expect($isolateScope.exists(5, array)).toEqual(false); + expect($isolateScope.exists(1, array)).toEqual(true); + }); + }); + +})(); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/draggable.directive.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/draggable.directive.js index 53a02f28..3f3c4383 100644 --- a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/draggable.directive.js +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/draggable.directive.js @@ -5,15 +5,21 @@ angular.module('horizon.dashboard.project.heat_dashboard.template_generator').directive('draggable', [function(){ return function ($scope, element){ var el = element[0]; - el.draggable = true; - el.addEventListener('dragstart', function(e){ - this.style.opacity = '0.4'; - e.dataTransfer.setData('text', e.target.id); - }, false); - el.addEventListener('dragend', function(e){ - this.style.opacity = '1.0'; - }, false); + el.draggable = true; + + $scope.dragstartHandler = function(e){ + el.style.opacity = '0.4'; + e.dataTransfer.setData('text', e.target.id); + } + $scope.dragendHandler = function(e){ + el.style.opacity = '1.0'; + } + + + el.addEventListener('dragstart', $scope.dragstartHandler, false); + + el.addEventListener('dragend', $scope.dragendHandler, false); } }]); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/draggable.directive.spec.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/draggable.directive.spec.js new file mode 100644 index 00000000..3e906533 --- /dev/null +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/draggable.directive.spec.js @@ -0,0 +1,52 @@ +(function() { + 'use strict'; + + describe('horizon.dashboard.project.heat_dashboard.template_generator draggable directive', function(){ + beforeEach(module('horizon.dashboard.project.heat_dashboard.template_generator')); + + var $compile, $rootScope, $scope, $isolateScope, element; + + beforeEach(inject(function($rootScope, $compile) { + $scope = $rootScope.$new(); + + // element will enable you to test your directive's element on the DOM + element = $compile(angular.element('
drag me
'))($scope); + + // Digest needs to be called to set any values on the directive's scope + $scope.$digest(); + + // If the directive uses isolate scope, we need to get a reference to it + // explicitly + $isolateScope = element.isolateScope(); + })); + + + it('Replaces the element with the appropriate content', function() { + expect(element[0].draggable).toEqual(true); + }); + + it('should change style when drag start', function() { + var mockEvent = { + 'type': 'dragstart', + 'dataTransfer': { + 'setData': function(key, value){}, + }, + 'target': {'id': 'icon-1'} + }; + $scope.dragstartHandler(mockEvent, element); + + expect(element[0].style.opacity).toEqual('0.4') + }); + + it('should change style when drag end', function() { + var mockEvent = { + 'type': 'dragend', + }; + $scope.dragendHandler(mockEvent, element); + + expect(element[0].style.opacity).toEqual('1') + }); + + }); + +})(); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/droppable.directive.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/droppable.directive.js index cd80f434..33d28331 100644 --- a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/droppable.directive.js +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/droppable.directive.js @@ -11,13 +11,7 @@ nodes: hotgenStates.get_nodes(), edges: hotgenStates.get_edges(), } - var el = element[0]; - el.addEventListener('dragover', function(e){ - if (e.preventDefault){ - e.preventDefault(); - } - },true); - el.addEventListener('drop', function(e){ + $scope.dropHandler = function(e){ var resource_types = hotgenGlobals.get_resource_icons(); var dropped_elem_id = e.dataTransfer.getData("text"); var dropped_elem_base = document.getElementById(dropped_elem_id); @@ -31,7 +25,7 @@ $scope.data.nodes.add({ id: id, label: node_label, - shape: 'image', + shape: 'circularImage', title: resource_type, icon: { face: 'FontAwesome', @@ -39,11 +33,22 @@ size: 50, color: dragged_resource.color, }, + borderWidth: 0, + borderWidthSelected: 0, + color: {border: '#ffffff', background: '#ffffff', highlight: '#ffffff', hover: '#ffffff'}, image: basePath+'js/resources/'+resource_type.toLowerCase()+'/'+resource_type.toLowerCase()+'-gray.svg', }); hotgenStates.update_saved_flags(id, false) e.preventDefault(); - },false); + } + $scope.dragoverHandler = function(e){ + if (e.preventDefault){ + e.preventDefault(); + } + } + var el = element[0]; + el.addEventListener('dragover', $scope.dragoverHandler, true); + el.addEventListener('drop', $scope.dropHandler, false); } } }]); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/droppable.directive.spec.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/droppable.directive.spec.js new file mode 100644 index 00000000..c26959ec --- /dev/null +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/droppable.directive.spec.js @@ -0,0 +1,70 @@ +(function() { + 'use strict'; + + describe('horizon.dashboard.project.heat_dashboard.template_generator droppable directive', function(){ + beforeEach(module('horizon.dashboard.project.heat_dashboard.template_generator')); + + var hotgenGlobals; + + beforeEach(inject(function($injector){ + hotgenGlobals = $injector.get('hotgenGlobals'); + })); + + var $compile, $rootScope, $scope, $isolateScope, element; + + beforeEach(inject(function($rootScope, $compile) { + $scope = $rootScope.$new(); + + // element will enable you to test your directive's element on the DOM + element = $compile('
drop me
')($scope); + + // Digest needs to be called to set any values on the directive's scope + $scope.$digest(); + + // If the directive uses isolate scope, we need to get a reference to it + // explicitly + $isolateScope = element.isolateScope(); + })); + + + it('Replaces the element with the appropriate content', function() { + expect(element.html()).toEqual('drop me'); + }); + + it('Dragover event with preventDefault', function() { + var mockEvent= { + type: 'dragover', + preventDefault: function(){}, + } + spyOn(mockEvent, 'preventDefault'); + $scope.dragoverHandler(mockEvent); + + expect(mockEvent.preventDefault).toHaveBeenCalled(); + }); + + it('Dragover event with !preventDefault', function() { + var mockEvent= { + type: 'dragover', + } + $scope.dragoverHandler(mockEvent); + }); + + it('Drop event', function() { + var resource_type = 'OS::Project::ResourceType'; + hotgenGlobals.update_resource_icons(resource_type, { + 'code': '', 'color': '#000' + }) + var mockEvent = { + type: 'drop', + dataTransfer: { + getData: function(key){return resource_type}, + }, + target: {id: 'icon-1'}, + preventDefault: function(){}, + }; + $scope.dropHandler(mockEvent); + }); + + }); + +})(); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/globals.service.spec.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/globals.service.spec.js new file mode 100644 index 00000000..4205d1e9 --- /dev/null +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/globals.service.spec.js @@ -0,0 +1,126 @@ +(function() { + 'use strict'; + + describe('hotgen-utils.hotgenGlobals', function(){ + beforeEach(module('hotgen-utils')); + + var hotgenGlobals; + + beforeEach(inject(function(_hotgenGlobals_){ + hotgenGlobals = _hotgenGlobals_; + })); + + it('should exist', function(){ + expect(hotgenGlobals).toBeDefined(); + }); + + it('check get_element', function(){ + var returnValue = hotgenGlobals.get_element('resource_icons'); + + expect(Object.keys(returnValue).length).toEqual(0); + }); + + it('check node_labels', function(){ + var returnValue = hotgenGlobals.get_node_labels(); + + expect(Object.keys(returnValue).length).toEqual(0); + + hotgenGlobals.update_node_labels('key1', 'label1') + + expect(Object.keys(returnValue).length).toEqual(1); + }); + + it('check node_admin', function(){ + var returnValue = hotgenGlobals.get_node_admin(); + + expect(Object.keys(returnValue).length).toEqual(0); + + hotgenGlobals.update_node_admin('key1', 'admin'); + + expect(Object.keys(returnValue).length).toEqual(1); + }); + + it('check resource_icons', function(){ + var returnValue = hotgenGlobals.get_resource_icons(); + + expect(Object.keys(returnValue).length).toEqual(0); + + hotgenGlobals.update_resource_icons('key1', 'admin'); + + expect(Object.keys(returnValue).length).toEqual(1); + }); + + it('check get_resource_components', function(){ + var returnValue = hotgenGlobals.get_resource_components(); + + expect(Object.keys(returnValue).length).toEqual(0); + + hotgenGlobals.update_resource_components('key1', 'component'); + + expect(Object.keys(returnValue).length).toEqual(1); + }); + + it('check get_edge_directions', function(){ + var returnValue = hotgenGlobals.get_edge_directions(); + + expect(Object.keys(returnValue).length).toEqual(0); + + hotgenGlobals.update_edge_directions('key1', 'edge'); + + expect(Object.keys(returnValue).length).toEqual(1); + }); + + it('check get_template_version', function(){ + var returnValue = hotgenGlobals.get_template_version(); + + expect(returnValue).toEqual(null); + + hotgenGlobals.set_template_version(['v1', 'v2']); + + expect(hotgenGlobals.get_template_version().length).toEqual(2); + }); + + it('check get_necessary_properties', function(){ + var returnValue = hotgenGlobals.get_necessary_properties(); + + expect(Object.keys(returnValue).length).toEqual(0); + + hotgenGlobals.update_necessary_properties('key1', ['p1', 'p2']); + + expect(hotgenGlobals.get_necessary_properties()['key1'].length).toEqual(2); + }); + + it('check get_resource_types', function(){ + var returnValue = hotgenGlobals.get_resource_types(); + + expect(Object.keys(returnValue).length).toEqual(0); + }); + + it('check get_resource_options', function(){ + var returnValue = hotgenGlobals.get_resource_options(); + + expect(Object.keys(returnValue).length).toEqual(1); + + hotgenGlobals.update_resource_options(['op1', 'op2']); + + expect(Object.keys(returnValue).length).toEqual(3); + }); + + it('check get_resource_outputs', function(){ + hotgenGlobals.set_resource_outputs('key1', ''); + var returnValue = hotgenGlobals.get_resource_outputs('key1'); + + expect(returnValue).toEqual(''); + }); + + it('check get_reference_file', function(){ + hotgenGlobals.set_reference_file('key1', ''); + var returnValue = hotgenGlobals.get_reference_file('key1'); + + expect(returnValue).toEqual(''); + }); + + }); + + +})(); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/icons.controller.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/icons.controller.js index dd7302e1..0314b3f2 100644 --- a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/icons.controller.js +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/icons.controller.js @@ -2,7 +2,7 @@ 'use strict'; angular.module('horizon.dashboard.project.heat_dashboard.template_generator') - .controller('horizon.dashboard.project.heat_dashboard.template_generator.IconCtrl', ['$scope', 'hotgenGlobals', + .controller('horizon.dashboard.project.heat_dashboard.template_generator.IconController', ['$scope', 'hotgenGlobals', 'horizon.dashboard.project.heat_dashboard.template_generator.basePath', function($scope, hotgenGlobals, basePath){ $scope.resource_types = hotgenGlobals.get_resource_icons(); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/icons.controller.spec.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/icons.controller.spec.js new file mode 100644 index 00000000..7f1acef7 --- /dev/null +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/icons.controller.spec.js @@ -0,0 +1,38 @@ +(function() { + 'use strict'; + + describe('horizon.dashboard.project.heat_dashboard.template_generator.IconController', function(){ + + beforeEach(module('horizon.dashboard.project.heat_dashboard.template_generator')); + + var $controller, controller, $scope, hotgenGlobals; + + beforeEach(inject(function($injector){ + hotgenGlobals = $injector.get('hotgenGlobals'); + })); + + beforeEach(inject(function(_$controller_, $rootScope) { + $controller = _$controller_; + $scope = $rootScope.$new(); + controller = $controller('horizon.dashboard.project.heat_dashboard.template_generator.IconController', { $scope: $scope,}); + })); + + it('should exist', function(){ + expect(controller).toBeDefined(); + }); + + it('check scope parameters', inject([ '$window', function($window){ + var icons_number = Object.keys(hotgenGlobals.get_resource_icons()).length; + + expect(Object.keys($scope.resource_types).length).toEqual(icons_number); + + var admin_number = Object.keys(hotgenGlobals.get_node_admin()).length; + + expect(Object.keys($scope.resource_admin).length).toEqual(admin_number); + expect($scope.admin).toEqual(false); + expect($scope.basePath).toBe($window.STATIC_URL + 'dashboard/project/heat_dashboard/template_generator/'); + + }])); + }); + +})(); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/loading.controller.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/loading.controller.js index 218e7d1e..9d3bda03 100644 --- a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/loading.controller.js +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/loading.controller.js @@ -4,7 +4,7 @@ angular .module('horizon.dashboard.project.heat_dashboard.template_generator') - .controller('horizon.dashboard.project.heat_dashboard.template_generator.LoadingCtrl', [ + .controller('horizon.dashboard.project.heat_dashboard.template_generator.LoadingController', [ '$scope', 'hotgenNotify', 'horizon.dashboard.project.heat_dashboard.template_generator.basePath', function($scope, hotgenNotify, basePath){ @@ -17,4 +17,4 @@ }]) -})(); \ No newline at end of file +})(); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/loading.controller.spec.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/loading.controller.spec.js new file mode 100644 index 00000000..0ad73ec9 --- /dev/null +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/loading.controller.spec.js @@ -0,0 +1,36 @@ +(function() { + 'use strict'; + describe('LoadingController', function(){ + beforeEach(module('horizon.dashboard.project.heat_dashboard.template_generator')); + + var $controller, controller, $scope, $rootScope; + + beforeEach(inject(function(_$controller_, $rootScope) { + $controller = _$controller_; + $scope = $rootScope.$new(); + controller = $controller('horizon.dashboard.project.heat_dashboard.template_generator.LoadingController', { $scope: $scope,}); + })); + + beforeEach(inject(function(_$rootScope_) { + $rootScope = _$rootScope_; + })); + + it('should exist', function(){ + expect(controller).toBeDefined(); + }); + + it('loading is false by default', function(){ + expect($scope.loading).toEqual(true); + }); + + it('loading is true after message received', function(){ + $rootScope.$broadcast('handle_resources_loaded'); + + expect($scope.loading).toEqual(false); + + }); + + }); + + +})(); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/menu.controller.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/menu.controller.js index 3b31ecb7..88d72ee7 100644 --- a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/menu.controller.js +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/menu.controller.js @@ -4,13 +4,15 @@ angular .module('horizon.dashboard.project.heat_dashboard.template_generator') - .controller('horizon.dashboard.project.heat_dashboard.template_generator.DraftMenuCtrl', ['$scope', - '$mdDialog', 'hotgenStates', 'hotgenNotify', 'hotgenMessage', + .controller('horizon.dashboard.project.heat_dashboard.template_generator.DraftMenuController', ['$scope', + '$mdDialog', 'hotgenStates', 'hotgenGlobals', 'hotgenNotify', 'hotgenMessage', 'horizon.dashboard.project.heat_dashboard.template_generator.basePath', - function($scope, $mdDialog, hotgenStates, hotgenNotify, hotgenMessage, basePath){ + function($scope, $mdDialog, hotgenStates, hotgenGlobals, hotgenNotify, hotgenMessage, basePath){ $scope.basePath = basePath; - $scope.openMenu = function($mdOpenMenu, ev){ - $mdOpenMenu(ev); + var originatorEv; + $scope.openMenu = function($mdMenu, ev){ + originatorEv = ev; + $mdMenu.open(ev); }; $scope.data = { nodes: hotgenStates.get_nodes(), @@ -33,7 +35,8 @@ saved_depends_ons: hotgenStates.get_saved_dependsons(), is_saved: hotgenStates.get_saved_flags(), incremented_labels: hotgenStates.get_incremented_labels(), - counter: hotgenStates.get_counters() + counter: hotgenStates.get_counters(), + template_version: hotgenGlobals.get_template_version(), } var today = new Date(); @@ -55,7 +58,7 @@ }]); angular.module('horizon.dashboard.project.heat_dashboard.template_generator') - .controller('horizon.dashboard.project.heat_dashboard.template_generator.ClearCanvasCtrl', ['$scope', + .controller('horizon.dashboard.project.heat_dashboard.template_generator.ClearCanvasController', ['$scope', 'hotgenStates', 'hotgenNotify', 'horizon.dashboard.project.heat_dashboard.template_generator.basePath', function($scope, hotgenStates, hotgenNotify, basePath){ @@ -74,4 +77,4 @@ }]); -})(); \ No newline at end of file +})(); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/menu.controller.spec.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/menu.controller.spec.js new file mode 100644 index 00000000..06f0e8f5 --- /dev/null +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/menu.controller.spec.js @@ -0,0 +1,135 @@ +(function() { + 'use strict'; + + describe('horizon.dashboard.project.heat_dashboard.template_generator.DraftMenuController', function(){ + + beforeEach(module('horizon.dashboard.project.heat_dashboard.template_generator')); + + var $controller, controller, $scope, $rootScope, $mdMenu; + + beforeEach(inject(function($injector){ + $rootScope = $injector.get('$rootScope'); + $mdMenu = $injector.get('$mdMenu'); + spyOn($rootScope, '$broadcast'); + $mdMenu.open = jasmine.createSpy().and.callFake(function() { + return function (callBack) { + callBack(true); //return the value to be assigned. + } + }); + })); + + beforeEach(inject(function(_$controller_, $rootScope) { + $controller = _$controller_; + $scope = $rootScope.$new(); + controller = $controller('horizon.dashboard.project.heat_dashboard.template_generator.DraftMenuController', { $scope: $scope,}); + })); + + afterEach(function() { + localStorage.clear(); + }); + + + it('DraftMenuController should exist', function(){ + expect(controller).toBeDefined(); + }); + + it('DraftMenuController basePath', inject([ '$window', function($window){ + expect($scope.basePath).toBe($window.STATIC_URL + 'dashboard/project/heat_dashboard/template_generator/'); + }])); + + it('scope.openMenu ', function(){ + $scope.openMenu($mdMenu, {}); + + expect($mdMenu.open).toHaveBeenCalled(); + }); + + it('DraftMenuController scope.data contains nodes and edges', function(){ + expect($scope.data.nodes.length).toEqual(0); + expect($scope.data.edges.length).toEqual(0); + }); + + it('scope.save_draft stores in localStorage', function(){ + expect(localStorage.length).toEqual(0); + + $scope.save_draft(); + + expect(localStorage.length).toEqual(0); + + $scope.data.nodes.add({'id': 'some-id'}); + $scope.save_draft(); + + expect(localStorage.length).toEqual(2); + + $scope.data.nodes.add({'id': 'some-id-2'}); + $scope.save_draft(); + + expect(localStorage.length).toEqual(3); + + }); + + it('scope.load_draft', function(){ + $scope.load_draft(); + + expect($rootScope.$broadcast).toHaveBeenCalledWith('handle_load_draft'); + }); + + it('scope.import_draft', function(){ + $scope.import_draft(); + }); + + it('scope.export_draft', function(){ + $scope.export_draft(); + }); + }); + + describe('horizon.dashboard.project.heat_dashboard.template_generator.ClearCanvasController', function(){ + beforeEach(module('horizon.dashboard.project.heat_dashboard.template_generator')); + + var $controller, controller, $scope, $rootScope; + + beforeEach(inject(function($injector){ + $rootScope = $injector.get('$rootScope'); + spyOn($rootScope, '$broadcast'); + })); + + beforeEach(inject(function(_$controller_, $rootScope) { + $controller = _$controller_; + $scope = $rootScope.$new(); + controller = $controller('horizon.dashboard.project.heat_dashboard.template_generator.ClearCanvasController', { $scope: $scope,}); + })); + + afterEach(function() { + localStorage.clear(); + }); + + + it('ClearCanvasController should exist', function(){ + expect(controller).toBeDefined(); + }); + + it('ClearCanvasController basePath', inject([ '$window', function($window){ + expect($scope.basePath).toBe($window.STATIC_URL + 'dashboard/project/heat_dashboard/template_generator/'); + }])); + + it('ClearCanvasController scope.data contains nodes and edges', function(){ + expect($scope.data.nodes.length).toEqual(0); + expect($scope.data.edges.length).toEqual(0); + }); + + it('scope.clear_canvas should empty $scope.data', function(){ + + $scope.data.nodes.add({'id': 'some-node-id'}); + $scope.data.edges.add({'id': 'some-edge-id'}); + + expect($scope.data.nodes.length).toEqual(1); + expect($scope.data.edges.length).toEqual(1); + + $scope.clear_canvas(); + + expect($scope.data.nodes.length).toEqual(0); + expect($scope.data.edges.length).toEqual(0); + }); + }); + + +})(); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/modal-draft.controller.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/modal-draft.controller.js index 02d873d9..4c7b4a21 100644 --- a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/modal-draft.controller.js +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/modal-draft.controller.js @@ -2,23 +2,11 @@ 'use strict'; angular.module('horizon.dashboard.project.heat_dashboard.template_generator') - .controller('horizon.dashboard.project.heat_dashboard.template_generator.DraftModalCtrl', ['$scope', - '$mdDialog', 'hotgenNotify', 'hotgenMessage', 'hotgenStates', + .controller('horizon.dashboard.project.heat_dashboard.template_generator.DraftModalController', ['$scope', + '$mdDialog', 'hotgenNotify', 'hotgenMessage', 'hotgenStates', 'hotgenGlobals', 'horizon.dashboard.project.heat_dashboard.template_generator.basePath', - function($scope, $mdDialog, hotgenNotify, hotgenMessage, hotgenStates, basePath){ - $scope.showDialog = function(){ - $mdDialog.show({ - controller: DraftDialogController, - templateUrl: basePath + 'templates/modal_draft.html', - parent: angular.element(document.body), - clickOutsideToClose:true - }).then(function(){ - hotgenNotify.show_success('The draft is loaded successfully.'); - }, function(){ -// hotgenNotify.show_error('dismiss a modal'); - }); - DraftDialogController.$inject = ['$scope', '$mdDialog', 'hotgenStates']; - function DraftDialogController($scope, $mdDialog, hotgenStates) { + function($scope, $mdDialog, hotgenNotify, hotgenMessage, hotgenStates, hotgenGlobals, basePath){ + $scope.draftDialogController = function ($scope, $mdDialog, hotgenStates) { $scope.draft_list = []; $scope.latest_draft = JSON.parse(localStorage.getItem('draft_'+localStorage.saved_counter)); for (var i = 0 ; i < 10; i++){ @@ -46,16 +34,31 @@ hotgenStates.set_saved_flags(draft.is_saved); hotgenStates.set_counters(draft.counter); hotgenStates.set_incremented_labels(draft.incremented_labels); + hotgenGlobals.set_template_version(draft.template_version); + hotgenMessage.broadcast_update_template_version(); }; $scope.cancel = function() { $mdDialog.cancel(); }; - } - } - $scope.$on('handle_load_draft', function(event, args){ - $scope.showDialog(); - }); + }; + $scope.showDialog = function(){ + $scope.draftDialogController.$inject = ['$scope', '$mdDialog', 'hotgenStates']; + $mdDialog.show({ + controller: $scope.draftDialogController, + templateUrl: basePath + 'templates/modal_draft.html', + parent: angular.element(document.body), + clickOutsideToClose:true + }).then(function(){ + hotgenNotify.show_success('The draft is loaded successfully.'); + }, function(){ +// hotgenNotify.show_error('dismiss a modal'); + }); + } + $scope.handle_load_draft = function(event, args){ + $scope.showDialog(); + } + $scope.$on('handle_load_draft', $scope.handle_load_draft); }]); -})(); \ No newline at end of file +})(); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/modal-draft.controller.spec.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/modal-draft.controller.spec.js new file mode 100644 index 00000000..19550a60 --- /dev/null +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/modal-draft.controller.spec.js @@ -0,0 +1,94 @@ +(function() { + 'use strict'; + + describe('horizon.dashboard.project.heat_dashboard.template_generator.DraftModalController', function(){ + + beforeEach(module('horizon.dashboard.project.heat_dashboard.template_generator')); + + beforeEach(module('appTemplates')); + + beforeEach(module('hotgen-utils')); + + var hotgenStates; + + beforeEach(inject(function(_hotgenStates_){ + hotgenStates = _hotgenStates_; + })); + + var $controller, controller, $scope, $rootScope, $mdDialog; + + beforeEach(inject(function($injector){ + $rootScope = $injector.get('$rootScope'); + $mdDialog = $injector.get('$mdDialog'); + })); + + + beforeEach(inject(function(_$controller_, $rootScope) { + $controller = _$controller_; + $scope = $rootScope.$new(); + spyOn($scope, '$on'); + spyOn($mdDialog, 'show'); + controller = $controller('horizon.dashboard.project.heat_dashboard.template_generator.DraftModalController', + { $scope: $scope, $mdDialog: $mdDialog}); + + $mdDialog.show = jasmine.createSpy().and.callFake(function() { + return { + then: (function (callBack) { + callBack(true); //return the value to be assigned. + }, function(callBack){ + callBack(false)} + ) + } + }); + })); + + afterEach(function(){ + localStorage.clear(); + $mdDialog.cancel(); + }) + + it('should exist', function(){ + expect(controller).toBeDefined(); + }); + + it('$scope.$on should be called', function(){ + var event = $rootScope.$broadcast('handle_load_draft'); + + expect($scope.$on).toHaveBeenCalled(); + + $scope.handle_load_draft(event, {}); + }); + + it('show dialog', function(){ + $scope.showDialog(); + $scope.$digest(); + + expect($mdDialog.show).toHaveBeenCalled(); + }); + + + it('draftDialogController', function(){ + var draft = {} + localStorage.setItem('draft_1', JSON.stringify(draft)) + $scope.draftDialogController($scope, $mdDialog, hotgenStates); + + expect($scope.data.nodes.length).toEqual(0); + + }); + + it('draftDialogController load draft', function(){ + var draft = {'nodes': {'node-1':{}}, 'edges': {'edge-1':{}}}; + $scope.draftDialogController($scope, $mdDialog, hotgenStates); + $scope.load(draft); + + expect($scope.data.nodes.length).toEqual(1); + expect($scope.data.edges.length).toEqual(1); + }); + + it('draftDialogController cancel', function(){ + $scope.draftDialogController($scope, $mdDialog, hotgenStates); + $scope.cancel(); + }); + }); + +})(); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/modal-edge.controller.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/modal-edge.controller.js index 4b9ab83a..a5671511 100644 --- a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/modal-edge.controller.js +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/modal-edge.controller.js @@ -2,59 +2,59 @@ 'use strict'; angular.module('horizon.dashboard.project.heat_dashboard.template_generator') - .controller('horizon.dashboard.project.heat_dashboard.template_generator.EdgeFormModalCtrl', ['$scope', + .controller('horizon.dashboard.project.heat_dashboard.template_generator.EdgeFormModalController', ['$scope', '$mdDialog', 'hotgenNotify', 'hotgenMessage', 'hotgenGlobals', 'hotgenStates', 'horizon.dashboard.project.heat_dashboard.template_generator.basePath', function($scope, $mdDialog, hotgenNotify, hotgenMessage, hotgenGlobals, hotgenStates, basePath){ - $scope.showTabDialog = function(){ - $mdDialog.show({ - controller: EdgeDialogController, - controllerAs: 'ctrl', - templateUrl: basePath+'templates/modal_edge.html', - parent: angular.element(document.body), - clickOutsideToClose:true - }).then(function(){ -// hotgenNotify.show_success('close the modal'); - }, function(){ -// hotgenNotify.show_error('dismiss a modal'); - }); - EdgeDialogController.$inject = ['$scope', '$mdDialog', 'hotgenStates']; - function EdgeDialogController($scope, $mdDialog, hotgenStates,) { - $scope.is_depends = false; - $scope.delete_resource = function() { - hotgenStates.get_network().deleteSelected(); - hotgenNotify.show_success('The selected edge has been delete successfully.') - $mdDialog.cancel(); - }; - $scope.cancel = function() { - $mdDialog.cancel(); - }; - $scope.selected = hotgenStates.get_selected(); - if ($scope.selected.id in hotgenStates.get_saved_resources()){ - $scope.resource = hotgenStates.get_saved_resources()[$scope.selected.id].data; - } else{ - $scope.resource = {} - } - if ($scope.selected.edge.arrows && $scope.selected.edge.arrows.middle == true){ - $scope.is_depends = true; - } - var from_type = $scope.selected.resource_type.from; - var to_type = $scope.selected.resource_type.to; - $scope.from_type = from_type.replace(/_/g, ':'); - $scope.to_type = to_type.replace(/_/g, ':'); - $scope.from_node = { - class: hotgenGlobals.get_resource_icons()[from_type].class, - color: hotgenGlobals.get_resource_icons()[from_type].color, - id: $scope.selected.from_node.id, - } - $scope.to_node = { - class: hotgenGlobals.get_resource_icons()[to_type].class, - color: hotgenGlobals.get_resource_icons()[to_type].color, - id: $scope.selected.to_node.id, - } + $scope.edgeDialogController = function($scope, $mdDialog, hotgenStates, basePath) { + $scope.is_depends = false; + $scope.delete_resource = function() { + hotgenStates.get_network().deleteSelected(); + hotgenNotify.show_success('The selected edge has been delete successfully.') + $mdDialog.cancel(); + }; + $scope.cancel = function() { + $mdDialog.cancel(); + }; + $scope.selected = hotgenStates.get_selected(); + if ($scope.selected.id in hotgenStates.get_saved_resources()){ + $scope.resource = hotgenStates.get_saved_resources()[$scope.selected.id].data; + } else{ + $scope.resource = {} } + if ($scope.selected.edge.arrows && $scope.selected.edge.arrows.middle == true){ + $scope.is_depends = true; + } + var from_type = $scope.selected.resource_type.from; + var to_type = $scope.selected.resource_type.to; + $scope.from_type = from_type.replace(/_/g, ':'); + $scope.to_type = to_type.replace(/_/g, ':'); + $scope.from_node = { + image: basePath+'js/resources/'+from_type.toLowerCase()+'/'+from_type.toLowerCase()+'.svg', + id: $scope.selected.from_node.id, + } + $scope.to_node = { + image: basePath+'js/resources/'+to_type.toLowerCase()+'/'+to_type.toLowerCase()+'.svg', + id: $scope.selected.to_node.id, + } + } + $scope.showTabDialog = function(){ + $scope.edgeDialogController.$inject = ['$scope', '$mdDialog', 'hotgenStates', + 'horizon.dashboard.project.heat_dashboard.template_generator.basePath']; + $mdDialog.show({ + controller: $scope.edgeDialogController, + controllerAs: 'ctrl', + templateUrl: basePath+'templates/modal_edge.html', + parent: angular.element(document.body), + clickOutsideToClose:true + }).then(function(){ +// hotgenNotify.show_success('close the modal'); + }, function(){ +// hotgenNotify.show_error('dismiss a modal'); + }); }; - $scope.$on('handle_edit_edge', function(event, args){ + + $scope.handle_edit_edge = function(event, args){ /* Click a edge and decide to show modal or not */ var from_type = args.from_type; var to_type = args.to_type; @@ -64,7 +64,7 @@ var depends_ons = hotgenStates.get_saved_dependsons(); if ( !( from_type in edge_directions) || !(to_type in edge_directions[from_type])){ if (from_id in depends_ons && depends_ons[from_id] == to_id){ - ; + //; } else { hotgenNotify.show_warning('The edge might be invalid.'); @@ -72,7 +72,11 @@ } } $scope.showTabDialog(); - }); + }; + + $scope.$on('handle_edit_edge', $scope.handle_edit_edge); + + }]); -})(); \ No newline at end of file +})(); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/modal-edge.controller.spec.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/modal-edge.controller.spec.js new file mode 100644 index 00000000..84ed0277 --- /dev/null +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/modal-edge.controller.spec.js @@ -0,0 +1,196 @@ +(function() { + 'use strict'; + + describe('horizon.dashboard.project.heat_dashboard.template_generator.EdgeFormModalController', function(){ + + beforeEach(module('horizon.dashboard.project.heat_dashboard.template_generator')); + + beforeEach(module('appTemplates')); + + var hotgenGlobals, hotgenStates, basePath; + beforeEach(inject(function($injector){ + hotgenGlobals = $injector.get('hotgenGlobals'); + hotgenStates = $injector.get('hotgenStates'); + basePath = $injector.get('horizon.dashboard.project.heat_dashboard.template_generator.basePath'); + })); + + var $controller, controller, $scope, $rootScope, $mdDialog; + + beforeEach(inject(function($injector){ + $rootScope = $injector.get('$rootScope'); + $mdDialog = $injector.get('$mdDialog'); + })); + + beforeEach(inject(function(_$controller_, $rootScope) { + $controller = _$controller_; + $scope = $rootScope.$new(); + spyOn($scope, '$on'); + spyOn($mdDialog, 'show'); + spyOn($mdDialog, 'cancel'); + controller = $controller('horizon.dashboard.project.heat_dashboard.template_generator.EdgeFormModalController', + { $scope: $scope, $mdDialog: $mdDialog}); + + $mdDialog.show = jasmine.createSpy().and.callFake(function() { + return { + then: (function (callBack) { + callBack(true); //return the value to be assigned. + }, function(callBack){ + callBack(false)} + ) + } + }); + $mdDialog.cancel = jasmine.createSpy().and.callFake(function() { + return function(callBack){callBack(true)}; + }); + })); + + it('should exist', function(){ + expect(controller).toBeDefined(); + }); + + it('$scope.$on should be called', function(){ + var event = $rootScope.$broadcast('handle_edit_edge'); + + expect($scope.$on).toHaveBeenCalled(); + }); + + it('show dialog with no parameters set.', function(){ + $scope.showTabDialog(); + $scope.$digest(); + + expect($mdDialog.show).toHaveBeenCalled(); + }); + + it('handle_edit_edge valid edges', function(){ + var event = $rootScope.$broadcast('handle_edit_edge'); + hotgenGlobals.update_edge_directions('from_id', {'to_id': {}}); + hotgenStates.update_saved_dependsons('from_id', 'to_id'); + + $scope.handle_edit_edge(event, { + 'from_type': 'from_type', 'to_type': 'to_type', + 'from_id': 'from_id', 'to_id': 'to_id', + }); + + expect($mdDialog.show).toHaveBeenCalled(); + }); + + it('handle_edit_edge invalid edges #1', function(){ + var event = $rootScope.$broadcast('handle_edit_edge'); + hotgenGlobals.update_edge_directions('from_type', {'to_type': {}}) + + expect($mdDialog.show).not.toHaveBeenCalled(); + + $scope.handle_edit_edge(event, { + 'from_type': 'from_type', 'to_type': 'to_type', + 'from_id': 'from_id', 'to_id': 'to_id', + }); + }); + + it('handle_edit_edge invalid edges #2', function(){ + var event = $rootScope.$broadcast('handle_edit_edge'); + hotgenGlobals.update_edge_directions('from_id', {'to': {}}) + + $scope.handle_edit_edge(event, { + 'from_type': 'from_type', 'to_type': 'to_type', + 'from_id': 'from_id', 'to_id': 'to_id', + }); + + expect($mdDialog.show).not.toHaveBeenCalled(); + }); + + it('cancel dialog', function(){ + hotgenStates.set_selected({ + id: 'edge-id', + edge: {arrows: {middle: true}}, + resource_type: {from: 'from_type', to: 'to_type'}, + from_node: {id: 'from_id'}, + to_node: {id: 'to_id'} + }); + hotgenStates.set_saved_resources({ + 'edge-id': {data: {'resource property': 'something'}} + }); + $scope.edgeDialogController($scope, $mdDialog, hotgenStates, basePath); + $scope.cancel(); + + expect($mdDialog.cancel).toHaveBeenCalled(); + + }); + + it('delete resource dialog', function(){ + hotgenStates.set_selected({ + id: 'edge-id', + edge: {arrows: {middle: true}}, + resource_type: {from: 'from_type', to: 'to_type'}, + from_node: {id: 'from_id'}, + to_node: {id: 'to_id'} + }); + hotgenStates.set_saved_resources({ + 'edge-id': {data: {'resource property': 'something'}} + }); + hotgenStates.set_network({ + deleteSelected: function(){} + }); + $scope.edgeDialogController($scope, $mdDialog, hotgenStates, basePath); + $scope.delete_resource(); + + expect($mdDialog.cancel).toHaveBeenCalled(); + + }); + + it('handle_edit_edge test depends on edge.', function(){ + hotgenStates.set_selected({ + id: 'edge-id', + edge: {arrows: {middle: true}}, + resource_type: {from: 'from_type', to: 'to_type'}, + from_node: {id: 'from_id'}, + to_node: {id: 'to_id'} + }); + hotgenStates.set_saved_resources({ + 'edge-id': {data: {'resource property': 'something'}} + }); + $scope.edgeDialogController($scope, $mdDialog, hotgenStates, basePath); + + expect($scope.is_depends).toEqual(true); + expect(Object.keys($scope.resource).length).toEqual(1); + expect($scope.from_node.image).toEqual(basePath+'js/resources/from_type/from_type.svg') + }); + + it('handle_edit_edge test properties edge.', function(){ + hotgenStates.set_selected({ + id: 'edge-id', + edge: {}, + resource_type: {from: 'from_type', to: 'to_type'}, + from_node: {id: 'from_id'}, + to_node: {id: 'to_id'} + }); + hotgenStates.set_saved_resources({ + 'edge-id': { + data: {'resource property': 'something'} + } + }) + $scope.edgeDialogController($scope, $mdDialog, hotgenStates, basePath); + + expect($scope.is_depends).toEqual(false); + expect(Object.keys($scope.resource).length).toEqual(1); + }); + + it('handle_edit_edge test not saved edge.', function (){ + hotgenStates.set_selected({ + id: 'edge-id', + edge: {}, + resource_type: {from: 'from_type', to: 'to_type'}, + from_node: {id: 'from_id'}, + to_node: {id: 'to_id'} + }); + hotgenStates.set_saved_resources({ + 'node-id': { + data: {'resource property': 'something'} + } + }) + $scope.edgeDialogController($scope, $mdDialog, hotgenStates, basePath); + + expect(Object.keys($scope.resource).length).toEqual(0) + }); + }); + +})(); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/modal-node.controller.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/modal-node.controller.js index 67d6385f..6d41a416 100644 --- a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/modal-node.controller.js +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/modal-node.controller.js @@ -2,16 +2,155 @@ 'use strict'; angular.module('horizon.dashboard.project.heat_dashboard.template_generator') - .controller('horizon.dashboard.project.heat_dashboard.template_generator.FormModalCtrl', ['$scope', '$compile', + .controller('horizon.dashboard.project.heat_dashboard.template_generator.FormModalController', ['$scope', '$compile', '$mdDialog', 'hotgenNotify', 'hotgenMessage', 'hotgenGlobals', 'hotgenUtils', 'hotgenStates', 'horizon.dashboard.project.heat_dashboard.template_generator.basePath', function($scope, $compile, $mdDialog, hotgenNotify, hotgenMessage, hotgenGlobals, hotgenUtils, hotgenStates, basePath){ $scope.selected = hotgenStates.get_selected(); + $scope.data = { + nodes: hotgenStates.get_nodes(), + edges: hotgenStates.get_edges(), + }; + $scope.dialogController = function ($scope, $mdDialog, hotgenStates) { + $scope.delete_resource = function() { + var label = hotgenStates.get_selected().node.label; + hotgenStates.get_network().deleteSelected(); + hotgenNotify.show_success(label + ' has been delete successfully.') + $mdDialog.cancel(); + }; + $scope.cancel = function() { + $mdDialog.cancel(); + }; + $scope.selected = hotgenStates.get_selected(); + $scope.data = { + nodes: hotgenStates.get_nodes(), + edges: hotgenStates.get_edges(), + }; + + $scope.save = function() { + $mdDialog.hide(); + hotgenStates.update_saved_resources($scope.selected.id, { + type: $scope.selected.resource_type, + data: angular.copy($scope.resource) + }); + hotgenStates.update_saved_dependsons($scope.selected.id, $scope.dependson); + + var label = hotgenStates.get_label_by_uuid($scope.selected.node.id); + var prop_label = $scope.get_label($scope.selected.resource_type); + if (prop_label && $scope.resource[prop_label]){ + label = label + '(' + $scope.resource[prop_label]+')'; + } + var new_node_image = $scope.data.nodes.get($scope.selected.id).image.replace('-gray.svg', '-blue.svg'); + var shape = $scope.selected.node.shape; + var color = "#3f51b5" + if (shape === 'icon'){ + color = $scope.selected.node.icon.color; + } + + $scope.data.nodes.update({ + id: $scope.selected.id, + label: label, + font: { color: color}, + image: new_node_image, + }) + // Mark the node is saved. + hotgenStates.update_saved_flags($scope.selected.id, true); + + // Update depends on edges + + var related_edges = hotgenStates.get_network().getConnectedEdges($scope.selected.id); + for ( var idx in related_edges){ + var edge = $scope.data.edges.get(related_edges[idx]); + if (edge.from == $scope.selected.id && edge.arrows && edge.arrows.middle == true){ + $scope.data.edges.remove(edge.id); + } + } + for (var idx in $scope.dependson){ + $scope.data.edges.add({ + from: $scope.selected.id, + to: $scope.dependson[idx], + arrows: {middle:true}, + dashes: false, + color: '#448AFF', + }); + } + + // Mark edges connected from the node are saved and update style. + for (var idx in $scope.connectedoptions){ + var connected_option = $scope.connectedoptions[idx]; + for (var idx_edge in connected_option){ + hotgenStates.update_saved_flags(connected_option[idx_edge].edge.id, true); + var color = "#3f51b5"; + $scope.data.edges.update({ + id: connected_option[idx_edge].edge.id, + dashes: false, + color: color, + }) + } + } + return true; + }; + + $scope.resource_type = $scope.selected.resource_type.replace(/_/g, ':'); + + if ($scope.selected.id in hotgenStates.get_saved_resources()){ + $scope.resource = hotgenStates.get_saved_resources()[$scope.selected.id].data; + } else{ + $scope.resource = {} + } + if ($scope.selected.id in hotgenStates.get_saved_dependsons()){ + $scope.dependson = hotgenStates.get_saved_dependsons()[$scope.selected.id]; + } else{ + $scope.dependson = [] + } + // Add connected edge resource + $scope.get_connected_options = function(){ + var related_edges = hotgenStates.get_network().getConnectedEdges($scope.selected.id); + var connected_options = {}; + for (var idx in related_edges){ + var edge = $scope.data.edges.get(related_edges[idx]); + if (edge.from != $scope.selected.id || (edge.arrows && edge.arrows.middle == true)){ + continue; + } + var node = $scope.data.nodes.get(edge.to); + var edge_directions = hotgenGlobals.get_edge_directions(); + if (! ($scope.selected.resource_type in edge_directions)){ + continue; + } + var mapping = edge_directions[$scope.selected.resource_type]; + if (!(node.title in mapping)){ + continue; + } + var property = mapping[node.title].property; + if (!(property in connected_options)){ + connected_options[property] = []; + } + connected_options[property].push({ + value: hotgenUtils.get_resource_string(hotgenStates.get_label_by_uuid(node.id)), + id: node.id, + resource_type: node.title, + edge: edge + }); + + } + return connected_options; + } + $scope.connectedoptions = $scope.get_connected_options(); + $scope.component = hotgenGlobals.get_resource_components()[$scope.selected.resource_type]; + + $scope.get_label = function(node_type){ + return hotgenGlobals.get_node_labels()[node_type]; + } + + } + $scope.showTabDialog = function(){ + $scope.dialogController.$inject = ['$scope', '$mdDialog', 'hotgenStates']; + $mdDialog.show({ - controller: DialogController, + controller: $scope.dialogController, controllerAs: 'ctrl', templateUrl: basePath+'templates/modal_resource.html', parent: angular.element(document.body), @@ -21,146 +160,13 @@ }, function(){ // hotgenNotify.show_error('dismiss a modal'); }); - DialogController.$inject = ['$scope', '$mdDialog', 'hotgenStates']; - function DialogController($scope, $mdDialog, hotgenStates) { - $scope.delete_resource = function() { - var label = hotgenStates.get_selected().node.label; - hotgenStates.get_network().deleteSelected(); - hotgenNotify.show_success(label + ' has been delete successfully.') - $mdDialog.cancel(); - }; - $scope.cancel = function() { - $mdDialog.cancel(); - }; - $scope.selected = hotgenStates.get_selected(); - - $scope.data = { - nodes: hotgenStates.get_nodes(), - edges: hotgenStates.get_edges(), - }; - - $scope.save = function() { - $mdDialog.hide(); - hotgenStates.update_saved_resources($scope.selected.id, { - type: $scope.selected.resource_type, - data: angular.copy($scope.resource) - }); - hotgenStates.update_saved_dependsons($scope.selected.id, $scope.dependson); - - var label = hotgenStates.get_label_by_uuid($scope.selected.node.id); - var prop_label = $scope.get_label($scope.selected.resource_type); - - if (prop_label && $scope.resource[prop_label]){ - label = label + '(' + $scope.resource[prop_label]+')'; - } - var new_node_image = $scope.data.nodes.get($scope.selected.id).image.replace('-gray.svg', '-blue.svg'); - var shape = $scope.selected.node.shape; - var color = "#3f51b5" - if (shape === 'icon'){ - color = $scope.selected.node.icon.color; - } - - $scope.data.nodes.update({ - id: $scope.selected.id, - label: label, - font: { color: color}, - image: new_node_image, - }) - // Mark the node is saved. - hotgenStates.update_saved_flags($scope.selected.id, true); - - // Update depends on edges - - var related_edges = hotgenStates.get_network().getConnectedEdges($scope.selected.id); - for ( var idx in related_edges){ - var edge = $scope.data.edges.get(related_edges[idx]); - if (edge.from == $scope.selected.id && edge.arrows && edge.arrows.middle == true){ - $scope.data.edges.remove(edge.id); - } - } - for (var idx in $scope.dependson){ - $scope.data.edges.add({ - from: $scope.selected.id, - to: $scope.dependson[idx], - arrows: {middle:true}, - dashes: false, - color: '#448AFF', - }); - } - - // Mark edges connected from the node are saved and update style. - for (var idx in $scope.connectedoptions){ - var connected_option = $scope.connectedoptions[idx]; - for (var idx_edge in connected_option){ - hotgenStates.update_saved_flags(connected_option[idx_edge].edge.id, true); - var color = "#3f51b5"; - $scope.data.edges.update({ - id: connected_option[idx_edge].edge.id, - dashes: false, - color: color, - }) - } - } - - }; - - $scope.resource_type = $scope.selected.resource_type.replace(/_/g, ':'); - - if ($scope.selected.id in hotgenStates.get_saved_resources()){ - $scope.resource = hotgenStates.get_saved_resources()[$scope.selected.id].data; - } else{ - $scope.resource = {} - } - if ($scope.selected.id in hotgenStates.get_saved_dependsons()){ - $scope.dependson = hotgenStates.get_saved_dependsons()[$scope.selected.id]; - } else{ - $scope.dependson = [] - } - // Add connected edge resource - $scope.get_connected_options = function(){ - var related_edges = hotgenStates.get_network().getConnectedEdges($scope.selected.id); - var connected_options = {}; - for (var idx in related_edges){ - var edge = $scope.data.edges.get(related_edges[idx]); - if (edge.from != $scope.selected.id || (edge.arrows && edge.arrows.middle == true)){ - continue; - } - var node = $scope.data.nodes.get(edge.to); - var edge_directions = hotgenGlobals.get_edge_directions(); - if (! ($scope.selected.resource_type in edge_directions)){ - continue; - } - var mapping = edge_directions[$scope.selected.resource_type]; - if (!(node.title in mapping)){ - continue; - } - var property = mapping[node.title].property; - if (!(property in connected_options)){ - connected_options[property] = []; - } - connected_options[property].push({ - value: hotgenUtils.get_resource_string(hotgenStates.get_label_by_uuid(node.id)), - id: node.id, - resource_type: node.title, - edge: edge - }); - - } - return connected_options; - } - $scope.connectedoptions = $scope.get_connected_options() - $scope.component = hotgenGlobals.get_resource_components()[$scope.selected.resource_type]; - - $scope.get_label = function(node_type){ - return hotgenGlobals.get_node_labels()[node_type]; - } - - } }; - $scope.$on('handle_edit_node', function(event, args){ + $scope.handle_edit_node = function(event, args){ hotgenNotify.show_info('Show details of resource ' + args.replace(/_/g, ':') +'.'); $scope.showTabDialog(); - }); + } + $scope.$on('handle_edit_node', $scope.handle_edit_node); }]); -})(); \ No newline at end of file +})(); + diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/modal-node.controller.spec.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/modal-node.controller.spec.js new file mode 100644 index 00000000..0b9c00ca --- /dev/null +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/modal-node.controller.spec.js @@ -0,0 +1,278 @@ +(function() { + 'use strict'; + + describe('horizon.dashboard.project.heat_dashboard.template_generator.FormModalController', function(){ + + beforeEach(module('horizon.dashboard.project.heat_dashboard.template_generator')); + + beforeEach(module('appTemplates')); + + var hotgenGlobals, hotgenStates, basePath; + beforeEach(inject(function($injector){ + hotgenGlobals = $injector.get('hotgenGlobals'); + hotgenStates = $injector.get('hotgenStates'); + basePath = $injector.get('horizon.dashboard.project.heat_dashboard.template_generator.basePath'); + })); + + var $controller, controller, $scope, $rootScope, $mdDialog; + + beforeEach(inject(function($injector){ + $rootScope = $injector.get('$rootScope'); + $mdDialog = $injector.get('$mdDialog'); + })); + + beforeEach(inject(function(_$controller_, $rootScope) { + $controller = _$controller_; + $scope = $rootScope.$new(); + spyOn($scope, '$on'); + spyOn($mdDialog, 'show'); + spyOn($mdDialog, 'hide'); + spyOn($mdDialog, 'cancel'); + controller = $controller('horizon.dashboard.project.heat_dashboard.template_generator.FormModalController', + { $scope: $scope, $mdDialog: $mdDialog}); + + $mdDialog.show = jasmine.createSpy().and.callFake(function() { + return { + then: (function (callBack) { + callBack(true); //return the value to be assigned. + }, function(callBack){ + callBack(false)} + ) + } + }); + $mdDialog.cancel = jasmine.createSpy().and.callFake(function() { + return function(callBack){callBack(true)}; + }); + })); + + it('should exist', function(){ + expect(controller).toBeDefined(); + }); + + it('$scope.$on should be called', function(){ + var event = $rootScope.$broadcast('handle_edit_node'); + + expect($scope.$on).toHaveBeenCalled(); + }); + + it('$scope.handle_edit_node', function(){ + var event = $rootScope.$broadcast('handle_edit_node'); + spyOn($scope, 'showTabDialog'); + $scope.handle_edit_node(event, 'OS__Project__ResourceType'); + + expect($scope.showTabDialog).toHaveBeenCalled(); + }); + + it('show dialog with no parameters set.', function(){ + $scope.showTabDialog(); + $scope.$digest(); + + expect($mdDialog.show).toHaveBeenCalled(); + }); + + it('cancel dialog', function(){ + var node = {id: 'node_id', label: 'Node_1', title: 'NodeType_1'} + var to_node = {id: 'to_node_id', label: 'ToNode_1', title: 'ToType_1'} + var edge1 = {id: 'edge_id_1', from: 'node_id', to: 'to_node_id'} + var edge2 = {id: 'edge_id_2', from: 'from_node_id', to: 'node_id'} + hotgenStates.set_selected({ + id: node.id, + node: node, + resource_type: node.title, + }); + var network = {getConnectedEdges: function(data){ + return [edge1.id, edge2.id]; + }} + hotgenStates.set_network(network); + $scope.data.nodes.add(node); + $scope.data.edges.add(edge1); + $scope.data.edges.add(edge2); + + $scope.dialogController($scope, $mdDialog, hotgenStates); + $scope.cancel(); + + expect($mdDialog.cancel).toHaveBeenCalled(); + + }); + + it('get label', function(){ + var node = {id: 'node_id', label: 'Node_1', title: 'NodeType_1'} + var to_node = {id: 'to_node_id', label: 'ToNode_1', title: 'ToType_1'} + var edge1 = {id: 'edge_id_1', from: 'node_id', to: 'to_node_id'} + var edge2 = {id: 'edge_id_2', from: 'from_node_id', to: 'node_id'} + hotgenStates.set_selected({ + id: node.id, + node: node, + resource_type: node.title, + }); + var network = {getConnectedEdges: function(data){ + return [edge1.id, edge2.id]; + }} + hotgenStates.set_network(network); + $scope.data.nodes.add(node); + $scope.data.edges.add(edge1); + $scope.data.edges.add(edge2); + hotgenGlobals.update_node_labels(node.title, node.label) + + $scope.dialogController($scope, $mdDialog, hotgenStates); + var nodelabel = $scope.get_label('NodeType_1'); + + expect(nodelabel).toEqual(node.label); + + }); + + it('delete resource', function(){ + var node = {id: 'node_id', label: 'Node_1', title: 'NodeType_1'} + var to_node = {id: 'to_node_id', label: 'ToNode_1', title: 'ToType_1'} + var edge1 = {id: 'edge_id_1', from: 'node_id', to: 'to_node_id'} + var edge2 = {id: 'edge_id_2', from: 'from_node_id', to: 'node_id'} + hotgenStates.set_selected({ + id: node.id, + node: node, + resource_type: node.title, + }); + var network = { + deleteSelected: function(){ + return true; + }, + getConnectedEdges: function(data){ + return [edge1.id, edge2.id]; + } + }; + hotgenStates.set_network(network); + $scope.data.nodes.add(node); + $scope.data.edges.add(edge1); + $scope.data.edges.add(edge2); + + $scope.dialogController($scope, $mdDialog, hotgenStates); + $scope.delete_resource(); + + expect($mdDialog.cancel).toHaveBeenCalled(); + + }); + + it('save without depends_on', function(){ + var node = {id: 'node_id', label: 'Node_1', title: 'NodeType_1', image: 'image-gray.svg'} + hotgenStates.set_selected({ + id: 'node_id', + node: node, + resource_type: 'NodeType_1', + }); + var network = { + deleteSelected: function(){ + return true; + }, + getConnectedEdges: function(data){ + return []; + } + }; + $scope.data.nodes.add(node); + hotgenGlobals.update_node_labels(node.id, node.label); + hotgenStates.set_incremented_label(node.id, node.label); + hotgenStates.set_network(network); + $scope.dialogController($scope, $mdDialog, hotgenStates); + $scope.dependson = []; + var returnValue = $scope.save(); + + expect($mdDialog.hide).toHaveBeenCalled(); + expect(returnValue).toEqual(true); + }); + + it('save with depends_on', function(){ + var node = {id: 'node_id', label: 'Node_1', title: 'NodeType_1', icon: {color: '#000'}, + shape: 'icon', image: 'image-gray.svg'} + var depend_node = {id: 'depend_node_id', label: 'Node_2', title: 'NodeType_2'} + var connected_node = {id: 'conn_node_id', label: 'Node_3', title: 'NodeType_3'} + var connected_node2 = {id: 'conn_node2_id', label: 'Node_4', title: 'NodeType_3'} + var edge = { id: 'edge_id', from: node.id, to: connected_node.id, + resource_type: {from: node.title, to: connected_node.title}, + from_node: node, to_node: connected_node}; + var edge2 = { id: 'edge2_id', from: node.id, to: connected_node2.id, + resource_type: {from: node.title, to: connected_node2.title}, + from_node: node, to_node: connected_node2}; + var depend_edge = {id: 'depend_edge_id', from: node.id, to: depend_node.id, + resource_type: {from: node.title, to: depend_node.title}, + from_node: node, to_node: depend_node, arrows: {middle: true}}; + $scope.data.nodes.add(node); + $scope.data.nodes.add(depend_node); + $scope.data.nodes.add(connected_node); + $scope.data.nodes.add(connected_node2); + $scope.data.edges.add(edge); + $scope.data.edges.add(edge2); + $scope.data.edges.add(depend_edge); + hotgenGlobals.update_node_labels(node.title, 'name'); + hotgenGlobals.update_edge_directions(node.title, {'NodeType_3': {property: 'name'}}); + + hotgenStates.update_saved_resources(node.id, {type: node.title, data: {name: node.label}}) + hotgenStates.set_incremented_label(node.id, node.label); + hotgenStates.update_saved_dependsons(node.title, [depend_node.id]); + hotgenStates.update_saved_dependsons(node.id, [depend_node.id]); + hotgenStates.set_selected({ + id: 'node_id', + node: node, + resource_type: 'NodeType_1', + }); + var network = { + deleteSelected: function(){ + return true; + }, + getConnectedEdges: function(data){ + return [edge.id, edge2.id, depend_edge.id,]; + } + }; + hotgenStates.set_network(network); + $scope.dialogController($scope, $mdDialog, hotgenStates); + $scope.dependson = [depend_node.id]; + var returnValue = $scope.save(); + + expect($mdDialog.hide).toHaveBeenCalled(); + expect(returnValue).toEqual(true); + }); + + it('save with trivial cases', function(){ + var node = {id: 'node_id', label: 'Node_1', title: 'NodeType_1', icon: {color: '#000'}, + shape: 'icon', image: 'image-gray.svg'} + var depend_node = {id: 'depend_node_id', label: 'Node_2', title: 'NodeType_2'} + var connected_node = {id: 'conn_node_id', label: 'Node_3', title: 'NodeType_3'} + var edge = { id: 'edge_id', from: node.id, to: connected_node.id, + resource_type: {from: node.title, to: connected_node.title}, + from_node: node, to_node: connected_node}; + var depend_edge = {id: 'depend_edge_id', from: node.id, to: depend_node.id, + resource_type: {from: node.title, to: depend_node.title}, + from_node: node, to_node: depend_node, arrows: {middle: true}}; + $scope.data.nodes.add(node); + $scope.data.nodes.add(depend_node); + $scope.data.nodes.add(connected_node); + $scope.data.edges.add(edge); + $scope.data.edges.add(depend_edge); + hotgenGlobals.update_node_labels(node.title, 'name'); + hotgenGlobals.update_edge_directions(node.title, {'NodeType_2': {}}); + + hotgenStates.update_saved_resources(node.id, {type: node.title, data: {name: node.label}}) + hotgenStates.set_incremented_label(node.id, node.label); + hotgenStates.update_saved_dependsons(node.title, [depend_node.id]); + hotgenStates.update_saved_dependsons(node.id, [depend_node.id]); + hotgenStates.set_selected({ + id: node.id, + node: node, + resource_type: node.title, + }); + var network = { + deleteSelected: function(){ + return true; + }, + getConnectedEdges: function(data){ + return [edge.id, depend_edge.id]; + } + }; + hotgenStates.set_network(network); + $scope.dialogController($scope, $mdDialog, hotgenStates); + $scope.dependson = [depend_node.id]; + var returnValue = $scope.save(); + + expect($mdDialog.hide).toHaveBeenCalled(); + expect(returnValue).toEqual(true); + }); + }); + +})(); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/modal-template.controller.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/modal-template.controller.js index 852cc3f8..7d9a2389 100644 --- a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/modal-template.controller.js +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/modal-template.controller.js @@ -2,163 +2,166 @@ 'use strict'; angular.module('horizon.dashboard.project.heat_dashboard.template_generator') - .controller('horizon.dashboard.project.heat_dashboard.template_generator.TempModalCtrl', ['$scope', + .controller('horizon.dashboard.project.heat_dashboard.template_generator.TempModalController', ['$scope', '$mdDialog', 'hotgenNotify', 'hotgenUtils', 'hotgenStates', 'hotgenGlobals', 'horizon.dashboard.project.heat_dashboard.template_generator.basePath', function($scope, $mdDialog, hotgenNotify, hotgenUtils, hotgenStates, hotgenGlobals, basePath){ $scope.basePath = basePath; + $scope.dialogController = function ($scope, $mdDialog, hotgenStates, hotgenGlobals, hotgenNotify) { + $scope.all_saved = false; + $scope.cancel = function() { + $mdDialog.cancel(); + }; + $scope.download = function() { + // TODO: jump to stack creation page, or send to heat api. + // Temporarily Download + var today = new Date(); + var filename = "template-"+today.toISOString(); + var blob = new Blob([$scope.template_contents], {type: "text/plain;charset=utf-8"}); + saveAs(blob, filename+".yaml.txt"); + + hotgenNotify.show_success('Template is downloaded.'); + }; + $scope.save = function() { + hotgenNotify.show_warning('Not implemented yet. To submit to create a stack.') + $mdDialog.cancel(); + }; + + $scope.extract_properties = function(resource_data){ + for (var property in resource_data){ + var func = null; + switch (property){ + case 'description': + case 'public_key': + func = hotgenUtils.escape_characters; + break; + case 'metadata': + case 'scheduler_hints': + case 'value_specs': + func = hotgenUtils.extract_keyvalue; + break; + case 'allocation_pools': + case 'allowed_address_pairs': + case 'block_device_mapping': + case 'block_device_mapping_v2': + case 'fixed_ips': + case 'host_routes': + case 'personality': + case 'rules': + func = hotgenUtils.extract_list_of_keyvalue; + break; + case 'dns_nameservers': + case 'dhcp_agent_ids': + case 'tags': + func = hotgenUtils.extract_list; + break; + case 'resource_def': + func = hotgenUtils.extract_resource_def; + break; + default: + break; + } + if ( func != null){ + resource_data[property] = func(resource_data[property]); + } + hotgenUtils.strip_property(resource_data, property); + + } + return resource_data; + } + $scope.warning = "Warning: Some resources remain unsaved." + + $scope.generate = function(){ + // Generate `resources` & `outputs` section + var resource_root = {}; + var outputs_root = {}; + + if( hotgenStates.get_saved_flags_length() == 0 || hotgenStates.get_saved_resources_length() == 0){ + $scope.all_saved = false; + $scope.warning = "Warning: Cannot generate, no resource has been saved."; + return ''; + } + $scope.all_saved = hotgenStates.is_all_saved(); + $scope.saved_resources = hotgenStates.get_saved_resources(); + $scope.data = { + nodes: hotgenStates.get_nodes(), + } + var depends_ons = hotgenStates.get_saved_dependsons(); + + for (var idkey in $scope.saved_resources){ + + // Generate `resources` section + var resource_type = $scope.saved_resources[idkey].type; + var resource_name = hotgenStates.get_label_by_uuid(idkey); + var copy_data = angular.copy($scope.saved_resources[idkey].data) + var properties = $scope.extract_properties(copy_data); + resource_root[resource_name] = { + type: resource_type.replace(/_/g, ':'), + }; + if (Object.keys(properties).length > 0){ + resource_root[resource_name]["properties"] = properties; + } + if (idkey in depends_ons){ + var depends_ids = angular.copy(depends_ons[idkey]); + if (depends_ons[idkey].length > 0){ + resource_root[resource_name]['depends_on'] = []; + for (var idx in depends_ids){ + resource_root[resource_name]['depends_on'].push(hotgenStates.get_label_by_uuid(depends_ids[idx])); + } + } + } + + // Generate `outputs` section + var output_detail = hotgenGlobals.get_resource_outputs(resource_type); + for (var idx in output_detail){ + var output_key = resource_name + '_' + output_detail[idx].property; + outputs_root[output_key] = { + description: 'The ' + output_detail[idx].property + ' of ' + resource_name +'.', + value: '{ get_attr: ['+resource_name+', '+output_detail[idx].property+'] }', + }; + } + + } + + var today = new Date(); + var template_version = hotgenGlobals.get_template_version().split('.')[1] + var template_root = { + heat_template_version: template_version, + description: 'version 2017-09-01 created by HOT Generator at '+ today.toUTCString() + '.', + resources: resource_root, + } + if (Object.keys(outputs_root).length > 0){ + template_root['outputs'] = outputs_root + } + var json_string = JSON.stringify(template_root); + return json2yaml(json_string); + } + + $scope.template_contents = $scope.generate(); + + $scope.template = { + title: 'Template', + content: $scope.template_contents, + }; + } $scope.open = function(){ if (hotgenGlobals.get_template_version() == null){ hotgenNotify.show_error('Please select template version at first.'); return; } + $scope.dialogController.$inject = ['$scope', '$mdDialog', 'hotgenStates', 'hotgenGlobals', 'hotgenNotify']; $mdDialog.show({ parent: angular.element(document.body), clickOutsideToClose:true, templateUrl: basePath+'templates/modal_template.html', - controller: DialogController, + controller: $scope.dialogController, }).then(function(){ - ; +// ; }, function(){ - ; +// ; }); }; - DialogController.$inject = ['$scope', '$mdDialog', 'hotgenStates', 'hotgenGlobals', 'hotgenNotify']; - function DialogController($scope, $mdDialog, hotgenStates, hotgenGlobals, hotgenNotify) { - $scope.all_saved = false; - $scope.cancel = function() { - $mdDialog.cancel(); - }; - $scope.download = function() { - // TODO: jump to stack creation page, or send to heat api. - // Temporarily Download - var today = new Date(); - var filename = "template-"+today.toISOString(); - var blob = new Blob([$scope.template_contents], {type: "text/plain;charset=utf-8"}); - saveAs(blob, filename+".yaml.txt"); - hotgenNotify.show_success('Template is downloaded.'); - }; - $scope.save = function() { - hotgenNotify.show_warning('Not implemented yet. To submit to create a stack.') - $mdDialog.cancel(); - }; - - $scope.extract_properties = function(resource_data){ - for (var property in resource_data){ - var func = null; - switch (property){ - case 'description': - case 'public_key': - func = hotgenUtils.escape_characters; - break; - case 'metadata': - case 'scheduler_hints': - case 'value_specs': - func = hotgenUtils.extract_keyvalue; - break; - case 'allocation_pools': - case 'allowed_address_pairs': - case 'block_device_mapping': - case 'block_device_mapping_v2': - case 'fixed_ips': - case 'host_routes': - case 'personality': - case 'rules': - func = hotgenUtils.extract_list_of_keyvalue; - break; - case 'dns_nameservers': - case 'dhcp_agent_ids': - case 'tags': - func = hotgenUtils.extract_list; - break; - case 'resource_def': - func = hotgenUtils.extract_resource_def; - break; - default: - break; - } - if ( func != null){ - resource_data[property] = func(resource_data[property]); - } - hotgenUtils.strip_property(resource_data, property); - - } - return resource_data; - } - - $scope.generate = function(){ - // Generate `resources` & `outputs` section - var resource_root = {}; - var outputs_root = {}; - - if( hotgenStates.get_saved_flags_length() == 0 || hotgenStates.get_saved_resources_length() == 0){ - $scope.all_saved = false; - return 'Cannot generate, no resource has been saved.'; - } - $scope.all_saved = hotgenStates.is_all_saved(); - $scope.saved_resources = hotgenStates.get_saved_resources(); - $scope.data = { - nodes: hotgenStates.get_nodes(), - } - var depends_ons = hotgenStates.get_saved_dependsons(); - - for (var idkey in $scope.saved_resources){ - - // Generate `resources` section - var resource_type = $scope.saved_resources[idkey].type; - var resource_name = hotgenStates.get_label_by_uuid(idkey); - var copy_data = angular.copy($scope.saved_resources[idkey].data) - var properties = $scope.extract_properties(copy_data); - resource_root[resource_name] = { - type: resource_type.replace(/_/g, ':'), - }; - if (Object.keys(properties).length > 0){ - resource_root[resource_name]["properties"] = properties; - } - if (idkey in depends_ons){ - var depends_ids = angular.copy(depends_ons[idkey]); - if (depends_ons[idkey].length > 0){ - resource_root[resource_name]['depends_on'] = []; - for (var idx in depends_ids){ - resource_root[resource_name]['depends_on'].push(hotgenStates.get_label_by_uuid(depends_ids[idx])); - } - } - } - - // Generate `outputs` section - var output_detail = hotgenGlobals.get_resource_outputs(resource_type); - for (var idx in output_detail){ - var output_key = resource_name + '_' + output_detail[idx].property; - outputs_root[output_key] = { - description: 'The ' + output_detail[idx].property + ' of ' + resource_name +'.', - value: '{ get_attr: ['+resource_name+', '+output_detail[idx].property+'] }', - }; - } - - } - - var today = new Date(); - var template_version = hotgenGlobals.get_template_version().split('.')[1] - var template_root = { - heat_template_version: template_version, - description: 'version 2017-09-01 created by HOT Generator at '+ today.toUTCString() + '.', - resources: resource_root, - } - if (Object.keys(outputs_root).length > 0){ - template_root['outputs'] = outputs_root - } - var json_string = JSON.stringify(template_root); - return json2yaml(json_string); - } - - $scope.template_contents = $scope.generate(); - - $scope.template = { - title: 'Template', - content: $scope.template_contents, - }; - } }]); })(); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/modal-template.controller.spec.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/modal-template.controller.spec.js new file mode 100644 index 00000000..ff76a6d2 --- /dev/null +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/modal-template.controller.spec.js @@ -0,0 +1,159 @@ +(function() { + 'use strict'; + + describe('horizon.dashboard.project.heat_dashboard.template_generator.TempModalController', function(){ + + beforeEach(module('horizon.dashboard.project.heat_dashboard.template_generator')); + + beforeEach(module('appTemplates')); + + var hotgenGlobals, hotgenStates, hotgenNotify, basePath; + beforeEach(inject(function($injector){ + hotgenGlobals = $injector.get('hotgenGlobals'); + hotgenStates = $injector.get('hotgenStates'); + hotgenNotify = $injector.get('hotgenNotify'); + basePath = $injector.get('horizon.dashboard.project.heat_dashboard.template_generator.basePath'); + })); + + var $controller, controller, $scope, $rootScope, $mdDialog; + + beforeEach(inject(function($injector){ + $rootScope = $injector.get('$rootScope'); + $mdDialog = $injector.get('$mdDialog'); + })); + + beforeEach(inject(function(_$controller_, $rootScope) { + $controller = _$controller_; + $scope = $rootScope.$new(); + spyOn($mdDialog, 'show'); + spyOn($mdDialog, 'cancel'); + spyOn(hotgenNotify, 'show_success'); + controller = $controller('horizon.dashboard.project.heat_dashboard.template_generator.TempModalController', + { $scope: $scope, $mdDialog: $mdDialog}); + + $mdDialog.show = jasmine.createSpy().and.callFake(function() { + return { + then: (function (callBack) { + callBack(true); //return the value to be assigned. + }, function(callBack){ + callBack(false)} + ) + } + }); + $mdDialog.cancel = jasmine.createSpy().and.callFake(function() { + return function(callBack){callBack(true)}; + }); + })); + + it('should exist', function(){ + expect(controller).toBeDefined(); + expect($mdDialog).toBeDefined(); + }); + + it('$scope.open', function(){ + $scope.open(); + + expect($mdDialog.show).not.toHaveBeenCalled(); + + hotgenGlobals.set_template_version('2017-09-01.template'); + $scope.open(); + + expect($mdDialog.show).toHaveBeenCalled(); + }); + + it('$scope.dialogController', function(){ + $scope.dialogController($scope, $mdDialog, hotgenStates, hotgenGlobals, hotgenNotify); + + expect($scope.all_saved).toEqual(false); + }); + + it('$scope.dialogController $cancel', function(){ + $scope.dialogController($scope, $mdDialog, hotgenStates, hotgenGlobals, hotgenNotify); + $scope.cancel(); + + expect($mdDialog.cancel).toHaveBeenCalled(); + }); + + it('$scope.dialogController download', function(){ + $scope.dialogController($scope, $mdDialog, hotgenStates, hotgenGlobals, hotgenNotify); + $scope.download(); + + expect(hotgenNotify.show_success).toHaveBeenCalled(); + }); + + it('$scope.dialogController save', function(){ + $scope.dialogController($scope, $mdDialog, hotgenStates, hotgenGlobals, hotgenNotify); + $scope.save(); + + expect($mdDialog.cancel).toHaveBeenCalled(); + }); + + it('$scope.dialogController extract_properties', function(){ + $scope.dialogController($scope, $mdDialog, hotgenStates, hotgenGlobals, hotgenNotify); + var to_extract = { + description: '', public_key: '', + metadata: '', scheduler_hints: '', value_specs: '', + allocation_pools: '', allowed_address_pairs: '', block_device_mapping: '', + block_device_mapping_v2: '', fixed_ips: '', host_routes: '', + personality: '', + rules: '', dns_nameservers: '', dhcp_agent_ids: '', tags: '', + resource_def: '', + others: '' + } + var resource_data = $scope.extract_properties(to_extract); + + expect(Object.keys(resource_data).length).toEqual(2); + }); + + it('$scope.dialogController generate', function(){ + $scope.dialogController($scope, $mdDialog, hotgenStates, hotgenGlobals, hotgenNotify); + hotgenStates.update_saved_resources('node_id', { + type: 'Node_Type', + data: { description: '', public_key: '', + metadata: '', scheduler_hints: '', value_specs: '', + allocation_pools: '', allowed_address_pairs: '', block_device_mapping: '', + block_device_mapping_v2: '', fixed_ips: '', host_routes: '', + personality: '', + rules: '', dns_nameservers: '', dhcp_agent_ids: '', tags: '', + resource_def: '', + others: ''} + }); + hotgenStates.set_saved_flags({'node_id': true}); + hotgenStates.update_saved_dependsons('node_id', ['depend_on_id']); + hotgenStates.set_incremented_label('depend_on_id', 'depend_on_label'); + hotgenGlobals.set_resource_outputs('Node_Type', {'property': 'public_key'}); + hotgenGlobals.set_template_version('2017-09-01.template'); + var yamlstring = $scope.generate(); + + expect(yamlstring.length).toBeGreaterThan(0); + }); + + + it('$scope.dialogController trivial generate', function(){ + $scope.dialogController($scope, $mdDialog, hotgenStates, hotgenGlobals, hotgenNotify); + hotgenStates.update_saved_resources('node_id', { + type: 'Node_Type', + data: {metadata: ''} + }); + hotgenStates.set_saved_flags({'node_id': true}); + hotgenGlobals.set_template_version('2017-09-01.template'); + var yamlstring = $scope.generate(); + + expect(yamlstring.length).toBeGreaterThan(0); + }); + + it('$scope.dialogController trivial dependson generate', function(){ + $scope.dialogController($scope, $mdDialog, hotgenStates, hotgenGlobals, hotgenNotify); + hotgenStates.update_saved_resources('node_id', { + type: 'Node_Type', + data: {metadata: ''} + }); + hotgenStates.set_saved_flags({'node_id': true}); + hotgenStates.update_saved_dependsons('node_id', []); + hotgenGlobals.set_template_version('2017-09-01.template'); + var yamlstring = $scope.generate(); + + expect(yamlstring.length).toBeGreaterThan(0); + }); + }); +})(); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/states.service.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/states.service.js index 28049a9c..7ca47bbf 100644 --- a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/states.service.js +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/states.service.js @@ -66,7 +66,7 @@ saved_dependsons = to_set; } var is_all_saved = function(){ - return ! (false in Object.keys(saved_flags)); + return(Object.values(saved_flags).indexOf(false) == -1); }; var get_saved_flags_length = function(){ return Object.keys(saved_flags).length; diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/states.service.spec.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/states.service.spec.js new file mode 100644 index 00000000..3b8e9f9b --- /dev/null +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/states.service.spec.js @@ -0,0 +1,123 @@ +(function() { + 'use strict'; + + describe('hotgen-utils.hotgenStates', function(){ + beforeEach(module('hotgen-utils')); + + var hotgenStates; + + beforeEach(inject(function(_hotgenStates_){ + hotgenStates = _hotgenStates_; + })); + + it('should exist', function(){ + expect(hotgenStates).toBeDefined(); + }); + + it('check nodes and edges', function(){ + expect(hotgenStates.get_nodes().length).toEqual(0); + + expect(hotgenStates.get_edges().length).toEqual(0); + }); + + it('check network', function(){ + expect(hotgenStates.get_network()).toEqual(null); + + var networkMock = {}; + hotgenStates.set_network(networkMock); + + expect( hotgenStates.get_network().constructor).toEqual(Object); + }); + + it('check increment counter/labels', function(){ + expect(Object.keys(hotgenStates.get_incremented_labels()).length).toEqual(0); + + expect(Object.keys(hotgenStates.get_counters()).length).toEqual(0); + + expect(hotgenStates.increment_counter('type1')).toEqual(1); + + expect(hotgenStates.increment_counter('type1')).toEqual(2); + + expect(hotgenStates.get_counter('type1')).toEqual(2); + + hotgenStates.set_incremented_labels({}); + hotgenStates.set_incremented_label('type1', 'type1_2'); + + expect(hotgenStates.get_label_by_uuid('type1')).toEqual('type1_2'); + + hotgenStates.set_counters({}); + }); + + it('check saved_flags', function(){ + expect(hotgenStates.get_saved_flags_length()).toEqual(0); + expect(hotgenStates.is_all_saved()).toEqual(true); + expect(Object.keys( hotgenStates.get_saved_flags()).length).toEqual(0); + + hotgenStates.set_saved_flags({'flag1': true}); + + expect(hotgenStates.is_all_saved()).toEqual(true); + expect(hotgenStates.get_saved_flags_length()).toEqual(1); + expect(hotgenStates.get_saved_flags()['flag1']).toEqual(true); + + hotgenStates.update_saved_flags('flag1', false); + + expect(hotgenStates.is_all_saved()).toEqual(false); + expect(hotgenStates.get_saved_flags()['flag1']).toEqual(false); + expect(hotgenStates.get_saved_flags_length()).toEqual(1); + + }); + + it('check dependsons', function(){ + expect(Object.keys(hotgenStates.get_saved_dependsons()).length).toEqual(0); + + hotgenStates.set_saved_dependsons({'type1': ['resource1', 'resource2']}); + + expect( hotgenStates.get_saved_dependsons()['type1'].length).toEqual(2); + + hotgenStates.update_saved_dependsons('type2', ['resource3']); + + expect( hotgenStates.get_saved_dependsons()['type2'].length).toEqual(1); + }); + + it('check saved resources', function(){ + var returnValue = hotgenStates.get_saved_resources(); + + expect(Object.keys(returnValue).length).toEqual(0); + expect(hotgenStates.get_saved_resources_length()).toEqual(0); + + hotgenStates.set_saved_resources({'resource_name': {'properties':{}}}); + returnValue = hotgenStates.get_saved_resources(); + + expect(Object.keys(returnValue).length).toEqual(1); + expect(hotgenStates.get_saved_resources_length()).toEqual(1); + + hotgenStates.update_saved_resources('resource_name', {'properties':{}}); + hotgenStates.delete_saved_resources('resource_name'); + + returnValue = hotgenStates.get_saved_resources(); + + expect(Object.keys(returnValue).length).toEqual(0); + expect(hotgenStates.get_saved_resources_length()).toEqual(0); + + }); + + it('check selected', function(){ + var returnValue = hotgenStates.get_selected(); + + expect(Object.keys(returnValue).length).toEqual(0); + + hotgenStates.set_selected({'nodes': {}}); + + expect(Object.keys(hotgenStates.get_selected()).length).toEqual(1); + + }); + + it('check clear', function(){ + hotgenStates.clear_states(); + + }); + + }); + + +})(); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/template-generator.module.spec.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/template-generator.module.spec.js new file mode 100644 index 00000000..f00f9176 --- /dev/null +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/template-generator.module.spec.js @@ -0,0 +1,42 @@ +(function () { + 'use strict'; + + describe('horizon.dashboard.project.heat_dashboard.template_generator module', function () { + it('should be defined', function () { + expect(angular.module('horizon.dashboard.project.heat_dashboard.template_generator')).toBeDefined(); + }); + }); + + describe('horizon.dashboard.project.heat_dashboard.template_generator.basePath', function () { + + beforeEach(module('horizon.dashboard.project.heat_dashboard.template_generator')); + + it('should be defined and set correctly', inject([ + 'horizon.dashboard.project.heat_dashboard.template_generator.basePath', '$window', + function (basePath, $window) { + expect(basePath).toBeDefined(); + expect(basePath).toBe($window.STATIC_URL + 'dashboard/project/heat_dashboard/template_generator/'); + }]) + ); + }); + + describe('horizon.dashboard.project.heat_dashboard.template_generator $locationProvider config', function () { + var $locationProvider; + beforeEach(function () { + angular.module('locationProviderConfig', []) + .config(function(_$locationProvider_) { + $locationProvider= _$locationProvider_; + spyOn($locationProvider, 'html5Mode'); + }); + module('locationProviderConfig'); + module('horizon.dashboard.project.heat_dashboard.template_generator'); + inject(); + }); + + it('should set html5 mode', function() { + expect($locationProvider.html5Mode) + .toHaveBeenCalledWith({ enabled: true, requireBase: false }); + }); + + }); +})(); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/utils.module.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/utils.module.js index b00b6f6a..30ac74eb 100644 --- a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/utils.module.js +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/utils.module.js @@ -14,42 +14,50 @@ }); var show_success = function(message) { if ($rootScope.message_level < 2){ - return; + return -1; } notify({ message: message, classes: ['alert-success',], duration: 3000, - }); }; + }); + return 0; + }; var show_error = function(message) { if ($rootScope.message_level < 0){ - return; + return -1; } notify({ message: message, classes: ['alert-danger',], // duration: 5000, - });}; + }); + return 0; + }; var show_info = function(message) { if ($rootScope.message_level < 3){ - return; + return -1; } notify({ message: message, classes: ['alert-info',], duration: 3000, - });}; + }); + return 0; + }; var show_warning = function(message) { if ($rootScope.message_level < 1){ - return; + return -1; } notify({ message: message, classes: ['alert-warning',], duration: 5000, - });}; + }); + return 0; + }; return { show_success: show_success, @@ -72,13 +80,17 @@ $rootScope.$broadcast('handle_load_draft'); }; var broadcast_resources_loaded = function(){ - $rootScope.$broadcast('handle_resources_loaded') + $rootScope.$broadcast('handle_resources_loaded'); + }; + var broadcast_update_template_version = function(){ + $rootScope.$broadcast('update_template_version'); }; return { broadcast_edit_node: broadcast_edit_node, broadcast_edit_edge: broadcast_edit_edge, broadcast_load_draft: broadcast_load_draft, broadcast_resources_loaded: broadcast_resources_loaded, + broadcast_update_template_version: broadcast_update_template_version, } }]) .factory('hotgenUtils', function(){ @@ -104,7 +116,7 @@ } var escape_characters = function(value){ return '"'+value.replace(/\\/g, '\\\\') - .replace(/\"/g, '\\"') + .replace(/"/g, '\\"') .replace(/\n/g, "\\n")+'"'; } var extract_keyvalue = function(value){ @@ -127,24 +139,26 @@ } var extract_list_of_keyvalue = function(value_list){ if (value_list instanceof Array ){ - for (var idx in value_list){ + for (var idx=value_list.length-1; idx>=0; --idx){ if (Object.keys(value_list[idx]).length == 0){ - value_list.splice(idx,1) + value_list.splice(idx, 1) } } + if (value_list.length == 0){ + return null; + } + return value_list } - if (value_list.length == 0){ - return null; - } - return value_list + return null; } var extract_list = function(value_list){ if (value_list instanceof Array){ if (value_list.length == 0){ return null; } + return value_list } - return value_list + return null; } var extract_dicts = function check_dicts(value_dict){ for (var key in value_dict){ @@ -160,7 +174,7 @@ } } var extract_array = function extract_array(value_list){ - for (var idx in value_list){ + for (var idx=value_list.length-1; idx>=0; --idx){ if (value_list[idx] == null || value_list[idx] == ''){ value_list.splice(idx, 1) } else if (value_list[idx].constructor && value_list[idx].constructor == Object){ @@ -216,4 +230,4 @@ }) -})(); \ No newline at end of file +})(); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/utils.module.spec.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/utils.module.spec.js new file mode 100644 index 00000000..d67e669b --- /dev/null +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/utils.module.spec.js @@ -0,0 +1,327 @@ +(function() { + 'use strict'; + + describe('hotgen-utils.hotgen-utils hotgenUUID', function(){ + beforeEach(module('hotgen-utils')); + + var hotgenUUID; + + beforeEach(inject(function(_hotgenUUID_){ + hotgenUUID = _hotgenUUID_; + })); + + it('hotgenUUID should exist', function(){ + expect(hotgenUUID).toBeDefined(); + }); + + it('uuid length > 0', function(){ + var returnValue = hotgenUUID.uuid(); + + expect(returnValue.length).toBeGreaterThan(0); + }); + }); + + describe('hotgen-utils.hotgen-utils hotgenNotify', function(){ + beforeEach(module('hotgen-utils')); + + /* inject hotgenNotify */ + var hotgenNotify; + + beforeEach(inject(function(_hotgenNotify_){ + hotgenNotify = _hotgenNotify_; + })); + + /* inject rootScope */ + var $rootScope; + + beforeEach(inject(function(_$rootScope_) { + $rootScope = _$rootScope_; + })); + + it('should exist', function(){ + expect(hotgenNotify).toBeDefined(); + }); + + it('should show success', function(){ + $rootScope.message_level = 4; + var returnValue = hotgenNotify.show_success('success notify unit test!'); + + expect(returnValue).toEqual(0); + }); + + it('should not show success', function(){ + $rootScope.message_level = 0; + var returnValue = hotgenNotify.show_success('success notify unit test!'); + + expect(returnValue).toEqual(-1); + }); + + it('should show error', function(){ + $rootScope.message_level = 4; + var returnValue = hotgenNotify.show_error('fail notify unit test!'); + + expect(returnValue).toEqual(0); + }); + + it('should not show error', function(){ + $rootScope.message_level = -1; + var returnValue = hotgenNotify.show_error('fail notify unit test!'); + + expect(returnValue).toEqual(-1); + }); + + it('should show info', function(){ + $rootScope.message_level = 4; + var returnValue = hotgenNotify.show_info('info notify unit test!'); + + expect(returnValue).toEqual(0); + }); + + it('should not show info', function(){ + $rootScope.message_level = 0; + var returnValue = hotgenNotify.show_info('info notify unit test!'); + + expect(returnValue).toEqual(-1); + }); + + it('should show warning', function(){ + $rootScope.message_level = 4; + var returnValue = hotgenNotify.show_warning('warning notify unit test!'); + + expect(returnValue).toEqual(0); + }); + + it('should not show warning', function(){ + $rootScope.message_level = 0; + var returnValue = hotgenNotify.show_warning('warning notify unit test!'); + + expect(returnValue).toEqual(-1); + }); + }); + + describe('hotgen-utils.hotgen-utils hotgenMessage', function(){ + beforeEach(module('hotgen-utils')); + + var hotgenMessage; + + beforeEach(inject(function(_hotgenMessage_){ + hotgenMessage = _hotgenMessage_; + })); + + /* inject rootScope */ + var $rootScope; + + beforeEach(inject(function(_$rootScope_) { + $rootScope = _$rootScope_; + spyOn($rootScope, '$broadcast'); + })); + + it('hotgenMessage should exist', function(){ + expect(hotgenMessage).toBeDefined(); + }); + + it('should call event handle_edit_node', function(){ + hotgenMessage.broadcast_edit_node('note_type'); + + expect($rootScope.$broadcast).toHaveBeenCalledWith('handle_edit_node', 'note_type'); + }); + + it('should call event handle_edit_edge', function(){ + hotgenMessage.broadcast_edit_edge('from_type', 'to_type', 'from_id', 'to_id'); + + expect($rootScope.$broadcast).toHaveBeenCalledWith('handle_edit_edge', { + 'from_type': 'from_type', 'to_type': 'to_type', + 'from_id': 'from_id', 'to_id': 'to_id', + }); + }); + + it('should call event handle_load_draft', function(){ + hotgenMessage.broadcast_load_draft('note_type'); + + expect($rootScope.$broadcast).toHaveBeenCalledWith('handle_load_draft'); + }); + + it('should call event handle_resources_loaded', function(){ + hotgenMessage.broadcast_resources_loaded(); + + expect($rootScope.$broadcast).toHaveBeenCalledWith('handle_resources_loaded'); + }); + + it('should call event update_template_version', function(){ + hotgenMessage.broadcast_update_template_version(); + + expect($rootScope.$broadcast).toHaveBeenCalledWith('update_template_version'); + }); + }); + + + describe('hotgen-utils.hotgen-utils hotgenUtils', function(){ + + beforeEach(module('hotgen-utils')); + + var hotgenUtils; + + beforeEach(inject(function(_hotgenUtils_){ + hotgenUtils = _hotgenUtils_; + })); + + it('hotgenUtils should exist', function(){ + expect(hotgenUtils).toBeDefined(); + }); + + it('should return string contains get_resource', function(){ + var returnValue = hotgenUtils.get_resource_string('identity'); + + expect(returnValue).toEqual('{ get_resource: identity }'); + }); + + it('should filter elements', function(){ + var property = 'name'; + var array = ['ignore me', 1, '{ get_resource: find me }', + {'name': '{ get_resource: find me too }'}, + {'no name': 'ignore me'}]; + var returnValue = hotgenUtils.filter_and_return_get_resource_element(array, property); + + expect(returnValue.length).toEqual(2); + }); + + it('should escape characters', function(){ + var returnValue = hotgenUtils.escape_characters('replace " and \\ and \n '); + + expect(returnValue).toEqual('"replace \\" and \\\\ and \\n "'); + }); + + it('should extrace keyvalue', function(){ + var keyvalue = [{'key': 'key1', 'value': 'value1'}, + {'key': 'key2', 'value': 'value2'}]; + var returnValue = hotgenUtils.extract_keyvalue(keyvalue); + + expect(returnValue['key1']).toEqual('value1'); + expect(returnValue['key2']).toEqual('value2'); + + keyvalue = [{}, {}]; + returnValue = hotgenUtils.extract_keyvalue(keyvalue); + + expect(returnValue).toEqual(null); + + keyvalue = ''; + returnValue = hotgenUtils.extract_keyvalue(keyvalue); + + expect(returnValue).toEqual(null); + + keyvalue = ['']; + returnValue = hotgenUtils.extract_keyvalue(keyvalue); + + expect(returnValue).toEqual(null); + }); + + it('should extract list of keyvalue', function(){ + var keyvalue = []; + var returnValue = hotgenUtils.extract_list_of_keyvalue(keyvalue); + + expect(returnValue).toEqual(null); + + keyvalue = 1; + returnValue = hotgenUtils.extract_list_of_keyvalue(keyvalue); + + expect(returnValue).toEqual(null); + + keyvalue = [{'destination': 'destination', 'nexthop': 'nexthop'}, {}]; + returnValue = hotgenUtils.extract_list_of_keyvalue(keyvalue); + + expect(returnValue.length).toEqual(1); + + keyvalue = [{}, {}]; + returnValue = hotgenUtils.extract_list_of_keyvalue(keyvalue); + + expect(returnValue).toEqual(null); + + }); + + it('should extract list', function(){ + var keyvalue = []; + var returnValue = hotgenUtils.extract_list(keyvalue); + + expect(returnValue).toEqual(null); + + keyvalue = 1; + returnValue = hotgenUtils.extract_list(keyvalue); + + expect(returnValue).toEqual(null); + + keyvalue = ['keep me', 'keep me too']; + returnValue = hotgenUtils.extract_list(keyvalue); + + expect(returnValue.length).toEqual(2); + + }); + + it('should extract dicts', function(){ + var keyvalue = {'discard me': '', 'discard me too': null}; + var returnValue = hotgenUtils.extract_dicts(keyvalue); + + expect(Object.keys(returnValue).length).toEqual(0); + + keyvalue = {'keep me': [], 'keep me too': 'me'}; + returnValue = hotgenUtils.extract_dicts(keyvalue); + + expect(Object.keys(returnValue).length).toEqual(2); + + }); + + it('should strip_property', function(){ + var keyvalue = {'property': {'discard me': '', 'discard me too': null}}; + hotgenUtils.strip_property(keyvalue, 'property'); + + expect(Object.keys(keyvalue).length).toEqual(0); + + keyvalue = {'property': {'keep me': [], 'keep me too': 'me'}}; + hotgenUtils.strip_property(keyvalue, 'property'); + + expect(Object.keys(keyvalue).length).toEqual(1); + + keyvalue = {'property': {'keep me': [{}, []], 'keep me too': 'me'}}; + hotgenUtils.strip_property(keyvalue, 'property'); + + expect(Object.keys(keyvalue).length).toEqual(1); + expect(Object.keys(keyvalue['property']).length).toEqual(1); + + keyvalue = {'property': [null, '', {}, [] ]}; + hotgenUtils.strip_property(keyvalue, 'property'); + + expect(Object.keys(keyvalue).length).toEqual(0); + + keyvalue = {'property': [1, 2, {'keep me': 3}, [4, 5, 6]]}; + hotgenUtils.strip_property(keyvalue, 'property'); + + expect(Object.keys(keyvalue).length).toEqual(1); + expect(Object.keys(keyvalue['property']).length).toEqual(4); + + keyvalue = {'property': [ ['', ''], [[[]]] ]}; + hotgenUtils.strip_property(keyvalue, 'property'); + + expect(Object.keys(keyvalue).length).toEqual(0); + + }); + + it('should extract resource_def', function(){ + var keyvalue = {'properties': [{'key': 'k1', 'value': 'v1'}], + 'metadata': [{'key': 'k2', 'value': 'v2'}], + 'type': 'some file'}; + var returnValue = hotgenUtils.extract_resource_def(keyvalue); + + expect(returnValue.properties['k1']).toEqual('v1'); + expect(returnValue.metadata['k2']).toEqual('v2'); + + var keyvalue = {'type': 'some file'}; + var returnValue = hotgenUtils.extract_resource_def(keyvalue); + + expect(returnValue.type).toEqual('some file'); + + }); + }); + + + + +})(); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/vis-network.controller.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/vis-network.controller.js index 66093dc6..5b536b2f 100644 --- a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/vis-network.controller.js +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/vis-network.controller.js @@ -2,7 +2,7 @@ 'use strict'; angular.module('horizon.dashboard.project.heat_dashboard.template_generator') - .controller('horizon.dashboard.project.heat_dashboard.template_generator.VisCtrl', + .controller('horizon.dashboard.project.heat_dashboard.template_generator.VisController', ['$scope', '$rootScope', 'hotgenNotify', 'hotgenMessage', 'hotgenGlobals', 'hotgenStates', 'horizon.dashboard.project.heat_dashboard.template_generator.basePath', function($scope, $rootScope, hotgenNotify, hotgenMessage, hotgenGlobals, hotgenStates, basePath) { @@ -127,6 +127,7 @@ $scope.click = function(params){ if (params.nodes.length > 0){ + $scope.network.disableEditMode(); var selected_id = params.nodes[0]; var selected_node = $scope.data.nodes.get(selected_id); var selected_type = selected_node.title @@ -136,9 +137,9 @@ id: selected_id, node: selected_node, }) ; - hotgenMessage.broadcast_edit_node(selected_type); } else if (params.edges.length > 0){ + $scope.network.disableEditMode(); var selected_id = params.edges[0]; var selected_edge = $scope.data.edges.get(selected_id); var from_node = $scope.data.nodes.get(selected_edge.from); @@ -154,7 +155,7 @@ }); hotgenMessage.broadcast_edit_edge(from_node.title, to_node.title, from_node.id, to_node.id); } else { - ; +// ; } }; @@ -199,7 +200,7 @@ $scope.validate_edge = function(data){ if (data.from == data.to ){ - hotgenNotify.show_error("The resource cannot be connected with itself."); +// hotgenNotify.show_warning(""); return false; } var from_node = $scope.get_node(data.from); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/vis-network.controller.spec.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/vis-network.controller.spec.js new file mode 100644 index 00000000..516dd128 --- /dev/null +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/vis-network.controller.spec.js @@ -0,0 +1,203 @@ +(function() { + 'use strict'; + + describe('horizon.dashboard.project.heat_dashboard.template_generator.VisController', function(){ + + beforeEach(module('horizon.dashboard.project.heat_dashboard.template_generator')); + + var $controller, controller, $scope, $rootScope, hotgenGlobals, hotgenStates; + + beforeEach(inject(function($injector){ + hotgenGlobals = $injector.get('hotgenGlobals'); + hotgenStates = $injector.get('hotgenStates'); + $rootScope = $injector.get('$rootScope'); + spyOn($rootScope, '$broadcast'); + })); + + beforeEach(inject(function(_$controller_, $rootScope) { + $controller = _$controller_; + $scope = $rootScope.$new(); + controller = $controller('horizon.dashboard.project.heat_dashboard.template_generator.VisController', { $scope: $scope,}); + })); + + it('should exist', function(){ + expect(controller).toBeDefined(); + }); + + it('check scope parameters', function(){ + expect($scope.data.nodes.length).toEqual(0); + expect($scope.data.edges.length).toEqual(0); + expect($scope.options.autoResize).toEqual(true); + }); + + it('check $scope.get_node found', function(){ + $scope.data.nodes.add({id: 'from_id'}); + var returnValue = $scope.get_node('from_id'); + + expect(returnValue.id).toEqual('from_id'); + }); + + it('check validate edge: invalid same node.', function(){ + var data = {from: 'from_id', to: 'from_id'}; + var returnValue = $scope.validate_edge(data); + + expect(returnValue).toEqual(false); + }); + + it('check validate edge: connection allowed/ not allowed.', function(){ + $scope.data.nodes.add({id: 'from_id', title: 'from_type'}); + $scope.data.nodes.add({id: 'to_id', title: 'to_type'}); + hotgenGlobals.update_edge_directions('from', {to: {}}); + + var data = {from: 'from_id', to: 'to_id'}; + + expect($scope.validate_edge(data)).toEqual(false); + + hotgenGlobals.update_edge_directions('from_type', {to: {}}); + + expect($scope.validate_edge(data)).toEqual(false); + + $scope.data.nodes.add({id: 'another_to_id', title: 'to_type'}); + $scope.data.nodes.add({id: 'third_to_id', title: 'from_type'}); + $scope.network = {getConnectedNodes: function(data){ + return ['another_to_id', 'third_to_id']; + }} + hotgenGlobals.update_edge_directions('from_type', {to_type: {limit: 0}}); + + expect($scope.validate_edge(data)).toEqual(false); + + hotgenGlobals.update_edge_directions('from_type', {to_type: {limit: 10, lonely: true}}); + + expect($scope.validate_edge(data)).toEqual(false); + + hotgenGlobals.update_edge_directions('from_type', {to_type: {limit: 10, lonely: false, occupied: true}}); + + expect($scope.validate_edge(data)).toEqual(false); + + hotgenGlobals.update_edge_directions('from_type', {to_type: {limit: 10, lonely: false, occupied: false}}); + + expect($scope.validate_edge(data)).toEqual(true); + + $scope.data.nodes.update({id: 'third_to_id', title: 'another_type'}); + hotgenGlobals.update_edge_directions('from_type', {to_type: {limit: 10, lonely: false, occupied: true}}); + + expect($scope.validate_edge(data)).toEqual(true); + + }); + + it('manipulation.addEdge: valid to add edge', function(){ + var addEdgeFunction = $scope.options.manipulation.addEdge; + var data = {from: 'from_id', to: 'to_id'}; + var mockCallbackFunction = jasmine.createSpy().and.callFake(function() {return function(){}}) + + spyOn($scope, 'validate_edge').and.callFake(function(){return true}); + addEdgeFunction(data, mockCallbackFunction); + + expect(mockCallbackFunction).toHaveBeenCalledWith(data); + + }); + + it('manipulation.addEdge: invalid to add edge', function(){ + var addEdgeFunction = $scope.options.manipulation.addEdge; + var data = {from: 'from_id', to: 'to_id'}; + var mockCallbackFunction = jasmine.createSpy().and.callFake(function() {return function(){}}) + + spyOn($scope, 'validate_edge').and.callFake(function(){return false}); + addEdgeFunction(data, mockCallbackFunction); + + expect(mockCallbackFunction).toHaveBeenCalledWith(null); + }); + + it('manipulation.deleteNode', function(){ + var deleteNodeFunction = $scope.options.manipulation.deleteNode; + var data = {nodes: ['node_id'], edges:['edge_id']} + var mockCallbackFunction = jasmine.createSpy().and.callFake(function() {return function(){}}) + deleteNodeFunction(data, mockCallbackFunction); + + expect(mockCallbackFunction).toHaveBeenCalledWith(data); + }); + + it('manipulation.deleteEdge', function(){ + $scope.data.nodes.add({id: 'from_id', title: 'from_type'}); + $scope.data.nodes.add({id: 'to_id', title: 'to_type'}); + $scope.data.edges.add({id: 'edge_id', from: 'from_id', to: 'to_id'}); + var deleteEdgeFunction = $scope.options.manipulation.deleteEdge; + var data = {edges:['edge_id']} + var mockCallbackFunction = jasmine.createSpy().and.callFake(function() {return function(){}}) + deleteEdgeFunction(data, mockCallbackFunction); + + expect(mockCallbackFunction).toHaveBeenCalledWith(data); + }); + + it('click nothing', function(){ + var param = {edges: [], nodes: []} + + $scope.click(param); + + expect($rootScope.$broadcast).not.toHaveBeenCalled(); + }); + + it('click to show node dialog', function(){ + $scope.data.nodes.add({id: 'from_id', title: 'from_type'}); + var param = {edges: [], nodes: ['from_id']} + $scope.network = {disableEditMode: function(data){}} + + $scope.click(param); + + expect($rootScope.$broadcast).toHaveBeenCalledWith('handle_edit_node', 'from_type'); + }); + + it('click to show edge dialog', function(){ + $scope.data.nodes.add({id: 'from_id', title: 'from_type'}); + $scope.data.nodes.add({id: 'to_id', title: 'to_type'}); + $scope.data.edges.add({id: 'edge_id', from: 'from_id', to: 'to_id'}); + var param = {edges:['edge_id'], nodes:[]} + $scope.network = {disableEditMode: function(data){}} + + $scope.click(param); + var broadcast_param = { + from_type: 'from_type', to_type: 'to_type', + from_id: 'from_id', to_id: 'to_id', + }; + + expect($rootScope.$broadcast).toHaveBeenCalledWith('handle_edit_edge', broadcast_param); + }); + + it('events on load', function(){ + var network = {} + spyOn(hotgenStates, 'set_network'); + var onloadFunction = $scope.events.onload; + onloadFunction(network); + + expect(hotgenStates.set_network).toHaveBeenCalledWith(network); + }); + + it('get_added_edge_id: find the extra item', function(){ + var old_ids = [1 ,2 ,3, 4]; + var new_ids = [1, 2, 5, 3, 4]; + var find = $scope.get_added_edge_id(old_ids, new_ids); + + expect(find).toEqual(5); + }); + + it('get mapping', function(){ + hotgenGlobals.update_edge_directions('from_type', {to_type: {limit: 10}}); + + expect($scope.get_mapping('from_type', 'to_type').limit).toEqual(10); + expect($scope.get_mapping('from_type', 'to')).toEqual(false); + expect($scope.get_mapping('from', 'to')).toEqual(false); + }); + + it('get modal: found/not found', function(){ + hotgenGlobals.update_edge_directions('from_type', {to_type: {limit: 10, modal: 'modal'}}); + $scope.data.nodes.add({id: 'from_id', title: 'from_type'}); + $scope.data.nodes.add({id: 'to_id', title: 'to_type'}); + $scope.data.nodes.add({id: 'from', title: 'from'}); + + expect($scope.get_modal({from: 'from_id', to: 'to_id'})).toEqual('modal'); + expect($scope.get_modal({from: 'from', to: 'to_id'})).toEqual(undefined); + + }) + }); + +})(); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__cinder__volume/os__cinder__volume.spec.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__cinder__volume/os__cinder__volume.spec.js new file mode 100644 index 00000000..89fbaeb7 --- /dev/null +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__cinder__volume/os__cinder__volume.spec.js @@ -0,0 +1,83 @@ +(function() { + 'use strict'; + + describe('component os-cinder-volume', function(){ + + beforeEach(module('horizon.dashboard.project.heat_dashboard.template_generator')); + + beforeEach(module('appTemplates')); + + var $scope, $isolateScope, $compile; + var element; + + beforeEach(inject(function($injector) { + $scope = $injector.get('$rootScope').$new(); + $compile = $injector.get('$compile'); + + $scope.resource = {}; + $scope.dependson = []; + $scope.connectedoptions = []; + $scope.resourceForm = {}; + + // element will enable you to test your directive's element on the DOM + element = $compile(angular.element(''))($scope); + + // Digest needs to be called to set any values on the directive's scope + $scope.$digest(); + + $isolateScope = element.isolateScope(); + })); + + it('find tab title Properties', function() { + expect(element.find('span').html()).toContain("Properties"); + }); + + it('find tab title with resource set', function() { + $scope.resource = {metadata: [], scheduler_hints:[]}; + + // element will enable you to test your directive's element on the DOM + element = $compile(angular.element(''))($scope); + + // Digest needs to be called to set any values on the directive's scope + $scope.$digest(); + + $isolateScope = element.isolateScope(); + + expect(element.find('span').html()).toContain("Properties"); + }); + + it('metadata should be successfully added', function() { + var $ctrl = element.isolateScope().$ctrl; + $ctrl.add_metadata(); + + expect($scope.resource.metadata.length).toEqual(2); + }); + + it('metadata should be successfully deleted', function() { + var $ctrl = element.isolateScope().$ctrl; + $ctrl.delete_metadata(); + + expect($scope.resource.metadata.length).toEqual(0); + }); + + it('scheduler_hints should be successfully added', function() { + var $ctrl = element.isolateScope().$ctrl; + $ctrl.add_scheduler_hints(); + + expect($scope.resource.scheduler_hints.length).toEqual(2); + }); + + it('scheduler_hints should be successfully deleted', function() { + var $ctrl = element.isolateScope().$ctrl; + $ctrl.delete_scheduler_hints(); + + expect($scope.resource.scheduler_hints.length).toEqual(0); + }); + + }); + +})(); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__cinder__volumeattachment/os__cinder__volumeattachment.spec.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__cinder__volumeattachment/os__cinder__volumeattachment.spec.js new file mode 100644 index 00000000..cb64b637 --- /dev/null +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__cinder__volumeattachment/os__cinder__volumeattachment.spec.js @@ -0,0 +1,78 @@ +(function() { + 'use strict'; + + describe('os-cinder-volume-attachment', function(){ + + beforeEach(module('horizon.dashboard.project.heat_dashboard.template_generator')); + + beforeEach(module('appTemplates')); + + var $scope, $isolateScope, $compile; + var hotgenGlobals; + var element; + + beforeEach(inject(function($injector) { + $scope = $injector.get('$rootScope').$new(); + $compile = $injector.get('$compile'); + hotgenGlobals = $injector.get('hotgenGlobals'); + + hotgenGlobals.update_resource_options({ + instances: [{id: 'instance1-id', name: 'instance1'}], + volumes: [{id: 'volume1-id', name: 'volume1-id'}], + }); + $scope.resource = {}; + $scope.dependson = []; + $scope.connectedoptions = []; + $scope.resourceForm = {}; + + // element will enable you to test your directive's element on the DOM + element = $compile(angular.element(''))($scope); + + // Digest needs to be called to set any values on the directive's scope + $scope.$digest(); + + $isolateScope = element.isolateScope(); + })); + + it('find tab title Properties', function() { + + expect(element.find('span').html()).toContain("Properties"); + }); + + it('find tab title with no connectedoptions set', function() { + element = $compile(angular.element(''))($scope); + + $scope.$digest(); + + $isolateScope = element.isolateScope(); + + expect(element.find('span').html()).toContain("Properties"); + }); + + it('find tab title with connectedoptions set', function() { + $scope.resource = {instance_uuid: 'instance-uuid', volume_id: 'volume-id'} + $scope.connectedoptions = {instance_uuid: [{value: 'instance-uuid'}], + volume_id: [{value: 'volume-id'}]}; + + element = $compile(angular.element(''))($scope); + + $scope.$digest(); + + $isolateScope = element.isolateScope(); + + expect(element.find('span').html()).toContain("Properties"); + expect($isolateScope.$ctrl.volumeattachment.instance_uuid).toEqual('instance-uuid'); + expect($isolateScope.$ctrl.volumeattachment.volume_id).toEqual('volume-id'); + }); + }); + +})(); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__heat__resourcegroup/os__heat__resourcegroup.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__heat__resourcegroup/os__heat__resourcegroup.js index c8ae8b83..85e0baf8 100644 --- a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__heat__resourcegroup/os__heat__resourcegroup.js +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__heat__resourcegroup/os__heat__resourcegroup.js @@ -70,12 +70,13 @@ if (oldValue === newValue){ return; } - if (newValue === true){ + if (newValue === true || newValue === 'true'){ $scope.controller.resourcegroup.resource_def.properties = [{}]; if (!($scope.filecontent && $scope.filecontent.length >= 0)){ $scope.controller.resourcegroup.resource_def.type = ''; } } else{ + // ; } }); $scope.file_upload = function(element){ @@ -91,8 +92,8 @@ hotgenNotify.show_success('Read file content.'); hotgenGlobals.set_reference_file(file.name, reader.result) $scope.filecontent = reader.result; - } - reader.readAsText(file); + } + reader.readAsText(file); } else { hotgenNotify.show_error('File type is not supported.'); } @@ -103,26 +104,26 @@ }, 0); }; this.delete_property = function(index){ - this.resourcegroup.resource_def.properties.splice(index, 1) + this.resourcegroup.resource_def.properties.splice(index, 1); } this.add_property = function(){ - this.resourcegroup.resource_def.properties.push({}) + this.resourcegroup.resource_def.properties.push({}); } this.delete_metadata = function(index){ - this.resourcegroup.resource_def.metadata.splice(index, 1) + this.resourcegroup.resource_def.metadata.splice(index, 1); } this.add_metadata = function(){ - this.resourcegroup.resource_def.metadata.push({}) + this.resourcegroup.resource_def.metadata.push({}); } - }; + } function osHeatResourceGroupPath (basePath){ return basePath + 'js/resources/os__heat__resourcegroup/os__heat__resourcegroup.html'; - }; + } osHeatResourceGroupController.$inject = ['$scope', 'hotgenGlobals', 'hotgenNotify', 'horizon.dashboard.project.heat_dashboard.template_generator.validationRules', diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__heat__resourcegroup/os__heat__resourcegroup.spec.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__heat__resourcegroup/os__heat__resourcegroup.spec.js new file mode 100644 index 00000000..628ec2d4 --- /dev/null +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__heat__resourcegroup/os__heat__resourcegroup.spec.js @@ -0,0 +1,144 @@ +(function() { + 'use strict'; + + describe('component os-heat-resource-group', function(){ + + beforeEach(module('horizon.dashboard.project.heat_dashboard.template_generator')); + + beforeEach(module('appTemplates')); + + var $scope, $isolateScope, $compile; + var hotgenNotify; + var element; + + beforeEach(inject(function($injector) { + $scope = $injector.get('$rootScope').$new(); + $compile = $injector.get('$compile'); + hotgenNotify = $injector.get('hotgenNotify'); + spyOn(hotgenNotify, 'show_success'); + spyOn(hotgenNotify, 'show_error'); + + $scope.resource = {}; + $scope.dependson = []; + $scope.connectedoptions = []; + $scope.resourceForm = {}; + + // element will enable you to test your directive's element on the DOM + element = $compile(angular.element(''))($scope); + + // Digest needs to be called to set any values on the directive's scope + $scope.$digest(); + + $isolateScope = element.isolateScope(); + })); + + it('find tab title Properties', function() { + expect(element.find('span').html()).toContain("Properties"); + expect($isolateScope.is_upload).toEqual('false'); + }); + + it('find tab title with resource set', function() { + $scope.resource = {resource_def: {type: 'filepath.yaml'}}; + + // element will enable you to test your directive's element on the DOM + element = $compile(angular.element(''))($scope); + + // Digest needs to be called to set any values on the directive's scope + $scope.$digest(); + + $isolateScope = element.isolateScope(); + + expect($isolateScope.is_upload ).toEqual('true'); + }); + + it('$scope.is_upload should be successfully watched', function() { + $isolateScope.is_upload = 'true'; + $isolateScope.$digest(); + + $isolateScope.is_upload = 'false'; + $isolateScope.$digest(); + $isolateScope.filecontent = 'some thing here'; + + $isolateScope.is_upload = 'true'; + $isolateScope.$digest(); + + expect($isolateScope.controller.resourcegroup.resource_def.type ).toEqual(''); + }); + + it('file should be successfully uploaded', function() { + var blob = new Blob([''], {type: '', }); + blob['name'] = 'filename.yaml' + var upload_element = {files: [blob], } + spyOn(window, 'FileReader').and.returnValue({ + readAsText: function(file) { + this.onload({}); + }, + result: 'file contents.' + }); + $isolateScope.file_upload(upload_element); + + expect($isolateScope.filecontent).toEqual('file contents.'); + expect(hotgenNotify.show_success).toHaveBeenCalled(); + }); + + it('file should be not uploaded return undefined', function() { + var upload_element = {files: []} + var returnValue = $isolateScope.file_upload(upload_element); + + expect(returnValue).toEqual(undefined); + + }); + + it('file should be not uploaded show error', function() { + var upload_element = {files: [{name: 'file.txt'}]} + var returnValue = $isolateScope.file_upload(upload_element); + + expect(hotgenNotify.show_error).toHaveBeenCalled(); + + }); + + it('metadata should be successfully added', function() { + var $ctrl = $isolateScope.$ctrl; + $ctrl.add_metadata(); + + expect($ctrl.resourcegroup.resource_def.metadata.length).toEqual(1); + }); + + + it('metadata should be successfully deleted', function() { + var $ctrl = $isolateScope.$ctrl; + $ctrl.add_metadata(); + $ctrl.delete_metadata(); + + expect($ctrl.resourcegroup.resource_def.metadata.length).toEqual(0); + }); + + it('property should be successfully added', function() { + var $ctrl = $isolateScope.$ctrl; + $ctrl.add_property(); + + expect($ctrl.resourcegroup.resource_def.properties.length).toEqual(2); + }); + + it('property should be successfully deleted', function() { + var $ctrl = $isolateScope.$ctrl; + $ctrl.delete_property(); + + expect($ctrl.resourcegroup.resource_def.properties.length).toEqual(0); + }); + + it('click upload', function() { + spyOn(window, 'setTimeout').and.callFake(function(){}); + + $isolateScope.clickUpload(); + + expect(setTimeout).toHaveBeenCalled(); + }); + + }); + +})(); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingip/os__neutron__floatingip.html b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingip/os__neutron__floatingip.html index e539ab8b..2f917995 100644 --- a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingip/os__neutron__floatingip.html +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingip/os__neutron__floatingip.html @@ -1,5 +1,5 @@ - + diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingip/os__neutron__floatingip.spec.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingip/os__neutron__floatingip.spec.js new file mode 100644 index 00000000..d994ec76 --- /dev/null +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingip/os__neutron__floatingip.spec.js @@ -0,0 +1,92 @@ +(function() { + 'use strict'; + + describe('component os-neutron-floatingip', function(){ + + beforeEach(module('horizon.dashboard.project.heat_dashboard.template_generator')); + + beforeEach(module('appTemplates')); + + var $scope, $isolateScope, $compile; + var hotgenGlobals; + var element; + + beforeEach(inject(function($injector) { + $scope = $injector.get('$rootScope').$new(); + $compile = $injector.get('$compile'); + hotgenGlobals = $injector.get('hotgenGlobals'); + + hotgenGlobals.update_resource_options({ + floating_networks: [{id: 'floating-network1-id', name: 'floating-network1-id'}], + floating_subnets: [{id: 'floating-subnet1-id', name: 'floating-subnet1-id'}], + ports: [{id: 'port1-id', name: 'port1-id'}], + }); + $scope.resource = {}; + $scope.dependson = []; + $scope.connectedoptions = []; + $scope.resourceForm = {}; + + // element will enable you to test your directive's element on the DOM + element = $compile(angular.element(''))($scope); + + // Digest needs to be called to set any values on the directive's scope + $scope.$digest(); + + $isolateScope = element.isolateScope(); + })); + + it('find tab title Properties', function() { + expect(element.find('span').html()).toContain("Properties"); + }); + + it('find tab title with no connectedoptions set', function() { + element = $compile(angular.element(''))($scope); + + $scope.$digest(); + + $isolateScope = element.isolateScope(); + + expect(element.find('span').html()).toContain("Properties"); + }); + + + it('find tab title with connectedoptions set', function() { + $scope.resource = {floating_network: 'floating-network-id', + floating_subnet: 'floating-subnet-id', + port_id: 'port_id'} + $scope.connectedoptions = {floating_network: [{value: 'floating-network-id'}], + floating_subnet: [{value: 'floating-subnet-id'}], + port_id: [{value: 'port-id'}], + }; + + element = $compile(angular.element(''))($scope); + + $scope.$digest(); + + $isolateScope = element.isolateScope(); + + expect(element.find('span').html()).toContain("Properties"); + }); + + it('value_spec should be successfully added', function() { + var $ctrl = element.isolateScope().$ctrl; + $ctrl.add_value_specs(); + + expect($scope.resource.value_specs.length).toEqual(2); + }); + + it('value_spec should be successfully deleted', function() { + var $ctrl = element.isolateScope().$ctrl; + $ctrl.delete_value_specs(); + + expect($scope.resource.value_specs.length).toEqual(0); + }); + }); + +})(); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingipassociation/os__neutron__floatingassociation.spec.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingipassociation/os__neutron__floatingassociation.spec.js new file mode 100644 index 00000000..95c1fde8 --- /dev/null +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingipassociation/os__neutron__floatingassociation.spec.js @@ -0,0 +1,78 @@ +(function() { + 'use strict'; + + describe('os-neutron-floatingip-association', function(){ + + beforeEach(module('horizon.dashboard.project.heat_dashboard.template_generator')); + + beforeEach(module('appTemplates')); + + var $scope, $isolateScope, $compile; + var hotgenGlobals; + var element; + + beforeEach(inject(function($injector) { + $scope = $injector.get('$rootScope').$new(); + $compile = $injector.get('$compile'); + hotgenGlobals = $injector.get('hotgenGlobals'); + + hotgenGlobals.update_resource_options({ + floatingips: [{id: 'floatingip1-id', name: 'floatingip1-id'}], + ports: [{id: 'port1-id', name: 'port1-id'}], + }); + $scope.resource = {}; + $scope.dependson = []; + $scope.connectedoptions = []; + $scope.resourceForm = {}; + + // element will enable you to test your directive's element on the DOM + element = $compile(angular.element(''+ + ''))($scope); + + // Digest needs to be called to set any values on the directive's scope + $scope.$digest(); + + $isolateScope = element.isolateScope(); + })); + + it('find tab title Properties', function() { + expect(element.find('span').html()).toContain("Properties"); + }); + + it('find tab title with no connectedoptions set', function() { + element = $compile(angular.element(''+ + ''))($scope); + + $scope.$digest(); + + $isolateScope = element.isolateScope(); + + expect(element.find('span').html()).toContain("Properties"); + }); + + + it('find tab title with connectedoptions set', function() { + $scope.resource = {floatingip_id: 'floatingip-id', + port_id: 'port_id'} + $scope.connectedoptions = {floatingip_id: [{value: 'floatingip-id'}], + port_id: [{value: 'port-id'}], + }; + + element = $compile(angular.element(''+ + ''))($scope); + + $scope.$digest(); + + $isolateScope = element.isolateScope(); + + expect(element.find('span').html()).toContain("Properties"); + }); + }); + +})(); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingipassociation/os__neutron__floatingipassociation.html b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingipassociation/os__neutron__floatingipassociation.html index 0f84d0f6..aec8d50d 100644 --- a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingipassociation/os__neutron__floatingipassociation.html +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingipassociation/os__neutron__floatingipassociation.html @@ -1,5 +1,5 @@ - + diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingipassociation/os__neutron__floatingipassociation.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingipassociation/os__neutron__floatingipassociation.js index caa4a27b..ca6297c8 100644 --- a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingipassociation/os__neutron__floatingipassociation.js +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__floatingipassociation/os__neutron__floatingipassociation.js @@ -14,7 +14,7 @@ color: '#40a5f2' }, label: 'fixed_ip_address', - modal_component: '', + modal_component: '', edge_settings: { 'OS__Neutron__FloatingIP': { 'type': 'property', diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__net/os__neutron__net.html b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__net/os__neutron__net.html index 2f784e29..488cc5e2 100644 --- a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__net/os__neutron__net.html +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__net/os__neutron__net.html @@ -1,5 +1,5 @@ - + diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__net/os__neutron__net.spec.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__net/os__neutron__net.spec.js new file mode 100644 index 00000000..6b1ec552 --- /dev/null +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__net/os__neutron__net.spec.js @@ -0,0 +1,61 @@ +(function() { + 'use strict'; + + describe('component os-neutron-net', function(){ + + beforeEach(module('horizon.dashboard.project.heat_dashboard.template_generator')); + + beforeEach(module('appTemplates')); + + var $scope, $isolateScope, $compile; + var element; + + beforeEach(inject(function($injector) { + $scope = $injector.get('$rootScope').$new(); + $compile = $injector.get('$compile'); + $scope.resource = {}; + $scope.dependson = []; + $scope.resourceForm = {}; + + // element will enable you to test your directive's element on the DOM + element = $compile(angular.element(''+ + ''))($scope); + + // Digest needs to be called to set any values on the directive's scope + $scope.$digest(); + + $isolateScope = element.isolateScope(); + })); + + it('find tab title Properties', function() { + expect(element.find('span').html()).toContain("Properties"); + }); + + it('find tab title Properties with resource properties set', function() { + $scope.resource = { tags: [], dhcp_agent_ids: [], admin_state_up: true, value_specs: []}; + element = $compile(angular.element(''+ + ''))($scope); + + $scope.$digest(); + + expect(element.find('span').html()).toContain("Properties"); + }); + + it('value_spec should be successfully added', function() { + var $ctrl = $isolateScope.$ctrl; + $ctrl.add_value_specs(); + + expect($scope.resource.value_specs.length).toEqual(2); + }); + + it('value_spec should be successfully deleted', function() { + var $ctrl = $isolateScope.$ctrl; + $ctrl.delete_value_specs(); + + expect($scope.resource.value_specs.length).toEqual(0); + }); + }); + +})(); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__port/os__neutron__port.html b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__port/os__neutron__port.html index 6de17f6f..0463e821 100644 --- a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__port/os__neutron__port.html +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__port/os__neutron__port.html @@ -1,5 +1,5 @@ - + diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__port/os__neutron__port.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__port/os__neutron__port.js index 589604e0..ddc19f05 100644 --- a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__port/os__neutron__port.js +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__port/os__neutron__port.js @@ -212,7 +212,7 @@ display: dev_owner } }); - }; + } function querySearch (query) { return query ? this.device_owners.filter( createFilterFor(query) ) : this.device_owners; diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__port/os__neutron__port.spec.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__port/os__neutron__port.spec.js new file mode 100644 index 00000000..36665347 --- /dev/null +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__port/os__neutron__port.spec.js @@ -0,0 +1,146 @@ +(function() { + 'use strict'; + + describe('component os-neutron-port', function(){ + + beforeEach(module('horizon.dashboard.project.heat_dashboard.template_generator')); + + beforeEach(module('appTemplates')); + + var $scope, $isolateScope, $compile; + var hotgenGlobals; + var element; + + beforeEach(inject(function($injector) { + $scope = $injector.get('$rootScope').$new(); + $compile = $injector.get('$compile'); + hotgenGlobals = $injector.get('hotgenGlobals'); + + hotgenGlobals.update_resource_options({ + networks: [{id: 'network1-id', name: 'network1-id'}], + security_groups: [{id: 'secgroup1-id', name: 'secgroup1-id'}], + subnets: [{id: 'subnet1-id', name: 'subnet-id'}] + }); + $scope.resource = {}; + $scope.dependson = []; + $scope.connectedoptions = []; + $scope.resourceForm = {}; + + // element will enable you to test your directive's element on the DOM + element = $compile(angular.element(''))($scope); + + // Digest needs to be called to set any values on the directive's scope + $scope.$digest(); + + $isolateScope = element.isolateScope(); + })); + + it('find tab title Properties', function() { + expect(element.find('span').html()).toContain("Properties"); + }); + + it('find tab title with no connectedoptions set', function() { + element = $compile(angular.element(''))($scope); + + $scope.$digest(); + + $isolateScope = element.isolateScope(); + + expect(element.find('span').html()).toContain("Properties"); + }); + + + it('find tab title with connectedoptions set', function() { + $scope.resource = {device_owner: 'someone', + network: 'network-id', + security_groups: ['secgroup-id'], + 'fixed_ips.subnet': ['subnet-id'],} + $scope.connectedoptions = {network: [{value: 'network-id'}], + security_groups: [{value: 'secgroup-id'}], + 'fixed_ips.subnet': [{value: 'subnet-id'}], + }; + + element = $compile(angular.element(''))($scope); + + $scope.$digest(); + + $isolateScope = element.isolateScope(); + + expect(element.find('span').html()).toContain("Properties"); + }); + + it('value_spec should be successfully added', function() { + var $ctrl = $isolateScope.$ctrl; + $ctrl.add_value_specs(); + + expect($scope.resource.value_specs.length).toEqual(2); + }); + + it('value_spec should be successfully deleted', function() { + var $ctrl = $isolateScope.$ctrl; + $ctrl.delete_value_specs(); + + expect($scope.resource.value_specs.length).toEqual(0); + }); + + it('allowed address pair should be successfully added', function() { + var $ctrl = $isolateScope.$ctrl; + $ctrl.add_allowed_address_pair(); + + expect($scope.resource.allowed_address_pairs.length).toEqual(2); + }); + + it('allowed address pair should be successfully deleted', function() { + var $ctrl = $isolateScope.$ctrl; + $ctrl.delete_allowed_address_pair(); + + expect($scope.resource.allowed_address_pairs.length).toEqual(0); + }); + + it('fixed_ip should be successfully added', function() { + var $ctrl = $isolateScope.$ctrl; + $ctrl.add_fixed_ip(); + + expect($scope.resource.fixed_ips.length).toEqual(2); + }); + + it('fixed_ip should be successfully deleted', function() { + var $ctrl = $isolateScope.$ctrl; + $ctrl.delete_fixed_ip(); + + expect($scope.resource.fixed_ips.length).toEqual(0); + }); + + it('searchTextChange set device_owner', function(){ + var $ctrl = $isolateScope.$ctrl; + $ctrl.searchTextChange('device_owner_01'); + + expect($scope.resource.device_owner).toEqual('device_owner_01'); + }); + + it('selectedItemChange set device_owner', function(){ + var $ctrl = $isolateScope.$ctrl; + $ctrl.selectedItemChange({display: 'device_owner_01'}); + + expect($scope.resource.device_owner).toEqual('device_owner_01'); + }); + + it('querySearch set device_owner', function(){ + var $ctrl = $isolateScope.$ctrl; + var retValue = $ctrl.querySearch(''); + + expect(retValue.length).toEqual(3); + + retValue = $ctrl.querySearch('network:dhcp'); + + expect(retValue).toEqual([ { value: 'network_dhcp', display: 'network:dhcp' }]); + }); + }); + +})(); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__router/os__neutron__router.html b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__router/os__neutron__router.html index 97f37299..002529fa 100644 --- a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__router/os__neutron__router.html +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__router/os__neutron__router.html @@ -1,5 +1,5 @@ - + diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__router/os__neutron__router.spec.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__router/os__neutron__router.spec.js new file mode 100644 index 00000000..42546b74 --- /dev/null +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__router/os__neutron__router.spec.js @@ -0,0 +1,99 @@ +(function() { + 'use strict'; + + describe('component os-neutron-router', function(){ + + beforeEach(module('horizon.dashboard.project.heat_dashboard.template_generator')); + + beforeEach(module('appTemplates')); + + var $scope, $isolateScope, $compile; + var hotgenGlobals; + var element; + + beforeEach(inject(function($injector) { + $scope = $injector.get('$rootScope').$new(); + $compile = $injector.get('$compile'); + hotgenGlobals = $injector.get('hotgenGlobals'); + + hotgenGlobals.update_resource_options({ + networks: [{id: 'network1-id', name: 'network1-id'}], + subnets: [{id: 'subnet1-id', name: 'subnet-id'}] + }); + $scope.resource = {}; + $scope.dependson = []; + $scope.connectedoptions = []; + $scope.resourceForm = {}; + + // element will enable you to test your directive's element on the DOM + element = $compile(angular.element(''))($scope); + + // Digest needs to be called to set any values on the directive's scope + $scope.$digest(); + + $isolateScope = element.isolateScope(); + })); + + it('find tab title Properties', function() { + expect(element.find('span').html()).toContain("Properties"); + }); + + it('find tab title with no connectedoptions set', function() { + element = $compile(angular.element(''))($scope); + + $scope.$digest(); + $isolateScope = element.isolateScope(); + + expect(element.find('span').html()).toContain("Properties"); + }); + + it('find tab title with connectedoptions set', function(){ + $scope.resource = {'external_gateway_info.network': 'network-id', + 'ext_fixed_ips.subnet': ['subnet-id'],} + $scope.connectedoptions = {'external_gateway_info.network': [{value: 'network-id'}], + 'ext_fixed_ips.subnet': [{value: 'subnet-id'}], + }; + element = $compile(angular.element(''))($scope); + $scope.$digest(); + $isolateScope = element.isolateScope(); + + expect(element.find('span').html()).toContain("Properties"); + }); + + it('value_spec should be successfully added', function() { + var $ctrl = $isolateScope.$ctrl; + $ctrl.add_value_specs(); + + expect($scope.resource.value_specs.length).toEqual(2); + }); + + it('value_spec should be successfully deleted', function() { + var $ctrl = $isolateScope.$ctrl; + $ctrl.delete_value_specs(); + + expect($scope.resource.value_specs.length).toEqual(0); + }); + + it('external_fixed_ip should be successfully added', function() { + var $ctrl = $isolateScope.$ctrl; + $ctrl.add_external_fixed_ip(); + + expect($scope.resource.external_gateway_info.external_fixed_ips.length).toEqual(2); + }); + + it('external_fixed_ip should be successfully deleted', function() { + var $ctrl = $isolateScope.$ctrl; + $ctrl.delete_external_fixed_ip(); + + expect($scope.resource.external_gateway_info.external_fixed_ips.length).toEqual(0); + }); + + }); + +})(); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__routerinterface/os__neutron__routerinterface.html b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__routerinterface/os__neutron__routerinterface.html index 5dc9d7ad..f3582403 100644 --- a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__routerinterface/os__neutron__routerinterface.html +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__routerinterface/os__neutron__routerinterface.html @@ -1,5 +1,5 @@ - +

{$ $ctrl.message $}

diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__routerinterface/os__neutron__routerinterface.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__routerinterface/os__neutron__routerinterface.js index 6b9baabc..12405d03 100644 --- a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__routerinterface/os__neutron__routerinterface.js +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__routerinterface/os__neutron__routerinterface.js @@ -131,7 +131,7 @@ } return $scope.options.routers; } - }; + } osNeutronRouterInterfaceController.$inject = ['$scope', 'hotgenGlobals', ]; osNeutronRouterInterfacePath.$inject = ['horizon.dashboard.project.heat_dashboard.template_generator.basePath']; diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__routerinterface/os__neutron__routerinterface.spec.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__routerinterface/os__neutron__routerinterface.spec.js new file mode 100644 index 00000000..007107c1 --- /dev/null +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__routerinterface/os__neutron__routerinterface.spec.js @@ -0,0 +1,75 @@ +(function() { + 'use strict'; + + describe('component os-neutron-routerinterface', function(){ + + beforeEach(module('horizon.dashboard.project.heat_dashboard.template_generator')); + + beforeEach(module('appTemplates')); + + var $scope, $isolateScope, $compile; + var hotgenGlobals; + var element; + + beforeEach(inject(function($injector) { + $scope = $injector.get('$rootScope').$new(); + $compile = $injector.get('$compile'); + hotgenGlobals = $injector.get('hotgenGlobals'); + + hotgenGlobals.update_resource_options({ + routers: [{id: 'router1-id', name: 'router1-id'}], + subnets: [{id: 'subnet1-id', name: 'subnet1-id'}], + ports: [{id: 'port1-id', name: 'port1-id'}], + }); + $scope.resource = {}; + $scope.dependson = []; + $scope.connectedoptions = []; + $scope.resourceForm = {}; + + // element will enable you to test your directive's element on the DOM + element = $compile(angular.element(''+ + ''))($scope); + + // Digest needs to be called to set any values on the directive's scope + $scope.$digest(); + + $isolateScope = element.isolateScope(); + })); + + it('find tab title Properties', function() { + expect(element.find('span').html()).toContain("Properties"); + }); + + it('find tab title with no connectedoptions set', function() { + element = $compile(angular.element(''+ + ''))($scope); + $scope.$digest(); + $isolateScope = element.isolateScope(); + + expect(element.find('span').html()).toContain("Properties"); + }); + + it('find tab title with connectedoptions set', function(){ + $scope.resource = {port: 'port-id', + subnet: 'subnet-id', + router: 'router-id'} + $scope.connectedoptions = {port: [{value: 'port-id'}], + subnet: [{value: 'subnet-id'}], + router: [{value: 'router-id'}], + }; + element = $compile(angular.element(''+ + ''))($scope); + $scope.$digest(); + $isolateScope = element.isolateScope(); + + expect(element.find('span').html()).toContain("Properties"); + }); + }); + +})(); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__securitygroup/os__neutron__securitygroup.html b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__securitygroup/os__neutron__securitygroup.html index ad609974..581a7200 100644 --- a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__securitygroup/os__neutron__securitygroup.html +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__securitygroup/os__neutron__securitygroup.html @@ -1,5 +1,5 @@ - + diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__securitygroup/os__neutron__securitygroup.spec.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__securitygroup/os__neutron__securitygroup.spec.js new file mode 100644 index 00000000..534d1a8c --- /dev/null +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__securitygroup/os__neutron__securitygroup.spec.js @@ -0,0 +1,62 @@ +(function() { + 'use strict'; + + describe('component os-neutron-security-group', function(){ + + beforeEach(module('horizon.dashboard.project.heat_dashboard.template_generator')); + + beforeEach(module('appTemplates')); + + var $scope, $isolateScope, $compile; + var element; + + beforeEach(inject(function($injector) { + $scope = $injector.get('$rootScope').$new(); + $compile = $injector.get('$compile'); + + $scope.resource = {}; + $scope.dependson = []; + $scope.resourceForm = {}; + + // element will enable you to test your directive's element on the DOM + element = $compile(angular.element(''))($scope); + + // Digest needs to be called to set any values on the directive's scope + $scope.$digest(); + + $isolateScope = element.isolateScope(); + })); + + it('find tab title Properties', function() { + expect(element.find('span').html()).toContain("Properties"); + }); + + it('find tab title Properties with rules undefined', function() { + $scope.resource = {rules: []} + element = $compile(angular.element(''))($scope); + $scope.$digest(); + $isolateScope = element.isolateScope(); + + expect(element.find('span').html()).toContain("Properties"); + }); + + it('rules should be successfully added', function() { + var $ctrl = $isolateScope.$ctrl; + $ctrl.add_rule(); + + expect($scope.resource.rules.length).toEqual(2); + }); + + it('rules should be successfully deleted', function() { + var $ctrl = $isolateScope.$ctrl; + $ctrl.delete_rule(); + + expect($scope.resource.rules.length).toEqual(0); + }); + }); + +})(); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__subnet/os__neutron__subnet.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__subnet/os__neutron__subnet.js index 43e1c005..171d6ba0 100644 --- a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__subnet/os__neutron__subnet.js +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__subnet/os__neutron__subnet.js @@ -92,7 +92,7 @@ this.subnet.host_routes.splice(index, 1) } $scope.validate_dns = function (input_string){ - var re = /^.*$/; + var re = /^[A-Za-z0-9_.-]+$/; var match = re.exec(input_string); if (match){ return input_string; diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__subnet/os__neutron__subnet.spec.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__subnet/os__neutron__subnet.spec.js new file mode 100644 index 00000000..e50c115c --- /dev/null +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__neutron__subnet/os__neutron__subnet.spec.js @@ -0,0 +1,100 @@ +(function() { + 'use strict'; + + describe('component os-neutron-subnet', function(){ + + beforeEach(module('horizon.dashboard.project.heat_dashboard.template_generator')); + + beforeEach(module('appTemplates')); + + var $scope, $isolateScope, $compile; + var hotgenGlobals; + var element; + + beforeEach(inject(function($injector) { + $scope = $injector.get('$rootScope').$new(); + $compile = $injector.get('$compile'); + hotgenGlobals = $injector.get('hotgenGlobals'); + hotgenGlobals.update_resource_options({ + networks: [{id: 'network1-id', name: 'network1-id'}], + }); + + $scope.resource = {}; + $scope.dependson = []; + $scope.connectedoptions = []; + $scope.resourceForm = {}; + + // element will enable you to test your directive's element on the DOM + element = $compile(angular.element(''))($scope); + + // Digest needs to be called to set any values on the directive's scope + $scope.$digest(); + + $isolateScope = element.isolateScope(); + })); + + it('find tab title Properties', function() { + expect(element.find('span').html()).toContain("Basic"); + }); + + it('find tab title with no connectedoptions set', function() { + element = $compile(angular.element(''))($scope); + + $scope.$digest(); + $isolateScope = element.isolateScope(); + + expect(element.find('span').html()).toContain("Basic"); + }); + + it('find tab title with connectedoptions set', function(){ + $scope.resource = {network: 'network-id',} + $scope.connectedoptions = {network: [{value: 'network-id'}]}; + element = $compile(angular.element(''))($scope); + + $scope.$digest(); + $isolateScope = element.isolateScope(); + + expect(element.find('span').html()).toContain("Basic"); + }); + + it('allocation_pool should be successfully added', function() { + var $ctrl = $isolateScope.$ctrl; + $ctrl.add_allocation_pool(); + + expect($scope.resource.allocation_pools.length).toEqual(2); + }); + + it('allocation_pool should be successfully deleted', function() { + var $ctrl = $isolateScope.$ctrl; + $ctrl.delete_allocation_pool(); + + expect($scope.resource.allocation_pools.length).toEqual(0); + }); + + it('hostroute should be successfully added', function() { + var $ctrl = $isolateScope.$ctrl; + $ctrl.add_hostroute(); + + expect($scope.resource.host_routes.length).toEqual(2); + }); + + it('hostroute should be successfully deleted', function() { + var $ctrl = $isolateScope.$ctrl; + $ctrl.delete_hostroute(); + + expect($scope.resource.host_routes.length).toEqual(0); + }); + + it('validate dns', function() { + expect( $isolateScope.validate_dns('@')).toEqual(null); + expect( $isolateScope.validate_dns('8.8.8.8')).toEqual('8.8.8.8'); + }); + }); + +})(); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__keypair/os__nova__keypair.html b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__keypair/os__nova__keypair.html index 939567d2..009014f4 100644 --- a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__keypair/os__nova__keypair.html +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__keypair/os__nova__keypair.html @@ -1,5 +1,5 @@ - + diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__keypair/os__nova__keypair.spec.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__keypair/os__nova__keypair.spec.js new file mode 100644 index 00000000..81158b62 --- /dev/null +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__keypair/os__nova__keypair.spec.js @@ -0,0 +1,39 @@ +(function() { + 'use strict'; + + describe('component os-nova-keypair', function(){ + + beforeEach(module('horizon.dashboard.project.heat_dashboard.template_generator')); + + beforeEach(module('appTemplates')); + + var $scope, $isolateScope, $compile; + var hotgenGlobals; + var element; + + beforeEach(inject(function($injector) { + $scope = $injector.get('$rootScope').$new(); + $compile = $injector.get('$compile'); + + $scope.resource = {}; + $scope.dependson = []; + $scope.resourceForm = {}; + + // element will enable you to test your directive's element on the DOM + element = $compile(angular.element(''+ + ''))($scope); + + // Digest needs to be called to set any values on the directive's scope + $scope.$digest(); + + $isolateScope = element.isolateScope(); + })); + + it('find tab title Properties', function() { + expect(element.find('span').html()).toContain("Properties"); + }); + + }); + +})(); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__server/os__nova__server.html b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__server/os__nova__server.html index 22e5ec56..0a883520 100644 --- a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__server/os__nova__server.html +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__server/os__nova__server.html @@ -1,5 +1,5 @@ - + diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__server/os__nova__server.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__server/os__nova__server.js index 1a5ce7bd..4841b8f9 100644 --- a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__server/os__nova__server.js +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__server/os__nova__server.js @@ -76,13 +76,13 @@ osNovaServerSettings.resource_key, osNovaServerSettings.modal_component); - for (var i in osNovaServerSettings.edge_settings){ - if (osNovaServerSettings.edge_settings[i].modal){ - hotgenGlobals.update_resource_components( - osNovaServerSettings.resource_key+'_'+i, - osNovaServerSettings.edge_settings[i].modal); - } - } +// for (var i in osNovaServerSettings.edge_settings){ +// if (osNovaServerSettings.edge_settings[i].modal){ +// hotgenGlobals.update_resource_components( +// osNovaServerSettings.resource_key+'_'+i, +// osNovaServerSettings.edge_settings[i].modal); +// } +// } hotgenGlobals.update_edge_directions( osNovaServerSettings.resource_key, @@ -109,9 +109,6 @@ if (typeof this.instance.personality === 'undefined'){ this.instance.personality = [{}]; } - if (typeof this.instance.scheduler_hints === 'undefined'){ - this.instance.scheduler_hints = []; - } if (typeof this.instance.block_device_mapping === 'undefined'){ this.instance.block_device_mapping = []; } @@ -123,7 +120,7 @@ } if (typeof this.instance.networks === 'undefined'){ this.instance.networks = [{}]; - }; + } this.disable = { 'key_name': false, @@ -303,7 +300,7 @@ $scope.show_passwd_type = "password"; $scope.bdpv2_source = {}; // Mark the source selected of every block_device_mapping_v2 item. $scope.how2config_networks = {} - $scope.update_boot_source = function(index){ + $scope.update_boot_source = function(){ if ($scope.boot_source == 'image'){ this.$ctrl.instance.image_snapshot = null; this.$ctrl.instance.volume = null; diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__server/os__nova__server.spec.js b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__server/os__nova__server.spec.js new file mode 100644 index 00000000..540568d9 --- /dev/null +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/os__nova__server/os__nova__server.spec.js @@ -0,0 +1,308 @@ +(function() { + 'use strict'; + + describe('component os-nova-server', function(){ + + beforeEach(module('horizon.dashboard.project.heat_dashboard.template_generator')); + + beforeEach(module('appTemplates')); + + var $scope, $isolateScope, $compile; + var hotgenGlobals, hotgenUtils; + var element; + + beforeEach(inject(function($injector) { + $scope = $injector.get('$rootScope').$new(); + $compile = $injector.get('$compile'); + hotgenGlobals = $injector.get('hotgenGlobals'); + hotgenUtils = $injector.get('hotgenUtils'); + hotgenGlobals.update_resource_options({ + networks: [{id: 'network1-id', name: 'network1-id'}], + subnets: [{id: 'subnet1-id', name: 'subnet1-id'}], + ports: [{id: 'port1-id', name: 'port1-id'}], + volumes: [{id: 'volume1-id', name: 'volume1-id'}], + floatingips: [{id: 'ipaddress', name: 'ipaddress'}], + security_groups: [{id: 'secgroup-id1', name: 'secgroup-id1'}], + keypairs: [{id: 'keyname1', name: 'keyname1'}], + }); + + $scope.resource = {}; + $scope.dependson = []; + $scope.connectedoptions = []; + $scope.resourceForm = {}; + + // element will enable you to test your directive's element on the DOM + element = $compile(angular.element(''))($scope); + + // Digest needs to be called to set any values on the directive's scope + $scope.$digest(); + + $isolateScope = element.isolateScope(); + })); + + it('find tab title Properties', function() { + expect(element.find('span').html()).toContain("Basic"); + }); + + it('find tab title with no connectedoptions set', function() { + element = $compile(angular.element(''))($scope); + + $scope.$digest(); + $isolateScope = element.isolateScope(); + + expect(element.find('span').html()).toContain("Basic"); + }); + + it('find tab title with connectedoptions set', function(){ + $scope.resource = {image: 'image-id', key_name: 'keyname', + security_groups: ['secgroup-01'], + block_device_mapping_v2: [ + {volume_id: '{ get_resource: vol01 }'}, + {image: 'image-id'}, {image: '{ get_resource: image01 }'}, + {snapshot_id: 'snapshot-id'}, + {ignore: 'ignore'} + ], + networks: [{network: '{ get_resource: network01 }'}, + {subnet: '{ get_resource: subnet01 }'}, + {port: '{ get_resource: port01 }'}, + {floating_ip: '{ get_resource: floatingip01 }'}, + {ignore: 'ignore'} + ], + } + $scope.connectedoptions = { + 'networks.network': [{value: 'network-id'}, {value: '{ get_resource: network01 }'}], + 'networks.subnet': [{value: 'subnet-id'}, {value: '{ get_resource: subnet01 }'}], + 'networks.port': [{value: 'port-id'}, {value: '{ get_resource: port01 }'}], + 'networks.floating_ip': [{value: 'floatingip'}, {value: '{ get_resource: floatingip01 }'}], + key_name: 'keyname', + security_groups: [{value: 'secgroup-id'}], + 'block_device_mapping_v2.volume_id': [{value: 'volume-id'}, + {value: '{ get_resource: vol01 }'}], + } + element = $compile(angular.element(''))($scope); + + $scope.$digest(); + $isolateScope = element.isolateScope(); + $isolateScope.update_boot_source(); + for (var i in $scope.resource.block_device_mapping_v2){ + $isolateScope.update_source(i); + } + for (var i in $scope.resource.networks){ + $isolateScope.update_nwconfig(i); + } + + expect(element.find('span').html()).toContain("Basic"); + }); + + + it('find tab title with connectedoptions set with error', function(){ + $scope.resource = {image: 'image-id', key_name: 'keyname', + security_groups: ['secgroup-01'], + block_device_mapping_v2: [ + {volume_id: '{ get_resource: vol01 }'}, + {image: 'image-id'}, {image: '{ get_resource: image01 }'}, + {snapshot_id: 'snapshot-id'}, + {ignore: 'ignore'} + ], + networks: [{network: '{ get_resource: network01 }'}, + {subnet: '{ get_resource: subnet01 }'}, + {port: '{ get_resource: port01 }'}, + {floating_ip: '{ get_resource: floatingip01 }'} + ], + } + $scope.connectedoptions = { + 'networks.network': [{value: 'network-id'}, {value: '{ get_resource: network01 }'}], + 'networks.subnet': [{value: 'subnet-id'}, {value: '{ get_resource: subnet01 }'}], + 'networks.port': [{value: 'port-id'}, {value: '{ get_resource: port01 }'}], + 'networks.floating_ip': [{value: 'floatingip'}, {value: '{ get_resource: floatingip01 }'}], + key_name: 'keyname', + security_groups: [{value: 'secgroup-id'}], + 'block_device_mapping_v2.volume_id': [{value: 'volume-id'}, + {value: '{ get_resource: vol01 }'}], + } + spyOn(hotgenUtils, 'filter_and_return_get_resource_element').and.callFake(function(){ + return [{}] + }); + element = $compile(angular.element(''))($scope); + + $scope.$digest(); + $isolateScope = element.isolateScope(); + + expect(element.find('span').html()).toContain("Basic"); + }); + + it('find tab title with boot from image snapshot', function(){ + $scope.resource = {image_snapshot: 'image-id'} + element = $compile(angular.element(''))($scope); + + $scope.$digest(); + $isolateScope = element.isolateScope(); + $isolateScope.update_boot_source(); + + expect(element.find('span').html()).toContain("Basic"); + }); + + it('find tab title with boot from volume ', function(){ + $scope.resource = {volume: 'vol-id'} + element = $compile(angular.element(''))($scope); + + $scope.$digest(); + $isolateScope = element.isolateScope(); + $isolateScope.update_boot_source(); + + expect(element.find('span').html()).toContain("Basic"); + }); + + it('find tab title with boot from volume snapshot', function(){ + $scope.resource = {volume_snapshot: 'vol-id'} + element = $compile(angular.element(''))($scope); + + $scope.$digest(); + $isolateScope = element.isolateScope(); + $isolateScope.update_boot_source(); + + expect(element.find('span').html()).toContain("Basic"); + }); + + it('find tab title with boot from nothing ', function(){ + $scope.resource = {ignore: 'nothing'} + element = $compile(angular.element(''))($scope); + + $scope.$digest(); + $isolateScope = element.isolateScope(); + $isolateScope.update_boot_source(); + + expect(element.find('span').html()).toContain("Basic"); + }); + + it('$scope.show_passwd should be successfully watched', function() { + $isolateScope.show_passwd = true; + $isolateScope.$digest(); + + expect($isolateScope.show_passwd_type).toEqual('text'); + + $isolateScope.show_passwd = false; + $isolateScope.$digest(); + + expect($isolateScope.show_passwd_type).toEqual('password'); + }); + + it('metadata should be successfully added', function() { + var $ctrl = $isolateScope.$ctrl; + $ctrl.add_metadata(); + + expect($scope.resource.metadata.length).toEqual(2); + }); + + it('metadata should be successfully deleted', function() { + var $ctrl = $isolateScope.$ctrl; + $ctrl.delete_metadata(); + + expect($scope.resource.metadata.length).toEqual(0); + }); + + it('personality should be successfully added', function() { + var $ctrl = $isolateScope.$ctrl; + $ctrl.add_personality(); + + expect($scope.resource.personality.length).toEqual(2); + }); + + it('personality should be successfully deleted', function() { + var $ctrl = $isolateScope.$ctrl; + $ctrl.delete_personality(); + + expect($scope.resource.personality.length).toEqual(0); + }); + + it('block_device_mapping should be successfully added', function() { + var $ctrl = $isolateScope.$ctrl; + $ctrl.add_block_device_mapping(); + + expect($scope.resource.block_device_mapping.length).toEqual(1); + }); + + it('block_device_mapping should be successfully deleted', function() { + var $ctrl = $isolateScope.$ctrl; + $ctrl.add_block_device_mapping(); + $ctrl.delete_block_device_mapping(0); + + expect($scope.resource.block_device_mapping.length).toEqual(0); + }); + + it('block_device_mapping_v2 should be successfully added', function() { + var $ctrl = $isolateScope.$ctrl; + $ctrl.add_block_device_mapping_v2(); + + expect($scope.resource.block_device_mapping_v2.length).toEqual(1); + }); + + it('block_device_mapping_v2 should be successfully deleted', function() { + $scope.resource = {block_device_mapping_v2: [{volume_id: 'vol-01'}]} + element = $compile(angular.element(''))($scope); + + $scope.$digest(); + $isolateScope = element.isolateScope(); + + var $ctrl = $isolateScope.$ctrl; + $ctrl.delete_block_device_mapping_v2(0); + + expect($scope.resource.block_device_mapping_v2.length).toEqual(0); + }); + + it('networks should be successfully added', function() { + var $ctrl = $isolateScope.$ctrl; + $ctrl.add_networks(); + + expect($scope.resource.networks.length).toEqual(2); + }); + + it('networks should be successfully deleted', function() { + $scope.resource = {networks: [{network: 'network-01'}]}; + element = $compile(angular.element(''))($scope); + + $scope.$digest(); + $isolateScope = element.isolateScope(); + + var $ctrl = $isolateScope.$ctrl; + $ctrl.delete_networks(0); + + expect($scope.resource.networks.length).toEqual(0); + }); + + it('scheduler_hints should be successfully added', function() { + var $ctrl = $isolateScope.$ctrl; + $ctrl.add_scheduler_hints(); + + expect($scope.resource.scheduler_hints.length).toEqual(2); + }); + + it('scheduler_hints should be successfully deleted', function() { + var $ctrl = $isolateScope.$ctrl; + $ctrl.delete_scheduler_hints(); + + expect($scope.resource.scheduler_hints.length).toEqual(0); + }); + }); + +})(); diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/templates/depends_on.html b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/templates/depends_on.html index 2cfe7377..f278b915 100644 --- a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/templates/depends_on.html +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/templates/depends_on.html @@ -9,8 +9,10 @@ - - - {{ node.label }} - - +
+ + + {{ node.label }} + + +
\ No newline at end of file diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/templates/modal_edge.html b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/templates/modal_edge.html index e625ef7f..5605c4c5 100644 --- a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/templates/modal_edge.html +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/templates/modal_edge.html @@ -14,22 +14,18 @@ FROM - - - -
+ +

{$ from_type $}

{$ from_node.id $}

-
+
TO - - - +

{$ to_type $}

{$ to_node.id $}

diff --git a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/templates/modal_template.html b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/templates/modal_template.html index afe41a5d..cbbecc44 100644 --- a/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/templates/modal_template.html +++ b/heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/templates/modal_template.html @@ -9,20 +9,18 @@
+ -
-
- - - - -
-
- {$ template.content $} -
-
+
+ {$ warning | translate $} + + + + + +
diff --git a/karma.conf.js b/karma.conf.js new file mode 100644 index 00000000..c71a2052 --- /dev/null +++ b/karma.conf.js @@ -0,0 +1,100 @@ +// Karma configuration +// Generated on Fri Oct 06 2017 11:56:14 GMT+0900 (JST) + +module.exports = function(config) { + config.set({ + + // base path that will be used to resolve all patterns (eg. files, exclude) + basePath: '', + + + // frameworks to use + // available frameworks: https://npmjs.org/browse/keyword/karma-adapter + frameworks: ['jasmine'], + + + // list of files / patterns to load in the browser + files: [ + 'node_modules/angular/angular.min.js', + 'node_modules/angular-ui-router/release/angular-ui-router.min.js', + 'node_modules/angular-mocks/angular-mocks.js', + 'heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/vendors/*.js', + 'heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/*.module.js', + 'heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/!(*.spec|*.module).js', + 'heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/*.spec.js', + 'heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/*/!(*.spec).js', + 'heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/*/*.spec.js', + 'heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/templates/*.html', + 'heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/*/*.html', + 'heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/img/icons/*.svg', + ], + + + // list of files to exclude + exclude: [ + ], + + + // preprocess matching files before serving them to the browser + // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor + preprocessors: { + 'heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/components/!(*.spec).js': 'coverage', + 'heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/*/!(*.spec).js': 'coverage', + 'heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/templates/*.html': ['ng-html2js'], + 'heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/resources/*/*.html': ['ng-html2js'], + 'heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/css/img/icons/*.svg': ['ng-html2js'], + }, + + ngHtml2JsPreprocessor: { +// stripPrefix: './heat_dashboard/static/', +// prependPrefix: 'undefined', + cacheIdFromPath: function(filepath) { + var cacheId; + if (filepath.indexOf('.svg') != -1){ + cacheId = filepath.replace('heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/', '{$ basePath $}'); + } else if (filepath.indexOf('.html') != -1){ + cacheId = filepath.replace('heat_dashboard/static/', 'undefined'); + } + console.log(filepath) + return cacheId; + }, + + moduleName: 'appTemplates', + }, + + // test results reporter to use + // possible values: 'dots', 'progress' + // available reporters: https://npmjs.org/browse/keyword/karma-reporter + reporters: ['progress', 'coverage'], + + // web server port + port: 9876, + + + // enable / disable colors in the output (reporters and logs) + colors: true, + + + // level of logging + // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG + logLevel: config.LOG_INFO, + + + // enable / disable watching file and executing tests whenever any file changes + autoWatch: true, + + + // start these browsers + // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher + browsers: ['Chrome', ], + + + // Continuous Integration mode + // if true, Karma captures browsers, runs the tests and exits + singleRun: false, + + // Concurrency level + // how many browser should be started simultaneous + concurrency: Infinity + }) +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..028e6d1a --- /dev/null +++ b/package.json @@ -0,0 +1,33 @@ +{ + "name": "heat-dashboard", + "version": "0.0.0", + "description": "OpenStack Heat Dashboard - Angular", + "main": "karma.conf.js", + "directories": { + "doc": "doc" + }, + "dependencies": { + "angular-ui-router": "0.4.3", + "angular-mocks": "1.5.8", + "angular": "1.5.8", + "jasmine": "2.8.0", + "jasmine-core": "2.8.0", + "karma-coverage": "1.1.1", + "karma-jasmine": "1.1.0", + "karma-firefox-launcher": "1.0.1", + "karma-chrome-launcher": "2.2.0", + "karma-ng-html2js-preprocessor": "1.0.0", + "karma": "1.7.1" + }, + "devDependencies": { + "eslint": "4.9.0", + "eslint-plugin-angular": "3.1.1", + "eslint-plugin-jasmine": "2.9.1" + }, + "scripts": { + "test": "karma start karma.conf.js --single-run", + "eslint": "eslint --no-color heat_dashboard/static/dashboard/project/heat_dashboard/template_generator/js/" + }, + "author": "", + "license": "Apache-2.0" +}