You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by al...@apache.org on 2016/03/28 11:46:39 UTC
[3/3] ambari git commit: AMBARI-15596. Add missing unit tests files
for ambari-web utils (alexantonenko)
AMBARI-15596. Add missing unit tests files for ambari-web utils (alexantonenko)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/d5d1afea
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/d5d1afea
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/d5d1afea
Branch: refs/heads/trunk
Commit: d5d1afea8be684fed1e712f7a80b5e06f4d79ba5
Parents: aa033d0
Author: Alex Antonenko <hi...@gmail.com>
Authored: Mon Mar 28 11:53:29 2016 +0300
Committer: Alex Antonenko <hi...@gmail.com>
Committed: Mon Mar 28 11:53:29 2016 +0300
----------------------------------------------------------------------
ambari-web/app/assets/test/tests.js | 9 +
ambari-web/app/utils/array_utils.js | 2 +-
ambari-web/app/utils/configs_collection.js | 2 +-
ambari-web/app/utils/heatmap.js | 1 -
ambari-web/app/utils/hosts.js | 10 +-
ambari-web/app/utils/polling.js | 20 +-
ambari-web/test/utils/action_sequence_test.js | 323 ++
ambari-web/test/utils/array_utils_test.js | 125 +
.../test/utils/configs_collection_test.js | 334 ++
ambari-web/test/utils/credentials_test.js | 717 ++++
ambari-web/test/utils/file_utils_test.js | 126 +
.../test/utils/handlebars_helpers_test.js | 57 +
ambari-web/test/utils/heatmap_test.js | 141 +
ambari-web/test/utils/hosts_test.js | 3467 ++++++++++++++++++
ambari-web/test/utils/polling_test.js | 1333 +++++++
15 files changed, 6646 insertions(+), 21 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/d5d1afea/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 d114379..db504f2 100644
--- a/ambari-web/app/assets/test/tests.js
+++ b/ambari-web/app/assets/test/tests.js
@@ -167,9 +167,13 @@ var files = [
'test/mixins/unit_convert/base_unit_convert_mixin_test',
'test/utils/ajax/ajax_test',
'test/utils/ajax/ajax_queue_test',
+ 'test/utils/action_sequence_test',
+ 'test/utils/array_utils_test',
'test/utils/batch_scheduled_requests_test',
'test/utils/blueprint_test',
'test/utils/config_test',
+ 'test/utils/configs_collection_test',
+ 'test/utils/credentials_test',
'test/utils/date/date_test',
'test/utils/date/timezone_test',
'test/utils/data_manipulation_test',
@@ -178,9 +182,14 @@ var files = [
'test/utils/ember_computed_test',
'test/utils/ember_reopen_test',
'test/utils/form_field_test',
+ 'test/utils/file_utils_test',
+ 'test/utils/handlebars_helpers_test',
+ 'test/utils/heatmap_test',
'test/utils/host_progress_popup_test',
+ 'test/utils/hosts_test',
'test/utils/misc_test',
'test/utils/number_utils_test',
+ 'test/utils/polling_test',
'test/utils/validator_test',
'test/utils/config_test',
'test/utils/string_utils_test',
http://git-wip-us.apache.org/repos/asf/ambari/blob/d5d1afea/ambari-web/app/utils/array_utils.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/array_utils.js b/ambari-web/app/utils/array_utils.js
index bee12ee..643ed67 100644
--- a/ambari-web/app/utils/array_utils.js
+++ b/ambari-web/app/utils/array_utils.js
@@ -26,7 +26,7 @@ module.exports = {
uniqObjectsbyId: function (arr, id) {
var result = [];
arr.forEach(function (item) {
- var isIdPresent = result.someProperty('id', item.id);
+ var isIdPresent = result.someProperty(id, item[id]);
if (!isIdPresent) {
result.pushObject(item);
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/d5d1afea/ambari-web/app/utils/configs_collection.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/configs_collection.js b/ambari-web/app/utils/configs_collection.js
index fde7a17..a9a570a 100644
--- a/ambari-web/app/utils/configs_collection.js
+++ b/ambari-web/app/utils/configs_collection.js
@@ -40,7 +40,7 @@ var configsCollection = [],
App.configsCollection = Em.Object.create({
/**
- * adds config property to configs array anf map
+ * adds config property to configs array and map
* should assert error if config has no id
* @param c
* @method add
http://git-wip-us.apache.org/repos/asf/ambari/blob/d5d1afea/ambari-web/app/utils/heatmap.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/heatmap.js b/ambari-web/app/utils/heatmap.js
index 9d8c178..e033005 100644
--- a/ambari-web/app/utils/heatmap.js
+++ b/ambari-web/app/utils/heatmap.js
@@ -16,7 +16,6 @@
* limitations under the License.
*/
-var App = require('app');
module.exports = {
mappers: Em.Mixin.create({
metricMapperWithTransform: function (json, metricName, transformValueFunction) {
http://git-wip-us.apache.org/repos/asf/ambari/blob/d5d1afea/ambari-web/app/utils/hosts.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/hosts.js b/ambari-web/app/utils/hosts.js
index 2467e1a..e4a437c 100644
--- a/ambari-web/app/utils/hosts.js
+++ b/ambari-web/app/utils/hosts.js
@@ -151,15 +151,11 @@ module.exports = {
host.set('filterColumnValue', value);
- if (!skip && filterText) {
- if ((value == null || !value.toString().match(filterText)) && !host.get('host.publicHostName').match(filterText)) {
- skip = true;
- }
+ if (!skip && filterText && (value == null || !value.toString().match(filterText)) && !host.get('host.publicHostName').match(filterText)) {
+ skip = true;
}
- if (!skip && filterComponent) {
- if (hostComponentNames.length > 0) {
+ if (!skip && filterComponent && hostComponentNames.length > 0) {
skip = !hostComponentNames.contains(filterComponent.get('componentName'));
- }
}
host.set('filtered', !skip);
}, this);
http://git-wip-us.apache.org/repos/asf/ambari/blob/d5d1afea/ambari-web/app/utils/polling.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/polling.js b/ambari-web/app/utils/polling.js
index b83ca23..7337fbb 100644
--- a/ambari-web/app/utils/polling.js
+++ b/ambari-web/app/utils/polling.js
@@ -76,7 +76,7 @@ App.Poll = Em.Object.extend(App.ReloadPopupMixin, {
self.set('isSuccess', true);
self.set('isError', false);
} else {
- var requestId = jsonData.Requests.id;
+ var requestId = Em.get(jsonData, 'Requests.id');
self.set('requestId', requestId);
self.doPolling();
}
@@ -101,7 +101,7 @@ App.Poll = Em.Object.extend(App.ReloadPopupMixin, {
},
doPolling: function () {
- if (this.get('requestId')) {
+ if (!Em.isNone(this.get('requestId'))) {
this.startPolling();
}
},
@@ -110,7 +110,7 @@ App.Poll = Em.Object.extend(App.ReloadPopupMixin, {
* server call to obtain task logs
*/
pollTaskLog: function () {
- if (this.get('currentTaskId')) {
+ if (!Em.isNone(this.get('currentTaskId'))) {
App.ajax.send({
name: 'background_operations.get_by_task',
sender: this,
@@ -119,7 +119,7 @@ App.Poll = Em.Object.extend(App.ReloadPopupMixin, {
taskId: this.get('currentTaskId')
},
success: 'pollTaskLogSuccessCallback'
- })
+ });
}
},
@@ -139,7 +139,7 @@ App.Poll = Em.Object.extend(App.ReloadPopupMixin, {
* @return {Boolean}
*/
startPolling: function () {
- if (!this.get('requestId')) return false;
+ if (Em.isNone(this.get('requestId'))) return false;
this.pollTaskLog();
App.ajax.send({
@@ -169,10 +169,8 @@ App.Poll = Em.Object.extend(App.ReloadPopupMixin, {
reloadErrorCallback: function (request, ajaxOptions, error, opt, params) {
this._super(request, ajaxOptions, error, opt, params);
- if (request.status) {
- if (!this.get('isSuccess')) {
- this.set('isError', true);
- }
+ if (request.status && !this.get('isSuccess')) {
+ this.set('isError', true);
}
},
@@ -182,7 +180,7 @@ App.Poll = Em.Object.extend(App.ReloadPopupMixin, {
replacePolledData: function (polledData) {
var currentTaskId = this.get('currentTaskId');
- if (currentTaskId) {
+ if (!Em.isNone(currentTaskId)) {
var task = this.get('polledData').findProperty('Tasks.id', currentTaskId);
var currentTask = polledData.findProperty('Tasks.id', currentTaskId);
if (task && currentTask) {
@@ -226,7 +224,7 @@ App.Poll = Em.Object.extend(App.ReloadPopupMixin, {
parseInfo: function (polledData) {
var tasksData = polledData.tasks;
var requestId = this.get('requestId');
- if (polledData.Requests && polledData.Requests.id && polledData.Requests.id != requestId) {
+ if (polledData.Requests && !Em.isNone(polledData.Requests.id) && polledData.Requests.id != requestId) {
// We don't want to use non-current requestId's tasks data to
// determine the current install status.
// Also, we don't want to keep polling if it is not the
http://git-wip-us.apache.org/repos/asf/ambari/blob/d5d1afea/ambari-web/test/utils/action_sequence_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/utils/action_sequence_test.js b/ambari-web/test/utils/action_sequence_test.js
new file mode 100644
index 0000000..4ae9dc8
--- /dev/null
+++ b/ambari-web/test/utils/action_sequence_test.js
@@ -0,0 +1,323 @@
+/**
+ * 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('utils/action_sequence');
+
+describe('App.actionSequence', function () {
+
+ var actionSequence;
+
+ beforeEach(function () {
+ actionSequence = App.actionSequence.create();
+ });
+
+ describe('#setSequence', function () {
+
+ var cases = [
+ {
+ sequenceIn: [{}, {}],
+ sequenceOut: [{}, {}],
+ title: 'array passed'
+ },
+ {
+ sequenceIn: {
+ '0': {},
+ '1': {},
+ 'length': 2
+ },
+ sequenceOut: [{}],
+ title: 'array-like object passed'
+ },
+ {
+ sequenceIn: 0,
+ sequenceOut: [{}],
+ title: 'primitive passed'
+ }
+ ],
+ result;
+
+ cases.forEach(function (item) {
+
+ describe(item.title, function () {
+
+ beforeEach(function () {
+ actionSequence.set('sequence', [{}]);
+ result = actionSequence.setSequence(item.sequenceIn);
+ });
+
+ it('should return context', function () {
+ expect(result).to.eql(actionSequence);
+ });
+
+ it('sequence property', function () {
+ expect(actionSequence.get('sequence')).to.eql(item.sequenceOut);
+ });
+
+ });
+
+ });
+
+ });
+
+ describe('#start', function () {
+
+ beforeEach(function () {
+ actionSequence.setProperties({
+ actionCounter: 0,
+ sequence: [{}]
+ });
+ sinon.stub(actionSequence, 'runNextAction', Em.K);
+ actionSequence.start();
+ });
+
+ afterEach(function () {
+ actionSequence.runNextAction.restore();
+ });
+
+ it('should set the counter', function () {
+ expect(actionSequence.get('actionCounter')).to.equal(1);
+ });
+
+ it('should start the sequence', function () {
+ expect(actionSequence.runNextAction.calledOnce).to.be.true;
+ });
+
+ it('should call runNextAction with correct arguments', function () {
+ expect(actionSequence.runNextAction.calledWith(0, null)).to.be.true;
+ });
+
+ });
+
+ describe('#onFinish', function () {
+
+ var cases = [
+ {
+ callbackIn: Em.isNone,
+ callbackOut: Em.isNone,
+ title: 'function passed'
+ },
+ {
+ callbackIn: 'function () {}',
+ callbackOut: Em.clb,
+ title: 'array-like object passed'
+ },
+ {
+ callbackIn: 'function () {}',
+ callbackOut: Em.clb,
+ title: 'primitive passed'
+ }
+ ],
+ result;
+
+ cases.forEach(function (item) {
+
+ describe(item.title, function () {
+
+ beforeEach(function () {
+ actionSequence.set('finishedCallback', Em.clb);
+ result = actionSequence.onFinish(item.callbackIn);
+ });
+
+ it('should return context', function () {
+ expect(result).to.eql(actionSequence);
+ });
+
+ it('finishedCallback property', function () {
+ expect(actionSequence.get('finishedCallback')).to.eql(item.callbackOut);
+ });
+
+ });
+
+ });
+
+ });
+
+ describe('#runNextAction', function () {
+
+ var actions = {
+ callback: Em.K,
+ sync: function (prevResponse) {
+ actions.callback(prevResponse);
+ return prevResponse;
+ },
+ async: function (prevResponse) {
+ actions.callback(prevResponse);
+ return {
+ done: function (callback) {
+ return callback.call(this, prevResponse);
+ }
+ };
+ }
+ },
+ prevResponse = {},
+ cases = [
+ {
+ index: 0,
+ actionCounter: 0,
+ sequence: [
+ {
+ callback: actions.sync,
+ type: 'sync'
+ }
+ ],
+ actionCallCount: 0,
+ title: 'no iterations left (case 1)'
+ },
+ {
+ index: 3,
+ actionCounter: 3,
+ sequence: [
+ {
+ callback: actions.sync,
+ type: 'sync'
+ },
+ {
+ callback: actions.sync,
+ type: 'sync'
+ },
+ {
+ callback: actions.sync,
+ type: 'sync'
+ }
+ ],
+ actionCallCount: 0,
+ title: 'no iterations left (case 2)'
+ },
+ {
+ index: 1,
+ actionCounter: 3,
+ sequence: [
+ {
+ callback: actions.sync,
+ type: 'sync'
+ },
+ {
+ callback: actions.sync,
+ type: 'sync'
+ },
+ {
+ callback: actions.sync,
+ type: 'sync'
+ }
+ ],
+ actionCallCount: 2,
+ title: 'starting from the middle'
+ },
+ {
+ index: 0,
+ actionCounter: 2,
+ sequence: [
+ {
+ callback: actions.sync,
+ type: 'sync'
+ },
+ {
+ callback: actions.sync,
+ type: 'sync'
+ },
+ {
+ callback: actions.sync,
+ type: 'sync'
+ }
+ ],
+ actionCallCount: 2,
+ title: 'ending at the middle'
+ },
+ {
+ index: 0,
+ actionCounter: 3,
+ sequence: [
+ {
+ callback: actions.sync,
+ type: 'sync'
+ },
+ {
+ callback: actions.sync,
+ type: 'sync'
+ },
+ {
+ callback: actions.sync,
+ type: 'sync'
+ }
+ ],
+ actionCallCount: 3,
+ title: 'all iterations'
+ },
+ {
+ index: 0,
+ actionCounter: 3,
+ sequence: [
+ {
+ callback: actions.sync,
+ type: 'sync'
+ },
+ {
+ callback: actions.async,
+ type: 'async'
+ },
+ {
+ callback: actions.sync,
+ type: 'sync'
+ }
+ ],
+ actionCallCount: 3,
+ title: 'asynchronous action'
+ }
+ ];
+
+ cases.forEach(function (item) {
+
+ describe(item.title, function () {
+
+ beforeEach(function () {
+ sinon.spy(actions, 'callback');
+ sinon.stub(actionSequence, 'finishedCallback', Em.K);
+ actionSequence.setProperties({
+ context: actionSequence,
+ actionCounter: item.actionCounter,
+ sequence: item.sequence
+ });
+ actionSequence.runNextAction(item.index, prevResponse);
+ });
+
+ afterEach(function () {
+ actions.callback.restore();
+ actionSequence.finishedCallback.restore();
+ });
+
+ it('number of calls', function () {
+ expect(actions.callback.callCount).to.equal(item.actionCallCount);
+ });
+
+ if (item.actionCallCount) {
+ it('argument passed to callback', function () {
+ expect(actions.callback.alwaysCalledWith(prevResponse)).to.be.true;
+ });
+ }
+
+ it('finish callback', function () {
+ expect(actionSequence.finishedCallback.calledOnce).to.be.true;
+ });
+
+ });
+ });
+
+ });
+
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/d5d1afea/ambari-web/test/utils/array_utils_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/utils/array_utils_test.js b/ambari-web/test/utils/array_utils_test.js
new file mode 100644
index 0000000..ec7c5d8
--- /dev/null
+++ b/ambari-web/test/utils/array_utils_test.js
@@ -0,0 +1,125 @@
+/**
+ * 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 arrayUtils = require('utils/array_utils');
+
+describe('array_utils', function () {
+
+ describe('#uniqObjectsbyId', function () {
+
+ var arr = [
+ {
+ n: 0,
+ v: 'v0'
+ },
+ {
+ n: 0,
+ v: 'v01'
+ },
+ {
+ n: 1,
+ v: 'v1'
+ },
+ {
+ n: '1',
+ v: 'v11'
+ },
+ {
+ n: 2,
+ v: 'v2'
+ }
+ ],
+ result = [
+ {
+ n: 0,
+ v: 'v0'
+ },
+ {
+ n: 1,
+ v: 'v1'
+ },
+ {
+ n: '1',
+ v: 'v11'
+ },
+ {
+ n: 2,
+ v: 'v2'
+ }
+ ];
+
+ it('should return one element for one id', function () {
+ expect(arrayUtils.uniqObjectsbyId(arr, 'n').toArray()).to.eql(result);
+ });
+
+ });
+
+ describe('#intersect', function () {
+
+ var cases = [
+ {
+ arr1: [Infinity, 0, 1, 2, {a: 1}, {b: 2}, null, undefined],
+ arr2: ['undefined', null, {b: '2'}, {a: 1}, 2.0, '1', 0, Infinity],
+ result: [null, 2, 0, Infinity],
+ title: 'arrays of the same length have common items'
+ },
+ {
+ arr1: [true, false, [0, 1], [2, 3], [4, 5], [6], null, undefined],
+ arr2: [undefined, 'null', 6, [4, 5], ['2', '3'], [String(0), String(1)], '0,1', false, 'true'],
+ result: [false, undefined],
+ title: 'arrays of different length have common items'
+ },
+ {
+ arr1: ['1', function () {}, NaN],
+ arr2: ['function () {}', Number('1'), NaN],
+ result: [],
+ title: 'arrays have no common items'
+ },
+ {
+ arr1: [[0], undefined, null],
+ arr2: [],
+ result: [],
+ title: 'one of arrays is empty'
+ },
+ {
+ arr1: [],
+ arr2: [],
+ result: [],
+ title: 'both arrays are empty'
+ }
+ ];
+
+ cases.forEach(function (item) {
+
+ describe(item.title, function () {
+
+ it('arrays intersection', function () {
+ expect(arrayUtils.intersect(item.arr1, item.arr2)).to.eql(item.result);
+ });
+
+ it('commutativity', function () {
+ expect(arrayUtils.intersect(item.arr1, item.arr2).sort()).to.eql(arrayUtils.intersect(item.arr2, item.arr1).sort());
+ });
+
+ });
+
+ });
+
+ });
+
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/d5d1afea/ambari-web/test/utils/configs_collection_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/utils/configs_collection_test.js b/ambari-web/test/utils/configs_collection_test.js
new file mode 100644
index 0000000..bd97950
--- /dev/null
+++ b/ambari-web/test/utils/configs_collection_test.js
@@ -0,0 +1,334 @@
+/**
+ * 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('utils/configs_collection');
+
+describe('App.configsCollection', function () {
+
+ var configsCollection;
+
+ beforeEach(function () {
+ configsCollection = Em.Object.create(App.configsCollection);
+ sinon.spy(Em, 'assert');
+ });
+
+ afterEach(function () {
+ Em.assert.restore();
+ });
+
+ describe('#add', function () {
+
+ var cases = [
+ {
+ collection: [],
+ isError: false,
+ title: 'initial state'
+ },
+ {
+ obj: undefined,
+ collection: [],
+ isError: true,
+ title: 'no item passed'
+ },
+ {
+ obj: undefined,
+ collection: [],
+ isError: true,
+ title: 'null passed'
+ },
+ {
+ obj: {},
+ collection: [],
+ isError: true,
+ title: 'no id passed'
+ },
+ {
+ obj: {
+ id: 1,
+ name: 'n10'
+ },
+ collection: [
+ {
+ id: 1,
+ name: 'n10'
+ }
+ ],
+ mapItem: {
+ id: 1,
+ name: 'n10'
+ },
+ isError: false,
+ title: 'new item'
+ },
+ {
+ obj: {
+ id: 1,
+ name: 'n11'
+ },
+ collection: [
+ {
+ id: 1,
+ name: 'n10'
+ }
+ ],
+ mapItem: {
+ id: 1,
+ name: 'n11'
+ },
+ isError: false,
+ title: 'duplicate id'
+ },
+ {
+ obj: {
+ id: '1',
+ name: 'n12'
+ },
+ collection: [
+ {
+ id: 1,
+ name: 'n10'
+ }
+ ],
+ mapItem: {
+ id: '1',
+ name: 'n12'
+ },
+ isError: false,
+ title: 'duplicate id, key name conversion'
+ }
+ ];
+
+ cases.forEach(function (item) {
+
+ describe(item.title, function () {
+
+ beforeEach(function () {
+ try {
+ if (item.hasOwnProperty('obj')) {
+ configsCollection.add(item.obj);
+ }
+ } catch (e) {}
+ });
+
+ it('thrown error', function () {
+ expect(Em.assert.threw()).to.equal(item.isError);
+ });
+
+ it('configs array', function () {
+ expect(configsCollection.getAll()).to.eql(item.collection);
+ });
+
+ if (item.obj && item.obj.id) {
+ it('configs map', function () {
+ expect(configsCollection.getConfig(item.obj.id)).to.eql(item.mapItem);
+ });
+ }
+
+ });
+
+ });
+
+ });
+
+ describe('#getConfig', function () {
+
+ var cases = [
+ {
+ result: undefined,
+ isError: true,
+ title: 'no id passed'
+ },
+ {
+ id: null,
+ result: undefined,
+ isError: true,
+ title: 'invalid id passed'
+ },
+ {
+ id: 1,
+ result: {
+ id: 1
+ },
+ isError: false,
+ title: 'existing item'
+ },
+ {
+ id: 1,
+ result: {
+ id: 1
+ },
+ isError: false,
+ title: 'existing item, key name conversion'
+ },
+ {
+ id: 2,
+ result: undefined,
+ isError: false,
+ title: 'item doesn\'t exist'
+ }
+ ];
+
+ cases.forEach(function (item) {
+
+ describe(item.title, function () {
+
+ var result;
+
+ beforeEach(function () {
+ configsCollection.add({
+ id: 1
+ });
+ try {
+ result = configsCollection.getConfig(item.id);
+ } catch (e) {}
+ });
+
+ it('thrown error', function () {
+ expect(Em.assert.threw()).to.equal(item.isError);
+ });
+
+ it('returned value', function () {
+ expect(result).to.eql(item.result);
+ });
+
+ });
+
+ });
+
+ });
+
+ describe('#getConfigByName', function () {
+
+ var configIds = ['n0_f0', 'n1_f1'],
+ cases = [
+ {
+ fileName: 'f0',
+ result: undefined,
+ isError: true,
+ title: 'no name passed'
+ },
+ {
+ name: 'n0',
+ result: undefined,
+ isError: true,
+ title: 'no filename passed'
+ },
+ {
+ name: 'n0',
+ fileName: 'f0',
+ result: {
+ id: 'n0_f0'
+ },
+ isError: false,
+ title: 'existing item'
+ },
+ {
+ name: 'n0',
+ fileName: 'f1',
+ result: undefined,
+ isError: false,
+ title: 'not existing item'
+ }
+ ];
+
+ cases.forEach(function (item) {
+
+ describe(item.title, function () {
+
+ var result;
+
+ beforeEach(function () {
+ sinon.stub(App.config, 'configId', function (name, fileName) {
+ return name + '_' + fileName;
+ });
+ configIds.forEach(function (id) {
+ configsCollection.add({
+ id: id
+ });
+ });
+ try {
+ result = configsCollection.getConfigByName(item.name, item.fileName);
+ } catch (e) {}
+ });
+
+ afterEach(function () {
+ App.config.configId.restore();
+ configsCollection.clearAll();
+ });
+
+
+ it('thrown error', function () {
+ expect(Em.assert.threw()).to.equal(item.isError);
+ });
+
+ it('returned value', function () {
+ expect(result).to.eql(item.result);
+ });
+
+ });
+
+ });
+
+ });
+
+ describe('#getAll', function () {
+
+ var configs = [
+ {
+ id: 'c0'
+ },
+ {
+ id: 'c1'
+ }
+ ];
+
+ beforeEach(function () {
+ configsCollection.clearAll();
+ });
+
+ it('should return all configs', function () {
+ configs.forEach(function (item) {
+ configsCollection.add(item);
+ });
+ expect(configsCollection.getAll()).to.eql(configs);
+ });
+
+ });
+
+
+ describe('#clearAll', function () {
+
+ beforeEach(function () {
+ configsCollection.add({
+ id: 'c0'
+ });
+ configsCollection.clearAll();
+ });
+
+ it('should clear configs array', function () {
+ expect(configsCollection.getAll()).to.have.length(0);
+ });
+
+ it('should clear configs map', function () {
+ expect(configsCollection.getConfig('c0')).to.be.undefined;
+ });
+
+ });
+
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/d5d1afea/ambari-web/test/utils/credentials_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/utils/credentials_test.js b/ambari-web/test/utils/credentials_test.js
new file mode 100644
index 0000000..7bf6791
--- /dev/null
+++ b/ambari-web/test/utils/credentials_test.js
@@ -0,0 +1,717 @@
+/**
+ * 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 credentials = require('utils/credentials');
+var testHelpers = require('test/helpers');
+
+describe('credentials utils', function () {
+
+ var storeTypeStatusMock = function (clusterName, key) {
+ var result = {};
+ result[key] = clusterName;
+ return result;
+ };
+
+ describe('#createCredentials', function () {
+
+ it('should send AJAX request', function () {
+ credentials.createCredentials('c', 'a', {});
+ expect(testHelpers.findAjaxRequest('name', 'credentials.create')).to.eql([
+ {
+ sender: credentials,
+ name: 'credentials.create',
+ data: {
+ clusterName: 'c',
+ resource: {},
+ alias: 'a'
+ },
+ error: 'createCredentialsErrorCallback'
+ }
+ ]);
+ });
+
+ });
+
+ describe('#credentialsSuccessCallback', function () {
+
+ var params = {
+ callback: Em.K
+ },
+ cases = [
+ {
+ items: [],
+ callbackArgument: [],
+ title: 'no data returned'
+ },
+ {
+ items: [{}, {}],
+ callbackArgument: [undefined, undefined],
+ title: 'empty data returned'
+ },
+ {
+ items: [
+ {
+ Credential: {
+ id: 0
+ }
+ },
+ {
+ Credential: {
+ id: 1
+ }
+ }
+ ],
+ callbackArgument: [
+ {
+ id: 0
+ },
+ {
+ id: 1
+ }
+ ],
+ title: 'valid data returned'
+ }
+ ];
+
+ beforeEach(function () {
+ sinon.spy(params, 'callback');
+ });
+
+ afterEach(function () {
+ params.callback.restore();
+ });
+
+ cases.forEach(function (item) {
+
+ it(item.title, function () {
+ credentials.credentialsSuccessCallback({
+ items: item.items
+ }, null, params);
+ expect(params.callback.firstCall.args).to.eql([item.callbackArgument]);
+ });
+
+ });
+
+ });
+
+ describe('#createOrUpdateCredentials', function () {
+
+ var mock = {
+ dfd: {
+ getCredential: null,
+ updateCredentials: null,
+ createCredentials: null
+ },
+ callback: Em.K,
+ getCredential: function () {
+ return mock.dfd.getCredential.promise();
+ },
+ updateCredentials: function () {
+ return mock.dfd.updateCredentials.promise();
+ },
+ createCredentials: function () {
+ return mock.dfd.createCredentials.promise();
+ }
+ },
+ cases = [
+ {
+ getCredentialResolve: true,
+ credentialsCallback: 'updateCredentials',
+ isCredentialsCallbackResolve: true,
+ status: 'success',
+ result: {
+ status: 200
+ },
+ callbackArgs: [
+ true,
+ {
+ status: 200
+ }
+ ],
+ title: 'successful credentials update'
+ },
+ {
+ getCredentialResolve: true,
+ credentialsCallback: 'updateCredentials',
+ isCredentialsCallbackResolve: false,
+ status: 'error',
+ result: {
+ status: 404
+ },
+ callbackArgs: [
+ false,
+ {
+ status: 404
+ }
+ ],
+ title: 'failed credentials update'
+ },
+ {
+ getCredentialResolve: false,
+ credentialsCallback: 'createCredentials',
+ isCredentialsCallbackResolve: true,
+ status: 'success',
+ result: {
+ status: 201
+ },
+ callbackArgs: [
+ true,
+ {
+ status: 201
+ }
+ ],
+ title: 'successful credentials creation'
+ },
+ {
+ getCredentialResolve: false,
+ credentialsCallback: 'createCredentials',
+ isCredentialsCallbackResolve: false,
+ status: 'error',
+ result: {
+ status: 500
+ },
+ callbackArgs: [
+ false,
+ {
+ status: 500
+ }
+ ],
+ title: 'failed credentials creation'
+ }
+ ];
+
+ beforeEach(function () {
+ sinon.stub(credentials, 'getCredential', mock.getCredential);
+ sinon.stub(credentials, 'updateCredentials', mock.updateCredentials);
+ sinon.stub(credentials, 'createCredentials', mock.createCredentials);
+ sinon.spy(mock, 'callback');
+ mock.dfd.getCredential = $.Deferred();
+ mock.dfd.updateCredentials = $.Deferred();
+ mock.dfd.createCredentials = $.Deferred();
+ });
+
+ afterEach(function () {
+ credentials.getCredential.restore();
+ credentials.updateCredentials.restore();
+ credentials.createCredentials.restore();
+ mock.callback.restore();
+ });
+
+ cases.forEach(function (item) {
+
+ var getCredentialMethod = item.getCredentialResolve ? 'resolve' : 'reject',
+ credentialsCallbackMethod = item.isCredentialsCallbackResolve ? 'resolve' : 'reject';
+
+ it(item.title, function () {
+ mock.dfd.getCredential[getCredentialMethod]();
+ mock.dfd[item.credentialsCallback][credentialsCallbackMethod](null, item.status, item.result);
+ credentials.createOrUpdateCredentials().done(mock.callback);
+ expect(mock.callback.firstCall.args).to.eql(item.callbackArgs);
+ });
+
+ });
+
+ });
+
+ describe('#getCredential', function () {
+
+ it('should send AJAX request', function () {
+ credentials.getCredential('c', 'a', Em.K);
+ expect(testHelpers.findAjaxRequest('name', 'credentials.get')).to.eql([
+ {
+ sender: credentials,
+ name: 'credentials.get',
+ data: {
+ clusterName: 'c',
+ alias: 'a',
+ callback: Em.K
+ },
+ success: 'getCredentialSuccessCallback',
+ error: 'getCredentialErrorCallback'
+ }
+ ]);
+ });
+
+ });
+
+ describe('#getCredentialSuccessCallback', function () {
+
+ var params = {
+ callback: Em.K
+ },
+ cases = [
+ {
+ data: null,
+ callback: undefined,
+ callbackCallCount: 0,
+ title: 'no callback passed'
+ },
+ {
+ data: null,
+ callback: null,
+ callbackCallCount: 0,
+ title: 'invalid callback passed'
+ },
+ {
+ data: null,
+ callbackCallCount: 1,
+ callbackArgument: null,
+ title: 'no data passed'
+ },
+ {
+ data: {},
+ callbackCallCount: 1,
+ callbackArgument: null,
+ title: 'no credential info passed'
+ },
+ {
+ data: {
+ Credential: 'c'
+ },
+ callbackCallCount: 1,
+ callbackArgument: 'c',
+ title: 'credential info passed'
+ }
+ ];
+
+ cases.forEach(function (item) {
+
+ describe(item.title, function () {
+
+ beforeEach(function () {
+ sinon.spy(params, 'callback');
+ credentials.getCredentialSuccessCallback(item.data, null, item.hasOwnProperty('callback') ? {
+ callback: item.callback
+ } : params);
+ });
+
+ afterEach(function () {
+ params.callback.restore();
+ });
+
+ it('callback call count', function () {
+ expect(params.callback.callCount).to.equal(item.callbackCallCount);
+ });
+
+ if (item.callbackCallCount) {
+ it('callback argument', function () {
+ expect(params.callback.firstCall.args).to.eql([item.callbackArgument]);
+ });
+ }
+
+ });
+
+ });
+
+ });
+
+ describe('#updateCredentials', function () {
+
+ it('should send AJAX request', function () {
+ credentials.updateCredentials('c', 'a', {});
+ expect(testHelpers.findAjaxRequest('name', 'credentials.update')).to.eql([
+ {
+ sender: credentials,
+ name: 'credentials.update',
+ data: {
+ clusterName: 'c',
+ alias: 'a',
+ resource: {}
+ }
+ }
+ ]);
+ });
+
+ });
+
+ describe('#credentials', function () {
+
+ it('should send AJAX request', function () {
+ credentials.credentials('c', Em.K);
+ expect(testHelpers.findAjaxRequest('name', 'credentials.list')).to.eql([
+ {
+ sender: credentials,
+ name: 'credentials.list',
+ data: {
+ clusterName: 'c',
+ callback: Em.K
+ },
+ success: 'credentialsSuccessCallback'
+ }
+ ]);
+ });
+
+ });
+
+ describe('#removeCredentials', function () {
+
+ it('should send AJAX request', function () {
+ credentials.removeCredentials('c', 'a');
+ expect(testHelpers.findAjaxRequest('name', 'credentials.delete')).to.eql([
+ {
+ sender: credentials,
+ name: 'credentials.delete',
+ data: {
+ clusterName: 'c',
+ alias: 'a'
+ }
+ }
+ ]);
+ });
+
+ });
+
+ describe('#storageInfo', function () {
+
+ it('should send AJAX request', function () {
+ credentials.storageInfo('c', Em.K);
+ expect(testHelpers.findAjaxRequest('name', 'credentials.store.info')).to.eql([
+ {
+ sender: credentials,
+ name: 'credentials.store.info',
+ data: {
+ clusterName: 'c',
+ callback: Em.K
+ },
+ success: 'storageInfoSuccessCallback'
+ }
+ ]);
+ });
+
+ });
+
+ describe('#storageInfoSuccessCallback', function () {
+
+ var params = {
+ callback: Em.K
+ },
+ cases = [
+ {
+ callbackArgument: null,
+ title: 'no clusters'
+ },
+ {
+ clusters: null,
+ callbackArgument: null,
+ title: 'invalid clusters info'
+ },
+ {
+ clusters: {},
+ callbackArgument: {
+ persistent: false,
+ temporary: false
+ },
+ title: 'empty clusters info'
+ },
+ {
+ clusters: {
+ credential_store_properties: {
+ 'storage.persistent': true,
+ 'storage.temporary': true
+ }
+ },
+ callbackArgument: {
+ persistent: false,
+ temporary: false
+ },
+ title: 'invalid storage properties format'
+ },
+ {
+ clusters: {
+ credential_store_properties: {}
+ },
+ callbackArgument: {
+ persistent: false,
+ temporary: false
+ },
+ title: 'no storage properties'
+ },
+ {
+ clusters: {
+ credential_store_properties: {
+ 'storage.persistent': 'true',
+ 'storage.temporary': 'false'
+ }
+ },
+ callbackArgument: {
+ persistent: true,
+ temporary: false
+ },
+ title: 'valid storage properties format - persistent storage'
+ },
+ {
+ clusters: {
+ credential_store_properties: {
+ 'storage.persistent': 'false',
+ 'storage.temporary': 'true'
+ }
+ },
+ callbackArgument: {
+ persistent: false,
+ temporary: true
+ },
+ title: 'valid storage properties format - temporary storage'
+ },
+ {
+ clusters: {
+ credential_store_properties: {
+ 'storage.persistent': 'true',
+ 'storage.temporary': 'true'
+ }
+ },
+ callbackArgument: {
+ persistent: true,
+ temporary: true
+ },
+ title: 'valid storage properties format - both types'
+ }
+ ];
+
+ cases.forEach(function (item) {
+
+ describe(item.title, function () {
+
+ beforeEach(function () {
+ sinon.spy(params, 'callback');
+ credentials.storageInfoSuccessCallback({
+ Clusters: item.clusters
+ }, null, params);
+ });
+
+ afterEach(function () {
+ params.callback.restore();
+ });
+
+ it('callback execution', function () {
+ expect(params.callback.calledOnce).to.be.true;
+ });
+
+ it('callback argument', function () {
+ expect(params.callback.firstCall.args).to.eql([item.callbackArgument]);
+ });
+
+ });
+
+ });
+
+ });
+
+ describe('#isStorePersisted', function () {
+
+ beforeEach(function () {
+ sinon.stub(credentials, 'storeTypeStatus', storeTypeStatusMock);
+ });
+
+ afterEach(function () {
+ credentials.storeTypeStatus.restore();
+ });
+
+ it('should return storeTypeStatus result', function () {
+ expect(credentials.isStorePersisted('c')).to.eql({
+ persistent: 'c'
+ });
+ });
+
+ });
+
+
+ describe('#isStoreTemporary', function () {
+
+ beforeEach(function () {
+ sinon.stub(credentials, 'storeTypeStatus', storeTypeStatusMock);
+ });
+
+ afterEach(function () {
+ credentials.storeTypeStatus.restore();
+ });
+
+ it('should return storeTypeStatus result', function () {
+ expect(credentials.isStoreTemporary('c')).to.eql({
+ temporary: 'c'
+ });
+ });
+
+ });
+
+ describe('#storeTypeStatus', function () {
+
+ var mock = {
+ successCallback: Em.K,
+ errorCallback: Em.K
+ },
+ data = {
+ clusterName: 'c'
+ },
+ error = {
+ status: 404
+ },
+ cases = [
+ {
+ isSuccess: true,
+ callbackArgument: data,
+ title: 'success'
+ },
+ {
+ isSuccess: false,
+ callbackArgument: error,
+ title: 'fail'
+ }
+ ];
+
+ cases.forEach(function (item) {
+
+ describe(item.title, function () {
+
+ var callbackName = item.isSuccess ? 'successCallback' : 'errorCallback';
+
+ beforeEach(function () {
+ sinon.spy(mock, 'successCallback');
+ sinon.spy(mock, 'errorCallback');
+ sinon.stub(credentials, 'storageInfo', function (clusterName, callback) {
+ var dfd = $.Deferred();
+ if (item.isSuccess) {
+ callback({
+ temporary: data
+ });
+ } else {
+ dfd.reject(error);
+ }
+ return dfd.promise();
+ });
+ credentials.storeTypeStatus(null, 'temporary').then(mock.successCallback, mock.errorCallback);
+ });
+
+ afterEach(function () {
+ mock.successCallback.restore();
+ mock.errorCallback.restore();
+ credentials.storageInfo.restore();
+ });
+
+ it('success callback', function () {
+ expect(mock.successCallback.called).to.equal(item.isSuccess);
+ });
+
+ it('error callback', function () {
+ expect(mock.errorCallback.called).to.not.equal(item.isSuccess);
+ });
+
+ it('callback called once', function () {
+ expect(mock[callbackName].calledOnce).to.be.true;
+ });
+
+ it('callback arguments', function () {
+ expect(mock[callbackName].firstCall.args).to.eql([item.callbackArgument]);
+ });
+
+ });
+
+ });
+
+ });
+
+ describe('#createCredentialResource', function () {
+
+ it('should return object with arguments', function () {
+ expect(credentials.createCredentialResource('p', 'c', 't')).to.eql({
+ principal: 'p',
+ key: 'c',
+ type: 't'
+ });
+ });
+
+ });
+
+ describe('#isKDCCredentialsPersisted', function () {
+
+ var cases = [
+ {
+ credentials: [],
+ isKDCCredentialsPersisted: false,
+ title: 'empty array passed'
+ },
+ {
+ credentials: [{}, {}],
+ isKDCCredentialsPersisted: false,
+ title: 'no aliases passed'
+ },
+ {
+ credentials: [
+ {
+ alias: 'a0'
+ },
+ {
+ alias: 'a1'
+ }
+ ],
+ isKDCCredentialsPersisted: false,
+ title: 'no KDC admin credentials passed'
+ },
+ {
+ credentials: [
+ {
+ alias: 'kdc.admin.credential'
+ },
+ {
+ alias: 'a2'
+ }
+ ],
+ isKDCCredentialsPersisted: false,
+ title: 'no KDC admin credentials type passed'
+ },
+ {
+ credentials: [
+ {
+ alias: 'kdc.admin.credential',
+ type: 'temporary'
+ },
+ {
+ alias: 'a3'
+ }
+ ],
+ isKDCCredentialsPersisted: false,
+ title: 'temporary storage'
+ },
+ {
+ credentials: [
+ {
+ alias: 'kdc.admin.credential',
+ type: 'persisted'
+ },
+ {
+ alias: 'kdc.admin.credential'
+ },
+ {
+ alias: 'a4'
+ }
+ ],
+ isKDCCredentialsPersisted: true,
+ title: 'persistent storage'
+ }
+ ];
+
+ cases.forEach(function (item) {
+
+ it(item.title, function () {
+ expect(credentials.isKDCCredentialsPersisted(item.credentials)).to.equal(item.isKDCCredentialsPersisted);
+ });
+
+ });
+
+ });
+
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/d5d1afea/ambari-web/test/utils/file_utils_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/utils/file_utils_test.js b/ambari-web/test/utils/file_utils_test.js
new file mode 100644
index 0000000..8c9eb6d
--- /dev/null
+++ b/ambari-web/test/utils/file_utils_test.js
@@ -0,0 +1,126 @@
+/**
+ * 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 fileUtils = require('utils/file_utils');
+
+describe('file_utils', function () {
+
+ describe('#openInfoInNewTab', function () {
+
+ var mock = {
+ document: {
+ write: Em.K
+ },
+ focus: Em.K
+ };
+
+ beforeEach(function () {
+ sinon.stub(window, 'open').returns(mock);
+ sinon.spy(mock.document, 'write');
+ sinon.spy(mock, 'focus');
+ fileUtils.openInfoInNewTab('data');
+ });
+
+ afterEach(function () {
+ window.open.restore();
+ mock.document.write.restore();
+ mock.focus.restore();
+ });
+
+ it('opening new window', function () {
+ expect(window.open.calledOnce).to.be.true;
+ });
+
+ it('no URL for new window', function () {
+ expect(window.open.firstCall.args).to.eql(['']);
+ });
+
+ it('writing document contents', function () {
+ expect(mock.document.write.calledOnce).to.be.true;
+ });
+
+ it('document contents', function () {
+ expect(mock.document.write.firstCall.args).to.eql(['data']);
+ });
+
+ it('focusing on new window', function () {
+ expect(mock.focus.calledOnce).to.be.true;
+ });
+
+ });
+
+ describe('#safariDownload', function () {
+
+ var linkEl = {
+ click: Em.K
+ };
+
+ beforeEach(function () {
+ sinon.stub(document, 'createElement').returns(linkEl);
+ sinon.stub(document.body, 'appendChild', Em.K);
+ sinon.stub(document.body, 'removeChild', Em.K);
+ sinon.spy(linkEl, 'click');
+ fileUtils.safariDownload('file data', 'csv', 'file.csv');
+ });
+
+ afterEach(function () {
+ document.createElement.restore();
+ document.body.appendChild.restore();
+ document.body.removeChild.restore();
+ linkEl.click.restore();
+ });
+
+ it('creating new element', function () {
+ expect(document.createElement.calledOnce).to.be.true;
+ });
+
+ it('new element is a link', function () {
+ expect(document.createElement.firstCall.args).to.eql(['a']);
+ });
+
+ it('link URL', function () {
+ expect(linkEl.href).to.equal('data:attachment/csv;charset=utf-8,file%20data');
+ });
+
+ it('file name', function () {
+ expect(linkEl.download).to.equal('file.csv');
+ });
+
+ it('appending element to document', function () {
+ expect(document.body.appendChild.calledOnce).to.be.true;
+ });
+
+ it('link is appended', function () {
+ expect(document.body.appendChild.firstCall.args).to.eql([linkEl]);
+ });
+
+ it('link is clicked', function () {
+ expect(linkEl.click.calledOnce).to.be.true;
+ });
+
+ it('removing element from document', function () {
+ expect(document.body.removeChild.calledOnce).to.be.true;
+ });
+
+ it('link is removed', function () {
+ expect(document.body.removeChild.firstCall.args).to.eql([linkEl]);
+ });
+
+ });
+
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/d5d1afea/ambari-web/test/utils/handlebars_helpers_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/utils/handlebars_helpers_test.js b/ambari-web/test/utils/handlebars_helpers_test.js
new file mode 100644
index 0000000..4e705ad
--- /dev/null
+++ b/ambari-web/test/utils/handlebars_helpers_test.js
@@ -0,0 +1,57 @@
+/**
+ * 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('utils/handlebars_helpers');
+
+describe('handlebars_helpers', function () {
+
+ describe('#registerBoundHelper', function () {
+
+ var options = {
+ hash: {}
+ };
+
+ beforeEach(function () {
+ sinon.stub(Em.Handlebars, 'registerHelper', function (name, callback) {
+ callback('prop', options);
+ });
+ sinon.stub(Em.Handlebars.helpers, 'view', Em.K);
+ App.registerBoundHelper('helper', {});
+ });
+
+ afterEach(function () {
+ Em.Handlebars.registerHelper.restore();
+ Em.Handlebars.helpers.view.restore();
+ });
+
+ it('contentBinding', function () {
+ expect(options.hash.contentBinding).to.equal('prop');
+ });
+
+ it('view', function () {
+ expect(Em.Handlebars.helpers.view.calledOnce).to.be.true;
+ });
+
+ it('view arguments', function () {
+ expect(Em.Handlebars.helpers.view.firstCall.args).to.eql([{}, options]);
+ });
+
+ });
+
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/d5d1afea/ambari-web/test/utils/heatmap_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/utils/heatmap_test.js b/ambari-web/test/utils/heatmap_test.js
new file mode 100644
index 0000000..0a63cbf
--- /dev/null
+++ b/ambari-web/test/utils/heatmap_test.js
@@ -0,0 +1,141 @@
+/**
+ * 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 heatmap = require('utils/heatmap');
+
+describe('heatmap utils', function () {
+
+ describe('mappers', function () {
+
+ var mappers;
+
+ beforeEach(function () {
+ mappers = Em.Object.create(heatmap.mappers);
+ });
+
+ describe('#metricMapperWithTransform', function () {
+
+ var cases = [
+ {
+ hostComponents: null,
+ hostToValueMap: {},
+ title: 'no host components data'
+ },
+ {
+ hostComponents: [null, null],
+ metricName: 'm0',
+ hostToValueMap: {},
+ title: 'host components data is absent'
+ },
+ {
+ hostComponents: [{}, {}],
+ metricName: 'm1',
+ hostToValueMap: {},
+ title: 'provided metric data is absent'
+ },
+ {
+ hostComponents: [{}, {}],
+ metricName: 'm2.m3',
+ hostToValueMap: {},
+ title: 'provided metrics data is absent'
+ },
+ {
+ hostComponents: [
+ null,
+ {},
+ {
+ m4: 1,
+ HostRoles: {
+ host_name: 'h0'
+ }
+ },
+ {
+ m4: 1.5,
+ HostRoles: {
+ host_name: 'h1'
+ }
+ },
+ {
+ m4: 1.60,
+ HostRoles: {
+ host_name: 'h2'
+ }
+ },
+ {
+ m4: 1.72,
+ HostRoles: {
+ host_name: 'h3'
+ }
+ },
+ {
+ m4: 1.85,
+ HostRoles: {
+ host_name: 'h4'
+ }
+ },
+ {
+ m4: 1.97,
+ HostRoles: {
+ host_name: 'h5'
+ }
+ }
+ ],
+ metricName: 'm4',
+ hostToValueMap: {
+ h0: '1.0',
+ h1: '1.5',
+ h2: '1.6',
+ h3: '1.7',
+ h4: '1.9',
+ h5: '2.0'
+ },
+ title: 'no transform function'
+ },
+ {
+ hostComponents: [
+ {
+ m5: 100,
+ HostRoles: {
+ host_name: 'h6'
+ }
+ }
+ ],
+ metricName: 'm5',
+ transformValueFunction: Math.sqrt,
+ hostToValueMap: {
+ h6: '10.0'
+ },
+ title: 'transform function provided'
+ }
+ ];
+
+ cases.forEach(function (item) {
+
+ it(item.title, function () {
+ expect(mappers.metricMapperWithTransform({
+ host_components: item.hostComponents
+ }, item.metricName, item.transformValueFunction)).to.eql(item.hostToValueMap);
+ });
+
+ });
+
+ });
+
+ });
+
+});