Repository: ambari Updated Branches: refs/heads/trunk 842f2d44d -> 5831b8dd7
AMBARI-6009 Usability: provide database connectivity checks in Customize Services page. (Buzhor Denys via ababiichuk) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/5831b8dd Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/5831b8dd Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/5831b8dd Branch: refs/heads/trunk Commit: 5831b8dd717c684a9edd0ea37bb78ab4456536e0 Parents: 842f2d4 Author: aBabiichuk <[email protected]> Authored: Tue Jun 3 18:36:50 2014 +0300 Committer: aBabiichuk <[email protected]> Committed: Tue Jun 3 18:42:22 2014 +0300 ---------------------------------------------------------------------- ambari-web/app/assets/test/tests.js | 1 + ambari-web/app/config.js | 3 +- .../controllers/global/cluster_controller.js | 3 +- .../app/controllers/wizard/step7_controller.js | 71 +++- ambari-web/app/data/HDP2/global_properties.js | 13 +- ambari-web/app/data/HDP2/site_properties.js | 10 +- ambari-web/app/messages.js | 10 + ambari-web/app/models/cluster_states.js | 1 + ambari-web/app/models/service_config.js | 6 + ambari-web/app/styles/application.less | 32 ++ .../templates/common/configs/service_config.hbs | 3 + .../app/templates/common/error_log_body.hbs | 33 ++ .../common/form/check_db_connection.hbs | 33 ++ ambari-web/app/utils/ajax/ajax.js | 34 ++ ambari-web/app/utils/db.js | 8 +- ambari-web/app/utils/helper.js | 19 + ambari-web/app/views/wizard/controls_view.js | 338 +++++++++++++++ ambari-web/test/utils/helper_test.js | 31 ++ .../test/views/wizard/controls_view_test.js | 406 +++++++++++++++++++ 19 files changed, 1040 insertions(+), 15 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/5831b8dd/ambari-web/app/assets/test/tests.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/assets/test/tests.js b/ambari-web/app/assets/test/tests.js index 8132f29..711047b 100644 --- a/ambari-web/app/assets/test/tests.js +++ b/ambari-web/app/assets/test/tests.js @@ -161,6 +161,7 @@ require('test/views/main/charts/heatmap/heatmap_rack_test'); require('test/views/main/service/info/config_test'); require('test/views/main/mirroring/edit_dataset_view_test'); require('test/views/common/configs/services_config_test'); +require('test/views/wizard/controls_view_test'); require('test/views/wizard/step3/hostLogPopupBody_view_test'); require('test/views/wizard/step3/hostWarningPopupBody_view_test'); require('test/views/wizard/step3/hostWarningPopupFooter_view_test'); http://git-wip-us.apache.org/repos/asf/ambari/blob/5831b8dd/ambari-web/app/config.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/config.js b/ambari-web/app/config.js index 4709a6f..8590bd5 100644 --- a/ambari-web/app/config.js +++ b/ambari-web/app/config.js @@ -77,7 +77,8 @@ App.supports = { jobs: true, ubuntu: false, views: false, - flume: false + flume: false, + databaseConnection: true }; if (App.enableExperimental) { http://git-wip-us.apache.org/repos/asf/ambari/blob/5831b8dd/ambari-web/app/controllers/global/cluster_controller.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers/global/cluster_controller.js b/ambari-web/app/controllers/global/cluster_controller.js index a1565e0..0524195 100644 --- a/ambari-web/app/controllers/global/cluster_controller.js +++ b/ambari-web/app/controllers/global/cluster_controller.js @@ -437,13 +437,12 @@ App.ClusterController = Em.Controller.extend({ }, loadAmbariProperties: function () { - App.ajax.send({ + return App.ajax.send({ name: 'ambari.service', sender: this, success: 'loadAmbariPropertiesSuccess', error: 'loadAmbariPropertiesError' }); - return this.get('ambariProperties'); }, loadAmbariPropertiesSuccess: function (data) { http://git-wip-us.apache.org/repos/asf/ambari/blob/5831b8dd/ambari-web/app/controllers/wizard/step7_controller.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers/wizard/step7_controller.js b/ambari-web/app/controllers/wizard/step7_controller.js index e365fde..e0b4e6d 100644 --- a/ambari-web/app/controllers/wizard/step7_controller.js +++ b/ambari-web/app/controllers/wizard/step7_controller.js @@ -986,6 +986,7 @@ App.WizardStep7Controller = Em.Controller.extend({ var hiveService = this.get('content.services').findProperty('serviceName', 'HIVE'); if (!hiveService || !hiveService.get('isSelected') || hiveService.get('isInstalled')) { this.moveNext(); + return; } var hiveDBType = this.get('stepConfigs').findProperty('serviceName', 'HIVE').configs.findProperty('name', 'hive_database').value; if (hiveDBType == 'New MySQL Database') { @@ -1025,6 +1026,71 @@ App.WizardStep7Controller = Em.Controller.extend({ } }, + checkDatabaseConnectionTest: function() { + var deferred = $.Deferred(); + if (!App.supports.databaseConnection) { + deferred.resolve(); + return deferred; + } + var configMap = [ + { + serviceName: 'OOZIE', + ignored: Em.I18n.t('installer.step7.oozie.database.new') + }, + { + serviceName: 'HIVE', + ignored: Em.I18n.t('installer.step7.hive.database.new') + } + ]; + configMap.forEach(function(config) { + var isConnectionNotTested = false; + var service = this.get('content.services').findProperty('serviceName', config.serviceName); + if (service && service.get('isSelected') && !service.get('isInstalled')) { + var serviceConfigs = this.get('stepConfigs').findProperty('serviceName', config.serviceName).configs; + var serviceDatabase = serviceConfigs.findProperty('name', config.serviceName.toLowerCase() + '_database').get('value'); + if (serviceDatabase !== config.ignored) { + var filledProperties = App.db.get('tmp', config.serviceName + '_connection'); + if (!filledProperties || App.isEmptyObject(filledProperties)) { + isConnectionNotTested = true; + } else { + for (var key in filledProperties) { + if (serviceConfigs.findProperty('name', key).get('value') !== filledProperties[key]) + isConnectionNotTested = true; + } + } + } + } + config.isCheckIgnored = isConnectionNotTested; + }, this); + var ignoredServices = configMap.filterProperty('isCheckIgnored', true); + if (ignoredServices.length) { + var displayedServiceNames = ignoredServices.mapProperty('serviceName').map(function(serviceName) { + return this.get('content.services').findProperty('serviceName', serviceName).get('displayName'); + }, this); + this.showDatabaseConnectionWarningPopup(displayedServiceNames, deferred); + } + else { + deferred.resolve(); + } + return deferred; + }, + + showDatabaseConnectionWarningPopup: function(serviceNames, deferred) { + return App.ModalPopup.show({ + header: Em.I18n.t('installer.step7.popup.database.connection.header'), + body: Em.I18n.t('installer.step7.popup.database.connection.body').format(serviceNames.join(', ')), + secondary: Em.I18n.t('common.cancel'), + primary: Em.I18n.t('common.proceedAnyway'), + onPrimary: function() { + deferred.resolve(); + this._super(); + }, + onSecondary: function() { + deferred.reject(); + this._super(); + } + }) + }, /** * Proceed to the next step **/ @@ -1037,8 +1103,11 @@ App.WizardStep7Controller = Em.Controller.extend({ * @method submit */ submit: function () { + var _this = this; if (!this.get('isSubmitDisabled')) { - this.resolveHiveMysqlDatabase(); + this.checkDatabaseConnectionTest().done(function() { + _this.resolveHiveMysqlDatabase(); + }); } } http://git-wip-us.apache.org/repos/asf/ambari/blob/5831b8dd/ambari-web/app/data/HDP2/global_properties.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/data/HDP2/global_properties.js b/ambari-web/app/data/HDP2/global_properties.js index 0922c1e..567d035 100644 --- a/ambari-web/app/data/HDP2/global_properties.js +++ b/ambari-web/app/data/HDP2/global_properties.js @@ -1029,7 +1029,7 @@ module.exports = "isRequired": false, "serviceName": "OOZIE", "category": "Oozie Server", - "index": 7 + "index": 9 }, { "id": "puppet var", @@ -1057,9 +1057,10 @@ module.exports = "isVisible": false, "isObserved": true, "serviceName": "OOZIE", - "category": "Oozie Server" + "category": "Oozie Server", + "index": 3 }, - { + { "id": "puppet var", "name": "oozie_existing_postgresql_host", "displayName": "Database Host", @@ -1071,7 +1072,8 @@ module.exports = "isVisible": false, "isObserved": true, "serviceName": "OOZIE", - "category": "Oozie Server" + "category": "Oozie Server", + "index": 3 }, { "id": "puppet var", @@ -1085,7 +1087,8 @@ module.exports = "isVisible": false, "isObserved": true, "serviceName": "OOZIE", - "category": "Oozie Server" + "category": "Oozie Server", + "index": 3 }, { "id": "puppet var", http://git-wip-us.apache.org/repos/asf/ambari/blob/5831b8dd/ambari-web/app/data/HDP2/site_properties.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/data/HDP2/site_properties.js b/ambari-web/app/data/HDP2/site_properties.js index d86d01d..b2ecd8f 100644 --- a/ambari-web/app/data/HDP2/site_properties.js +++ b/ambari-web/app/data/HDP2/site_properties.js @@ -377,7 +377,7 @@ module.exports = "isObserved": true, "category": "Oozie Server", "serviceName": "OOZIE", - "index": 3 + "index": 4 }, { "id": "site property", @@ -387,7 +387,7 @@ module.exports = "displayType": "host", "category": "Oozie Server", "serviceName": "OOZIE", - "index": 4 + "index": 5 }, { "id": "site property", @@ -398,7 +398,7 @@ module.exports = "category": "Oozie Server", "serviceName": "OOZIE", "filename": "oozie-site.xml", - "index": 5 + "index": 6 }, { "id": "site property", @@ -407,7 +407,7 @@ module.exports = "isOverridable": false, "category": "Oozie Server", "serviceName": "OOZIE", - "index": 6 + "index": 7 }, { "id": "site property", @@ -417,7 +417,7 @@ module.exports = "displayType": "advanced", "category": "Oozie Server", "serviceName": "OOZIE", - "index": 7 + "index": 8 }, /**********************************************hive-site***************************************/ http://git-wip-us.apache.org/repos/asf/ambari/blob/5831b8dd/ambari-web/app/messages.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js index 8b3fd94..69bd3ab 100644 --- a/ambari-web/app/messages.js +++ b/ambari-web/app/messages.js @@ -172,6 +172,7 @@ Em.I18n.translations = { 'common.path': 'Path', 'common.package': 'Package', 'common.proceed': 'Proceed', + 'common.proceedAnyway': 'Proceed Anyway', 'common.process': 'Process', 'common.property': 'Property', 'common.installed': 'Installed', @@ -609,6 +610,11 @@ Em.I18n.translations = { 'installer.step7.popup.mySQLWarning.button.dismiss': 'Dismiss', 'installer.step7.popup.mySQLWarning.confirmation.header': 'Confirmation: Go to Assign Masters', 'installer.step7.popup.mySQLWarning.confirmation.body': 'You will be brought back to the \"Assign Masters\" step and will lose all your current customizations. Are you sure?', + 'installer.step7.popup.database.connection.header': 'Database Connectivity Warning', + 'installer.step7.popup.database.connection.body': 'You have not run the database connectivity check for {0}. It is recommended that you run the check before proceeding to prevent failures during deployment.', + + 'installer.step7.oozie.database.new': 'New Derby Database', + 'installer.step7.hive.database.new': 'New MySQL Database', 'installer.step8.header':'Review', 'installer.step8.body':'Please review the configuration before installation', @@ -1282,6 +1288,10 @@ Em.I18n.translations = { 'services.service.config.propertyFilterPopover.title':'Properties filter', 'services.service.config.propertyFilterPopover.content':'Enter keywords to filter properties by property name, value, or description.', 'services.service.config.hive.oozie.postgresql': 'Existing PostgreSQL Database', + 'services.service.config.database.connection.success': 'Connection OK', + 'services.service.config.database.connection.failed': 'Connection Failed', + 'services.service.config.database.btn.idle': 'Test Connection', + 'services.service.config.database.btn.connecting': 'Connecting...', 'services.add.header':'Add Service Wizard', 'services.reassign.header':'Move Master Wizard', http://git-wip-us.apache.org/repos/asf/ambari/blob/5831b8dd/ambari-web/app/models/cluster_states.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/models/cluster_states.js b/ambari-web/app/models/cluster_states.js index 320c3f4..9927e8d 100644 --- a/ambari-web/app/models/cluster_states.js +++ b/ambari-web/app/models/cluster_states.js @@ -191,6 +191,7 @@ App.clusterStatus = Em.Object.create(App.UserPref, { var login = App.db.getLoginName(); var val = {clusterName: this.get('clusterName')}; if (newValue) { + App.db.cleanTmp(); //setter if (newValue.clusterName) { this.set('clusterName', newValue.clusterName); http://git-wip-us.apache.org/repos/asf/ambari/blob/5831b8dd/ambari-web/app/models/service_config.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/models/service_config.js b/ambari-web/app/models/service_config.js index 8db9a19..fe42d10 100644 --- a/ambari-web/app/models/service_config.js +++ b/ambari-web/app/models/service_config.js @@ -170,6 +170,12 @@ App.ServiceConfigProperty = Ember.Object.extend({ editDone: false, //Text field: on focusOut: true, on focusIn: false serviceValidator: null, isNotSaved: false, // user property was added but not saved + /** + * Usage example see on <code>App.ServiceConfigRadioButtons.handleDBConnectionProperty()</code> + * + * @property {Ember.View} additionalView - custom view related to property + **/ + additionalView: null, /** * On Overridable property error message, change overrideErrorTrigger value to recount number of errors service have http://git-wip-us.apache.org/repos/asf/ambari/blob/5831b8dd/ambari-web/app/styles/application.less ---------------------------------------------------------------------- diff --git a/ambari-web/app/styles/application.less b/ambari-web/app/styles/application.less index 85dc6b0..d046f3f 100644 --- a/ambari-web/app/styles/application.less +++ b/ambari-web/app/styles/application.less @@ -1178,6 +1178,34 @@ h1 { .dropdown-menu > li > a:hover { text-shadow: none; } + .db-connection { + .spinner { + width: 30px; + height: 30px; + background-size: 30px 30px; + } + .icon-ok-sign, .icon-warning-sign { + font-size: 27px; + line-height: 30px; + } + .icon-ok-sign { + color: @health-status-green; + } + .icon-warning-sign { + color: @health-status-red; + } + .connection-result { + font-size: 15px; + line-height: 30px; + } + a.mute { + color: #333; + &:hover { + text-decoration: none; + color: #333; + } + } + } } .running-host-components-table{ @@ -6100,6 +6128,10 @@ i.icon-asterisks { margin-top: @space-m; } +.mll { + margin-left: @space-l; +} + #cleanerContainer { z-index: 2; position: absolute; http://git-wip-us.apache.org/repos/asf/ambari/blob/5831b8dd/ambari-web/app/templates/common/configs/service_config.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/common/configs/service_config.hbs b/ambari-web/app/templates/common/configs/service_config.hbs index 15c930a..c66181a 100644 --- a/ambari-web/app/templates/common/configs/service_config.hbs +++ b/ambari-web/app/templates/common/configs/service_config.hbs @@ -144,6 +144,9 @@ {{/if}} </div> </div> + {{#if this.additionalView}} + {{view additionalView}} + {{/if}} {{/each}} {{! For Advanced, Advanced Core Site, Advanced HDFS Site sections, show the 'Add Property' link.}} http://git-wip-us.apache.org/repos/asf/ambari/blob/5831b8dd/ambari-web/app/templates/common/error_log_body.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/common/error_log_body.hbs b/ambari-web/app/templates/common/error_log_body.hbs new file mode 100644 index 0000000..62f1b65 --- /dev/null +++ b/ambari-web/app/templates/common/error_log_body.hbs @@ -0,0 +1,33 @@ +{{! +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +}} + +<div class="task-detail-log-info"> + <div class="content-area"> + <div class="task-detail-log-clipboard-wrap"></div> + <div class="task-detail-log-maintext"> + <h5>stderr: <span class="muted">{{view.openedTask.errorLog}} </span></h5> + <pre class="stderr">{{view.openedTask.stderr}}</pre> + <h5>stdout: <span class="muted"> {{view.openedTask.outputLog}} </span></h5> + <pre class="stdout">{{view.openedTask.stdout}}</pre> + {{#if view.openedTask.structuredOut}} + <h5>structured_out: </h5> + <pre class="stdout">{{view.openedTask.structuredOut}}</pre> + {{/if}} + </div> + </div> +</div> http://git-wip-us.apache.org/repos/asf/ambari/blob/5831b8dd/ambari-web/app/templates/common/form/check_db_connection.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/common/form/check_db_connection.hbs b/ambari-web/app/templates/common/form/check_db_connection.hbs new file mode 100644 index 0000000..1a62242 --- /dev/null +++ b/ambari-web/app/templates/common/form/check_db_connection.hbs @@ -0,0 +1,33 @@ +{{! +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +}} + +<div class="entry-row db-connection"> + <span class="control-label"></span> + <div class="controls"> + <div class="control-group"> + <div class="span9"> + <span {{bindAttr class=":pull-left :btn :btn-primary view.isBtnDisabled:disabled"}} {{action connectToDatabase target="view"}}>{{view.btnCaption}}</span> + <div {{bindAttr class=":spinner :mll :pull-left view.isConnecting::hide"}}></div> + <div class="pull-left connection-result mll"> + <a {{bindAttr class="view.isConnectionSuccess:mute:action view.isRequestResolved::hide"}} {{action showLogsPopup target="view"}}>{{view.responseCaption}}</a> + </div> + <i {{bindAttr class=":pull-right view.isConnectionSuccess:icon-ok-sign:icon-warning-sign view.isRequestResolved::hide"}}></i> + </div> + </div> + </div> +</div> http://git-wip-us.apache.org/repos/asf/ambari/blob/5831b8dd/ambari-web/app/utils/ajax/ajax.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/utils/ajax/ajax.js b/ambari-web/app/utils/ajax/ajax.js index 26b2de0..0f48fac 100644 --- a/ambari-web/app/utils/ajax/ajax.js +++ b/ambari-web/app/utils/ajax/ajax.js @@ -2150,6 +2150,40 @@ var urls = { 'hosts.heatmaps': { 'real': '/clusters/{clusterName}/hosts?fields=Hosts/host_name,Hosts/maintenance_state,Hosts/public_host_name,Hosts/cpu_count,Hosts/ph_cpu_count,Hosts/total_mem,Hosts/host_status,Hosts/last_heartbeat_time,Hosts/os_arch,Hosts/os_type,Hosts/ip,host_components/HostRoles/state,host_components/HostRoles/maintenance_state,Hosts/disk_info,metrics/disk,metrics/load/load_one,metrics/cpu/cpu_system,metrics/cpu/cpu_user,metrics/memory/mem_total,metrics/memory/mem_free,alerts/summary&minimal_response=true', 'mock': '' + }, + + 'custom_action.create': { + 'real': '/requests', + 'mock': '', + 'format': function(data) { + var requestInfo = { + context: 'Check host', + action: 'check_host', + parameters: { } + }; + $.extend(true, requestInfo, data.requestInfo) + return { + type: 'POST', + async: true, + data: JSON.stringify({ + 'RequestInfo': requestInfo, + 'Requests/resource_filters': [{ + hosts: data.filteredHosts.join(',') + }] + }) + } + } + }, + 'custom_action.request': { + 'real': '/requests/{requestId}/tasks/{taskId}', + 'mock': '', + 'format': function(data) { + return { + async: true, + requestId: data.requestId, + taskId: data.taskId || '' + } + } } }; /** http://git-wip-us.apache.org/repos/asf/ambari/blob/5831b8dd/ambari-web/app/utils/db.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/utils/db.js b/ambari-web/app/utils/db.js index 24f95d0..e06b002 100644 --- a/ambari-web/app/utils/db.js +++ b/ambari-web/app/utils/db.js @@ -37,7 +37,8 @@ var InitialData = { 'ReassignMaster' : {}, 'AddSecurity': {}, 'HighAvailabilityWizard': {}, - 'RollbackHighAvailabilityWizard': {} + 'RollbackHighAvailabilityWizard': {}, + 'tmp': {} }; @@ -74,6 +75,11 @@ App.db.cleanUp = function () { localStorage.setObject('ambari', App.db.data); }; +App.db.cleanTmp = function() { + App.db.data.tmp = {}; + localStorage.setObject('ambari', App.db.data); +} + App.db.updateStorage = function() { App.db.data = localStorage.getObject('ambari'); if (App.db.data && App.db.data.app && App.db.data.app.tables && App.db.data.app.configs) { http://git-wip-us.apache.org/repos/asf/ambari/blob/5831b8dd/ambari-web/app/utils/helper.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/utils/helper.js b/ambari-web/app/utils/helper.js index 5ec945a..cfb5303 100644 --- a/ambari-web/app/utils/helper.js +++ b/ambari-web/app/utils/helper.js @@ -276,6 +276,25 @@ App.isEmptyObject = function(obj) { return empty; } /** + * Returns object with defined keys only. + * + * @memberof App + * @method permit + * @param {Object} obj - input object + * @param {String|Array} keys - allowed keys + * @return {Object} + */ +App.permit = function(obj, keys) { + var result = {}; + if (typeof obj !== 'object' || App.isEmptyObject(obj)) return result; + if (typeof keys == 'string') keys = Array(keys); + keys.forEach(function(key) { + if (obj.hasOwnProperty(key)) + result[key] = obj[key]; + }); + return result; +}; +/** * * @namespace App * @namespace App.format http://git-wip-us.apache.org/repos/asf/ambari/blob/5831b8dd/ambari-web/app/views/wizard/controls_view.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/wizard/controls_view.js b/ambari-web/app/views/wizard/controls_view.js index 74eda07..a0dd176 100644 --- a/ambari-web/app/views/wizard/controls_view.js +++ b/ambari-web/app/views/wizard/controls_view.js @@ -335,6 +335,30 @@ App.ServiceConfigRadioButtons = Ember.View.extend({ } }.property('serviceConfig.serviceName'), + /** + * `Observer` that add <code>additionalView</code> to <code>App.ServiceConfigProperty</code> + * that responsible for checking database connection. + * + * @method handleDBConnectionProperty + **/ + handleDBConnectionProperty: function() { + if (!App.supports.databaseConnection) return; + if (!['addServiceController', 'installerController'].contains(App.clusterStatus.wizardControllerName)) return; + var handledProperties = ['oozie_database', 'hive_database']; + var currentValue = this.get('serviceConfig.value'); + var databases = /MySQL|PostgreSQL|Oracle|Derby/gi; + var currentDB = currentValue.match(databases)[0]; + var existingDatabase = /existing/gi.test(currentValue); + var propertyAppendTo = this.get('categoryConfigsAll').findProperty('displayName', 'Database URL'); + if (currentDB && existingDatabase) { + if (handledProperties.contains(this.get('serviceConfig.name'))) { + if (propertyAppendTo) propertyAppendTo.set('additionalView', App.CheckDBConnectionView.extend({databaseName: currentDB})); + } + } else { + propertyAppendTo.set('additionalView', null); + } + }.observes('serviceConfig.value', '[email protected]'), + optionsBinding: 'serviceConfig.options' }); @@ -656,4 +680,318 @@ App.SlaveComponentChangeGroupNameView = Ember.View.extend({ } } }); +/** + * View for testing connection to database. + **/ +App.CheckDBConnectionView = Ember.View.extend({ + templateName: require('templates/common/form/check_db_connection'), + /** @property {string} btnCaption - text for button **/ + btnCaption: Em.I18n.t('services.service.config.database.btn.idle'), + /** @property {string} responseCaption - text for status link **/ + responseCaption: null, + /** @property {boolean} isConnecting - is request to server activated **/ + isConnecting: false, + /** @property {boolean} isValidationPassed - check validation for required fields **/ + isValidationPassed: null, + /** @property {string} databaseName- name of current database **/ + databaseName: null, + /** @property {boolean} isRequestResolved - check for finished request to server **/ + isRequestResolved: false, + /** @property {boolean} isConnectionSuccess - check for successful connection to database **/ + isConnectionSuccess: null, + /** @property {string} responseFromServer - message from server response **/ + responseFromServer: null, + /** @property {Object} ambariRequiredProperties - properties that need for custom action request **/ + ambariRequiredProperties: null, + /** @property {Number} currentRequestId - current custom action request id **/ + currentRequestId: null, + /** @property {Number} currentTaskId - current custom action task id **/ + currentTaskId: null, + /** @property {jQuery.Deferred} request - current $.ajax request **/ + request: null, + /** @property {Number} pollInterval - timeout interval for ajax polling **/ + pollInterval: 3000, + /** @property {string} hostNameProperty - host name property based on service and database names **/ + hostNameProperty: function() { + return '{0}_existing_{1}_host'.format(this.get('parentView.service.serviceName').toLowerCase(), this.get('databaseName').toLowerCase()); + }.property('databaseName'), + /** @property {boolean} isBtnDisabled - disable button on failed validation or active request **/ + isBtnDisabled: function() { + return !this.get('isValidationPassed') || this.get('isConnecting'); + }.property('isValidationPassed', 'isConnecting'), + /** @property {object} requiredProperties - properties that necessary for database connection **/ + requiredProperties: function() { + var propertiesMap = { + OOZIE: ['oozie.db.schema.name','oozie.service.JPAService.jdbc.username','oozie.service.JPAService.jdbc.password','oozie.service.JPAService.jdbc.driver','oozie.service.JPAService.jdbc.url'], + HIVE: ['ambari.hive.db.schema.name','javax.jdo.option.ConnectionUserName','javax.jdo.option.ConnectionPassword','javax.jdo.option.ConnectionDriverName','javax.jdo.option.ConnectionURL'] + }; + return propertiesMap[this.get('parentView.service.serviceName')]; + }.property(), + /** @property {Object} propertiesPattern - check pattern according to type of connection properties **/ + propertiesPattern: function() { + return { + user_name: /username$/ig, + user_passwd: /password$/ig, + db_connection_url: /jdbc\.url|connectionurl/ig + } + }.property(), + /** @property {Object} connectionProperties - service specific config values mapped for custom action request **/ + connectionProperties: function() { + var propObj = {}; + for (var key in this.get('propertiesPattern')) { + propObj[key] = this.getConnectionProperty(this.get('propertiesPattern')[key]); + } + return propObj; + }.property('[email protected]'), + /** + * Properties that stores in local storage used for handling + * last success connection. + * + * @property {Object} preparedDBProperties + **/ + preparedDBProperties: function() { + var propObj = {}; + for (var key in this.get('propertiesPattern')) { + var propName = this.getConnectionProperty(this.get('propertiesPattern')[key], true); + propObj[propName] = this.get('parentView.categoryConfigsAll').findProperty('name', propName).get('value'); + } + return propObj; + }.property(), + /** Check validation and load ambari properties **/ + didInsertElement: function() { + this.handlePropertiesValidation(); + this.getAmbariProperties(); + }, + /** On view destroy **/ + willDestroyElement: function() { + this.set('isConnecting', false); + this._super(); + }, + /** + * Observer that take care about enabling/disabling button based on required properties validation. + * + * @method handlePropertiesValidation + **/ + handlePropertiesValidation: function() { + this.restore(); + var isValid = true; + var properties = [].concat(this.get('requiredProperties')); + properties.push(this.get('hostNameProperty')); + properties.forEach(function(propertyName) { + if(!this.get('parentView.categoryConfigsAll').findProperty('name', propertyName).get('isValid')) isValid = false; + }, this); + this.set('isValidationPassed', isValid); + }.observes('[email protected]', '[email protected]', 'databaseName'), + + getConnectionProperty: function(regexp, isGetName) { + var _this = this; + var propertyName = _this.get('requiredProperties').filter(function(item) { + return regexp.test(item); + })[0]; + return (isGetName) ? propertyName : _this.get('parentView.categoryConfigsAll').findProperty('name', propertyName).get('value'); + }, + /** + * Set up ambari properties required for custom action request + * + * @method getAmbariProperties + **/ + getAmbariProperties: function() { + var clusterController = App.router.get('clusterController'); + var _this = this; + if (!App.isEmptyObject(App.db.get('tmp', 'ambariProperties')) && !this.get('ambariProperties')) { + this.set('ambariProperties', App.db.get('tmp', 'ambariProperties')); + return; + } + if (App.isEmptyObject(clusterController.get('ambariProperties'))) { + clusterController.loadAmbariProperties().done(function(data) { + _this.formatAmbariProperties(data.RootServiceComponents.properties); + }); + } else { + this.formatAmbariProperties(clusterController.get('ambariProperties')); + } + }, + + formatAmbariProperties: function(properties) { + var defaults = { + threshold: "60", + ambari_server_host: location.hostname, + check_execute_list : "db_connection_check" + }; + var properties = App.permit(properties, ['jdk.name','jdk_location','java.home']); + var renameKey = function(oldKey, newKey) { + if (properties[oldKey]) { + defaults[newKey] = properties[oldKey]; + delete properties[oldKey]; + } + }; + renameKey('java.home', 'java_home'); + renameKey('jdk.name', 'jdk_name'); + $.extend(properties, defaults); + App.db.set('tmp', 'ambariProperties', properties); + this.set('ambariProperties', properties); + }, + /** + * `Action` method for starting connect to current database. + * + * @method connectToDatabase + **/ + connectToDatabase: function() { + var self = this; + self.set('isRequestResolved', false); + App.db.set('tmp', this.get('parentView.service.serviceName') + '_connection', {}); + this.setConnectingStatus(true); + this.createCustomAction(); + }, + /** + * Run custom action for database connection. + * + * @method createCustomAction + **/ + createCustomAction: function() { + var databaseHost = this.get('parentView.categoryConfigsAll').findProperty('name', this.get('hostNameProperty')).get('value'); + var params = $.extend(true, {}, { db_name: this.get('databaseName').toLowerCase() }, this.get('connectionProperties'), this.get('ambariProperties')); + App.ajax.send({ + name: 'custom_action.create', + sender: this, + data: { + requestInfo: { + parameters: params + }, + filteredHosts: [databaseHost] + }, + success: 'onCreateActionSuccess', + error: 'onCreateActionError' + }); + }, + /** + * Run updater if task is created successfully. + * + * @method onConnectActionS + **/ + onCreateActionSuccess: function(data) { + this.set('currentRequestId', data.Requests.id); + App.ajax.send({ + name: 'custom_action.request', + sender: this, + data: { + requestId: this.get('currentRequestId') + }, + success: 'setCurrentTaskId' + }); + }, + + setCurrentTaskId: function(data) { + this.set('currentTaskId', data.items[0].Tasks.id); + this.startPolling(); + }, + + startPolling: function() { + if (this.get('isConnecting')) + this.getTaskInfo(); + }, + + getTaskInfo: function() { + var request = App.ajax.send({ + name: 'custom_action.request', + sender: this, + data: { + requestId: this.get('currentRequestId'), + taskId: this.get('currentTaskId') + }, + success: 'getTaskInfoSuccess' + }); + this.set('request', request); + }, + + getTaskInfoSuccess: function(data) { + var task = data.Tasks; + if (task.status === 'COMPLETED') { + var structuredOut = JSON.parse(task.structured_out).db_connection_check; + if (structuredOut.exit_code != 0) { + this.set('responseFromServer', { + stderr: task.stderr, + stdout: task.stdout, + structuredOut: structuredOut.message + }); + this.setResponseStatus('failed'); + } else { + App.db.set('tmp', this.get('parentView.service.serviceName') + '_connection', this.get('preparedDBProperties')); + this.setResponseStatus('success'); + } + } + if (task.status === 'FAILED') { + this.set('responseFromServer', { + stderr: task.stderr, + stdout: task.stdout + }); + this.setResponseStatus('failed'); + } + if (/PENDING|QUEUED|IN_PROGRESS/.test(task.status)) { + Em.run.later(this, function() { + this.startPolling(); + }, this.get('pollInterval')); + } + }, + + onCreateActionError: function(jqXhr, status, errorMessage) { + this.setResponseStatus('failed'); + this.set('responseFromServer', errorMessage); + }, + + setResponseStatus: function(isSuccess) { + var isSuccess = isSuccess == 'success'; + this.setConnectingStatus(false); + this.set('responseCaption', isSuccess ? Em.I18n.t('services.service.config.database.connection.success') : Em.I18n.t('services.service.config.database.connection.failed')); + this.set('isConnectionSuccess', isSuccess); + this.set('isRequestResolved', true); + }, + /** + * Switch captions and statuses for active/non-active request. + * + * @method setConnectionStatus + * @param {Boolean} [active] + */ + setConnectingStatus: function(active) { + if (active) { + this.set('responseCaption', null); + this.set('responseFromServer', null); + } + this.set('btnCaption', !!active ? Em.I18n.t('services.service.config.database.btn.connecting') : Em.I18n.t('services.service.config.database.btn.idle')); + this.set('isConnecting', !!active); + }, + /** + * Set view to init status. + * + * @method restore + **/ + restore: function() { + if (this.get('request')) { + this.get('request').abort(); + this.set('request', null); + } + this.set('responseCaption', null); + this.set('responseFromServer', null); + this.setConnectingStatus(false); + this.set('isRequestResolved', false); + }, + /** + * `Action` method for showing response from server in popup. + * + * @method showLogsPopup + **/ + showLogsPopup: function() { + if (this.get('isConnectionSuccess')) return; + var _this = this; + var popup = App.showAlertPopup('Error: {0} connection'.format(this.get('databaseName'))); + if (typeof this.get('responseFromServer') == 'object') { + popup.set('bodyClass', Em.View.extend({ + templateName: require('templates/common/error_log_body'), + openedTask: _this.get('responseFromServer') + })); + } else { + popup.set('body', this.get('responseFromServer')); + } + return popup; + } +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/5831b8dd/ambari-web/test/utils/helper_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/utils/helper_test.js b/ambari-web/test/utils/helper_test.js index 3718aef..8918b39 100644 --- a/ambari-web/test/utils/helper_test.js +++ b/ambari-web/test/utils/helper_test.js @@ -206,4 +206,35 @@ describe('utils/helper', function() { }); }); }); + describe('#App.permit()', function() { + var obj = { + a1: 'v1', + a2: 'v2', + a3: 'v3' + } + + var tests = [ + { + keys: 'a1', + e: { + a1: 'v1' + } + }, + { + keys: ['a2','a3','a4'], + e: { + a2: 'v2', + a3: 'v3' + } + } + ]; + + tests.forEach(function(test) { + it('should return object `{0}` permitted keys `{1}`'.format(JSON.stringify(test.e), JSON.stringify(test.keys)), function() { + expect(App.permit(obj, test.keys)).to.deep.eql(test.e); + }); + }); + + + }); }); http://git-wip-us.apache.org/repos/asf/ambari/blob/5831b8dd/ambari-web/test/views/wizard/controls_view_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/views/wizard/controls_view_test.js b/ambari-web/test/views/wizard/controls_view_test.js new file mode 100644 index 0000000..bfec1e2 --- /dev/null +++ b/ambari-web/test/views/wizard/controls_view_test.js @@ -0,0 +1,406 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var App = require('app'); +require('views/wizard/controls_view'); +require('utils/ajax/ajax'); +require('router'); + +describe('views/wizard/control_views', function() { + describe('App.CheckDBConnectionView', function() { + var createView = function(serviceName) { + return App.CheckDBConnectionView.extend({ + parentView: Em.View.create({ + service: Em.Object.create({ + serviceName: serviceName + }), + categoryConfigsAll: function() { + return Em.A( + require('data/HDP2/global_properties').configProperties.concat(require('data/HDP2/site_properties').configProperties) + .filterProperty('serviceName', serviceName).map(function(property) { return App.ServiceConfigProperty.create(property)}) + ); + }.property() + }) + }); + }; + var generateTypeValueProp = function(type, value) { + return { + type: type, + value: value + } + }; + var prepareConfigsTesting = function() { + var view = createView('HIVE').create({ databaseName: 'MySQL'}); + var setConfigProperty = function(name, value) { + view.get('parentView.categoryConfigsAll').findProperty('name', name).set('value', value); + }; + + setConfigProperty('javax.jdo.option.ConnectionUserName', 'hive_user'); + setConfigProperty('javax.jdo.option.ConnectionPassword', 'hive_pass'); + setConfigProperty('ambari.hive.db.schema.name', 'hive_scheme'); + setConfigProperty('javax.jdo.option.ConnectionURL', 'hive_c_url'); + return view; + } + describe('`Oozie` properties checking', function() { + var view = createView('OOZIE').create(); + describe('#requiredProperties', function() { + var expectedProperties = ['oozie.db.schema.name','oozie.service.JPAService.jdbc.username','oozie.service.JPAService.jdbc.password','oozie.service.JPAService.jdbc.driver','oozie.service.JPAService.jdbc.url']; + it('required properties present {0}'.format(expectedProperties.join(',')), function() { + expect(view.get('requiredProperties')).to.have.members(expectedProperties); + }); + }); + describe('#hostNameProperty', function() { + var testMessage = 'property name should be `{0}`'; + var tests = [ + { + databaseName: 'MySQL', + e: 'oozie_existing_mysql_host' + }, + { + databaseName: 'PostgreSQL', + e: 'oozie_existing_postgresql_host' + }, + { + databaseName: 'Oracle', + e: 'oozie_existing_oracle_host' + } + ]; + tests.forEach(function(test) { + it(testMessage.format(test.e), function() { + view.set('databaseName', test.databaseName); + expect(view.get('hostNameProperty')).to.eql(test.e); + }); + }); + }); + }); + + describe('`Hive` properties checking', function() { + var view = createView('HIVE').create(); + describe('#requiredProperties', function() { + var expectedProperties = ['ambari.hive.db.schema.name','javax.jdo.option.ConnectionUserName','javax.jdo.option.ConnectionPassword','javax.jdo.option.ConnectionDriverName','javax.jdo.option.ConnectionURL']; + it('required properties present {0}'.format(expectedProperties.join(',')), function() { + expect(view.get('requiredProperties')).to.have.members(expectedProperties); + }); + }); + describe('#hostNameProperty', function() { + var testMessage = 'property name should be `{0}`'; + var tests = [ + { + databaseName: 'MySQL', + e: 'hive_existing_mysql_host' + }, + { + databaseName: 'PostgreSQL', + e: 'hive_existing_postgresql_host' + }, + { + databaseName: 'Oracle', + e: 'hive_existing_oracle_host' + } + ]; + tests.forEach(function(test) { + it(testMessage.format(test.e), function() { + view.set('databaseName', test.databaseName); + expect(view.get('hostNameProperty')).to.eql(test.e); + }); + }, this); + }); + describe('#connectionProperties', function() { + var view = prepareConfigsTesting(); + var tests = [ + generateTypeValueProp('user_name', 'hive_user'), + generateTypeValueProp('user_passwd', 'hive_pass'), + generateTypeValueProp('db_connection_url', 'hive_c_url'), + generateTypeValueProp('db_name', 'hive_scheme') + ]; + var testMessage = 'property `{0}` should have `{1}`'; + tests.forEach(function(test) { + it(testMessage.format(test.value, test.type), function() { + expect(view.get('connectionProperties')[test.type]).to.eql(test.value); + }); + }); + }); + + describe('#preparedDBProperties', function() { + var view = prepareConfigsTesting(); + var tests = [ + generateTypeValueProp('javax.jdo.option.ConnectionUserName', 'hive_user'), + generateTypeValueProp('javax.jdo.option.ConnectionPassword', 'hive_pass'), + generateTypeValueProp('javax.jdo.option.ConnectionURL', 'hive_c_url'), + generateTypeValueProp('ambari.hive.db.schema.name', 'hive_scheme') + ]; + var testMessage = 'property `{1}` should have `{0}`'; + tests.forEach(function(test) { + it(testMessage.format(test.value, test.type), function() { + expect(view.get('preparedDBProperties')[test.type]).to.eql(test.value); + }); + }); + }); + + + }); + + describe('#isBtnDisabled', function() { + var view = createView('HIVE').create({ databaseName: 'MySQL' }); + var testMessage = 'button should be {0} if `isValidationPassed`/`isConnecting`: {1}/{2}'; + var tests = [ + { + isValidationPassed: true, + isConnecting: true, + e: true + }, + { + isValidationPassed: true, + isConnecting: false, + e: false + } + ]; + tests.forEach(function(test) { + it(testMessage.format(!!test.e ? 'disabled' : 'enabled', test.isValidationPassed, test.isConnecting), function() { + view.set('isValidationPassed', test.isValidationPassed); + view.set('isConnecting', test.isConnecting); + expect(view.get('isBtnDisabled')).to.be.eql(test.e); + }); + }) + }); + + describe('#connectToDatabase()', function() { + before(function() { + sinon.spy(App.ajax, 'send'); + }); + describe('connection request validation', function() { + var view = createView('HIVE').create({ databaseName: 'MySQL'}); + var setConfigProperty = function(name, value) { + view.get('parentView.categoryConfigsAll').findProperty('name', name).set('value', value); + }; + + setConfigProperty('javax.jdo.option.ConnectionUserName', 'hive_user'); + setConfigProperty('javax.jdo.option.ConnectionPassword', 'hive_pass'); + setConfigProperty('ambari.hive.db.schema.name', 'hive_scheme'); + setConfigProperty('javax.jdo.option.ConnectionURL', 'hive_c_url'); + + it('request should be passed with correct params', function() { + view.connectToDatabase(); + expect(App.ajax.send.calledOnce).to.be.ok; + }) + }); + after(function() { + App.ajax.send.restore(); + }) + }); + + }); + + describe('App.ServiceConfigRadioButtons', function() { + var createView = function(serviceName) { + return App.ServiceConfigRadioButtons.extend({ + categoryConfigsAll: function() { + return Em.A( + require('data/HDP2/global_properties').configProperties.concat(require('data/HDP2/site_properties').configProperties) + .filterProperty('serviceName', serviceName).map(function(property) { return App.ServiceConfigProperty.create(property)}) + ); + }.property() + }); + }; + + var setProperties = function(properties, propertyMap) { + for (var propertyName in propertyMap) { + properties.findProperty('name', propertyName).set('value', propertyMap[propertyName]); + } + }; + + before(function() { + App.clusterStatus.set('wizardControllerName','installerController'); + }); + describe('#onOptionsChange()', function() { + var oozieDerby = { + serviceConfig: { value: 'New Derby Database' }, + setupProperties: { + 'oozie.db.schema.name': 'derby.oozie.schema', + 'oozie.service.JPAService.jdbc.driver': 'oozie.driver', + 'oozie_ambari_host': 'derby.host.com' + }, + expectedProperties: [ + { + path: 'databaseName', + value: 'derby.oozie.schema' + }, + { + path: 'dbClass.name', + value: 'oozie.service.JPAService.jdbc.driver' + }, + { + path: 'dbClass.value', + value: 'org.apache.derby.jdbc.EmbeddedDriver' + }, + { + path: 'hostName', + value: 'derby.host.com' + }, + { + path: 'connectionUrl.name', + value: 'oozie.service.JPAService.jdbc.url' + }, + { + path: 'connectionUrl.value', + value: 'jdbc:derby:${oozie.data.dir}/${oozie.db.schema.name}-db;create=true' + } + ] + }; + var oozieExistingMysql = { + serviceConfig: { value: 'Existing MySQL Database' }, + setupProperties: { + 'oozie.db.schema.name': 'mysql.oozie.schema', + 'oozie.service.JPAService.jdbc.driver': 'oozie.driver', + 'oozie_existing_mysql_host': 'mysql.host.com' + }, + expectedProperties: [ + { + path: 'databaseName', + value: 'mysql.oozie.schema' + }, + { + path: 'dbClass.name', + value: 'oozie.service.JPAService.jdbc.driver' + }, + { + path: 'dbClass.value', + value: 'com.mysql.jdbc.Driver' + }, + { + path: 'hostName', + value: 'mysql.host.com' + }, + { + path: 'connectionUrl.name', + value: 'oozie.service.JPAService.jdbc.url' + }, + { + path: 'connectionUrl.value', + value: 'jdbc:mysql://mysql.host.com/mysql.oozie.schema' + } + ] + }; + var oozieExistingPostgresql = { + serviceConfig: { value: 'Existing PostgreSQL Database' }, + setupProperties: { + 'oozie.db.schema.name': 'postgresql.oozie.schema', + 'oozie.service.JPAService.jdbc.driver': 'oozie.driver', + 'oozie_existing_postgresql_host': 'postgresql.host.com' + }, + expectedProperties: [ + { + path: 'databaseName', + value: 'postgresql.oozie.schema' + }, + { + path: 'dbClass.name', + value: 'oozie.service.JPAService.jdbc.driver' + }, + { + path: 'dbClass.value', + value: 'org.postgresql.Driver' + }, + { + path: 'hostName', + value: 'postgresql.host.com' + }, + { + path: 'connectionUrl.name', + value: 'oozie.service.JPAService.jdbc.url' + }, + { + path: 'connectionUrl.value', + value: 'jdbc:postgresql://postgresql.host.com:5432/postgresql.oozie.schema' + } + ] + }; + var oozieExistingOracle = { + serviceConfig: { value: 'Existing Oracle Database' }, + setupProperties: { + 'oozie.db.schema.name': 'oracle.oozie.schema', + 'oozie.service.JPAService.jdbc.driver': 'oozie.driver', + 'oozie_existing_oracle_host': 'oracle.host.com' + }, + expectedProperties: [ + { + path: 'databaseName', + value: 'oracle.oozie.schema' + }, + { + path: 'dbClass.name', + value: 'oozie.service.JPAService.jdbc.driver' + }, + { + path: 'dbClass.value', + value: 'oracle.jdbc.driver.OracleDriver' + }, + { + path: 'hostName', + value: 'oracle.host.com' + }, + { + path: 'connectionUrl.name', + value: 'oozie.service.JPAService.jdbc.url' + }, + { + path: 'connectionUrl.value', + value: 'jdbc:oracle:thin:@//oracle.host.com:1521/oracle.oozie.schema' + } + ] + }; + var tests = [ + { + serviceName: 'OOZIE', + mockData: [ + oozieDerby, + oozieExistingMysql, + oozieExistingPostgresql, + oozieExistingOracle + ] + } + ]; + tests.forEach(function(test) { + describe('`{0}` service processing'.format(test.serviceName), function() { + test.mockData.forEach(function(test) { + describe('`oozie_database` value "{0}"'.format(test.serviceConfig.value), function() { + var view = createView('OOZIE').create(); + before(function() { + var categoryConfigs = view.get('categoryConfigsAll'); + view.reopen({ + serviceConfig: function() { + var property = categoryConfigs.findProperty('name', 'oozie_database'); + property.set('value', test.serviceConfig.value); + return property; + }.property() + }); + setProperties(categoryConfigs, test.setupProperties); + view.didInsertElement(); + }) + test.expectedProperties.forEach(function(property) { + it('#{0} should be "{1}"'.format(property.path, property.value), function() { + expect(view.get(property.path)).to.eql(property.value); + }); + }); + }); + }); + }) + }); + }); + }); +});
