2020-06-23 00:09:42 +05:30
|
|
|
import createDiff from '~/ide/lib/create_diff';
|
|
|
|
import {
|
|
|
|
canConnect,
|
|
|
|
createMirror,
|
|
|
|
SERVICE_NAME,
|
|
|
|
PROTOCOL,
|
|
|
|
MSG_CONNECTION_ERROR,
|
|
|
|
SERVICE_DELAY,
|
|
|
|
} from '~/ide/lib/mirror';
|
|
|
|
import { getWebSocketUrl } from '~/lib/utils/url_utility';
|
|
|
|
|
|
|
|
jest.mock('~/ide/lib/create_diff', () => jest.fn());
|
|
|
|
|
|
|
|
const TEST_PATH = '/project/ide/proxy/path';
|
|
|
|
const TEST_DIFF = {
|
|
|
|
patch: 'lorem ipsum',
|
|
|
|
toDelete: ['foo.md'],
|
|
|
|
};
|
|
|
|
const TEST_ERROR = 'Something bad happened...';
|
|
|
|
const TEST_SUCCESS_RESPONSE = {
|
|
|
|
data: JSON.stringify({ error: { code: 0 }, payload: { status_code: 200 } }),
|
|
|
|
};
|
|
|
|
const TEST_ERROR_RESPONSE = {
|
|
|
|
data: JSON.stringify({ error: { code: 1, Message: TEST_ERROR }, payload: { status_code: 200 } }),
|
|
|
|
};
|
|
|
|
const TEST_ERROR_PAYLOAD_RESPONSE = {
|
|
|
|
data: JSON.stringify({
|
|
|
|
error: { code: 0 },
|
|
|
|
payload: { status_code: 500, error_message: TEST_ERROR },
|
|
|
|
}),
|
|
|
|
};
|
|
|
|
|
|
|
|
const buildUploadMessage = ({ toDelete, patch }) =>
|
|
|
|
JSON.stringify({
|
|
|
|
code: 'EVENT',
|
|
|
|
namespace: '/files',
|
|
|
|
event: 'PATCH',
|
|
|
|
payload: { diff: patch, delete_files: toDelete },
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('ide/lib/mirror', () => {
|
|
|
|
describe('canConnect', () => {
|
|
|
|
it('can connect if the session has the expected service', () => {
|
|
|
|
const result = canConnect({ services: ['test1', SERVICE_NAME, 'test2'] });
|
|
|
|
|
|
|
|
expect(result).toBe(true);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('cannot connect if the session does not have the expected service', () => {
|
|
|
|
const result = canConnect({ services: ['test1', 'test2'] });
|
|
|
|
|
|
|
|
expect(result).toBe(false);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('createMirror', () => {
|
|
|
|
const origWebSocket = global.WebSocket;
|
|
|
|
let mirror;
|
|
|
|
let mockWebSocket;
|
|
|
|
|
|
|
|
beforeEach(() => {
|
|
|
|
mockWebSocket = {
|
|
|
|
close: jest.fn(),
|
|
|
|
send: jest.fn(),
|
|
|
|
};
|
|
|
|
global.WebSocket = jest.fn().mockImplementation(() => mockWebSocket);
|
|
|
|
mirror = createMirror();
|
|
|
|
});
|
|
|
|
|
|
|
|
afterEach(() => {
|
|
|
|
global.WebSocket = origWebSocket;
|
|
|
|
});
|
|
|
|
|
|
|
|
const waitForConnection = (delay = SERVICE_DELAY) => {
|
2021-03-08 18:12:59 +05:30
|
|
|
const wait = new Promise((resolve) => {
|
2020-06-23 00:09:42 +05:30
|
|
|
setTimeout(resolve, 10);
|
|
|
|
});
|
|
|
|
|
|
|
|
jest.advanceTimersByTime(delay);
|
|
|
|
|
|
|
|
return wait;
|
|
|
|
};
|
|
|
|
const connectPass = () => waitForConnection().then(() => mockWebSocket.onopen());
|
|
|
|
const connectFail = () => waitForConnection().then(() => mockWebSocket.onerror());
|
2021-03-08 18:12:59 +05:30
|
|
|
const sendResponse = (msg) => {
|
2020-06-23 00:09:42 +05:30
|
|
|
mockWebSocket.onmessage(msg);
|
|
|
|
};
|
|
|
|
|
|
|
|
describe('connect', () => {
|
|
|
|
let connection;
|
|
|
|
|
|
|
|
beforeEach(() => {
|
|
|
|
connection = mirror.connect(TEST_PATH);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('waits before creating web socket', () => {
|
|
|
|
// ignore error when test suite terminates
|
|
|
|
connection.catch(() => {});
|
|
|
|
|
|
|
|
return waitForConnection(SERVICE_DELAY - 10).then(() => {
|
|
|
|
expect(global.WebSocket).not.toHaveBeenCalled();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('is canceled when disconnected before finished waiting', () => {
|
|
|
|
mirror.disconnect();
|
|
|
|
|
|
|
|
return waitForConnection(SERVICE_DELAY).then(() => {
|
|
|
|
expect(global.WebSocket).not.toHaveBeenCalled();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('when connection is successful', () => {
|
|
|
|
beforeEach(connectPass);
|
|
|
|
|
|
|
|
it('connects to service', () => {
|
|
|
|
const expectedPath = `${getWebSocketUrl(TEST_PATH)}?service=${SERVICE_NAME}`;
|
|
|
|
|
|
|
|
return connection.then(() => {
|
|
|
|
expect(global.WebSocket).toHaveBeenCalledWith(expectedPath, [PROTOCOL]);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('disconnects when connected again', () => {
|
|
|
|
const result = connection
|
|
|
|
.then(() => {
|
|
|
|
// https://gitlab.com/gitlab-org/gitlab/issues/33024
|
|
|
|
// eslint-disable-next-line promise/no-nesting
|
|
|
|
mirror.connect(TEST_PATH).catch(() => {});
|
|
|
|
})
|
|
|
|
.then(() => {
|
|
|
|
expect(mockWebSocket.close).toHaveBeenCalled();
|
|
|
|
});
|
|
|
|
|
|
|
|
return result;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('when connection fails', () => {
|
|
|
|
beforeEach(connectFail);
|
|
|
|
|
|
|
|
it('rejects with error', () => {
|
|
|
|
return expect(connection).rejects.toEqual(new Error(MSG_CONNECTION_ERROR));
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('upload', () => {
|
|
|
|
let state;
|
|
|
|
|
|
|
|
beforeEach(() => {
|
|
|
|
state = { changedFiles: [] };
|
|
|
|
createDiff.mockReturnValue(TEST_DIFF);
|
|
|
|
|
|
|
|
const connection = mirror.connect(TEST_PATH);
|
|
|
|
|
|
|
|
return connectPass().then(() => connection);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('creates a diff from the given state', () => {
|
|
|
|
const result = mirror.upload(state);
|
|
|
|
|
|
|
|
sendResponse(TEST_SUCCESS_RESPONSE);
|
|
|
|
|
|
|
|
return result.then(() => {
|
|
|
|
expect(createDiff).toHaveBeenCalledWith(state);
|
|
|
|
expect(mockWebSocket.send).toHaveBeenCalledWith(buildUploadMessage(TEST_DIFF));
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it.each`
|
|
|
|
response | description
|
|
|
|
${TEST_ERROR_RESPONSE} | ${'error in error'}
|
|
|
|
${TEST_ERROR_PAYLOAD_RESPONSE} | ${'error in payload'}
|
|
|
|
`('rejects if response has $description', ({ response }) => {
|
|
|
|
const result = mirror.upload(state);
|
|
|
|
|
|
|
|
sendResponse(response);
|
|
|
|
|
|
|
|
return expect(result).rejects.toEqual({ message: TEST_ERROR });
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|