diff --git a/src/shared/modules/commands/cypher.test.js b/src/shared/modules/commands/cypher.test.js new file mode 100644 index 00000000000..8aedb4b05e3 --- /dev/null +++ b/src/shared/modules/commands/cypher.test.js @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2002-2018 "Neo4j, Inc" + * Network Engine for Objects in Lund AB [http://neotechnology.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* global jest, describe, afterEach, test, expect */ +import { version } from 'project-root/package.json' +import { createEpicMiddleware } from 'redux-observable' +import { createBus } from 'suber' +import { + executeSystemCommand, + executeSingleCommand, + handleSingleCommandEpic +} from './commandsDuck' + +jest.mock('services/bolt/bolt', () => { + const orig = require.requireActual('services/bolt/bolt') + return { + ...orig, + routedWriteTransaction: jest.fn(() => [ + 'id', + Promise.resolve({ records: [] }) + ]) + } +}) +const bolt = require.requireMock('services/bolt/bolt') + +jest.mock('shared/modules/settings/settingsDuck', () => { + const orig = require.requireActual('shared/modules/settings/settingsDuck') + return { + ...orig, + getCmdChar: () => ':', + shouldUseCypherThread: () => false + } +}) + +jest.mock('shared/modules/params/paramsDuck', () => { + const orig = require.requireActual('shared/modules/params/paramsDuck') + return { + ...orig, + getParams: () => ({}) + } +}) + +jest.mock('shared/modules/dbMeta/dbMetaDuck', () => { + const orig = require.requireActual('shared/modules/dbMeta/dbMetaDuck') + return { + ...orig, + getVersion: () => '3.5.0' // support for tx metadata + } +}) + +describe('tx metadata with cypher', () => { + afterEach(() => { + bolt.routedWriteTransaction.mockReset() + }) + + it('it adds tx metadata for user entered cypher queries', done => { + // Given + const bus = createBus() + bus.applyReduxMiddleware(createEpicMiddleware(handleSingleCommandEpic)) + const $$responseChannel = 'test-channel' + const action = executeSingleCommand('RETURN 1', 'id', 'rqid') + action.$$responseChannel = $$responseChannel + + bus.send(action.type, action) + flushPromises().then(() => { + expect(bolt.routedWriteTransaction).toHaveBeenCalledTimes(1) + expect(bolt.routedWriteTransaction).toHaveBeenCalledWith( + 'RETURN 1', + {}, + expect.objectContaining({ + txMetadata: { app: `neo4j-browser_v${version}`, type: 'user-direct' } + }) + ) + done() + }) + }) + + it('it adds tx metadata for system cypher queries', done => { + // Given + const bus = createBus() + bus.applyReduxMiddleware(createEpicMiddleware(handleSingleCommandEpic)) + const $$responseChannel = 'test-channel2' + const action = executeSystemCommand('RETURN 1') + action.$$responseChannel = $$responseChannel + + bus.send(action.type, action) + flushPromises().then(() => { + expect(bolt.routedWriteTransaction).toHaveBeenCalledTimes(1) + expect(bolt.routedWriteTransaction).toHaveBeenCalledWith( + 'RETURN 1', + {}, + expect.objectContaining({ + txMetadata: { app: `neo4j-browser_v${version}`, type: 'system' } + }) + ) + done() + }) + }) +}) + +function flushPromises () { + return new Promise(resolve => setImmediate(resolve)) +} diff --git a/src/shared/services/bolt/txMetaData.test.js b/src/shared/services/bolt/txMetaData.test.js new file mode 100644 index 00000000000..46b55ffefff --- /dev/null +++ b/src/shared/services/bolt/txMetaData.test.js @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2002-2018 "Neo4j, Inc" + * Network Engine for Objects in Lund AB [http://neotechnology.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import { version } from 'project-root/package.json' +import { getBackgroundTxMetadata, getUserTxMetadata } from './txMetadata' + +test('getBackgroundTxMetadata has the expected format', () => { + const res = getBackgroundTxMetadata({ hasServerSupport: true }) + expect(res.txMetadata).toEqual({ + type: 'system', + app: `neo4j-browser_v${version}` + }) +}) + +test('getUserTxMetadata has the expected format', () => { + const res = getUserTxMetadata({ hasServerSupport: true }) + expect(res.txMetadata).toEqual({ + type: 'user-direct', + app: `neo4j-browser_v${version}` + }) +}) diff --git a/src/shared/services/bolt/txMetadata.js b/src/shared/services/bolt/txMetadata.js index be90268bf80..188d2524c3e 100644 --- a/src/shared/services/bolt/txMetadata.js +++ b/src/shared/services/bolt/txMetadata.js @@ -20,12 +20,10 @@ import { version } from 'project-root/package.json' -let counter = 0 - // Application info -const NEO4J_BROWSER_BACKGROUND_QUERY = `NEO4J_BROWSER_BACKGROUND_QUERY` -const NEO4J_BROWSER_USER_QUERY = `NEO4J_BROWSER_USER_QUERY` -const NEO4J_BROWSER_APP_ID = `NEO4J_BROWSER_V${version}` +const NEO4J_BROWSER_BACKGROUND_QUERY = `system` +const NEO4J_BROWSER_USER_QUERY = `user-direct` +const NEO4J_BROWSER_APP_ID = `neo4j-browser_v${version}` export const getBackgroundTxMetadata = ({ hasServerSupport = false }) => { if (!hasServerSupport) { @@ -34,8 +32,7 @@ export const getBackgroundTxMetadata = ({ hasServerSupport = false }) => { return { txMetadata: { type: NEO4J_BROWSER_BACKGROUND_QUERY, - application: NEO4J_BROWSER_APP_ID, - query_number: ++counter + app: NEO4J_BROWSER_APP_ID } } } @@ -47,8 +44,7 @@ export const getUserTxMetadata = ({ hasServerSupport = false }) => { return { txMetadata: { type: NEO4J_BROWSER_USER_QUERY, - application: NEO4J_BROWSER_APP_ID, - query_number: ++counter + app: NEO4J_BROWSER_APP_ID } } } diff --git a/src/shared/services/commandInterpreterHelper.js b/src/shared/services/commandInterpreterHelper.js index dd9d71fbc95..1dc712ec3bf 100644 --- a/src/shared/services/commandInterpreterHelper.js +++ b/src/shared/services/commandInterpreterHelper.js @@ -39,7 +39,8 @@ import { showErrorMessage, cypher, successfulCypher, - unsuccessfulCypher + unsuccessfulCypher, + SINGLE_COMMAND_QUEUED } from 'shared/modules/commands/commandsDuck' import { handleParamsCommand } from 'shared/modules/commands/helpers/params' import { @@ -59,7 +60,10 @@ import { import { fetchRemoteGrass } from 'shared/modules/commands/helpers/grass' import { parseGrass } from 'shared/services/grassUtils' import { shouldUseCypherThread } from 'shared/modules/settings/settingsDuck' -import { getUserTxMetadata } from 'shared/services/bolt/txMetadata' +import { + getUserTxMetadata, + getBackgroundTxMetadata +} from 'shared/services/bolt/txMetadata' const availableCommands = [ { @@ -154,9 +158,13 @@ const availableCommands = [ put, getParams(state), shouldUseCypherThread(state), - getUserTxMetadata({ - hasServerSupport: canSendTxMetadata(store.getState()) - }) + action.type === SINGLE_COMMAND_QUEUED + ? getUserTxMetadata({ + hasServerSupport: canSendTxMetadata(store.getState()) + }) + : getBackgroundTxMetadata({ + hasServerSupport: canSendTxMetadata(store.getState()) + }) ) put(cypher(action.cmd)) put(frames.add({ ...action, type: 'cypher', requestId: id }))