diff --git a/e2e-tests/desktop/fixtures/electronTest.js b/e2e-tests/desktop/fixtures/electronTest.js index 181381ead..093c4cb36 100644 --- a/e2e-tests/desktop/fixtures/electronTest.js +++ b/e2e-tests/desktop/fixtures/electronTest.js @@ -133,6 +133,8 @@ export const electronTest = test.extend({ electronPage: async ({ electronApp }, use) => { const page = await electronApp.firstWindow(); await page.evaluate(() => localStorage.clear()); + // Reset the cluster URL stored by electron + await page.evaluate(() => window.desktop.cluster.resetClusterUrl()); await page.context().tracing.start({ screenshots: true, snapshots: true }); await use(page); diff --git a/ui/desktop/app/controllers/application.js b/ui/desktop/app/controllers/application.js index 78c534fd3..904862cfa 100644 --- a/ui/desktop/app/controllers/application.js +++ b/ui/desktop/app/controllers/application.js @@ -45,7 +45,7 @@ export default class ApplicationController extends Controller { * @type {object} */ get currentScope() { - if (this.scope.org.isOrg) { + if (this.scope.org?.isOrg) { return { name: this.scope.org.displayName, icon: 'org' }; } else { return { name: this.intl.t('titles.global'), icon: 'globe' }; @@ -100,13 +100,14 @@ export default class ApplicationController extends Controller { } /** - * Disconnects from clusterUrl and invalidates session, thereby resetting - * the client and reloading to the onboarding clusterUrl screen. + * Invalidates the session and navigates to the cluster-url route. + * The cluster URL is preserved so that upon reload the user is directed + * back to the authentication screen for the same cluster. */ @action disconnect() { - this.clusterUrl.resetClusterUrl(); this.session.invalidate(); + this.router.replaceWith('cluster-url'); } @action diff --git a/ui/desktop/app/initializers/cluster-url.js b/ui/desktop/app/initializers/cluster-url.js deleted file mode 100644 index fac5228de..000000000 --- a/ui/desktop/app/initializers/cluster-url.js +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright IBM Corp. 2021, 2026 - * SPDX-License-Identifier: BUSL-1.1 - */ - -import { getOwner } from '@ember/application'; - -export function initialize(registry) { - // Lookup the application route - const ApplicationRoute = registry.resolveRegistration - ? registry.resolveRegistration('route:application') - : registry.resolve('route:application'); - - ApplicationRoute.reopen({ - init() { - this._super(...arguments); - const originalBeforeModel = this.beforeModel; - - // Override the beforeModel hook and initialize the clusterUrl - this.beforeModel = async function () { - const clusterUrl = getOwner(this).lookup('service:clusterUrl'); - return clusterUrl.updateClusterUrl().then( - () => originalBeforeModel.apply(this, arguments), - () => originalBeforeModel.apply(this, arguments), - ); - }; - }, - }); -} - -export default { - after: 'ember-simple-auth', - initialize, -}; diff --git a/ui/desktop/app/routes/application.js b/ui/desktop/app/routes/application.js index 191ba5fbf..e5d73ff0d 100644 --- a/ui/desktop/app/routes/application.js +++ b/ui/desktop/app/routes/application.js @@ -15,6 +15,7 @@ export default class ApplicationRoute extends Route { @service session; @service clusterUrl; @service intl; + @service store; @service rdp; @service terminal; @@ -25,19 +26,20 @@ export default class ApplicationRoute extends Route { */ routeIfUnauthenticated = 'index'; - /** - * Check that the clusterUrl specified in the renderer matches the clusterUrl - * reported by the main process. If they differ, update the main process - * clusterUrl so that the renderer's CSP can be rewritten to allow requests. - */ @notifyError(({ message }) => message, { catch: true, log: { origin: 'ApplicationRoute:beforeModel' }, }) async beforeModel() { this.intl.setLocale(['en-us']); + + const clusterUrl = await this.clusterUrl.getClusterUrl(); + if (clusterUrl) { + const adapter = this.store.adapterFor('application'); + adapter.host = clusterUrl; + } + await this.session.setup(); - await this.clusterUrl.updateClusterUrl(); const theme = this.session.get('data.theme'); /* eslint-disable-next-line ember/no-controller-access-in-routes */ const controller = this.controllerFor(this.routeName); diff --git a/ui/desktop/app/routes/cluster-url.js b/ui/desktop/app/routes/cluster-url.js index 6494080e3..5ff9bc586 100644 --- a/ui/desktop/app/routes/cluster-url.js +++ b/ui/desktop/app/routes/cluster-url.js @@ -41,9 +41,9 @@ export default class ClusterUrlRoute extends Route { * Adds the existing clusterUrl, if any, to the controller scope. * @param {Controller} controller */ - setupController(controller) { + async setupController(controller) { super.setupController(...arguments); - let clusterUrl = this.clusterUrl.rendererClusterUrl; + let clusterUrl = await this.clusterUrl.getClusterUrl(); // If clusterUrl is unset and this is a development environment, // auto-set the clusterUrl field of the UI for better DX. // The controller URL is almost always the same as the current window when diff --git a/ui/desktop/app/routes/index.js b/ui/desktop/app/routes/index.js index 16a7af83e..b3ae29160 100644 --- a/ui/desktop/app/routes/index.js +++ b/ui/desktop/app/routes/index.js @@ -18,12 +18,12 @@ export default class IndexRoute extends Route { /** * If no clusterUrl is specified yet, redirects to cluster-url, otherwise scopes. */ - redirect() { + async beforeModel() { // cleanup terminal view when navigating to index route - on window reload this.terminal.cleanup(); - const rendererClusterUrl = this.clusterUrl.rendererClusterUrl; - if (!rendererClusterUrl) { + const clusterUrl = await this.clusterUrl.getClusterUrl(); + if (!clusterUrl) { this.router.replaceWith('cluster-url'); } else { this.router.replaceWith('scopes'); diff --git a/ui/desktop/app/routes/scopes/scope/authenticate.js b/ui/desktop/app/routes/scopes/scope/authenticate.js index 52bc046b0..4c84354ad 100644 --- a/ui/desktop/app/routes/scopes/scope/authenticate.js +++ b/ui/desktop/app/routes/scopes/scope/authenticate.js @@ -17,8 +17,11 @@ export default class ScopesScopeAuthenticateRoute extends Route { // =methods - beforeModel() { - if (this.session.isAuthenticated) { + async beforeModel() { + const clusterUrl = await this.clusterUrl.getClusterUrl(); + if (!clusterUrl) { + this.router.replaceWith('cluster-url'); + } else if (this.session.isAuthenticated) { this.router.replaceWith('scopes.scope.index'); } } @@ -64,17 +67,13 @@ export default class ScopesScopeAuthenticateRoute extends Route { }; } - redirect() { - if (!this.clusterUrl.rendererClusterUrl) this.router.replaceWith('index'); - } - /** * Adds the existing clusterUrl, if any, to the controller scope. * @param {Controller} controller */ - setupController(controller) { + async setupController(controller) { super.setupController(...arguments); - const clusterUrl = this.clusterUrl.rendererClusterUrl; + const clusterUrl = await this.clusterUrl.getClusterUrl(); controller.setProperties({ clusterUrl }); } } diff --git a/ui/desktop/app/routes/scopes/scope/projects/settings/index.js b/ui/desktop/app/routes/scopes/scope/projects/settings/index.js index 59d2b3a80..4f8697b95 100644 --- a/ui/desktop/app/routes/scopes/scope/projects/settings/index.js +++ b/ui/desktop/app/routes/scopes/scope/projects/settings/index.js @@ -22,7 +22,7 @@ export default class ScopesScopeProjectsSettingsIndexRoute extends Route { const logLevel = await window.desktop.logging.getLogLevel(); const logPath = await window.desktop.logging.getLogPath(); - const serverInformation = this.clusterUrl.rendererClusterUrl; + const serverInformation = await this.clusterUrl.getClusterUrl(); const { isLinux } = await window.desktop.system.checkOS(); return { diff --git a/ui/desktop/app/routes/scopes/scope/projects/targets/index.js b/ui/desktop/app/routes/scopes/scope/projects/targets/index.js index dd4e9d9da..3ed9afe53 100644 --- a/ui/desktop/app/routes/scopes/scope/projects/targets/index.js +++ b/ui/desktop/app/routes/scopes/scope/projects/targets/index.js @@ -18,7 +18,6 @@ export default class ScopesScopeProjectsTargetsIndexRoute extends Route { // =services @service abilities; - @service clusterUrl; @service resourceFilterStore; @service router; @service session; diff --git a/ui/desktop/app/services/cluster-url.js b/ui/desktop/app/services/cluster-url.js index 0480e3e67..5b5365fe0 100644 --- a/ui/desktop/app/services/cluster-url.js +++ b/ui/desktop/app/services/cluster-url.js @@ -12,7 +12,6 @@ export default class ClusterUrlService extends Service { // =services @service store; - @service storage; // =attributes @@ -23,35 +22,10 @@ export default class ClusterUrlService extends Service { return this.store.adapterFor('application'); } - /** - * @type {?string} - */ - get rendererClusterUrl() { - return this.storage.getItem('cluster-url'); - } - - /** - * @param {?string} clusterUrl - */ - set rendererClusterUrl(clusterUrl) { - this.storage.setItem('cluster-url', clusterUrl); - } - - /** - * @type {Promise{?string}} - */ - get mainClusterUrl() { - return window.desktop.cluster.getClusterUrl(); - } - // =methods - /** - * Sets the main clusterUrl equal to the current renderer clusterUrl (if any). - */ - async updateClusterUrl() { - const rendererClusterUrl = this.rendererClusterUrl; - if (rendererClusterUrl) await this.setClusterUrl(rendererClusterUrl); + async getClusterUrl() { + return window.desktop.cluster.getClusterUrl(); } /** @@ -73,26 +47,24 @@ export default class ClusterUrlService extends Service { clusterUrl = clusterUrl.trim(); clusterUrl = clusterUrl.replace(/\/*$/, ''); this.adapter.host = clusterUrl; - this.rendererClusterUrl = clusterUrl; - if (clusterUrl !== (await this.mainClusterUrl)) { + if (clusterUrl !== (await this.getClusterUrl())) { await window.desktop.cluster.setClusterUrl(clusterUrl); } } catch (e) { this.adapter.host = originalHost; - this.rendererClusterUrl = null; throw e; } } /** - * Resets the clusterUrl. + * Resets the clusterUrl in both the electron store and the adapter host. */ @notifyError(({ message }) => message, { catch: true, log: { origin: 'resetClusterUrl' }, }) async resetClusterUrl() { - this.rendererClusterUrl = null; - await window.desktop.cluster.resetClusterUrl(); + this.adapter.host = undefined; + return window.desktop.cluster.resetClusterUrl(); } } diff --git a/ui/desktop/electron-app/src/ipc/handlers.js b/ui/desktop/electron-app/src/ipc/handlers.js index 493516010..e6e4e77c5 100644 --- a/ui/desktop/electron-app/src/ipc/handlers.js +++ b/ui/desktop/electron-app/src/ipc/handlers.js @@ -33,7 +33,7 @@ handle('getClusterUrl', () => runtimeSettings.clusterUrl); handle('setClusterUrl', async (requestOrigin) => { const clusterUrl = sanitizer.urlValidate(requestOrigin); await runtimeSettings.validateClusterUrl(clusterUrl); - await runtimeSettings.setClusterUrl(clusterUrl); + await runtimeSettings.triggerClusterUrlUpdate(clusterUrl); }); /** diff --git a/ui/desktop/electron-app/src/models/runtime-settings.js b/ui/desktop/electron-app/src/models/runtime-settings.js index 0dfa45249..a0dddc3bb 100644 --- a/ui/desktop/electron-app/src/models/runtime-settings.js +++ b/ui/desktop/electron-app/src/models/runtime-settings.js @@ -4,26 +4,25 @@ */ const { netRequest } = require('../helpers/request-promise.js'); +const store = require('../services/electron-store-manager'); // Runtime settings are any configuration, especially user-specified, // set up at runtime. For example, the Boundary clusterUrl is a runtime setting. class RuntimeSettings { - // Internal private clusterUrl is exposed via getter/setter below. - #clusterUrl = undefined; - /** * The user-specified Boundary clusterUrl, which should be allowed by CSP. * @type {?string} */ get clusterUrl() { - return this.#clusterUrl; + return store.get('clusterUrl'); } - async setClusterUrl(clusterUrl) { - if (this.#clusterUrl !== clusterUrl) { - this.#clusterUrl = clusterUrl; - await this.triggerClusterUrlChanged(); - } + /** + * Sets the user specified Boundary clusterUrl. + * @param value {string} + */ + set clusterUrl(value) { + store.set('clusterUrl', value); } /** @@ -51,8 +50,8 @@ class RuntimeSettings { /** * Sets the clusterUrl to null. */ - async resetClusterUrl() { - await this.setClusterUrl(null); + resetClusterUrl() { + store.delete('clusterUrl'); } // Quick and dirty event handler pattern to enable the application to respond @@ -63,11 +62,14 @@ class RuntimeSettings { this.#clusterUrlWatchers.push(fn); } - async triggerClusterUrlChanged() { - // We currently only store one function but this will execute serially - // which may or may not be the desired behavior if there ever is more - for (const fn of this.#clusterUrlWatchers) { - await fn(this.#clusterUrl); + async triggerClusterUrlUpdate(clusterUrl) { + if (this.clusterUrl !== clusterUrl) { + this.clusterUrl = clusterUrl; + for (const fn of this.#clusterUrlWatchers) { + // We currently only store one function but this will execute serially + // which may or may not be the desired behavior if there ever is more + await fn(this.clusterUrl); + } } } } diff --git a/ui/desktop/tests/acceptance/authentication-test.js b/ui/desktop/tests/acceptance/authentication-test.js index 75f8049d5..d1522269b 100644 --- a/ui/desktop/tests/acceptance/authentication-test.js +++ b/ui/desktop/tests/acceptance/authentication-test.js @@ -71,12 +71,6 @@ module('Acceptance | authentication', function (hooks) { const MODAL_CANCEL_BTN = '.hds-modal__footer .hds-button--color-secondary'; const HEADER_DROPDOWN_BTN = '.app-header__utility-actions button'; - const setDefaultClusterUrl = (test) => { - const windowOrigin = window.location.origin; - const clusterUrl = test.owner.lookup('service:clusterUrl'); - clusterUrl.rendererClusterUrl = windowOrigin; - }; - hooks.beforeEach(async function () { await invalidateSession(); @@ -130,7 +124,7 @@ module('Acceptance | authentication', function (hooks) { urls.targets = `${urls.projects}/targets`; urls.sessions = `${urls.projects}/sessions`; - setDefaultClusterUrl(this); + window.desktop.cluster.getClusterUrl.resolves(window.location.origin); }); hooks.afterEach(async function () { @@ -147,8 +141,17 @@ module('Acceptance | authentication', function (hooks) { test('visiting authenticate route without clusterUrl redirects to clusterUrl index', async function (assert) { assert.expect(1); - this.owner.lookup('service:clusterUrl').rendererClusterUrl = null; - await visit(urls.authenticate.global); + window.desktop.cluster.getClusterUrl.resolves(null); + + try { + await visit(urls.authenticate.global); + } catch (e) { + if (e.message === 'TransitionAborted') { + // Ignore the expected transition abort error caused by the redirect in beforeModel + } else { + throw e; + } + } assert.strictEqual(currentURL(), urls.clusterUrl); }); diff --git a/ui/desktop/tests/acceptance/cluster-url-test.js b/ui/desktop/tests/acceptance/cluster-url-test.js index 8e39b391d..da05aac2b 100644 --- a/ui/desktop/tests/acceptance/cluster-url-test.js +++ b/ui/desktop/tests/acceptance/cluster-url-test.js @@ -8,13 +8,11 @@ import { visit, currentURL, fillIn, click, find } from '@ember/test-helpers'; import { setupApplicationTest } from 'desktop/tests/helpers'; import sinon from 'sinon'; import { invalidateSession } from 'ember-simple-auth/test-support'; -import { setupBrowserFakes } from 'ember-browser-services/test-support'; import { setupDesktopContextBridgeApiMock } from '../helpers/desktop-context-bridge-api-mock'; import config from '../../config/environment'; module('Acceptance | clusterUrl', function (hooks) { setupApplicationTest(hooks); - setupBrowserFakes(hooks, { window: true }); const currentOrigin = window.location.origin; @@ -108,7 +106,15 @@ module('Acceptance | clusterUrl', function (hooks) { test('visiting index without a clusterUrl specified redirects to clusterUrl route', async function (assert) { assert.expect(2); - await visit(urls.index); + try { + await visit(urls.index); + } catch (e) { + if (e.message === 'TransitionAborted') { + // Ignore the expected transition abort error caused by the redirect in beforeModel + } else { + throw e; + } + } assert.notOk(window.desktop.clusterUrl); assert.strictEqual(currentURL(), urls.clusterUrl); diff --git a/ui/desktop/tests/acceptance/projects-test.js b/ui/desktop/tests/acceptance/projects-test.js index da5be4cfc..1dc79122d 100644 --- a/ui/desktop/tests/acceptance/projects-test.js +++ b/ui/desktop/tests/acceptance/projects-test.js @@ -49,12 +49,6 @@ module('Acceptance | projects', function (hooks) { projects: null, }; - const setDefaultClusterUrl = (test) => { - const windowOrigin = window.location.origin; - const clusterUrl = test.owner.lookup('service:clusterUrl'); - clusterUrl.rendererClusterUrl = windowOrigin; - }; - hooks.beforeEach(async function () { instances.scopes.global = this.server.schema.scopes.find('global'); instances.authMethods.global = this.server.schema.authMethods.first(); @@ -87,7 +81,7 @@ module('Acceptance | projects', function (hooks) { urls.authenticate.methods.global = `${urls.authenticate.global}/${instances.authMethods.global.id}`; urls.projects = `${urls.scopes.org}/projects`; - setDefaultClusterUrl(this); + window.desktop.cluster.getClusterUrl.resolves(window.location.origin); }); test('visiting index while unauthenticated redirects to global authenticate method', async function (assert) { diff --git a/ui/desktop/tests/acceptance/projects/sessions/index-test.js b/ui/desktop/tests/acceptance/projects/sessions/index-test.js index c5b6a91fb..706ba165c 100644 --- a/ui/desktop/tests/acceptance/projects/sessions/index-test.js +++ b/ui/desktop/tests/acceptance/projects/sessions/index-test.js @@ -72,12 +72,6 @@ module('Acceptance | projects | sessions | index', function (hooks) { session: null, }; - const setDefaultClusterUrl = (test) => { - const windowOrigin = window.location.origin; - const clusterUrl = test.owner.lookup('service:clusterUrl'); - clusterUrl.rendererClusterUrl = windowOrigin; - }; - hooks.beforeEach(async function () { // create scopes instances.scopes.global = this.server.schema.scopes.find('global'); @@ -148,8 +142,7 @@ module('Acceptance | projects | sessions | index', function (hooks) { urls.sessions2 = `${urls.projects2}/sessions`; urls.session = `${urls.projects}/sessions/${instances.session.id}`; - setDefaultClusterUrl(this); - + window.desktop.cluster.getClusterUrl.resolves(window.location.origin); window.desktop.daemon.isCacheDaemonRunning.resolves(true); this.stubCacheDaemonSearch('sessions', 'sessions', 'targets'); diff --git a/ui/desktop/tests/acceptance/projects/sessions/session-test.js b/ui/desktop/tests/acceptance/projects/sessions/session-test.js index cccfd9295..fdc7d9b7e 100644 --- a/ui/desktop/tests/acceptance/projects/sessions/session-test.js +++ b/ui/desktop/tests/acceptance/projects/sessions/session-test.js @@ -58,12 +58,6 @@ module('Acceptance | projects | sessions | session', function (hooks) { rdpSession: null, }; - const setDefaultClusterUrl = (test) => { - const windowOrigin = window.location.origin; - const clusterUrl = test.owner.lookup('service:clusterUrl'); - clusterUrl.rendererClusterUrl = windowOrigin; - }; - let originalUncaughtException = QUnit.onUncaughtException; hooks.beforeEach(async function () { @@ -139,7 +133,7 @@ module('Acceptance | projects | sessions | session', function (hooks) { urls.session = `${urls.projects}/sessions/${instances.session.id}`; urls.rdpSession = `${urls.projects}/sessions/${instances.rdpSession.id}`; - setDefaultClusterUrl(this); + window.desktop.cluster.getClusterUrl.resolves(window.location.origin); // mock RDP service calls this.rdpService = this.owner.lookup('service:rdp'); diff --git a/ui/desktop/tests/acceptance/projects/settings/index-test.js b/ui/desktop/tests/acceptance/projects/settings/index-test.js index 3140f9170..9dd7ba62a 100644 --- a/ui/desktop/tests/acceptance/projects/settings/index-test.js +++ b/ui/desktop/tests/acceptance/projects/settings/index-test.js @@ -69,12 +69,6 @@ module('Acceptance | projects | settings | index', function (hooks) { const RDP_RECOMMENDED_CLIENT = '[data-test-recommended-rdp-client]'; const RDP_RECOMMENDED_CLIENT_LINK = '[data-test-recommended-rdp-client] a'; - const setDefaultClusterUrl = (test) => { - const windowOrigin = window.location.origin; - const clusterUrl = test.owner.lookup('service:clusterUrl'); - clusterUrl.rendererClusterUrl = windowOrigin; - }; - hooks.beforeEach(async function () { // Generate scopes instances.scopes.global = this.server.schema.scopes.find('global'); @@ -96,7 +90,7 @@ module('Acceptance | projects | settings | index', function (hooks) { urls.projects = `${urls.scopes.org}/projects`; urls.settings = `${urls.projects}/settings`; - setDefaultClusterUrl(this); + window.desktop.cluster.getClusterUrl.resolves(window.location.origin); // mock RDP client data window.desktop.rdp.getRdpClients.resolves([ diff --git a/ui/desktop/tests/acceptance/projects/targets/index-test.js b/ui/desktop/tests/acceptance/projects/targets/index-test.js index 2e2e50992..1ad5e18d4 100644 --- a/ui/desktop/tests/acceptance/projects/targets/index-test.js +++ b/ui/desktop/tests/acceptance/projects/targets/index-test.js @@ -90,12 +90,6 @@ module('Acceptance | projects | targets | index', function (hooks) { sessions: null, }; - const setDefaultClusterUrl = (test) => { - const windowOrigin = window.location.origin; - const clusterUrl = test.owner.lookup('service:clusterUrl'); - clusterUrl.rendererClusterUrl = windowOrigin; - }; - hooks.beforeEach(async function () { // bypass mirage config that expects recursive to be passed in as queryParam this.server.get('/targets', ({ targets }) => targets.all()); @@ -165,7 +159,7 @@ module('Acceptance | projects | targets | index', function (hooks) { // Generate resource counter getTargetCount = () => this.server.schema.targets.all().models.length; - setDefaultClusterUrl(this); + window.desktop.cluster.getClusterUrl.resolves(window.location.origin); window.desktop.daemon.isCacheDaemonRunning.resolves(true); this.stubCacheDaemonSearch('sessions', 'targets', 'aliases', 'sessions'); diff --git a/ui/desktop/tests/acceptance/projects/targets/target-test.js b/ui/desktop/tests/acceptance/projects/targets/target-test.js index bff8331f0..ac469140e 100644 --- a/ui/desktop/tests/acceptance/projects/targets/target-test.js +++ b/ui/desktop/tests/acceptance/projects/targets/target-test.js @@ -77,12 +77,6 @@ module('Acceptance | projects | targets | target', function (hooks) { targetWithManyHosts: null, }; - const setDefaultClusterUrl = (test) => { - const windowOrigin = window.location.origin; - const clusterUrl = test.owner.lookup('service:clusterUrl'); - clusterUrl.rendererClusterUrl = windowOrigin; - }; - hooks.beforeEach(async function () { // bypass mirage config that expects recursive to be passed in as queryParam this.server.get('/targets', ({ targets }) => targets.all()); @@ -150,8 +144,7 @@ module('Acceptance | projects | targets | target', function (hooks) { urls.targetWithTwoHosts = `${urls.targets}/${instances.targetWithTwoHosts.id}`; urls.targetWithManyHosts = `${urls.targets}/${instances.targetWithManyHosts.id}`; - setDefaultClusterUrl(this); - + window.desktop.cluster.getClusterUrl.resolves(window.location.origin); window.desktop.daemon.isCacheDaemonRunning.resolves(true); this.stubCacheDaemonSearch('sessions', 'targets', 'aliases', 'sessions'); diff --git a/ui/desktop/tests/acceptance/scopes-test.js b/ui/desktop/tests/acceptance/scopes-test.js index 2e273c00e..46e0928b9 100644 --- a/ui/desktop/tests/acceptance/scopes-test.js +++ b/ui/desktop/tests/acceptance/scopes-test.js @@ -73,12 +73,6 @@ module('Acceptance | scopes', function (hooks) { target: null, }; - const setDefaultClusterUrl = (test) => { - const windowOrigin = window.location.origin; - const clusterUrl = test.owner.lookup('service:clusterUrl'); - clusterUrl.rendererClusterUrl = windowOrigin; - }; - hooks.beforeEach(async function () { // bypass mirage config that expects recursive to be passed in as queryParam this.server.get('/targets', ({ targets }) => targets.all()); @@ -135,8 +129,7 @@ module('Acceptance | scopes', function (hooks) { urls.globalTargets = `${urls.globalProjects}/targets`; urls.target = `${urls.targets}/${instances.target.id}`; - setDefaultClusterUrl(this); - + window.desktop.cluster.getClusterUrl.resolves(window.location.origin); window.desktop.daemon.isCacheDaemonRunning.resolves(true); this.stubCacheDaemonSearch('sessions', 'targets', 'aliases', 'sessions'); diff --git a/ui/desktop/tests/integration/components/settings-card/server-test.js b/ui/desktop/tests/integration/components/settings-card/server-test.js index 7fffff61c..c5f26e02c 100644 --- a/ui/desktop/tests/integration/components/settings-card/server-test.js +++ b/ui/desktop/tests/integration/components/settings-card/server-test.js @@ -16,25 +16,17 @@ module('Integration | Component | settings-card/server', function (hooks) { setupRenderingTest(hooks); setupIntl(hooks, 'en-us'); - const setDefaultClusterUrl = (test) => { - const windowOrigin = 'hashicorp.cloud'; - const clusterUrl = test.owner.lookup('service:clusterUrl'); - clusterUrl.rendererClusterUrl = windowOrigin; - }; - - setDefaultClusterUrl(this); - test('it displays HCP cluster url in server information section', async function (assert) { - await render(hbs``); + this.set('model', { serverInformation: 'boundary.hashicorp.cloud' }); + await render(hbs``); assert.dom(SERVER_NAME).hasText('HashiCorp Cloud Platform'); - assert.dom(SERVER_URL).hasText('hashicorp.cloud'); + assert.dom(SERVER_URL).hasText('boundary.hashicorp.cloud'); }); test('it displays non HCP cluster url in server information section', async function (assert) { - this.owner.lookup('service:clusterUrl').rendererClusterUrl = - 'everythingelse'; - await render(hbs``); - assert.dom(SERVER_NAME).hasText('Self-Managed'); + this.set('model', { serverInformation: 'everythingelse' }); + await render(hbs``); + assert.dom(SERVER_NAME).hasText('Self-managed'); assert.dom(SERVER_URL).hasText('everythingelse'); }); }); diff --git a/ui/desktop/tests/unit/controllers/application-test.js b/ui/desktop/tests/unit/controllers/application-test.js index d44aa473b..76783d4cf 100644 --- a/ui/desktop/tests/unit/controllers/application-test.js +++ b/ui/desktop/tests/unit/controllers/application-test.js @@ -7,6 +7,7 @@ import { module, test } from 'qunit'; import { setupTest } from 'ember-qunit'; import { authenticateSession } from 'ember-simple-auth/test-support'; import { setupDesktopContextBridgeApiMock } from '../../helpers/desktop-context-bridge-api-mock'; +import sinon from 'sinon'; module('Unit | Controller | application', function (hooks) { setupTest(hooks); @@ -40,18 +41,19 @@ module('Unit | Controller | application', function (hooks) { assert.strictEqual(session.data.theme, 'light'); }); - test('disconnect action de-authenticates a user and resets cluster url', async function (assert) { + test('disconnect action de-authenticates a user and keeps last cluster url', async function (assert) { const url = 'http://localhost:9200'; await clusterUrl.setClusterUrl(url); assert.true(session.isAuthenticated); - assert.strictEqual(clusterUrl.rendererClusterUrl, url); assert.strictEqual(await window.desktop.cluster.getClusterUrl(), url); + assert.strictEqual(clusterUrl.adapter.host, url); + sinon.stub(controller.router, 'replaceWith'); await controller.disconnect(); assert.false(session.isAuthenticated); - assert.notOk(clusterUrl.rendererClusterUrl); - assert.notOk(await window.desktop.cluster.getClusterUrl()); + assert.strictEqual(await window.desktop.cluster.getClusterUrl(), url); + assert.strictEqual(clusterUrl.adapter.host, url); }); }); diff --git a/ui/desktop/tests/unit/controllers/cluster-url-test.js b/ui/desktop/tests/unit/controllers/cluster-url-test.js index d733e91cb..db86bdb97 100644 --- a/ui/desktop/tests/unit/controllers/cluster-url-test.js +++ b/ui/desktop/tests/unit/controllers/cluster-url-test.js @@ -12,16 +12,13 @@ import { setupDesktopContextBridgeApiMock } from '../../helpers/desktop-context- module('Unit | Controller | cluster-url', function (hooks) { setupTest(hooks); setupIntl(hooks, 'en-us'); + setupDesktopContextBridgeApiMock(hooks); let controller; - let clusterUrl; - - setupDesktopContextBridgeApiMock(hooks); hooks.beforeEach(async function () { await authenticateSession({}); controller = this.owner.lookup('controller:cluster-url'); - clusterUrl = this.owner.lookup('service:cluster-url'); }); test('it exists', function (assert) { @@ -30,12 +27,10 @@ module('Unit | Controller | cluster-url', function (hooks) { test('setClusterUrl action de-authenticates a user and resets cluster url', async function (assert) { const newClusterUrl = 'http://localhost:9200'; - assert.notEqual(clusterUrl.rendererClusterUrl, newClusterUrl); assert.notEqual(window.desktop.clusterUrl, newClusterUrl); await controller.setClusterUrl(newClusterUrl); - assert.strictEqual(clusterUrl.rendererClusterUrl, newClusterUrl); assert.strictEqual(window.desktop.clusterUrl, newClusterUrl); }); }); diff --git a/ui/desktop/tests/unit/controllers/scopes/scope/authenticate/method/index-test.js b/ui/desktop/tests/unit/controllers/scopes/scope/authenticate/method/index-test.js index 76c98c51e..2cc73c529 100644 --- a/ui/desktop/tests/unit/controllers/scopes/scope/authenticate/method/index-test.js +++ b/ui/desktop/tests/unit/controllers/scopes/scope/authenticate/method/index-test.js @@ -35,12 +35,6 @@ module( targets: null, }; - const setDefaultClusterUrl = (test) => { - const windowOrigin = window.location.origin; - const clusterUrl = test.owner.lookup('service:clusterUrl'); - clusterUrl.rendererClusterUrl = windowOrigin; - }; - hooks.beforeEach(async function () { controller = this.owner.lookup( 'controller:scopes/scope/authenticate/method/index', @@ -58,7 +52,7 @@ module( urls.targets = '/scopes/global/projects/targets'; - setDefaultClusterUrl(this); + window.desktop.cluster.getClusterUrl.resolves(window.location.origin); }); test('it exists', function (assert) { diff --git a/ui/desktop/tests/unit/services/cluster-url-test.js b/ui/desktop/tests/unit/services/cluster-url-test.js index f97b85065..dac267ebb 100644 --- a/ui/desktop/tests/unit/services/cluster-url-test.js +++ b/ui/desktop/tests/unit/services/cluster-url-test.js @@ -17,37 +17,69 @@ module('Unit | Service | clusterUrl', function (hooks) { service = this.owner.lookup('service:clusterUrl'); }); - test('resets clusterUrl on error', async function (assert) { - assert.expect(4); - + test('keeps clusterUrl on error', async function (assert) { + assert.expect(3); await service.setClusterUrl(window.location.origin); - - assert.strictEqual(service.rendererClusterUrl, window.location.origin); assert.strictEqual(service.adapter.host, window.location.origin); window.desktop.cluster.setClusterUrl.rejects(); - service.setClusterUrl('invalid-origin').catch(() => { - assert.notOk(service.rendererClusterUrl); + + try { + await service.setClusterUrl('http://other-origin'); + } catch { assert.strictEqual(service.adapter.host, window.location.origin); - }); + assert.true( + window.desktop.cluster.setClusterUrl.calledWithExactly( + 'http://other-origin', + ), + ); + } }); test('drops trailing slashes from clusterUrl on setClusterUrl', async function (assert) { assert.expect(4); await service.setClusterUrl(`${window.location.origin}/`); - assert.strictEqual(service.rendererClusterUrl, window.location.origin); assert.strictEqual(service.adapter.host, window.location.origin); + assert.true( + window.desktop.cluster.setClusterUrl.calledWithExactly( + window.location.origin, + ), + ); + await service.setClusterUrl(`${window.location.origin}//////`); - assert.strictEqual(service.rendererClusterUrl, window.location.origin); assert.strictEqual(service.adapter.host, window.location.origin); + assert.true( + window.desktop.cluster.setClusterUrl.calledWithExactly( + window.location.origin, + ), + ); }); test('trim spaces from clusterUrl on setClusterUrl', async function (assert) { assert.expect(4); await service.setClusterUrl(` ${window.location.origin}/ `); - assert.strictEqual(service.rendererClusterUrl, window.location.origin); assert.strictEqual(service.adapter.host, window.location.origin); + assert.true( + window.desktop.cluster.setClusterUrl.calledWithExactly( + window.location.origin, + ), + ); + await service.setClusterUrl(` ${window.location.origin} `); - assert.strictEqual(service.rendererClusterUrl, window.location.origin); assert.strictEqual(service.adapter.host, window.location.origin); + assert.true( + window.desktop.cluster.setClusterUrl.calledWithExactly( + window.location.origin, + ), + ); + }); + + test('resetClusterUrl clears adapter host and invokes IPC', async function (assert) { + await service.setClusterUrl(window.location.origin); + assert.strictEqual(service.adapter.host, window.location.origin); + + await service.resetClusterUrl(); + + assert.strictEqual(service.adapter.host, undefined); + assert.true(window.desktop.cluster.resetClusterUrl.calledOnce); }); });