feat(Redis Node): Add support for TLS (#9266)

This commit is contained in:
कारतोफ्फेलस्क्रिप्ट™ 2024-05-02 17:35:41 +02:00 committed by GitHub
parent 30c8efc4cc
commit 0a2de093c0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 158 additions and 104 deletions

View file

@ -35,5 +35,11 @@ export class Redis implements ICredentialType {
type: 'number',
default: 0,
},
{
displayName: 'SSL',
name: 'ssl',
type: 'boolean',
default: false,
},
];
}

View file

@ -1,14 +1,59 @@
import { mock } from 'jest-mock-extended';
import type { RedisClientType } from '@redis/client';
import type { IExecuteFunctions } from 'n8n-workflow';
import { Redis } from '../Redis.node';
const mockClient = mock<RedisClientType>();
jest.mock('redis', () => ({
createClient: () => mockClient,
}));
const createClient = jest.fn().mockReturnValue(mockClient);
jest.mock('redis', () => ({ createClient }));
import { Redis } from '../Redis.node';
import { setupRedisClient } from '../utils';
describe('Redis Node', () => {
const node = new Redis();
beforeEach(() => jest.clearAllMocks());
describe('setupRedisClient', () => {
it('should not configure TLS by default', () => {
setupRedisClient({
host: 'redis.domain',
port: 1234,
database: 0,
});
expect(createClient).toHaveBeenCalledWith({
database: 0,
password: undefined,
socket: {
host: 'redis.domain',
port: 1234,
tls: false,
},
});
});
it('should configure TLS', () => {
setupRedisClient({
host: 'redis.domain',
port: 1234,
database: 0,
ssl: true,
});
expect(createClient).toHaveBeenCalledWith({
database: 0,
password: undefined,
socket: {
host: 'redis.domain',
port: 1234,
tls: true,
},
});
});
});
describe('operations', () => {
const thisArg = mock<IExecuteFunctions>({});
const mockCredential = {
host: 'redis',
port: 1234,
@ -16,19 +61,17 @@ describe('Redis Node', () => {
password: 'random',
};
const node = new Redis();
const thisArg = mock<IExecuteFunctions>({});
thisArg.getCredentials.calledWith('redis').mockResolvedValue(mockCredential);
beforeEach(() => jest.clearAllMocks());
afterEach(() => {
expect(createClient).toHaveBeenCalled();
expect(mockClient.connect).toHaveBeenCalled();
expect(mockClient.ping).toHaveBeenCalled();
expect(mockClient.quit).toHaveBeenCalled();
});
it('info operation', async () => {
describe('info operation', () => {
it('should return info', async () => {
thisArg.getNodeParameter.calledWith('operation', 0).mockReturnValue('info');
mockClient.info.mockResolvedValue(`
# Server
@ -76,8 +119,10 @@ master_failover_state:no-failover
master_failover_state: 'no-failover',
});
});
});
it('delete operation', async () => {
describe('delete operation', () => {
it('should delete', async () => {
thisArg.getInputData.mockReturnValue([{ json: { x: 1 } }]);
thisArg.getNodeParameter.calledWith('operation', 0).mockReturnValue('delete');
thisArg.getNodeParameter.calledWith('key', 0).mockReturnValue('key1');
@ -87,6 +132,7 @@ master_failover_state:no-failover
expect(mockClient.del).toHaveBeenCalledWith('key1');
expect(output[0][0].json).toEqual({ x: 1 });
});
});
describe('get operation', () => {
beforeEach(() => {
@ -155,4 +201,5 @@ master_failover_state:no-failover
expect(output[0][0].json).toEqual({ key1: 'value1', key2: 'value2' });
});
});
});
});

View file

@ -8,14 +8,15 @@ import type {
} from 'n8n-workflow';
import { NodeOperationError } from 'n8n-workflow';
import { createClient } from 'redis';
import { type RedisClientOptions, createClient } from 'redis';
export type RedisClientType = ReturnType<typeof createClient>;
export function setupRedisClient(credentials: ICredentialDataDecryptedObject): RedisClientType {
const redisOptions = {
const redisOptions: RedisClientOptions = {
socket: {
host: credentials.host as string,
port: credentials.port as number,
tls: credentials.ssl === true,
},
database: credentials.database as number,
password: (credentials.password as string) || undefined,