Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[93] fix: Connected Grafana Api to the response-time-interceptor #150

Open
wants to merge 24 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
f4ec971
feat(wip): move response time interceptor to use grafana api
techsavvyash Mar 10, 2024
125e67d
feat(wip): interceptor changes w api
techsavvyash Mar 15, 2024
3b0e08e
fix: connected grafana api with response-time-interceptor
DarrenDsouza7273 Jul 4, 2024
3fa0a9c
Added Monitoring
DarrenDsouza7273 Jul 6, 2024
9154a6d
fix: fixed dashboard generation to row level generation
Savio629 Jul 25, 2024
eae1619
Merge branch 'dev' of https://github.com/DarrenDsouza7273/stencil int…
Savio629 Jul 25, 2024
f3bde9c
fix: removed extra repo
Savio629 Jul 25, 2024
03b87d2
fix: updated test
Savio629 Jul 27, 2024
9d0d4a1
fix: added grafana level test
Savio629 Jul 28, 2024
04dbe76
fix: fixed the failing ci
Savio629 Aug 10, 2024
b4560f4
fix: updated the naming convection
Savio629 Aug 18, 2024
10660ff
fix: updated test
Savio629 Aug 20, 2024
9913ebe
fix: updated test and increased the coverage
Savio629 Sep 22, 2024
e0f6699
Merge branch 'Response-time-grafana' of https://github.com/DarrenDsou…
Savio629 Sep 22, 2024
db9a51d
fix: updated suggested changes
Savio629 Sep 22, 2024
4b9e67a
fix: updated test
Savio629 Sep 24, 2024
e528e29
fix: updated ci test
Savio629 Sep 24, 2024
6e4dc55
fix: fixed ci test
Savio629 Sep 24, 2024
0a6a022
fix: updating the failing ci
Savio629 Sep 24, 2024
a51767e
fix: updated ci test
Savio629 Sep 24, 2024
f472c86
fix: updated test
Savio629 Sep 24, 2024
683deb5
fix: updated test
Savio629 Sep 24, 2024
0cb6522
fix: failing test
Savio629 Sep 28, 2024
abe17ae
fix: updated yarn.lock file
Savio629 Oct 29, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 11 additions & 41 deletions packages/common/test/interceptor/response-time.interceptor.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { ResponseTimeInterceptor } from '../../src/interceptors/response-time.interceptor';
import { ExecutionContext, CallHandler } from '@nestjs/common';
import { of, throwError } from 'rxjs';
import { Test, TestingModule } from '@nestjs/testing';
import { Histogram } from 'prom-client';
import * as fs from 'fs';
import { performance } from 'perf_hooks';
import { ResponseTimeInterceptor } from '../../src/interceptors/response-time.interceptor';

