Skip to content

Commit

Permalink
feat(odbc): Add remote agent option in ODBC south connector and repla…
Browse files Browse the repository at this point in the history
…ce params by connection string
  • Loading branch information
burgerni10 committed Aug 18, 2023
1 parent 937d9fc commit 5a8f151
Show file tree
Hide file tree
Showing 11 changed files with 839 additions and 266 deletions.
1 change: 1 addition & 0 deletions backend/src/south/south-mssql/manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ const manifest: SouthConnectorManifest = {
type: 'OibCheckbox',
label: 'Use encryption',
defaultValue: false,
validators: [{ key: 'required' }],
newRow: true,
displayInViewMode: true
},
Expand Down
24 changes: 3 additions & 21 deletions backend/src/south/south-mssql/south-mssql.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,24 +103,7 @@ const items: Array<SouthConnectorItemDTO<SouthMSSQLItemSettings>> = [
connectorId: 'southId',
settings: {
query: 'SELECT * FROM table',
dateTimeFields: [
{
fieldName: 'anotherTimestamp',
useAsReference: false,
type: 'unix-epoch-ms',
timezone: null,
format: null,
locale: null
} as unknown as SouthMSSQLItemSettingsDateTimeFields,
{
fieldName: 'timestamp',
useAsReference: true,
type: 'string',
timezone: 'Europe/Paris',
format: 'yyyy-MM-dd HH:mm:ss.SSS',
locale: 'en-US'
}
],
dateTimeFields: [],
serialization: {
type: 'csv',
filename: '[email protected]',
Expand Down Expand Up @@ -199,7 +182,7 @@ describe('SouthMSSQL with authentication', () => {
username: 'username',
password: 'password',
domain: 'domain',
encryption: true,
encryption: null,
connectionTimeout: 1000,
requestTimeout: 1000,
trustServerCertificate: true
Expand Down Expand Up @@ -286,7 +269,6 @@ describe('SouthMSSQL with authentication', () => {
connectionTimeout: configuration.settings.connectionTimeout,
requestTimeout: configuration.settings.requestTimeout,
options: {
encrypt: configuration.settings.encryption,
trustServerCertificate: configuration.settings.trustServerCertificate,
useUTC: true
},
Expand Down Expand Up @@ -320,7 +302,7 @@ describe('SouthMSSQL without authentication', () => {
username: null,
password: null,
domain: '',
encryption: false,
encryption: true,
connectionTimeout: 1000,
requestTimeout: 1000,
trustServerCertificate: false
Expand Down
5 changes: 1 addition & 4 deletions backend/src/south/south-mssql/south-mssql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export default class SouthMSSQL
connectionTimeout: this.connector.settings.connectionTimeout,
requestTimeout: this.connector.settings.requestTimeout,
options: {
encrypt: this.connector.settings.encryption == null ? undefined : this.connector.settings.encryption,
encrypt: this.connector.settings.encryption || undefined,
trustServerCertificate: this.connector.settings.trustServerCertificate,
useUTC: true
}
Expand All @@ -78,9 +78,6 @@ export default class SouthMSSQL
request = pool.request();
} catch (error: any) {
this.logger.error(`Unable to connect to database: ${error.message}`);
if (pool) {
await pool.close();
}

switch (error.code) {
case 'ETIMEOUT':
Expand Down
50 changes: 18 additions & 32 deletions backend/src/south/south-odbc/manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,47 +15,31 @@ const manifest: SouthConnectorManifest = {
},
settings: [
{
key: 'driverPath',
type: 'OibText',
label: 'ODBC Driver Path',
key: 'remoteAgent',
type: 'OibCheckbox',
label: 'Use remote agent',
defaultValue: false,
newRow: true,
validators: [{ key: 'required' }],
displayInViewMode: true
},
{
key: 'host',
key: 'agentUrl',
type: 'OibText',
label: 'Host',
defaultValue: 'localhost',
newRow: true,
label: 'Use remote agent',
defaultValue: 'http://ip-adress-or-host:2224',
validators: [{ key: 'required' }],
displayInViewMode: true
},
{
key: 'port',
type: 'OibNumber',
label: 'Port',
defaultValue: 1433,
newRow: false,
class: 'col-2',
validators: [{ key: 'required' }, { key: 'min', params: { min: 1 } }, { key: 'max', params: { max: 65535 } }],
displayInViewMode: true
conditionalDisplay: { field: 'remoteAgent', values: [true] }
},
{
key: 'database',
key: 'connectionString',
type: 'OibText',
label: 'Database',
defaultValue: 'db',
label: 'Connection string',
defaultValue: 'localhost',
newRow: true,
validators: [{ key: 'required' }],
displayInViewMode: true
},
{
key: 'username',
type: 'OibText',
label: 'Username',
displayInViewMode: true
},
{
key: 'password',
type: 'OibSecret',
Expand All @@ -74,11 +58,13 @@ const manifest: SouthConnectorManifest = {
displayInViewMode: false
},
{
key: 'trustServerCertificate',
type: 'OibCheckbox',
label: 'Accept self-signed certificate',
defaultValue: false,
validators: [{ key: 'required' }],
key: 'requestTimeout',
type: 'OibNumber',
label: 'Request timeout',
defaultValue: 15_000,
unitLabel: 'ms',
class: 'col-4',
validators: [{ key: 'required' }, { key: 'min', params: { min: 100 } }, { key: 'max', params: { max: 30000 } }],
displayInViewMode: false
}
],
Expand Down
100 changes: 100 additions & 0 deletions backend/src/south/south-odbc/south-odbc-no-lib.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import SouthODBC from './south-odbc';
import DatabaseMock from '../../tests/__mocks__/database.mock';
import pino from 'pino';
// eslint-disable-next-line import/no-unresolved
import PinoLogger from '../../tests/__mocks__/logger.mock';
import EncryptionService from '../../service/encryption.service';
import EncryptionServiceMock from '../../tests/__mocks__/encryption-service.mock';
import RepositoryService from '../../service/repository.service';
import RepositoryServiceMock from '../../tests/__mocks__/repository-service.mock';
import { SouthConnectorDTO, SouthConnectorItemDTO } from '../../../../shared/model/south-connector.model';
import { SouthODBCItemSettings, SouthODBCSettings } from '../../../../shared/model/south-settings.model';

jest.mock('../../service/utils');
jest.mock('odbc', () => {
throw new Error('bad');
});
jest.mock('node:fs/promises');

const database = new DatabaseMock();
jest.mock(
'../../service/south-cache.service',
() =>
function () {
return {
createSouthCacheScanModeTable: jest.fn(),
southCacheRepository: {
database
}
};
}
);

jest.mock(
'../../service/south-connector-metrics.service',
() =>
function () {
return {
initMetrics: jest.fn(),
updateMetrics: jest.fn(),
get stream() {
return { stream: 'myStream' };
},
metrics: {
numberOfValuesRetrieved: 1,
numberOfFilesRetrieved: 1
}
};
}
);
const addValues = jest.fn();
const addFile = jest.fn();

const logger: pino.Logger = new PinoLogger();
const encryptionService: EncryptionService = new EncryptionServiceMock('', '');
const repositoryService: RepositoryService = new RepositoryServiceMock();
const items: Array<SouthConnectorItemDTO<SouthODBCItemSettings>> = [];

let south: SouthODBC;

// Spy on console info and error
jest.spyOn(global.console, 'info').mockImplementation(() => {});
jest.spyOn(global.console, 'error').mockImplementation(() => {});

describe('SouthODBC without ODBC Library', () => {
const configuration: SouthConnectorDTO<SouthODBCSettings> = {
id: 'southId',
name: 'south',
type: 'odbc',
description: 'my test connector',
enabled: true,
history: {
maxInstantPerItem: true,
maxReadInterval: 3600,
readDelay: 0
},
settings: {
remoteAgent: false,
connectionString: 'Driver={SQL Server};SERVER=127.0.0.1;TrustServerCertificate=yes',
password: 'password',
connectionTimeout: 1000,
requestTimeout: 1000
}
};

beforeEach(() => {
jest.clearAllMocks();

south = new SouthODBC(configuration, items, addValues, addFile, encryptionService, repositoryService, logger, 'baseFolder');
});

it('should throw error if library not loaded', async () => {
await expect(south.testOdbcConnection()).rejects.toThrow(new Error('odbc library not loaded'));

const startTime = '2020-01-01T00:00:00.000Z';
const endTime = '2022-01-01T00:00:00.000Z';
await expect(south.queryOdbcData({} as SouthConnectorItemDTO, startTime, endTime)).rejects.toThrow(
new Error('odbc library not loaded')
);
});
});
Loading

0 comments on commit 5a8f151

Please sign in to comment.