Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion bin/accessibility-automation/constants.js
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
exports.API_URL = 'https://accessibility.browserstack.com/api';
const { getEnvironmentUrl } = require('../helpers/environmentUrl');

// BROWSERSTACK_ENV=preprod|staging (internal only) swaps the host; production when unset.
exports.API_URL = getEnvironmentUrl('https://accessibility.browserstack.com/api');
6 changes: 6 additions & 0 deletions bin/helpers/config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
var config = require('./config.json');
const { getEnvironmentUrl } = require('./environmentUrl');

config.env = process.env.BSTACK_CYPRESS_NODE_ENV || "production";

Expand All @@ -10,6 +11,11 @@ if(config.env !== "production") {
config.rails_host = process.env.RAILS_HOST;
config.dashboardUrl = process.env.DASHBOARD_URL;
config.usageReportingUrl = process.env.USAGE_REPORTING_URL;
} else {
// BROWSERSTACK_ENV=preprod|staging (internal only); a no-op when unset.
['uploadUrl', 'rails_host', 'dashboardUrl', 'turboScaleUrl', 'turboScaleAPIUrl'].forEach((key) => {
config[key] = getEnvironmentUrl(config[key]);
});
}

config.cypress_v1 = `${config.rails_host}/automate/cypress/v1`;
Expand Down
55 changes: 55 additions & 0 deletions bin/helpers/environmentUrl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
'use strict';

// Internal, non-production only: BROWSERSTACK_ENV=preprod|staging points the cli at that
// environment's hosts, the same switch browserstack-binary (core/utils/environment-url.js) and
// browserstack-node-agent use. Unset, or any other value, keeps the production hosts.
const ENV_VAR = 'BROWSERSTACK_ENV';

const PREPROD_HOSTS = [
['api-cloud.browserstack.com', 'api-cloud-preprod.bsstag.com'],
['api.browserstack.com', 'api-preprod.bsstag.com'],
['automate.browserstack.com', 'automate-preprod.bsstag.com'],
['automation.browserstack.com', 'automation-preprod.bsstag.com'],
['collector-observability.browserstack.com', 'collector-observability-preprod.bsstag.com'],
['accessibility.browserstack.com', 'accessibility-preprod.bsstag.com'],
['grid.browserstack.com', 'grid-preprod.bsstag.com'],
];

const STAGING_HOSTS = [
['api-cloud.browserstack.com', 'api-cloud-devtestops.bsstag.com'],
['api.browserstack.com', 'apidevtestops.bsstag.com'],
['automate.browserstack.com', 'automate-devtestops.bsstag.com'],
['automation.browserstack.com', 'automation.bsstag.com'],
['collector-observability.browserstack.com', 'collector-observability-devtestops.bsstag.com'],
['accessibility.browserstack.com', 'accessibility.bsstag.com'],
['grid.browserstack.com', 'grid-devhst.bsstag.com'],
];

const getEnvironment = () => {
const value = (process.env[ENV_VAR] || '').trim().toLowerCase();
if (value === 'preprod' || value === 'pre-prod') return 'preprod';
if (value === 'staging' || value === 'stag') return 'staging';
return undefined;
};

// Swaps the host only (exact match), so paths, ports and query strings are kept and a host that
// merely contains a mapped name (e.g. app-automate.browserstack.com) is left alone.
const getEnvironmentUrl = (url) => {
const env = getEnvironment();
if (!env || typeof url !== 'string') return url;
const hosts = env === 'preprod' ? PREPROD_HOSTS : STAGING_HOSTS;
let parsed;
try {
parsed = new URL(url);
} catch (err) {
return url;
}
const match = hosts.find(([from]) => parsed.hostname === from);
if (!match) return url;
parsed.hostname = match[1];
const result = parsed.toString();
// URL.toString() adds a trailing slash to a bare origin; keep the caller's shape.
return url.endsWith('/') ? result : result.replace(/\/$/, '');
};

module.exports = { ENV_VAR, getEnvironment, getEnvironmentUrl };
5 changes: 4 additions & 1 deletion bin/testObservability/helper/constants.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const path = require('path');
const { getEnvironmentUrl } = require('../../helpers/environmentUrl');

exports.consoleHolder = Object.assign({},console);
exports.BATCH_SIZE = 1000;
Expand Down Expand Up @@ -37,7 +38,9 @@ const REMOTE_API_URL_ENV = 'BROWSERSTACK_TEST_OBSERVABILITY_REMOTE_API_URL';
exports.API_URL_ENV = API_URL_ENV;
exports.REMOTE_API_URL_ENV = REMOTE_API_URL_ENV;

exports.apiUrl = () => httpsOverride(API_URL_ENV) || DEFAULT_API_URL;
// An explicit override wins; otherwise BROWSERSTACK_ENV=preprod|staging picks that environment's
// collector. setSystemEnvs forwards the result to the remote reporter, so both sides agree.
exports.apiUrl = () => httpsOverride(API_URL_ENV) || getEnvironmentUrl(DEFAULT_API_URL);
exports.remoteReporterApiUrl = () => httpsOverride(REMOTE_API_URL_ENV) || exports.apiUrl();