// Mock dependencies
jest.mock('prom-client', () => {
const labels = jest.fn().mockReturnThis();
const observe = jest.fn();
Expand All @@ -18,12 +18,6 @@ jest.mock('prom-client', () => {
};
});

jest.mock('fs', () => ({
readFileSync: jest.fn(),
writeFileSync: jest.fn(),
existsSync: jest.fn(),
}));

jest.mock('perf_hooks', () => ({
performance: {
now: jest.fn(),
Expand All @@ -35,19 +29,19 @@ describe('ResponseTimeInterceptor', () => {
let mockHistogram: Histogram;
let mockExecutionContext: ExecutionContext;
let mockCallHandler: CallHandler;
const jsonPath = 'path/to/json';

const grafanaUrl = 'http://localhost:7889';
const grafanaToken = '<GRAFANA_TOKEN>';
const histogramTitle = 'test_histogram';

beforeEach(async () => {
mockHistogram = new (jest.requireMock('prom-client')
.Histogram as jest.Mock)();

mockHistogram = new (jest.requireMock('prom-client').Histogram as jest.Mock)();

const module: TestingModule = await Test.createTestingModule({
providers: [
{
provide: ResponseTimeInterceptor,
useFactory: () =>
new ResponseTimeInterceptor(histogramTitle, jsonPath),
useFactory: () => new ResponseTimeInterceptor(histogramTitle, grafanaUrl, grafanaToken),
},
],
}).compile();
Expand All @@ -64,9 +58,6 @@ describe('ResponseTimeInterceptor', () => {
mockCallHandler = {
handle: jest.fn().mockReturnValue(of('test')),
};

(fs.readFileSync as jest.Mock).mockImplementation(() => JSON.stringify({}));
(fs.writeFileSync as jest.Mock).mockImplementation(() => {});
});

afterEach(() => {
Expand All @@ -82,15 +73,12 @@ describe('ResponseTimeInterceptor', () => {
.mockReturnValueOnce(0)
.mockReturnValueOnce(100);

await interceptor
.intercept(mockExecutionContext, mockCallHandler)
.toPromise();
await interceptor.intercept(mockExecutionContext, mockCallHandler).toPromise();

expect(mockHistogram.labels).toHaveBeenCalledWith({
statusCode: 200,
endpoint: '/test',
});
// expect(mockHistogram.observe).toHaveBeenCalledWith(100);
});

it('should log response time and error on failed request', async () => {
Expand All @@ -102,30 +90,12 @@ describe('ResponseTimeInterceptor', () => {
.mockReturnValueOnce(0)
.mockReturnValueOnce(200);

await expect(
interceptor.intercept(mockExecutionContext, mockCallHandler).toPromise(),
).rejects.toThrow('Test Error');
await expect(interceptor.intercept(mockExecutionContext, mockCallHandler).toPromise()).rejects.toThrow('Test Error');

expect(mockHistogram.labels).toHaveBeenCalledWith({
statusCode: 500,
endpoint: '/test',
});
// expect(mockHistogram.observe).toHaveBeenCalledWith(200);
});
});

it('should handle JSON parsing errors gracefully', async () => {
(fs.readFileSync as jest.Mock).mockImplementationOnce(() => {
throw new SyntaxError('Invalid JSON');
});

await expect(
interceptor.intercept(mockExecutionContext, mockCallHandler).toPromise(),
).resolves.toBe('test');

expect(mockHistogram.labels).toHaveBeenCalledWith({
statusCode: 200,
endpoint: '/test',
});
// expect(mockHistogram.observe).toHaveBeenCalledWith(100);
});
});
6 changes: 3 additions & 3 deletions sample/01-monitoring/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "02-monitoring",
"name": "01-monitoring",
"version": "0.0.1",
"description": "",
"author": "",
Expand All @@ -17,14 +17,14 @@
"test:watch": "jest --passWithNoTests --watch",
"test:cov": "jest --passWithNoTests --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --passWithNoTests --config ./test/jest-e2e.json"
"test:e2e": "jest --passWithNoTests --runInBand --detectOpenHandles --forceExit --config ./test/jest-e2e.json"
},
"dependencies": {
"@nestjs/common": "^10.0.0",
"@nestjs/config": "^3.2.3",
"@nestjs/core": "^10.0.0",
"@nestjs/platform-express": "^10.0.0",
"@samagra-x/stencil": "^0.0.2",
"@samagra-x/stencil": "^0.0.6",
"axios": "^1.6.7",
"reflect-metadata": "^0.1.13",
"rxjs": "^7.8.1",
Expand Down
72 changes: 72 additions & 0 deletions sample/01-monitoring/test/app.e2e-spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { Test, TestingModule } from '@nestjs/testing';
import * as request from 'supertest';
import { INestApplication, Logger } from '@nestjs/common';
import { AppModule } from '../src/app.module';
import { ResponseTimeInterceptor } from '@samagra-x/stencil';
import { delay } from 'rxjs';
import { ConfigService } from '@nestjs/config';

describe('ResponseTimeInterceptor (Integration)', () => {

let app: INestApplication;
const mockLogger = {
log: jest.fn(),
error: jest.fn(),
};
let configService: ConfigService;
let grafanaBaseURL: string;
let apiToken : string;

beforeAll(async () => {
jest.spyOn(Logger.prototype, 'log').mockImplementation(mockLogger.log);
jest.spyOn(Logger.prototype, 'error').mockImplementation(mockLogger.error);

const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
}).compile();

app = moduleFixture.createNestApplication();
await app.init();
configService = app.get(ConfigService);
grafanaBaseURL = configService.get<string>('GRAFANA_BASE_URL');
apiToken = configService.get<string>('GRAFANA_API_TOKEN');

});
afterAll(async () => {
await app.close();
});

// it('should log sucessfull message of the logger', async () => {
Savio629 marked this conversation as resolved.
Show resolved Hide resolved
// expect(mockLogger.log).toHaveBeenCalledWith(
// expect.stringContaining('Successfully added histogram to dashboard!')
// );
// console.log(mockLogger.log.mock.calls);
// });

it('should contain only controller level interceptor response', async () => {

const metrics = await request(app.getHttpServer())
.get('/metrics')
.expect(200);
expect(metrics.text).toContain('controller_response_time');
});

it('should contain both controller and global level interceptor response', async () => {

app.useGlobalInterceptors(
new ResponseTimeInterceptor(
'global',
grafanaBaseURL,
apiToken,
),
);

const metrics = await request(app.getHttpServer())
.get('/metrics')
.expect(200);
expect(metrics.text).toContain('global_response_time');
expect(metrics.text).toContain('controller_response_time');

});

});
Loading