diff --git a/packages/node/test/lib/log.test.ts b/packages/node/test/lib/log.test.ts new file mode 100644 index 0000000000..0875ba3f80 --- /dev/null +++ b/packages/node/test/lib/log.test.ts @@ -0,0 +1,46 @@ +import type { ExtendedIncomingMessage, ExtendedResponse, Options } from 'src/lib/log'; +import type { GroupingObject } from 'src/lib/metrics-log'; + +import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest'; + +import { log } from '../../src/lib/log'; +import { metricsAPICall } from '../../src/lib/metrics-log'; + +describe('log', function () { + vi.mock('../../src/lib/metrics-log'); + + let req: ExtendedIncomingMessage; + let res: ExtendedResponse; + let group: GroupingObject; + let options: Options; + + beforeEach(() => { + req = { + method: 'GET', + headers: {}, + url: '/', + } as ExtendedIncomingMessage; + + res = { + statusCode: 200, + getHeader: vi.fn(), + setHeader: vi.fn(), + removeListener: vi.fn(), + once: vi.fn(), + } as unknown as ExtendedResponse; + + group = { apiKey: 'test-api-key' }; + options = { bufferLength: 1 }; + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + + it('should not log OPTIONS requests', function () { + req.method = 'OPTIONS'; + const logId = log('api-key', req, res, group, options); + expect(logId).toBeUndefined(); + expect(metricsAPICall).not.toHaveBeenCalled(); + }); +}); diff --git a/packages/php/tests/MetricsTest.php b/packages/php/tests/MetricsTest.php index 8aaf4bb902..61dab32c5b 100644 --- a/packages/php/tests/MetricsTest.php +++ b/packages/php/tests/MetricsTest.php @@ -227,6 +227,29 @@ public function testTrackHandlesApiServerUnavailability(bool $development_mode): } } + /** + * @group track + */ + public function testTrackIgnoresOptionsMethod(): void + { + $request = new Request([], [], [], [], [], ['REQUEST_METHOD' => 'OPTIONS']); + $response = $this->getMockJsonResponse(); + + $handlers = $this->getMockHandlers( + new \GuzzleHttp\Psr7\Response(200, [], 'OK'), + new \GuzzleHttp\Psr7\Response(200, [], json_encode(['baseUrl' => $this->base_log_url])) + ); + + $this->metrics = new Metrics($this->readme_api_key, $this->group_handler, [ + 'development_mode' => false, + 'client' => new Client(['handler' => $handlers->metrics]), + 'client_readme' => new Client(['handler' => $handlers->readme]) + ]); + + $this->metrics->track($request, $response); + $this->assertEmpty($this->api_calls, 'No API calls should be made for OPTIONS requests.'); + } + /** * @group getProjectBaseUrl * @dataProvider providerDevelopmentModeToggle diff --git a/packages/python/readme_metrics/flask_readme.py b/packages/python/readme_metrics/flask_readme.py index f4ac87bba9..78da6c23b1 100644 --- a/packages/python/readme_metrics/flask_readme.py +++ b/packages/python/readme_metrics/flask_readme.py @@ -42,9 +42,6 @@ def before_request(self): self.config.LOGGER.exception(e) def after_request(self, response): - if request.method == "OPTIONS": - return response - try: response_info = ResponseInfoWrapper( response.headers, diff --git a/packages/python/readme_metrics/tests/django_test.py b/packages/python/readme_metrics/tests/django_test.py index 9869286c4f..cbf74a28e7 100644 --- a/packages/python/readme_metrics/tests/django_test.py +++ b/packages/python/readme_metrics/tests/django_test.py @@ -63,3 +63,11 @@ def test_missing_content_length(self): request.headers = {} middleware(request) assert getattr(request, "rm_content_length") == "0" + + def test_options_request(self): + middleware = MetricsMiddleware(Mock(), config=mock_config) + middleware.metrics_core = Mock() + request = Mock() + request.method = "OPTIONS" + result = middleware(request) + assert not middleware.metrics_core.process.called \ No newline at end of file diff --git a/packages/python/readme_metrics/tests/flask_test.py b/packages/python/readme_metrics/tests/flask_test.py index 67ab84084b..accd802608 100644 --- a/packages/python/readme_metrics/tests/flask_test.py +++ b/packages/python/readme_metrics/tests/flask_test.py @@ -69,3 +69,15 @@ def test_after_request(self): assert call_args[0][0] == request assert isinstance(call_args[0][1], ResponseInfoWrapper) assert call_args[0][1].headers.get("X-Header") == "X Value!" + + def test_before_request_options(self): + app = Flask(__name__) + extension = ReadMeMetrics(config=mock_config, app=app) + + with app.test_request_context("/", method="OPTIONS"): + extension.before_request() + + assert not hasattr(request, "rm_start_dt") + assert not hasattr(request, "rm_start_ts") + assert not hasattr(request, "rm_content_length") + assert not hasattr(request, "rm_body")