exports.IPC_EVENTS = {
Expand Down
3 changes: 2 additions & 1 deletion bin/testObservability/helper/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const { runOptions } = require('../../helpers/runnerArgs')

const pGitconfig = promisify(gitconfig);

const { getEnvironmentUrl } = require('../../helpers/environmentUrl');
const logger = require("../../helpers/logger").winstonLogger;
const utils = require('../../helpers/utils');
const helper = require('../../helpers/helper');
Expand Down Expand Up @@ -114,7 +115,7 @@ exports.printBuildLink = async (shouldStopSession, exitCode = null) => {
&& process.env.BS_TESTOPS_BUILD_HASHED_ID != "null"
&& process.env.BS_TESTOPS_BUILD_HASHED_ID != "undefined") {
console.log();
logger.info(`Visit https://automation.browserstack.com/builds/${process.env.BS_TESTOPS_BUILD_HASHED_ID} to view build report, insights, and many more debugging information all at one place!\n`);
logger.info(`Visit ${getEnvironmentUrl('https://automation.browserstack.com')}/builds/${process.env.BS_TESTOPS_BUILD_HASHED_ID} to view build report, insights, and many more debugging information all at one place!\n`);
}
} catch(err) {
exports.debug('Build Not Found');
Expand Down
66 changes: 66 additions & 0 deletions test/unit/bin/helpers/environmentUrl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
const { expect } = require('chai');

const { getEnvironment, getEnvironmentUrl } = require('../../../../bin/helpers/environmentUrl');

describe('environmentUrl (BROWSERSTACK_ENV)', () => {
const original = process.env.BROWSERSTACK_ENV;
afterEach(() => {
if (original === undefined) delete process.env.BROWSERSTACK_ENV;
else process.env.BROWSERSTACK_ENV = original;
});

it('leaves every url unchanged when unset', () => {
delete process.env.BROWSERSTACK_ENV;
expect(getEnvironment()).to.equal(undefined);
expect(getEnvironmentUrl('https://api.browserstack.com')).to.equal('https://api.browserstack.com');
});

it('leaves urls unchanged for an unknown value', () => {
process.env.BROWSERSTACK_ENV = 'production';
expect(getEnvironment()).to.equal(undefined);
expect(getEnvironmentUrl('https://accessibility.browserstack.com/api')).to.equal('https://accessibility.browserstack.com/api');
});

it('maps every preprod host the cli uses, keeping paths', () => {
process.env.BROWSERSTACK_ENV = 'Preprod';
expect(getEnvironmentUrl('https://api.browserstack.com')).to.equal('https://api-preprod.bsstag.com');
expect(getEnvironmentUrl('https://api-cloud.browserstack.com/automate-frameworks/cypress/upload'))
.to.equal('https://api-cloud-preprod.bsstag.com/automate-frameworks/cypress/upload');
expect(getEnvironmentUrl('https://automate.browserstack.com/dashboard/v2/builds/'))
.to.equal('https://automate-preprod.bsstag.com/dashboard/v2/builds/');
expect(getEnvironmentUrl('https://automation.browserstack.com')).to.equal('https://automation-preprod.bsstag.com');
expect(getEnvironmentUrl('https://collector-observability.browserstack.com'))
.to.equal('https://collector-observability-preprod.bsstag.com');
expect(getEnvironmentUrl('https://accessibility.browserstack.com/api')).to.equal('https://accessibility-preprod.bsstag.com/api');
});

it('accepts pre-prod and maps staging', () => {
process.env.BROWSERSTACK_ENV = 'pre-prod';
expect(getEnvironment()).to.equal('preprod');
process.env.BROWSERSTACK_ENV = 'stag';
expect(getEnvironmentUrl('https://api.browserstack.com')).to.equal('https://apidevtestops.bsstag.com');
});

it('matches whole hosts only', () => {
process.env.BROWSERSTACK_ENV = 'preprod';
expect(getEnvironmentUrl('https://app-automate.browserstack.com/x')).to.equal('https://app-automate.browserstack.com/x');
expect(getEnvironmentUrl('https://eds.browserstack.com:443/send_event_cy_internal'))
.to.equal('https://eds.browserstack.com:443/send_event_cy_internal');
expect(getEnvironmentUrl('not a url')).to.equal('not a url');
});

it('feeds the observability collector default, while an explicit override still wins', () => {
const { apiUrl } = require('../../../../bin/testObservability/helper/constants');
const savedOverride = process.env.BROWSERSTACK_TEST_OBSERVABILITY_API_URL;
delete process.env.BROWSERSTACK_TEST_OBSERVABILITY_API_URL;
try {
process.env.BROWSERSTACK_ENV = 'preprod';
expect(apiUrl()).to.equal('https://collector-observability-preprod.bsstag.com');
process.env.BROWSERSTACK_TEST_OBSERVABILITY_API_URL = 'https://collector.example.test';
expect(apiUrl()).to.equal('https://collector.example.test');
} finally {
if (savedOverride === undefined) delete process.env.BROWSERSTACK_TEST_OBSERVABILITY_API_URL;
else process.env.BROWSERSTACK_TEST_OBSERVABILITY_API_URL = savedOverride;
}
});
});
Loading