Refactored API URL generation to function calls and added tests

This commit is contained in:
Jordan Pellizzari
2017-01-31 16:09:10 -08:00
committed by jpellizzari
parent 43cb7548d8
commit f65f39b128
3 changed files with 72 additions and 34 deletions

View File

@@ -9,7 +9,7 @@ import Term from 'xterm';
import { clickCloseTerminal } from '../actions/app-actions';
import { getNeutralColor } from '../utils/color-utils';
import { setDocumentTitle } from '../utils/title-utils';
import { getPipeStatus, doResizeTty, wsUrl } from '../utils/web-api-utils';
import { getPipeStatus, doResizeTty, getWebsocketUrl } from '../utils/web-api-utils';
const log = debug('scope:terminal');
@@ -101,14 +101,14 @@ class Terminal extends React.Component {
}
createWebsocket(term) {
const socket = new WebSocket(`${wsUrl}/api/pipe/${this.getPipeId()}`);
const socket = new WebSocket(`${getWebsocketUrl()}/api/pipe/${this.getPipeId()}`);
socket.binaryType = 'arraybuffer';
getPipeStatus(this.getPipeId(), this.props.dispatch);
socket.onopen = () => {
clearTimeout(this.reconnectTimeout);
log('socket open to', wsUrl);
log('socket open to', getWebsocketUrl());
this.setState({connected: true});
};

View File

@@ -1,12 +1,9 @@
import {OrderedMap as makeOrderedMap} from 'immutable';
import { buildOptionsQuery, basePath, getApiPath, getWebsocketUrl } from '../web-api-utils';
describe('WebApiUtils', () => {
const WebApiUtils = require('../web-api-utils');
describe('basePath', () => {
const basePath = WebApiUtils.basePath;
it('should handle /scope/terminal.html', () => {
expect(basePath('/scope/terminal.html')).toBe('/scope');
});
@@ -25,8 +22,6 @@ describe('WebApiUtils', () => {
});
describe('buildOptionsQuery', () => {
const buildOptionsQuery = WebApiUtils.buildOptionsQuery;
it('should handle empty options', () => {
expect(buildOptionsQuery(makeOrderedMap({}))).toBe('');
});
@@ -38,4 +33,55 @@ describe('WebApiUtils', () => {
]))).toBe('foo=2&bar=4');
});
});
describe('getApiPath', () => {
afterEach(() => {
delete process.env.SCOPE_API_PREFIX;
});
it('returns the correct url when running standalone', () => {
expect(getApiPath('/')).toEqual('');
});
it('returns the correct url when running in an iframe', () => {
expect(getApiPath('/api/app/proud-cloud-77')).toEqual('/api/app/proud-cloud-77');
});
it('returns the correct url when running as a component', () => {
process.env.SCOPE_API_PREFIX = '/api';
expect(getApiPath('/app/proud-cloud-77')).toEqual('/api/app/proud-cloud-77');
});
it('returns the correct url from an arbitrary path', () => {
expect(getApiPath('/demo/')).toEqual('/demo');
});
it('returns the correct url from an *.html page', () => {
expect(getApiPath('/contrast.html')).toEqual('');
});
it('returns the correct url from an /*.html page while in an iframe', () => {
expect(getApiPath('/api/app/proud-cloud-77/contrast.html')).toEqual('/api/app/proud-cloud-77');
});
});
describe('getWebsocketUrl', () => {
const host = 'localhost:4042';
afterEach(() => {
delete process.env.SCOPE_API_PREFIX;
});
it('returns the correct url when running standalone', () => {
expect(getWebsocketUrl(host, '/')).toEqual(`ws://${host}`);
});
it('returns the correct url when running in an iframe', () => {
expect(getWebsocketUrl(host, '/api/app/proud-cloud-77')).toEqual(`ws://${host}/api/app/proud-cloud-77`);
});
it('returns the correct url when running as a component', () => {
process.env.SCOPE_API_PREFIX = '/api';
expect(getWebsocketUrl(host, '/app/proud-cloud-77')).toEqual(`ws://${host}/api/app/proud-cloud-77`);
});
it('returns the correct url from an arbitrary path', () => {
expect(getWebsocketUrl(host, '/demo/')).toEqual(`ws://${host}/demo`);
});
it('returns the correct url from an *.html page', () => {
expect(getWebsocketUrl(host, '/contrast.html')).toEqual(`ws://${host}`);
});
it('returns the correct url from an /*.html page while in an iframe', () => {
expect(getWebsocketUrl(host, '/api/app/proud-cloud-77/contrast.html')).toEqual(`ws://${host}/api/app/proud-cloud-77`);
});
});
});

View File

