Skip to main content
Glama
csv-parsing.test.js7.91 kB
import { jest } from "@jest/globals"; // Test timeout jest.setTimeout(10000); describe("CSV Parsing Edge Cases - Issue #8", () => { let bucketMeasurements; let mockInfluxRequest; beforeAll(async () => { // Mock the influxClient module before importing the handler jest.unstable_mockModule("../src/utils/influxClient.js", () => ({ influxRequest: jest.fn(), })); // Mock the env module jest.unstable_mockModule("../src/config/env.js", () => ({ INFLUXDB_URL: "http://localhost:8086", INFLUXDB_TOKEN: "test-token", DEFAULT_ORG: "test-org", validateEnvironment: () => {}, })); // Import the handler after mocking const measurementsHandler = await import( "../src/handlers/measurementsHandler.js" ); bucketMeasurements = measurementsHandler.bucketMeasurements; // Get reference to the mocked function const influxClient = await import("../src/utils/influxClient.js"); mockInfluxRequest = influxClient.influxRequest; }); test("should handle CSV with Flux metadata rows (Issue #8)", async () => { console.log( "Testing CSV parsing with Flux metadata rows - reproducing Issue #8", ); // This CSV response reproduces the exact issue from #8: // - Flux metadata rows starting with # appear before the header row // - Without the fix, the code would try to parse line[0] (a metadata row) // as the header, causing indexOf("_value") to return -1 const problematicCsvResponse = "#datatype,string,long,string\n" + "#group,false,false,false\n" + "#default,_result,,\n" + ",result,table,_value\n" + ",,0,cpu_usage\n" + ",,0,temperature\n" + ",,0,memory_usage\n"; // Mock the influxRequest to return this problematic CSV mockInfluxRequest.mockResolvedValueOnce({ status: 200, ok: true, text: async () => problematicCsvResponse, }); // Call the handler const uri = new URL("influxdb://bucket/test-bucket/measurements"); const params = { bucketName: "test-bucket" }; const response = await bucketMeasurements(uri, params); // Verify the response expect(response).toBeDefined(); expect(response.contents).toBeDefined(); expect(response.contents[0]).toBeDefined(); expect(response.contents[0].text).toBeDefined(); // Parse the JSON response const result = JSON.parse(response.contents[0].text); // Validate measurements were correctly extracted expect(result.measurements).toBeDefined(); expect(Array.isArray(result.measurements)).toBe(true); expect(result.measurements).toHaveLength(3); expect(result.measurements).toContain("cpu_usage"); expect(result.measurements).toContain("temperature"); expect(result.measurements).toContain("memory_usage"); console.log("✓ Successfully parsed CSV by filtering metadata rows"); }); test("should trim whitespace from header names", async () => { console.log("Testing CSV parsing with whitespace in headers"); // CSV with whitespace in header names (though uncommon, the fix handles it) const csvWithWhitespace = "#datatype,string,long,string\n" + ", result , table , _value \n" + ",,0,disk_usage\n" + ",,0,network_traffic\n"; mockInfluxRequest.mockResolvedValueOnce({ status: 200, ok: true, text: async () => csvWithWhitespace, }); const uri = new URL("influxdb://bucket/test-bucket/measurements"); const params = { bucketName: "test-bucket" }; const response = await bucketMeasurements(uri, params); const result = JSON.parse(response.contents[0].text); expect(result.measurements).toHaveLength(2); expect(result.measurements).toContain("disk_usage"); expect(result.measurements).toContain("network_traffic"); console.log("✓ Successfully parsed CSV with whitespace in headers"); }); test("should handle CSV with extensive metadata rows", async () => { console.log("Testing CSV parsing with extensive metadata"); // CSV with many metadata rows (all starting with #) const csvWithMetadata = "#datatype,string,long,string\r\n" + "#group,false,false,false\r\n" + "#default,_result,,\r\n" + "# This is a comment\r\n" + "#another,metadata,row\r\n" + ",result,table,_value\r\n" + ",,0,sensor_data\r\n"; mockInfluxRequest.mockResolvedValueOnce({ status: 200, ok: true, text: async () => csvWithMetadata, }); const uri = new URL("influxdb://bucket/test-bucket/measurements"); const params = { bucketName: "test-bucket" }; const response = await bucketMeasurements(uri, params); const result = JSON.parse(response.contents[0].text); expect(result.measurements).toHaveLength(1); expect(result.measurements).toContain("sensor_data"); console.log("✓ Successfully filtered metadata rows"); }); test("should handle empty CSV response", async () => { console.log("Testing CSV parsing with empty response"); // CSV with only metadata, no data rows const emptyCsv = "#datatype,string,long,string\r\n" + "#group,false,false,false\r\n"; mockInfluxRequest.mockResolvedValueOnce({ status: 200, ok: true, text: async () => emptyCsv, }); const uri = new URL("influxdb://bucket/test-bucket/measurements"); const params = { bucketName: "test-bucket" }; const response = await bucketMeasurements(uri, params); const result = JSON.parse(response.contents[0].text); expect(result.measurements).toBeDefined(); expect(Array.isArray(result.measurements)).toBe(true); expect(result.measurements).toHaveLength(0); console.log("✓ Successfully handled empty CSV"); }); test("should handle CSV with missing _value column", async () => { console.log("Testing CSV parsing without _value column"); // CSV without the _value column const csvWithoutValue = ",result,table,measurement\r\n" + ",,0,cpu_usage\r\n"; mockInfluxRequest.mockResolvedValueOnce({ status: 200, ok: true, text: async () => csvWithoutValue, }); const uri = new URL("influxdb://bucket/test-bucket/measurements"); const params = { bucketName: "test-bucket" }; const response = await bucketMeasurements(uri, params); const result = JSON.parse(response.contents[0].text); // Should return empty array when _value column is missing expect(result.measurements).toBeDefined(); expect(Array.isArray(result.measurements)).toBe(true); expect(result.measurements).toHaveLength(0); console.log("✓ Successfully handled missing _value column"); }); test("should handle CSV with values containing whitespace", async () => { console.log("Testing CSV parsing with whitespace in values"); // CSV with whitespace in the actual measurement values const csvWithValueWhitespace = ",result,table,_value\r\n" + ",,0, cpu_usage \r\n" + ",,0, temperature \r\n" + ",,0,memory_usage \r\n"; mockInfluxRequest.mockResolvedValueOnce({ status: 200, ok: true, text: async () => csvWithValueWhitespace, }); const uri = new URL("influxdb://bucket/test-bucket/measurements"); const params = { bucketName: "test-bucket" }; const response = await bucketMeasurements(uri, params); const result = JSON.parse(response.contents[0].text); // Values should be trimmed expect(result.measurements).toHaveLength(3); expect(result.measurements).toContain("cpu_usage"); expect(result.measurements).toContain("temperature"); expect(result.measurements).toContain("memory_usage"); // Verify no whitespace remains result.measurements.forEach((m) => { expect(m).toBe(m.trim()); }); console.log("✓ Successfully trimmed whitespace from values"); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/idoru/influxdb-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server