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/09/14 15:26:13 UTC
ambari git commit: AMBARI-18158. Add UI unit tests for App.HttpClient
(alexantonenko)
Repository: ambari
Updated Branches:
refs/heads/branch-2.5 e01fb6019 -> a4f749429
AMBARI-18158. Add UI unit tests for App.HttpClient (alexantonenko)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/a4f74942
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/a4f74942
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/a4f74942
Branch: refs/heads/branch-2.5
Commit: a4f74942972908f29663de07c4b9818854b538f0
Parents: e01fb60
Author: Alex Antonenko <hi...@gmail.com>
Authored: Tue Aug 16 13:00:43 2016 +0300
Committer: Alex Antonenko <hi...@gmail.com>
Committed: Wed Sep 14 18:26:07 2016 +0300
----------------------------------------------------------------------
ambari-web/app/assets/test/tests.js | 1 +
ambari-web/app/utils/http_client.js | 55 +--
.../global/errors_handler_controller_test.js | 1 +
ambari-web/test/utils/http_client_test.js | 433 +++++++++++++++++++
4 files changed, 451 insertions(+), 39 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/a4f74942/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 005c97b..34f0db8 100644
--- a/ambari-web/app/assets/test/tests.js
+++ b/ambari-web/app/assets/test/tests.js
@@ -195,6 +195,7 @@ var files = [
'test/utils/heatmap_test',
'test/utils/host_progress_popup_test',
'test/utils/hosts_test',
+ 'test/utils/http_client_test',
'test/utils/misc_test',
'test/utils/number_utils_test',
'test/utils/polling_test',
http://git-wip-us.apache.org/repos/asf/ambari/blob/a4f74942/ambari-web/app/utils/http_client.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/http_client.js b/ambari-web/app/utils/http_client.js
index 6b94d81..dbfc640 100644
--- a/ambari-web/app/utils/http_client.js
+++ b/ambari-web/app/utils/http_client.js
@@ -49,32 +49,10 @@ App.HttpClient = Em.Object.create({
* @param {string} url
* @param {Object} ajaxOptions
* @param {App.ServerDataMapper} mapper - json processor
+ * @param {boolean} isGetAsPost - if true, do POST-request equal to GET-request but with some params put to body
* @param {callback} errorHandler
*/
- request: function (url, ajaxOptions, mapper, errorHandler) {
-
- if (!errorHandler) {
- errorHandler = this.defaultErrorHandler;
- }
-
- var xhr = new XMLHttpRequest();
- var curTime = App.dateTime();
-
- xhr.open('GET', url + (url.indexOf('?') >= 0 ? '&_=' : '?_=') + curTime, true);
- xhr.send(null);
-
- this.onReady(xhr, "", ajaxOptions, mapper, errorHandler, url);
- },
-
- /**
- * Do POST-request equal to GET-request but with some params put to body
- * @param {string} url
- * @param {{params: string, success: callback, error: callback}} ajaxOptions
- * @param {App.QuickDataMapper} mapper
- * @param errorHandler
- * @method getAsPostRequest
- */
- getAsPostRequest: function (url, ajaxOptions, mapper, errorHandler) {
+ request: function (url, ajaxOptions, mapper, errorHandler, isGetAsPost) {
if (!errorHandler) {
errorHandler = this.defaultErrorHandler;
@@ -82,19 +60,22 @@ App.HttpClient = Em.Object.create({
var xhr = new XMLHttpRequest(),
curTime = App.dateTime(),
- params = JSON.stringify({
- "RequestInfo": {"query" : ajaxOptions.params }
- });
-
- xhr.open('POST', url + (url.indexOf('?') >= 0 ? '&_=' : '?_=') + curTime, true);
- xhr.setRequestHeader("X-Http-Method-Override", "GET");
- xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
+ method = isGetAsPost ? 'POST': 'GET',
+ params = isGetAsPost ? JSON.stringify({
+ "RequestInfo": {"query" : ajaxOptions.params}
+ }) : null;
+
+ xhr.open(method, url + (url.indexOf('?') >= 0 ? '&_=' : '?_=') + curTime, true);
+ if (isGetAsPost) {
+ xhr.setRequestHeader("X-Http-Method-Override", "GET");
+ xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
+ }
xhr.send(params);
this.onReady(xhr, "", ajaxOptions, mapper, errorHandler, url);
},
- /*
+ /**
This function checks if we get response from server
Not using onreadystatechange cuz of possible closure
*/
@@ -140,12 +121,8 @@ App.HttpClient = Em.Object.create({
}
var client = this,
request = function () {
- if (data.doGetAsPost && !App.get('testMode')) {
- client.getAsPostRequest(url, data, mapper, errorHandler);
- }
- else {
- client.request(url, data, mapper, errorHandler);
- }
+ var isGetAsPost = Boolean(data.doGetAsPost && !App.get('testMode'));
+ client.request(url, data, mapper, errorHandler, isGetAsPost);
url = null;
data = null;
mapper = null;
@@ -169,6 +146,6 @@ App.HttpClient = Em.Object.create({
* @param {number} interval - frequency request
*/
post: function (url, data, mapper, errorHandler, interval) {
- this.get(url, data, mapper, errorHandler, interval);
+ this.get.apply(this, arguments);
}
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/a4f74942/ambari-web/test/controllers/global/errors_handler_controller_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/global/errors_handler_controller_test.js b/ambari-web/test/controllers/global/errors_handler_controller_test.js
index b255dcc..2a726ee 100644
--- a/ambari-web/test/controllers/global/errors_handler_controller_test.js
+++ b/ambari-web/test/controllers/global/errors_handler_controller_test.js
@@ -47,6 +47,7 @@ describe('App.ErrorsHandlerController', function () {
describe("#saveErrorLogs()", function () {
beforeEach(function() {
+ localStorage.removeItem('errors');
sinon.stub(controller, 'postUserPref');
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/a4f74942/ambari-web/test/utils/http_client_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/utils/http_client_test.js b/ambari-web/test/utils/http_client_test.js
new file mode 100644
index 0000000..9e158a4
--- /dev/null
+++ b/ambari-web/test/utils/http_client_test.js
@@ -0,0 +1,433 @@
+/**
+ * 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/http_client');
+
+describe('App.HttpClient', function () {
+
+ describe('#defaultErrorHandler', function () {
+
+ var cases = [
+ {
+ isAsserted: false,
+ title: 'no response text'
+ },
+ {
+ responseText: null,
+ title: 'empty response text'
+ },
+ {
+ responseText: 404,
+ title: 'invalid response text (number)'
+ },
+ {
+ responseText: 'error',
+ title: 'invalid response text (string)'
+ },
+ {
+ responseText: '{error}',
+ title: 'malformed response text (incorrect literal)'
+ },
+ {
+ responseText: '{error: 404}',
+ title: 'malformed response text (no parentheses)'
+ },
+ {
+ responseText: '{\'error\': 404}',
+ title: 'malformed response text (incorrect parentheses)'
+ },
+ {
+ responseText: '{"error": 404}',
+ title: 'valid response text'
+ }
+ ];
+
+ cases.forEach(function (item) {
+
+ describe(item.title, function () {
+
+ var jqXHR = {
+ responseText: item.responseText
+ };
+
+ beforeEach(function () {
+ sinon.stub(App.ajax, 'defaultErrorHandler', Em.K);
+ sinon.spy(Em, 'assert');
+ try {
+ App.HttpClient.defaultErrorHandler(jqXHR, '', '', 'http://localhost');
+ } catch (e) {}
+ });
+
+ afterEach(function () {
+ App.ajax.defaultErrorHandler.restore();
+ Em.assert.restore();
+ });
+
+ it('default error handler call', function () {
+ expect(App.ajax.defaultErrorHandler.calledOnce).to.be.true;
+ });
+
+ it('default error handler arguments', function () {
+ expect(App.ajax.defaultErrorHandler.firstCall.args).to.eql([jqXHR, 'http://localhost']);
+ });
+
+ it('no console error assertion', function () {
+ expect(Em.assert.threw()).to.be.false;
+ });
+
+ });
+
+ });
+
+ });
+
+ describe('#request', function () {
+
+ var errorHandler = Em.K,
+ ajaxOptions = {
+ params: 'property=value'
+ },
+ mapper = {},
+ cases = [
+ {
+ url: 'url',
+ generatedUrl: 'url?_=1000',
+ errorHandler: null,
+ passedErrorHandler: App.HttpClient.defaultErrorHandler,
+ isGetAsPost: false,
+ method: 'GET',
+ setRequestHeaderCallCount: 0,
+ params: null,
+ title: 'no request parameters, default error handler'
+ },
+ {
+ url: 'url?property0=value0&property1=value1',
+ generatedUrl: 'url?property0=value0&property1=value1&_=1000',
+ errorHandler: errorHandler,
+ passedErrorHandler: errorHandler,
+ isGetAsPost: true,
+ method: 'POST',
+ setRequestHeaderCallCount: 2,
+ params: '{"RequestInfo":{"query":"property=value"}}',
+ title: 'request parameters passed, POST request'
+ }
+ ];
+
+ cases.forEach(function (item) {
+
+ describe(item.title, function () {
+
+ beforeEach(function () {
+ sinon.stub(XMLHttpRequest.prototype, 'open', Em.K);
+ sinon.stub(XMLHttpRequest.prototype, 'setRequestHeader', Em.K);
+ sinon.stub(XMLHttpRequest.prototype, 'send', Em.K);
+ sinon.stub(App, 'dateTime').returns(1000);
+ sinon.stub(App.HttpClient, 'onReady', Em.K);
+ App.HttpClient.request(item.url, ajaxOptions, mapper, item.errorHandler, item.isGetAsPost);
+ });
+
+ afterEach(function () {
+ XMLHttpRequest.prototype.open.restore();
+ XMLHttpRequest.prototype.setRequestHeader.restore();
+ XMLHttpRequest.prototype.send.restore();
+ App.dateTime.restore();
+ App.HttpClient.onReady.restore();
+ });
+
+ it('request method', function () {
+ expect(XMLHttpRequest.prototype.open.firstCall.args[0]).to.equal(item.method);
+ });
+
+ it('request URL', function () {
+ expect(XMLHttpRequest.prototype.open.firstCall.args[1]).to.equal(item.generatedUrl);
+ });
+
+ it('setting request headers', function () {
+ expect(XMLHttpRequest.prototype.setRequestHeader.callCount).to.equal(item.setRequestHeaderCallCount);
+ });
+
+ it('request params', function () {
+ expect(XMLHttpRequest.prototype.send.firstCall.args[0]).to.equal(item.params);
+ });
+
+ it('onReady callback: ajaxOptions', function () {
+ expect(App.HttpClient.onReady.firstCall.args[2]).to.eql(ajaxOptions);
+ });
+
+ it('onReady callback: mapper', function () {
+ expect(App.HttpClient.onReady.firstCall.args[3]).to.eql(mapper);
+ });
+
+ it('onReady callback: errorHandler', function () {
+ expect(App.HttpClient.onReady.firstCall.args[4]).to.eql(item.passedErrorHandler);
+ });
+
+ it('onReady callback: url', function () {
+ expect(App.HttpClient.onReady.firstCall.args[5]).to.equal(item.url);
+ });
+
+ });
+
+ });
+
+ });
+
+ describe('#onReady', function () {
+
+ var clock,
+ xhr = {
+ responseText: '{"property": "value"}',
+ statusText: 'status',
+ abort: Em.K
+ },
+ ajaxOptions = {
+ complete: Em.K
+ },
+ mapper = {
+ map: Em.K
+ },
+ mock = {
+ errorHandler: Em.K
+ },
+ cases = [
+ {
+ readyState: 4,
+ status: 200,
+ isCommitError: false,
+ commitCallCount: 1,
+ mapCallCount: 1,
+ completeCallCount: 1,
+ abortCallCount: 1,
+ errorHandlerCallCount: 0,
+ onReadyCallCount: 1,
+ title: 'successful request'
+ },
+ {
+ readyState: 4,
+ status: 200,
+ isCommitError: true,
+ commitCallCount: 1,
+ mapCallCount: 1,
+ completeCallCount: 1,
+ abortCallCount: 1,
+ errorHandlerCallCount: 0,
+ onReadyCallCount: 1,
+ title: 'successful request, App.store.commit error'
+ },
+ {
+ readyState: 4,
+ status: 404,
+ isCommitError: false,
+ commitCallCount: 0,
+ mapCallCount: 0,
+ completeCallCount: 0,
+ abortCallCount: 0,
+ errorHandlerCallCount: 1,
+ onReadyCallCount: 1,
+ title: 'failed request'
+ },
+ {
+ readyState: 3,
+ status: 200,
+ isCommitError: false,
+ commitCallCount: 1,
+ mapCallCount: 1,
+ completeCallCount: 1,
+ abortCallCount: 1,
+ errorHandlerCallCount: 0,
+ onReadyCallCount: 2,
+ title: 'incomplete request, later successful'
+ },
+ {
+ readyState: 3,
+ status: 404,
+ isCommitError: false,
+ commitCallCount: 0,
+ mapCallCount: 0,
+ completeCallCount: 0,
+ abortCallCount: 0,
+ errorHandlerCallCount: 1,
+ onReadyCallCount: 2,
+ title: 'incomplete request, later failed'
+ }
+ ];
+
+ cases.forEach(function (item) {
+
+ describe(item.title, function () {
+
+ beforeEach(function () {
+ clock = sinon.useFakeTimers();
+ sinon.stub(App.store, 'commit');
+ sinon.spy(xhr, 'abort');
+ sinon.spy(mapper, 'map');
+ sinon.spy(mock, 'errorHandler');
+ sinon.spy(ajaxOptions, 'complete');
+ sinon.spy(App.HttpClient, 'onReady');
+ xhr.readyState = item.readyState;
+ xhr.status = item.status;
+ if (item.isCommitError) {
+ App.store.commit.throws();
+ }
+ App.HttpClient.onReady(xhr, null, ajaxOptions, mapper, mock.errorHandler, 'url');
+ clock.tick(10);
+ xhr.readyState = 4;
+ clock.tick(10);
+ });
+
+ afterEach(function () {
+ clock.restore();
+ App.store.commit.restore();
+ xhr.abort.restore();
+ mapper.map.restore();
+ mock.errorHandler.restore();
+ ajaxOptions.complete.restore();
+ App.HttpClient.onReady.restore();
+ });
+
+ it('App.store.commit call', function () {
+ expect(App.store.commit.callCount).to.equal(item.commitCallCount);
+ });
+
+ it('mapping data', function () {
+ expect(mapper.map.callCount).to.equal(item.mapCallCount);
+ });
+
+ if (item.mapCallCount) {
+ it('mapped data', function () {
+ expect(mapper.map.alwaysCalledWith({
+ property: 'value'
+ })).to.be.true;
+ });
+ }
+
+ it('complete callback call', function () {
+ expect(ajaxOptions.complete.callCount).to.equal(item.completeCallCount);
+ });
+
+ if (item.completeCallCount) {
+ it('complete callback context', function () {
+ expect(ajaxOptions.complete.alwaysCalledOn(App.HttpClient)).to.be.true;
+ });
+ }
+
+ it('abort request', function () {
+ expect(xhr.abort.callCount).to.equal(item.abortCallCount);
+ });
+
+ it('error handler call', function () {
+ expect(mock.errorHandler.callCount).to.equal(item.errorHandlerCallCount);
+ });
+
+ if (item.errorHandlerCallCount) {
+ it('error handler arguments', function () {
+ expect(mock.errorHandler.alwaysCalledWith(xhr, 'error', 'status', 'url')).to.be.true;
+ });
+ }
+
+ it('onReady iterations number', function () {
+ expect(App.HttpClient.onReady.callCount).to.equal(item.onReadyCallCount);
+ });
+
+ });
+
+ });
+
+ });
+
+ describe('#get', function () {
+
+ var mapper = {},
+ cases = [
+ {
+ data: {
+ error: Em.clb
+ },
+ errorHandler: Em.K,
+ passedErrorHandler: Em.K,
+ isGetAsPost: false,
+ title: 'custom error handler'
+ },
+ {
+ data: {
+ error: Em.clb,
+ doGetAsPost: true
+ },
+ interval: 1,
+ passedErrorHandler: Em.clb,
+ isGetAsPost: true,
+ title: 'error handler from data, interval provided, POST request'
+ }
+ ];
+
+ cases.forEach(function (item) {
+
+ describe(item.title, function () {
+
+ beforeEach(function () {
+ sinon.stub(App.HttpClient, 'request', Em.K);
+ sinon.stub($, 'periodic', function (options, callback) {
+ callback();
+ });
+ App.HttpClient.get('url', mapper, item.data, item.errorHandler, item.interval);
+ });
+
+ afterEach(function () {
+ App.HttpClient.request.restore();
+ $.periodic.restore();
+ });
+
+ it('request call', function () {
+ expect(App.HttpClient.request.calledOnce).to.be.true;
+ });
+
+ it('request arguments', function () {
+ expect(App.HttpClient.request.firstCall.args).to.eql(['url', item.data, mapper, item.passedErrorHandler, item.isGetAsPost]);
+ });
+
+ });
+
+ });
+
+ });
+
+ describe('#post', function () {
+
+ var args = ['url', {}, {}, Em.K, 1];
+
+ beforeEach(function () {
+ sinon.stub(App.HttpClient, 'get', Em.K);
+ App.HttpClient.post.apply(App.HttpClient, args);
+ });
+
+ afterEach(function () {
+ App.HttpClient.get.restore();
+ });
+
+ it('should call get method', function () {
+ expect(App.HttpClient.get.calledOnce).to.be.true;
+ });
+
+ it('get method arguments', function () {
+ expect(App.HttpClient.get.firstCall.args).to.eql(args);
+ });
+
+ });
+
+});
\ No newline at end of file