@@ -58,26 +58,18 @@ export function basePathSlash(urlPath) {
return `${basePath(urlPath)}/`;
}
// JJP - `apiPath` is used to get API URLs right when running as a React component.
// This needs to be refactored to just accept a URL prop on the scope component.
let apiPath;
let websocketUrl;
const isIframe = window.location !== window.parent.location;
const isStandalone = window.location.pathname === '/'
|| window.location.pathname === '/demo/'
|| window.location.pathname === '/scoped/'
|| /\/(.+).html/.test(window.location.pathname);
const wsProto = location.protocol === 'https:' ? 'wss' : 'ws';
export function getApiPath(pathname = window.location.pathname) {
if (process.env.SCOPE_API_PREFIX) {
return basePath(`${process.env.SCOPE_API_PREFIX}${pathname}`);
}
if (isIframe || isStandalone) {
apiPath = 'api';
websocketUrl = `${wsProto}://${location.host}${basePath(location.pathname)}`;
} else {
apiPath = `/api${basePath(window.location.pathname)}/api`;
websocketUrl = `${wsProto}://${location.host}/api${basePath(window.location.pathname)}`;
return basePath(pathname);
}
export const wsUrl = websocketUrl;
export function getWebsocketUrl(host = window.location.host, pathname = window.location.pathname) {
const wsProto = location.protocol === 'https:' ? 'wss' : 'ws';
return `${wsProto}://${host}${process.env.SCOPE_API_PREFIX || ''}${basePath(pathname)}`;
}
function createWebsocket(topologyUrl, optionsQuery, dispatch) {
if (socket) {
@@ -92,7 +84,7 @@ function createWebsocket(topologyUrl, optionsQuery, dispatch) {
createWebsocketAt = new Date();
firstMessageOnWebsocketAt = 0;
socket = new WebSocket(`${wsUrl}${topologyUrl}/ws?t=${updateFrequency}&${optionsQuery}`);
socket = new WebSocket(`${getWebsocketUrl()}${topologyUrl}/ws?t=${updateFrequency}&${optionsQuery}`);
socket.onopen = () => {
dispatch(openWebsocket());
@@ -154,7 +146,7 @@ export function getAllNodes(getState, dispatch) {
export function getTopologies(options, dispatch) {
clearTimeout(topologyTimer);
const optionsQuery = buildOptionsQuery(options);
const url = `${apiPath}/topology?${optionsQuery}`;
const url = `${getApiPath()}/api/topology?${optionsQuery}`;
reqwest({
url,
success: (res) => {
@@ -189,7 +181,7 @@ export function getNodeDetails(topologyUrlsById, currentTopologyId, options, nod
const obj = nodeMap.last();
if (obj && topologyUrlsById.has(obj.topologyId)) {
const topologyUrl = topologyUrlsById.get(obj.topologyId);
let urlComponents = [apiPath, '/', trimStart(topologyUrl, '/api'), '/', encodeURIComponent(obj.id)];
let urlComponents = [getApiPath(), topologyUrl, '/', encodeURIComponent(obj.id)];
if (currentTopologyId === obj.topologyId) {
// Only forward filters for nodes in the current topology
const optionsQuery = buildOptionsQuery(options);
@@ -222,7 +214,7 @@ export function getNodeDetails(topologyUrlsById, currentTopologyId, options, nod
export function getApiDetails(dispatch) {
clearTimeout(apiDetailsTimer);
const url = apiPath;
const url = getApiPath();
reqwest({
url,
success: (res) => {
@@ -243,7 +235,7 @@ export function getApiDetails(dispatch) {
export function doControlRequest(nodeId, control, dispatch) {
clearTimeout(controlErrorTimer);
const url = `${apiPath}/control/${encodeURIComponent(control.probeId)}/`
const url = `${getApiPath()}/api/control/${encodeURIComponent(control.probeId)}/`
+ `${encodeURIComponent(control.nodeId)}/${control.id}`;
reqwest({
method: 'POST',
@@ -279,7 +271,7 @@ export function doControlRequest(nodeId, control, dispatch) {
export function doResizeTty(pipeId, control, cols, rows) {
const url = `${apiPath}/control/${encodeURIComponent(control.probeId)}/`
const url = `${getApiPath()}/api/control/${encodeURIComponent(control.probeId)}/`
+ `${encodeURIComponent(control.nodeId)}/${control.id}`;
return reqwest({
@@ -294,7 +286,7 @@ export function doResizeTty(pipeId, control, cols, rows) {
export function deletePipe(pipeId, dispatch) {
const url = `${apiPath}/pipe/${encodeURIComponent(pipeId)}`;
const url = `${getApiPath()}/api/pipe/${encodeURIComponent(pipeId)}`;
reqwest({
method: 'DELETE',
url,
@@ -310,7 +302,7 @@ export function deletePipe(pipeId, dispatch) {
export function getPipeStatus(pipeId, dispatch) {
const url = `${apiPath}/pipe/${encodeURIComponent(pipeId)}/check`;
const url = `${getApiPath()}/api/pipe/${encodeURIComponent(pipeId)}/check`;
reqwest({
method: 'GET',
url,