From 7e0c156aabf06b5e79667ebc7574a58fab2e7bd3 Mon Sep 17 00:00:00 2001 From: Tomer <42910634+tomer-friedman@users.noreply.github.com> Date: Tue, 28 Mar 2023 17:56:40 -0700 Subject: [PATCH] feat: redis tests (#61) --- packages/expect-opentelemetry/src/index.ts | 4 ++ .../src/matchers/service/index.ts | 1 + .../matchers/service/to-send-redis-command.ts | 28 +++++++++++ .../src/resources/index.ts | 1 + .../src/resources/redis-command.ts | 47 +++++++++++++++++++ 5 files changed, 81 insertions(+) create mode 100644 packages/expect-opentelemetry/src/matchers/service/to-send-redis-command.ts create mode 100644 packages/expect-opentelemetry/src/resources/redis-command.ts diff --git a/packages/expect-opentelemetry/src/index.ts b/packages/expect-opentelemetry/src/index.ts index 3d89ea1..94f1bbe 100644 --- a/packages/expect-opentelemetry/src/index.ts +++ b/packages/expect-opentelemetry/src/index.ts @@ -4,12 +4,14 @@ import { toQueryPostgreSQL, toReceiveGrpcRequest, toSendGrpcRequest, + toSendRedisCommand, } from './matchers/service'; import { expect } from '@jest/globals'; import { GrpcRequest, HttpRequest, PostgreSQLQuery, + RedisCommand, Service, } from './resources'; export { setDefaultOptions, getDefaultOptions } from './options'; @@ -24,6 +26,7 @@ const serviceMatchers = { toQueryPostgreSQL, toReceiveGrpcRequest, toSendGrpcRequest, + toSendRedisCommand, }; interface TraceMatchers { @@ -32,6 +35,7 @@ interface TraceMatchers { toQueryPostgreSQL(): PostgreSQLQuery; toReceiveGrpcRequest(): GrpcRequest; toSendGrpcRequest(): GrpcRequest; + toSendRedisCommand(): RedisCommand; } function createMatcher(matcher, type) { diff --git a/packages/expect-opentelemetry/src/matchers/service/index.ts b/packages/expect-opentelemetry/src/matchers/service/index.ts index 3177f0c..154aa62 100644 --- a/packages/expect-opentelemetry/src/matchers/service/index.ts +++ b/packages/expect-opentelemetry/src/matchers/service/index.ts @@ -3,3 +3,4 @@ export * from './to-send-http-request'; export * from './to-query-postgresql'; export * from './to-receive-grpc-request'; export * from './to-send-grpc-request'; +export * from './to-send-redis-command'; diff --git a/packages/expect-opentelemetry/src/matchers/service/to-send-redis-command.ts b/packages/expect-opentelemetry/src/matchers/service/to-send-redis-command.ts new file mode 100644 index 0000000..54262de --- /dev/null +++ b/packages/expect-opentelemetry/src/matchers/service/to-send-redis-command.ts @@ -0,0 +1,28 @@ +import { SemanticAttributes } from '@opentelemetry/semantic-conventions'; +import { opentelemetry } from '@traceloop/otel-proto'; +import { RedisCommand, Service } from '../../resources'; + +export function toSendRedisCommand(service: Service): RedisCommand { + const { name: serviceName, spans } = service; + + const filteredSpans = spans.filter((span) => { + return ( + span.kind === + opentelemetry.proto.trace.v1.Span.SpanKind.SPAN_KIND_CLIENT && + span.attributes?.find( + (attribute: opentelemetry.proto.common.v1.IKeyValue) => { + return ( + attribute.key === SemanticAttributes.DB_SYSTEM && + attribute.value?.stringValue === 'redis' + ); + }, + ) + ); + }); + + if (filteredSpans.length === 0) { + throw new Error(`No redis command from ${serviceName} found`); + } + + return new RedisCommand(filteredSpans, serviceName); +} diff --git a/packages/expect-opentelemetry/src/resources/index.ts b/packages/expect-opentelemetry/src/resources/index.ts index 1c61268..1b630f1 100644 --- a/packages/expect-opentelemetry/src/resources/index.ts +++ b/packages/expect-opentelemetry/src/resources/index.ts @@ -2,3 +2,4 @@ export * from './http-request'; export * from './service'; export * from './postgresql-query'; export * from './grpc-request'; +export * from './redis-command'; diff --git a/packages/expect-opentelemetry/src/resources/redis-command.ts b/packages/expect-opentelemetry/src/resources/redis-command.ts new file mode 100644 index 0000000..c6b917c --- /dev/null +++ b/packages/expect-opentelemetry/src/resources/redis-command.ts @@ -0,0 +1,47 @@ +import { SemanticAttributes } from '@opentelemetry/semantic-conventions'; +import { opentelemetry } from '@traceloop/otel-proto'; +import { + CompareOptions, + filterByAttributeStringValue, +} from '../matchers/utils'; + +export class RedisCommand { + constructor( + readonly spans: opentelemetry.proto.trace.v1.ISpan[], + private readonly serviceName: string, + ) {} + + withDatabaseName(name: string | RegExp, options: CompareOptions) { + const filteredSpans = filterByAttributeStringValue( + this.spans, + SemanticAttributes.DB_NAME, + name, + options, + ); + + if (filteredSpans.length === 0) { + throw new Error( + `No redis command from service ${this.serviceName} to database ${name} found`, + ); + } + + return new RedisCommand(filteredSpans, this.serviceName); + } + + withStatement(statement: string | RegExp, options: CompareOptions) { + const filteredSpans = filterByAttributeStringValue( + this.spans, + SemanticAttributes.DB_STATEMENT, + statement, + options, + ); + + if (filteredSpans.length === 0) { + throw new Error( + `No redis command with statement ${statement} from service ${this.serviceName} found`, + ); + } + + return new RedisCommand(filteredSpans, this.serviceName); + } +}