/** * 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'); var testHelpers = require('test/helpers'); require('router'); describe('App.Router', function () { var router = App.Router.create(); describe('#initAdmin()', function () { var cases = [ { user: { admin: true }, isAdmin: true, isOperator: false, isPermissionDataLoaded: true, title: 'admin' }, { user: { operator: true }, isAdmin: false, isOperator: true, isPermissionDataLoaded: true, title: 'operator' }, { user: {}, isAdmin: false, isOperator: false, isPermissionDataLoaded: true, title: 'read only access' }, { user: null, isAdmin: false, isOperator: false, isPermissionDataLoaded: false, title: 'no user' } ]; beforeEach(function () { this.getUser = sinon.stub(App.db, 'getUser'); App.setProperties({ isAdmin: false, isOperator: false, isPermissionDataLoaded: false }); }); afterEach(function () { this.getUser.restore(); }); cases.forEach(function (item) { it(item.title, function () { this.getUser.returns(item.user); router.initAdmin(); expect(App.get('isAdmin')).to.equal(item.isAdmin); expect(App.get('isOperator')).to.equal(item.isOperator); expect(App.get('isPermissionDataLoaded')).to.equal(item.isPermissionDataLoaded); }); }); }); describe('#adminViewInfoSuccessCallback', function () { beforeEach(function () { sinon.stub(window.location, 'replace', Em.K); }); afterEach(function () { window.location.replace.restore(); }); var tests = [{ mockData: { components: [{ 'RootServiceComponents': { 'component_version': '1.9.0' } }, { 'RootServiceComponents': { 'component_version': '2.0.0' } }] }, expected: '/views/ADMIN_VIEW/2.0.0/INSTANCE/#/' }, { mockData: { components: [{ 'RootServiceComponents': { 'component_version': '1.9.0' } }, { 'RootServiceComponents': { 'component_version': '2.1.0' } }, { 'RootServiceComponents': { 'component_version': '2.0.0' } }] }, expected: '/views/ADMIN_VIEW/2.1.0/INSTANCE/#/' }, { mockData: { components: [{ 'RootServiceComponents': { component_version: '2.1.0' } }] }, expected: '/views/ADMIN_VIEW/2.1.0/INSTANCE/#/' }]; tests.forEach(function (data, index) { it('should redirect to the latest version of admin view ("' + data.expected + '") #' + (index + 1), function () { router.adminViewInfoSuccessCallback(data.mockData); expect(window.location.replace.calledWith(data.expected)).to.be.true; }); }); }); describe.skip("#savePreferedPath()", function () { beforeEach(function () { router.set('preferedPath', null); }); it("has no key", function () { router.savePreferedPath('path'); expect(router.get('preferedPath')).to.equal('path'); }); it("path does not contain key", function () { router.savePreferedPath('path', 'key'); expect(router.get('preferedPath')).to.be.null; }); it("path contains key", function () { router.savePreferedPath('key=path', 'key='); expect(router.get('preferedPath')).to.equal('path'); }); }); describe.skip("#restorePreferedPath()", function () { it("preferedPath is null", function () { router.set('preferedPath', null); expect(router.restorePreferedPath()).to.be.false; expect(router.get('preferedPath')).to.be.null; }); it("preferedPath is '/relativeURL'", function () { router.set('preferedPath', '/relativeURL'); expect(router.restorePreferedPath()).to.be.true; expect(router.get('preferedPath')).to.be.null; }); it("preferedPath is '#/relativeURL'", function () { router.set('preferedPath', '#/relativeURL'); expect(router.restorePreferedPath()).to.be.true; expect(router.get('preferedPath')).to.be.null; }); it("preferedPath is '#/login'", function () { router.set('preferedPath', '#/login'); expect(router.restorePreferedPath()).to.be.false; expect(router.get('preferedPath')).to.be.null; }); it("preferedPath is 'http://absoluteURL'", function () { router.set('preferedPath', 'http://absoluteURL'); expect(router.restorePreferedPath()).to.be.false; expect(router.get('preferedPath')).to.be.null; }); }); describe.skip("#loginGetClustersSuccessCallback()", function () { var mock = {dataLoading: Em.K}; beforeEach(function () { sinon.stub(router, 'setClusterInstalled', Em.K); sinon.stub(router, 'transitionToApp', Em.K); sinon.stub(router, 'transitionToViews', Em.K); sinon.stub(router, 'transitionToAdminView', Em.K); sinon.stub(App.router, 'get').returns(mock); sinon.spy(mock, 'dataLoading'); App.setProperties({ isAdmin: false, isOperator: false, isPermissionDataLoaded: false }); }); afterEach(function () { router.setClusterInstalled.restore(); router.transitionToApp.restore(); router.transitionToViews.restore(); router.transitionToAdminView.restore(); App.router.get.restore(); mock.dataLoading.restore(); }); it("cluster exists, OPERATOR privileges", function () { var clusterData = { items: [{ Clusters: { cluster_name: 'c1' } }] }; var params = { loginData: { privileges: [{ PrivilegeInfo: { cluster_name: 'c1', permission_name: 'CLUSTER.ADMINISTRATOR' } }] } }; router.loginGetClustersSuccessCallback(clusterData, {}, params); expect(router.setClusterInstalled.calledWith(clusterData)).to.be.true; expect(router.transitionToApp.calledOnce).to.be.true; expect(App.get('isAdmin')).to.be.true; expect(App.get('isOperator')).to.be.true; expect(App.get('isPermissionDataLoaded')).to.be.true; expect(mock.dataLoading.calledOnce).to.be.true; }); it("cluster exists, READ privileges", function () { var clusterData = { items: [{ Clusters: { cluster_name: 'c1' } }] }; var params = { loginData: { privileges: [{ PrivilegeInfo: { cluster_name: 'c1', permission_name: 'CLUSTER.USER' } }] } }; router.loginGetClustersSuccessCallback(clusterData, {}, params); expect(router.setClusterInstalled.calledWith(clusterData)).to.be.true; expect(router.transitionToApp.calledOnce).to.be.true; expect(App.get('isAdmin')).to.be.false; expect(App.get('isOperator')).to.be.false; expect(App.get('isPermissionDataLoaded')).to.be.true; expect(mock.dataLoading.calledOnce).to.be.true; }); it("cluster exists, ADMIN privileges", function () { var clusterData = { items: [{ Clusters: { cluster_name: 'c1' } }] }; var params = { loginData: { privileges: [{ PrivilegeInfo: { cluster_name: 'c1', permission_name: 'AMBARI.ADMINISTRATOR' } }] } }; router.loginGetClustersSuccessCallback(clusterData, {}, params); expect(router.setClusterInstalled.calledWith(clusterData)).to.be.true; expect(router.transitionToApp.calledOnce).to.be.true; expect(App.get('isAdmin')).to.be.true; expect(App.get('isOperator')).to.be.false; expect(App.get('isPermissionDataLoaded')).to.be.true; expect(mock.dataLoading.calledOnce).to.be.true; }); it("cluster exists, no privileges", function () { var clusterData = { items: [{ Clusters: { cluster_name: 'c1' } }] }; var params = { loginData: { privileges: [] } }; router.loginGetClustersSuccessCallback(clusterData, {}, params); expect(router.setClusterInstalled.calledWith(clusterData)).to.be.true; expect(router.transitionToViews.calledOnce).to.be.true; expect(App.get('isAdmin')).to.be.false; expect(App.get('isOperator')).to.be.false; expect(App.get('isPermissionDataLoaded')).to.be.true; expect(mock.dataLoading.calledOnce).to.be.true; }); it("cluster not installed, ADMIN privileges", function () { var clusterData = { items: [] }; var params = { loginData: { privileges: [{ PrivilegeInfo: { cluster_name: 'c1', permission_name: 'AMBARI.ADMINISTRATOR' } }] } }; router.loginGetClustersSuccessCallback(clusterData, {}, params); expect(router.transitionToAdminView.calledOnce).to.be.true; expect(App.get('isAdmin')).to.be.true; expect(App.get('isOperator')).to.be.false; expect(App.get('isPermissionDataLoaded')).to.be.true; expect(mock.dataLoading.calledOnce).to.be.true; }); it("cluster not installed, non-admin privileges", function () { var clusterData = { items: [] }; var params = { loginData: { privileges: [] } }; router.loginGetClustersSuccessCallback(clusterData, {}, params); expect(router.transitionToViews.calledOnce).to.be.true; expect(App.get('isAdmin')).to.be.false; expect(App.get('isOperator')).to.be.false; expect(App.get('isPermissionDataLoaded')).to.be.true; expect(mock.dataLoading.calledOnce).to.be.true; }); }); describe("#transitionToAdminView()", function () { it("valid request is sent", function () { router.transitionToAdminView(); var args = testHelpers.findAjaxRequest('name', 'ambari.service.load_server_version'); expect(args[0]).to.exists; }); }); describe("#transitionToApp()", function () { beforeEach(function () { this.mock = sinon.stub(router, 'restorePreferedPath'); sinon.stub(router, 'getSection', function (callback) { callback('route'); }); sinon.stub(router, 'transitionTo'); }); afterEach(function () { this.mock.restore(); router.getSection.restore(); router.transitionTo.restore(); }); it("has restore path", function () { this.mock.returns(true); router.transitionToApp(); expect(router.getSection.called).to.be.false; expect(router.transitionTo.called).to.be.false; }); it("does not have restore path", function () { this.mock.returns(false); router.transitionToApp(); expect(router.getSection.calledOnce).to.be.true; expect(router.transitionTo.calledWith('route')).to.be.true; }); }); describe("#transitionToViews()", function () { var mock = {loadAmbariViews: Em.K}; beforeEach(function () { sinon.stub(App.router, 'get').returns(mock); sinon.stub(router, 'transitionTo'); sinon.spy(mock, 'loadAmbariViews'); }); afterEach(function () { App.router.get.restore(); router.transitionTo.restore(); mock.loadAmbariViews.restore(); }); it("transitionTo called with corrent route", function () { router.transitionToViews(); expect(mock.loadAmbariViews.calledOnce).to.be.true; expect(router.transitionTo.calledWith('main.views.index')).to.be.true; }); }); describe("#adminViewInfoErrorCallback()", function () { beforeEach(function () { sinon.stub(router, 'transitionToViews'); }); afterEach(function () { router.transitionToViews.restore(); }); it("transitionToViews called once", function () { router.adminViewInfoErrorCallback(); expect(router.transitionToViews.calledOnce).to.be.true; }); }); describe("#getAuthenticated", function () { beforeEach(function () { router = App.Router.create(); this.mockGetCurrentLocationUrl = sinon.stub(router, 'getCurrentLocationUrl'); sinon.stub(router, 'redirectByURL', Em.K); }); afterEach(function () { router.getCurrentLocationUrl.restore(); router.redirectByURL.restore(); this.mockGetCurrentLocationUrl.restore(); }); [ { lastSetURL: '/login/local', isResolved: false, responseData: { responseText: "", status: 403 }, redirectCalled: false, m: 'no jwtProviderUrl in auth response, no redirect' }, { lastSetURL: '/main/dashboard', isResolved: false, responseData: { responseText: JSON.stringify({jwtProviderUrl: 'http://some.com?originalUrl='}), status: 403 }, redirectCalled: true, m: 'jwtProviderUrl is present, current location not local login url, redirect according to jwtProviderUrl value' }, { lastSetURL: '/login/local', isResolved: false, responseData: { responseText: JSON.stringify({jwtProviderUrl: 'http://some.com?originalUrl='}), status: 403 }, redirectCalled: false, m: 'jwtProviderUrl is present, current location is local login url, no redirect' } ].forEach(function (test) { describe(test.m, function () { var mockCurrentUrl; beforeEach(function () { mockCurrentUrl = 'http://localhost:3333/#/some/hash'; router.set('location.lastSetURL', test.lastSetURL); App.ajax.send.restore(); // default ajax-mock can't be used here sinon.stub(App.ajax, 'send', function () { if (!test.isResolved) { router.onAuthenticationError(test.responseData); } return { complete: function () { } }; }); this.mockGetCurrentLocationUrl.returns(mockCurrentUrl); router.getAuthenticated(); }); it('redirectByURL is ' + (test.redirectCalled ? '' : 'not') + ' called', function () { expect(router.redirectByURL.calledOnce).to.be.eql(test.redirectCalled); }); if (test.redirectCalled) { it('redirectByURL is correct', function () { expect(router.redirectByURL.args[0][0]).to.be.eql(JSON.parse(test.responseData.responseText).jwtProviderUrl + encodeURIComponent(mockCurrentUrl)); }); } }); }); }); describe('#setClusterData', function () { var data = { loginName: 'user', loginData: { PrivilegeInfo: {} } }, clusterData = { items: [] }, cases = [ { clusterData: clusterData, callbackCallCount: 1, isAjaxCalled: false, title: 'cluster data available' }, { clusterData: null, callbackCallCount: 0, isAjaxCalled: true, title: 'no cluster data' } ]; beforeEach(function () { sinon.stub(router, 'loginGetClustersSuccessCallback', Em.K); }); afterEach(function () { router.loginGetClustersSuccessCallback.restore(); }); cases.forEach(function (item) { describe(item.title, function () { var ajaxCallArgs; beforeEach(function () { router.set('clusterData', item.clusterData); router.setClusterData({}, {}, data); ajaxCallArgs = testHelpers.findAjaxRequest('name', 'router.login.clusters'); }); it('loginGetClustersSuccessCallback', function () { expect(router.loginGetClustersSuccessCallback.callCount).to.equal(item.callbackCallCount); }); if (item.isAjaxCalled) { it('App.ajax.send is called', function () { expect(ajaxCallArgs).to.have.length(1); }); it('data for AJAX request', function () { expect(ajaxCallArgs).to.eql([ { name: 'router.login.clusters', sender: router, data: data, success: 'loginGetClustersSuccessCallback' } ]); }); } else { it('App.ajax.send is not called', function () { expect(ajaxCallArgs).to.be.undefined; }); it('arguments for callback', function () { expect(router.loginGetClustersSuccessCallback.firstCall.args).to.eql([clusterData, {}, data]); }); } }); }); }); }); describe('App.StepRoute', function () { beforeEach(function () { this.route = App.StepRoute.create(); this.nextTransitionSpy = sinon.spy(this.route, 'nextTransition'); this.backTransitionSpy = sinon.spy(this.route, 'backTransition'); this.appGetStub = sinon.stub(App, 'get'); this.appSetStub = sinon.stub(App, 'set'); this.runNextStub = sinon.stub(Em.run, 'next', Em.clb); }); afterEach(function () { this.nextTransitionSpy.restore(); this.backTransitionSpy.restore(); this.appGetStub.restore(); this.appSetStub.restore(); this.runNextStub.restore(); }); describe('#back', function () { [ { btnClickInProgress: true, backBtnClickInProgressIsSet: false, backTransitionIsCalled: false, m: 'backTransition is not called' }, { btnClickInProgress: false, backBtnClickInProgressIsSet: true, backTransitionIsCalled: true, m: 'backTransition is called' } ].forEach(function (test) { describe(test.m, function () { beforeEach(function () { this.appGetStub.withArgs('router.btnClickInProgress').returns(test.btnClickInProgress); this.route.back({}); }); it('backTransition call', function () { expect(this.backTransitionSpy.called).to.be.equal(test.backTransitionIsCalled); }); it('backBtnClickInProgress is set', function () { expect(this.appSetStub.calledWith('router.backBtnClickInProgress')).to.be.equal(test.backBtnClickInProgressIsSet); }); }); }); }); describe('#next', function () { [ { btnClickInProgress: true, nextBtnClickInProgressIsSet: false, nextTransitionIsCalled: false, m: 'nextTransition is not called' }, { btnClickInProgress: false, nextBtnClickInProgressIsSet: true, nextTransitionIsCalled: true, m: 'nextTransition is called' } ].forEach(function (test) { describe(test.m, function () { beforeEach(function () { this.appGetStub.withArgs('router.btnClickInProgress').returns(test.btnClickInProgress); this.route.next({}); }); it('nextTransition call', function () { expect(this.nextTransitionSpy.called).to.be.equal(test.nextTransitionIsCalled); }); it('nextBtnClickInProgress is set', function () { expect(this.appSetStub.calledWith('router.nextBtnClickInProgress')).to.be.equal(test.nextBtnClickInProgressIsSet); }); }); }); }); });