router_test.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672
  1. /**
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. var App = require('app');
  19. var testHelpers = require('test/helpers');
  20. require('router');
  21. describe('App.Router', function () {
  22. var router = App.Router.create();
  23. describe('#initAdmin()', function () {
  24. var cases = [
  25. {
  26. user: {
  27. admin: true
  28. },
  29. isAdmin: true,
  30. isOperator: false,
  31. isPermissionDataLoaded: true,
  32. title: 'admin'
  33. },
  34. {
  35. user: {
  36. operator: true
  37. },
  38. isAdmin: false,
  39. isOperator: true,
  40. isPermissionDataLoaded: true,
  41. title: 'operator'
  42. },
  43. {
  44. user: {},
  45. isAdmin: false,
  46. isOperator: false,
  47. isPermissionDataLoaded: true,
  48. title: 'read only access'
  49. },
  50. {
  51. user: null,
  52. isAdmin: false,
  53. isOperator: false,
  54. isPermissionDataLoaded: false,
  55. title: 'no user'
  56. }
  57. ];
  58. beforeEach(function () {
  59. this.getUser = sinon.stub(App.db, 'getUser');
  60. App.setProperties({
  61. isAdmin: false,
  62. isOperator: false,
  63. isPermissionDataLoaded: false
  64. });
  65. });
  66. afterEach(function () {
  67. this.getUser.restore();
  68. });
  69. cases.forEach(function (item) {
  70. it(item.title, function () {
  71. this.getUser.returns(item.user);
  72. router.initAdmin();
  73. expect(App.get('isAdmin')).to.equal(item.isAdmin);
  74. expect(App.get('isOperator')).to.equal(item.isOperator);
  75. expect(App.get('isPermissionDataLoaded')).to.equal(item.isPermissionDataLoaded);
  76. });
  77. });
  78. });
  79. describe('#adminViewInfoSuccessCallback', function () {
  80. beforeEach(function () {
  81. sinon.stub(window.location, 'replace', Em.K);
  82. });
  83. afterEach(function () {
  84. window.location.replace.restore();
  85. });
  86. var tests = [{
  87. mockData: {
  88. components: [{
  89. 'RootServiceComponents': {
  90. 'component_version': '1.9.0'
  91. }
  92. }, {
  93. 'RootServiceComponents': {
  94. 'component_version': '2.0.0'
  95. }
  96. }]
  97. },
  98. expected: '/views/ADMIN_VIEW/2.0.0/INSTANCE/#/'
  99. }, {
  100. mockData: {
  101. components: [{
  102. 'RootServiceComponents': {
  103. 'component_version': '1.9.0'
  104. }
  105. }, {
  106. 'RootServiceComponents': {
  107. 'component_version': '2.1.0'
  108. }
  109. }, {
  110. 'RootServiceComponents': {
  111. 'component_version': '2.0.0'
  112. }
  113. }]
  114. },
  115. expected: '/views/ADMIN_VIEW/2.1.0/INSTANCE/#/'
  116. }, {
  117. mockData: {
  118. components: [{
  119. 'RootServiceComponents': {
  120. component_version: '2.1.0'
  121. }
  122. }]
  123. },
  124. expected: '/views/ADMIN_VIEW/2.1.0/INSTANCE/#/'
  125. }];
  126. tests.forEach(function (data, index) {
  127. it('should redirect to the latest version of admin view ("' + data.expected + '") #' + (index + 1), function () {
  128. router.adminViewInfoSuccessCallback(data.mockData);
  129. expect(window.location.replace.calledWith(data.expected)).to.be.true;
  130. });
  131. });
  132. });
  133. describe.skip("#savePreferedPath()", function () {
  134. beforeEach(function () {
  135. router.set('preferedPath', null);
  136. });
  137. it("has no key", function () {
  138. router.savePreferedPath('path');
  139. expect(router.get('preferedPath')).to.equal('path');
  140. });
  141. it("path does not contain key", function () {
  142. router.savePreferedPath('path', 'key');
  143. expect(router.get('preferedPath')).to.be.null;
  144. });
  145. it("path contains key", function () {
  146. router.savePreferedPath('key=path', 'key=');
  147. expect(router.get('preferedPath')).to.equal('path');
  148. });
  149. });
  150. describe.skip("#restorePreferedPath()", function () {
  151. it("preferedPath is null", function () {
  152. router.set('preferedPath', null);
  153. expect(router.restorePreferedPath()).to.be.false;
  154. expect(router.get('preferedPath')).to.be.null;
  155. });
  156. it("preferedPath is '/relativeURL'", function () {
  157. router.set('preferedPath', '/relativeURL');
  158. expect(router.restorePreferedPath()).to.be.true;
  159. expect(router.get('preferedPath')).to.be.null;
  160. });
  161. it("preferedPath is '#/relativeURL'", function () {
  162. router.set('preferedPath', '#/relativeURL');
  163. expect(router.restorePreferedPath()).to.be.true;
  164. expect(router.get('preferedPath')).to.be.null;
  165. });
  166. it("preferedPath is '#/login'", function () {
  167. router.set('preferedPath', '#/login');
  168. expect(router.restorePreferedPath()).to.be.false;
  169. expect(router.get('preferedPath')).to.be.null;
  170. });
  171. it("preferedPath is 'http://absoluteURL'", function () {
  172. router.set('preferedPath', 'http://absoluteURL');
  173. expect(router.restorePreferedPath()).to.be.false;
  174. expect(router.get('preferedPath')).to.be.null;
  175. });
  176. });
  177. describe.skip("#loginGetClustersSuccessCallback()", function () {
  178. var mock = {dataLoading: Em.K};
  179. beforeEach(function () {
  180. sinon.stub(router, 'setClusterInstalled', Em.K);
  181. sinon.stub(router, 'transitionToApp', Em.K);
  182. sinon.stub(router, 'transitionToViews', Em.K);
  183. sinon.stub(router, 'transitionToAdminView', Em.K);
  184. sinon.stub(App.router, 'get').returns(mock);
  185. sinon.spy(mock, 'dataLoading');
  186. App.setProperties({
  187. isAdmin: false,
  188. isOperator: false,
  189. isPermissionDataLoaded: false
  190. });
  191. });
  192. afterEach(function () {
  193. router.setClusterInstalled.restore();
  194. router.transitionToApp.restore();
  195. router.transitionToViews.restore();
  196. router.transitionToAdminView.restore();
  197. App.router.get.restore();
  198. mock.dataLoading.restore();
  199. });
  200. it("cluster exists, OPERATOR privileges", function () {
  201. var clusterData = {
  202. items: [{
  203. Clusters: {
  204. cluster_name: 'c1'
  205. }
  206. }]
  207. };
  208. var params = {
  209. loginData: {
  210. privileges: [{
  211. PrivilegeInfo: {
  212. cluster_name: 'c1',
  213. permission_name: 'CLUSTER.ADMINISTRATOR'
  214. }
  215. }]
  216. }
  217. };
  218. router.loginGetClustersSuccessCallback(clusterData, {}, params);
  219. expect(router.setClusterInstalled.calledWith(clusterData)).to.be.true;
  220. expect(router.transitionToApp.calledOnce).to.be.true;
  221. expect(App.get('isAdmin')).to.be.true;
  222. expect(App.get('isOperator')).to.be.true;
  223. expect(App.get('isPermissionDataLoaded')).to.be.true;
  224. expect(mock.dataLoading.calledOnce).to.be.true;
  225. });
  226. it("cluster exists, READ privileges", function () {
  227. var clusterData = {
  228. items: [{
  229. Clusters: {
  230. cluster_name: 'c1'
  231. }
  232. }]
  233. };
  234. var params = {
  235. loginData: {
  236. privileges: [{
  237. PrivilegeInfo: {
  238. cluster_name: 'c1',
  239. permission_name: 'CLUSTER.USER'
  240. }
  241. }]
  242. }
  243. };
  244. router.loginGetClustersSuccessCallback(clusterData, {}, params);
  245. expect(router.setClusterInstalled.calledWith(clusterData)).to.be.true;
  246. expect(router.transitionToApp.calledOnce).to.be.true;
  247. expect(App.get('isAdmin')).to.be.false;
  248. expect(App.get('isOperator')).to.be.false;
  249. expect(App.get('isPermissionDataLoaded')).to.be.true;
  250. expect(mock.dataLoading.calledOnce).to.be.true;
  251. });
  252. it("cluster exists, ADMIN privileges", function () {
  253. var clusterData = {
  254. items: [{
  255. Clusters: {
  256. cluster_name: 'c1'
  257. }
  258. }]
  259. };
  260. var params = {
  261. loginData: {
  262. privileges: [{
  263. PrivilegeInfo: {
  264. cluster_name: 'c1',
  265. permission_name: 'AMBARI.ADMINISTRATOR'
  266. }
  267. }]
  268. }
  269. };
  270. router.loginGetClustersSuccessCallback(clusterData, {}, params);
  271. expect(router.setClusterInstalled.calledWith(clusterData)).to.be.true;
  272. expect(router.transitionToApp.calledOnce).to.be.true;
  273. expect(App.get('isAdmin')).to.be.true;
  274. expect(App.get('isOperator')).to.be.false;
  275. expect(App.get('isPermissionDataLoaded')).to.be.true;
  276. expect(mock.dataLoading.calledOnce).to.be.true;
  277. });
  278. it("cluster exists, no privileges", function () {
  279. var clusterData = {
  280. items: [{
  281. Clusters: {
  282. cluster_name: 'c1'
  283. }
  284. }]
  285. };
  286. var params = {
  287. loginData: {
  288. privileges: []
  289. }
  290. };
  291. router.loginGetClustersSuccessCallback(clusterData, {}, params);
  292. expect(router.setClusterInstalled.calledWith(clusterData)).to.be.true;
  293. expect(router.transitionToViews.calledOnce).to.be.true;
  294. expect(App.get('isAdmin')).to.be.false;
  295. expect(App.get('isOperator')).to.be.false;
  296. expect(App.get('isPermissionDataLoaded')).to.be.true;
  297. expect(mock.dataLoading.calledOnce).to.be.true;
  298. });
  299. it("cluster not installed, ADMIN privileges", function () {
  300. var clusterData = {
  301. items: []
  302. };
  303. var params = {
  304. loginData: {
  305. privileges: [{
  306. PrivilegeInfo: {
  307. cluster_name: 'c1',
  308. permission_name: 'AMBARI.ADMINISTRATOR'
  309. }
  310. }]
  311. }
  312. };
  313. router.loginGetClustersSuccessCallback(clusterData, {}, params);
  314. expect(router.transitionToAdminView.calledOnce).to.be.true;
  315. expect(App.get('isAdmin')).to.be.true;
  316. expect(App.get('isOperator')).to.be.false;
  317. expect(App.get('isPermissionDataLoaded')).to.be.true;
  318. expect(mock.dataLoading.calledOnce).to.be.true;
  319. });
  320. it("cluster not installed, non-admin privileges", function () {
  321. var clusterData = {
  322. items: []
  323. };
  324. var params = {
  325. loginData: {
  326. privileges: []
  327. }
  328. };
  329. router.loginGetClustersSuccessCallback(clusterData, {}, params);
  330. expect(router.transitionToViews.calledOnce).to.be.true;
  331. expect(App.get('isAdmin')).to.be.false;
  332. expect(App.get('isOperator')).to.be.false;
  333. expect(App.get('isPermissionDataLoaded')).to.be.true;
  334. expect(mock.dataLoading.calledOnce).to.be.true;
  335. });
  336. });
  337. describe("#transitionToAdminView()", function () {
  338. it("valid request is sent", function () {
  339. router.transitionToAdminView();
  340. var args = testHelpers.findAjaxRequest('name', 'ambari.service.load_server_version');
  341. expect(args[0]).to.exists;
  342. });
  343. });
  344. describe("#transitionToApp()", function () {
  345. beforeEach(function () {
  346. this.mock = sinon.stub(router, 'restorePreferedPath');
  347. sinon.stub(router, 'getSection', function (callback) {
  348. callback('route');
  349. });
  350. sinon.stub(router, 'transitionTo');
  351. });
  352. afterEach(function () {
  353. this.mock.restore();
  354. router.getSection.restore();
  355. router.transitionTo.restore();
  356. });
  357. it("has restore path", function () {
  358. this.mock.returns(true);
  359. router.transitionToApp();
  360. expect(router.getSection.called).to.be.false;
  361. expect(router.transitionTo.called).to.be.false;
  362. });
  363. it("does not have restore path", function () {
  364. this.mock.returns(false);
  365. router.transitionToApp();
  366. expect(router.getSection.calledOnce).to.be.true;
  367. expect(router.transitionTo.calledWith('route')).to.be.true;
  368. });
  369. });
  370. describe("#transitionToViews()", function () {
  371. var mock = {loadAmbariViews: Em.K};
  372. beforeEach(function () {
  373. sinon.stub(App.router, 'get').returns(mock);
  374. sinon.stub(router, 'transitionTo');
  375. sinon.spy(mock, 'loadAmbariViews');
  376. });
  377. afterEach(function () {
  378. App.router.get.restore();
  379. router.transitionTo.restore();
  380. mock.loadAmbariViews.restore();
  381. });
  382. it("transitionTo called with corrent route", function () {
  383. router.transitionToViews();
  384. expect(mock.loadAmbariViews.calledOnce).to.be.true;
  385. expect(router.transitionTo.calledWith('main.views.index')).to.be.true;
  386. });
  387. });
  388. describe("#adminViewInfoErrorCallback()", function () {
  389. beforeEach(function () {
  390. sinon.stub(router, 'transitionToViews');
  391. });
  392. afterEach(function () {
  393. router.transitionToViews.restore();
  394. });
  395. it("transitionToViews called once", function () {
  396. router.adminViewInfoErrorCallback();
  397. expect(router.transitionToViews.calledOnce).to.be.true;
  398. });
  399. });
  400. describe("#getAuthenticated", function () {
  401. beforeEach(function () {
  402. router = App.Router.create();
  403. this.mockGetCurrentLocationUrl = sinon.stub(router, 'getCurrentLocationUrl');
  404. sinon.stub(router, 'redirectByURL', Em.K);
  405. });
  406. afterEach(function () {
  407. router.getCurrentLocationUrl.restore();
  408. router.redirectByURL.restore();
  409. this.mockGetCurrentLocationUrl.restore();
  410. });
  411. [
  412. {
  413. lastSetURL: '/login/local',
  414. isResolved: false,
  415. responseData: {
  416. responseText: "",
  417. status: 403
  418. },
  419. redirectCalled: false,
  420. m: 'no jwtProviderUrl in auth response, no redirect'
  421. },
  422. {
  423. lastSetURL: '/main/dashboard',
  424. isResolved: false,
  425. responseData: {
  426. responseText: JSON.stringify({jwtProviderUrl: 'http://some.com?originalUrl='}),
  427. status: 403
  428. },
  429. redirectCalled: true,
  430. m: 'jwtProviderUrl is present, current location not local login url, redirect according to jwtProviderUrl value'
  431. },
  432. {
  433. lastSetURL: '/login/local',
  434. isResolved: false,
  435. responseData: {
  436. responseText: JSON.stringify({jwtProviderUrl: 'http://some.com?originalUrl='}),
  437. status: 403
  438. },
  439. redirectCalled: false,
  440. m: 'jwtProviderUrl is present, current location is local login url, no redirect'
  441. }
  442. ].forEach(function (test) {
  443. describe(test.m, function () {
  444. var mockCurrentUrl;
  445. beforeEach(function () {
  446. mockCurrentUrl = 'http://localhost:3333/#/some/hash';
  447. router.set('location.lastSetURL', test.lastSetURL);
  448. App.ajax.send.restore(); // default ajax-mock can't be used here
  449. sinon.stub(App.ajax, 'send', function () {
  450. if (!test.isResolved) {
  451. router.onAuthenticationError(test.responseData);
  452. }
  453. return {
  454. complete: function () {
  455. }
  456. };
  457. });
  458. this.mockGetCurrentLocationUrl.returns(mockCurrentUrl);
  459. router.getAuthenticated();
  460. });
  461. it('redirectByURL is ' + (test.redirectCalled ? '' : 'not') + ' called', function () {
  462. expect(router.redirectByURL.calledOnce).to.be.eql(test.redirectCalled);
  463. });
  464. if (test.redirectCalled) {
  465. it('redirectByURL is correct', function () {
  466. expect(router.redirectByURL.args[0][0]).to.be.eql(JSON.parse(test.responseData.responseText).jwtProviderUrl + encodeURIComponent(mockCurrentUrl));
  467. });
  468. }
  469. });
  470. });
  471. });
  472. describe('#setClusterData', function () {
  473. var data = {
  474. loginName: 'user',
  475. loginData: {
  476. PrivilegeInfo: {}
  477. }
  478. },
  479. clusterData = {
  480. items: []
  481. },
  482. cases = [
  483. {
  484. clusterData: clusterData,
  485. callbackCallCount: 1,
  486. isAjaxCalled: false,
  487. title: 'cluster data available'
  488. },
  489. {
  490. clusterData: null,
  491. callbackCallCount: 0,
  492. isAjaxCalled: true,
  493. title: 'no cluster data'
  494. }
  495. ];
  496. beforeEach(function () {
  497. sinon.stub(router, 'loginGetClustersSuccessCallback', Em.K);
  498. });
  499. afterEach(function () {
  500. router.loginGetClustersSuccessCallback.restore();
  501. });
  502. cases.forEach(function (item) {
  503. describe(item.title, function () {
  504. var ajaxCallArgs;
  505. beforeEach(function () {
  506. router.set('clusterData', item.clusterData);
  507. router.setClusterData({}, {}, data);
  508. ajaxCallArgs = testHelpers.findAjaxRequest('name', 'router.login.clusters');
  509. });
  510. it('loginGetClustersSuccessCallback', function () {
  511. expect(router.loginGetClustersSuccessCallback.callCount).to.equal(item.callbackCallCount);
  512. });
  513. if (item.isAjaxCalled) {
  514. it('App.ajax.send is called', function () {
  515. expect(ajaxCallArgs).to.have.length(1);
  516. });
  517. it('data for AJAX request', function () {
  518. expect(ajaxCallArgs).to.eql([
  519. {
  520. name: 'router.login.clusters',
  521. sender: router,
  522. data: data,
  523. success: 'loginGetClustersSuccessCallback'
  524. }
  525. ]);
  526. });
  527. } else {
  528. it('App.ajax.send is not called', function () {
  529. expect(ajaxCallArgs).to.be.undefined;
  530. });
  531. it('arguments for callback', function () {
  532. expect(router.loginGetClustersSuccessCallback.firstCall.args).to.eql([clusterData, {}, data]);
  533. });
  534. }
  535. });
  536. });
  537. });
  538. });
  539. describe('App.StepRoute', function () {
  540. beforeEach(function () {
  541. this.route = App.StepRoute.create();
  542. this.nextTransitionSpy = sinon.spy(this.route, 'nextTransition');
  543. this.backTransitionSpy = sinon.spy(this.route, 'backTransition');
  544. this.appGetStub = sinon.stub(App, 'get');
  545. this.appSetStub = sinon.stub(App, 'set');
  546. this.runNextStub = sinon.stub(Em.run, 'next', Em.clb);
  547. });
  548. afterEach(function () {
  549. this.nextTransitionSpy.restore();
  550. this.backTransitionSpy.restore();
  551. this.appGetStub.restore();
  552. this.appSetStub.restore();
  553. this.runNextStub.restore();
  554. });
  555. describe('#back', function () {
  556. [
  557. {
  558. btnClickInProgress: true,
  559. backBtnClickInProgressIsSet: false,
  560. backTransitionIsCalled: false,
  561. m: 'backTransition is not called'
  562. },
  563. {
  564. btnClickInProgress: false,
  565. backBtnClickInProgressIsSet: true,
  566. backTransitionIsCalled: true,
  567. m: 'backTransition is called'
  568. }
  569. ].forEach(function (test) {
  570. describe(test.m, function () {
  571. beforeEach(function () {
  572. this.appGetStub.withArgs('router.btnClickInProgress').returns(test.btnClickInProgress);
  573. this.route.back({});
  574. });
  575. it('backTransition call', function () {
  576. expect(this.backTransitionSpy.called).to.be.equal(test.backTransitionIsCalled);
  577. });
  578. it('backBtnClickInProgress is set', function () {
  579. expect(this.appSetStub.calledWith('router.backBtnClickInProgress')).to.be.equal(test.backBtnClickInProgressIsSet);
  580. });
  581. });
  582. });
  583. });
  584. describe('#next', function () {
  585. [
  586. {
  587. btnClickInProgress: true,
  588. nextBtnClickInProgressIsSet: false,
  589. nextTransitionIsCalled: false,
  590. m: 'nextTransition is not called'
  591. },
  592. {
  593. btnClickInProgress: false,
  594. nextBtnClickInProgressIsSet: true,
  595. nextTransitionIsCalled: true,
  596. m: 'nextTransition is called'
  597. }
  598. ].forEach(function (test) {
  599. describe(test.m, function () {
  600. beforeEach(function () {
  601. this.appGetStub.withArgs('router.btnClickInProgress').returns(test.btnClickInProgress);
  602. this.route.next({});
  603. });
  604. it('nextTransition call', function () {
  605. expect(this.nextTransitionSpy.called).to.be.equal(test.nextTransitionIsCalled);
  606. });
  607. it('nextBtnClickInProgress is set', function () {
  608. expect(this.appSetStub.calledWith('router.nextBtnClickInProgress')).to.be.equal(test.nextBtnClickInProgressIsSet);
  609. });
  610. });
  611. });
  612. });
  613. });