Skip to content

Commit af4a9f8

Browse files
committed
feat: adding InfluxDB support
1 parent 82d1109 commit af4a9f8

File tree

8 files changed

+549
-0
lines changed

8 files changed

+549
-0
lines changed

package-lock.json

Lines changed: 23 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
FROM influxdb:2.7
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
{
2+
"name": "@testcontainers/influxdb",
3+
"version": "11.5.1",
4+
"license": "MIT",
5+
"keywords": [
6+
"influxdb",
7+
"influx",
8+
"timeseries",
9+
"testing",
10+
"docker",
11+
"testcontainers"
12+
],
13+
"description": "InfluxDB module for Testcontainers",
14+
"homepage": "https://github.com/testcontainers/testcontainers-node#readme",
15+
"repository": {
16+
"type": "git",
17+
"url": "git+https://github.com/testcontainers/testcontainers-node.git"
18+
},
19+
"bugs": {
20+
"url": "https://github.com/testcontainers/testcontainers-node/issues"
21+
},
22+
"main": "build/index.js",
23+
"files": [
24+
"build"
25+
],
26+
"publishConfig": {
27+
"access": "public"
28+
},
29+
"scripts": {
30+
"prepack": "shx cp ../../../README.md . && shx cp ../../../LICENSE .",
31+
"build": "tsc --project tsconfig.build.json"
32+
},
33+
"devDependencies": {
34+
"@influxdata/influxdb-client": "^1.35.0",
35+
"axios": "^1.7.9"
36+
},
37+
"dependencies": {
38+
"testcontainers": "^11.5.1"
39+
}
40+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { InfluxDBContainer, StartedInfluxDBContainer } from "./influxdb-container";
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
import { InfluxDBContainer, StartedInfluxDBContainer } from "./influxdb-container";
2+
import { getImage } from "../../../testcontainers/src/utils/test-helper";
3+
import axios from "axios";
4+
5+
const IMAGE = getImage(__dirname);
6+
7+
describe("InfluxDBContainer", { timeout: 240_000 }, () => {
8+
9+
describe("InfluxDB 2.x", { timeout: 240_000 }, () => {
10+
let container: StartedInfluxDBContainer;
11+
12+
afterEach(async () => {
13+
if (container) {
14+
await container.stop();
15+
}
16+
});
17+
18+
it("should start with default configuration", async () => {
19+
container = await new InfluxDBContainer(IMAGE).start();
20+
21+
expect(container.getPort()).toBeGreaterThan(0);
22+
expect(container.getUsername()).toBe("test-user");
23+
expect(container.getPassword()).toBe("test-password");
24+
expect(container.getOrganization()).toBe("test-org");
25+
expect(container.getBucket()).toBe("test-bucket");
26+
expect(container.isInfluxDB2()).toBe(true);
27+
});
28+
29+
it("should start with custom configuration", async () => {
30+
container = await new InfluxDBContainer(IMAGE)
31+
.withUsername("custom-user")
32+
.withPassword("custom-password")
33+
.withOrganization("custom-org")
34+
.withBucket("custom-bucket")
35+
.withRetention("7d")
36+
.withAdminToken("my-super-secret-token")
37+
.start();
38+
39+
expect(container.getUsername()).toBe("custom-user");
40+
expect(container.getPassword()).toBe("custom-password");
41+
expect(container.getOrganization()).toBe("custom-org");
42+
expect(container.getBucket()).toBe("custom-bucket");
43+
expect(container.getAdminToken()).toBe("my-super-secret-token");
44+
});
45+
46+
it("should respond to ping endpoint", async () => {
47+
container = await new InfluxDBContainer(IMAGE).start();
48+
49+
const response = await axios.get(`${container.getUrl()}/ping`);
50+
expect(response.status).toBe(204);
51+
});
52+
53+
it("should provide correct connection string", async () => {
54+
container = await new InfluxDBContainer(IMAGE)
55+
.withOrganization("my-org")
56+
.withBucket("my-bucket")
57+
.withAdminToken("my-token")
58+
.start();
59+
60+
const connectionString = container.getConnectionString();
61+
expect(connectionString).toContain(container.getUrl());
62+
expect(connectionString).toContain("org=my-org");
63+
expect(connectionString).toContain("bucket=my-bucket");
64+
expect(connectionString).toContain("token=my-token");
65+
});
66+
67+
it("should be able to write and query data", async () => {
68+
const adminToken = "test-admin-token";
69+
container = await new InfluxDBContainer(IMAGE)
70+
.withAdminToken(adminToken)
71+
.start();
72+
73+
// Write data using the InfluxDB 2.x API
74+
const writeUrl = `${container.getUrl()}/api/v2/write?org=${container.getOrganization()}&bucket=${container.getBucket()}`;
75+
const writeData = "temperature,location=room1 value=23.5";
76+
77+
const writeResponse = await axios.post(writeUrl, writeData, {
78+
headers: {
79+
Authorization: `Token ${adminToken}`,
80+
"Content-Type": "text/plain",
81+
},
82+
});
83+
84+
expect(writeResponse.status).toBe(204);
85+
86+
// Query data
87+
const queryUrl = `${container.getUrl()}/api/v2/query?org=${container.getOrganization()}`;
88+
const query = {
89+
query: `from(bucket: "${container.getBucket()}") |> range(start: -1h) |> filter(fn: (r) => r._measurement == "temperature")`,
90+
type: "flux",
91+
};
92+
93+
const queryResponse = await axios.post(queryUrl, query, {
94+
headers: {
95+
Authorization: `Token ${adminToken}`,
96+
"Content-Type": "application/json",
97+
},
98+
});
99+
100+
expect(queryResponse.status).toBe(200);
101+
});
102+
103+
it("should start with specific version", async () => {
104+
container = await new InfluxDBContainer(IMAGE).start();
105+
106+
expect(container.isInfluxDB2()).toBe(true);
107+
108+
const response = await axios.get(`${container.getUrl()}/ping`);
109+
expect(response.status).toBe(204);
110+
});
111+
});
112+
113+
describe("InfluxDB 1.x", { timeout: 240_000 }, () => {
114+
let container: StartedInfluxDBContainer;
115+
116+
afterEach(async () => {
117+
if (container) {
118+
await container.stop();
119+
}
120+
});
121+
122+
it("should start InfluxDB 1.8 with default configuration", async () => {
123+
container = await new InfluxDBContainer("influxdb:1.8").start();
124+
125+
expect(container.getPort()).toBeGreaterThan(0);
126+
expect(container.getUsername()).toBe("test-user");
127+
expect(container.getPassword()).toBe("test-password");
128+
expect(container.isInfluxDB2()).toBe(false);
129+
});
130+
131+
it("should start InfluxDB 1.8 with custom database", async () => {
132+
container = await new InfluxDBContainer("influxdb:1.8")
133+
.withDatabase("mydb")
134+
.withUsername("dbuser")
135+
.withPassword("dbpass")
136+
.withAuthEnabled(true)
137+
.withAdmin("superadmin")
138+
.withAdminPassword("superpass")
139+
.start();
140+
141+
expect(container.getDatabase()).toBe("mydb");
142+
expect(container.getUsername()).toBe("dbuser");
143+
expect(container.getPassword()).toBe("dbpass");
144+
});
145+
146+
it("should respond to ping endpoint for v1", async () => {
147+
container = await new InfluxDBContainer("influxdb:1.8")
148+
.withAuthEnabled(false)
149+
.start();
150+
151+
const response = await axios.get(`${container.getUrl()}/ping`);
152+
expect(response.status).toBe(204);
153+
});
154+
155+
it("should provide correct connection string for v1", async () => {
156+
container = await new InfluxDBContainer("influxdb:1.8")
157+
.withDatabase("testdb")
158+
.withUsername("user1")
159+
.withPassword("pass1")
160+
.start();
161+
162+
const connectionString = container.getConnectionString();
163+
expect(connectionString).toContain(container.getHost());
164+
expect(connectionString).toContain("user1");
165+
expect(connectionString).toContain("pass1");
166+
expect(connectionString).toContain("/testdb");
167+
});
168+
169+
it("should be able to write data with v1 API", async () => {
170+
container = await new InfluxDBContainer("influxdb:1.8")
171+
.withDatabase("testdb")
172+
.withAuthEnabled(false)
173+
.start();
174+
175+
// Write data using the InfluxDB 1.x API
176+
const writeUrl = `${container.getUrl()}/write?db=testdb`;
177+
const writeData = "cpu_usage,host=server01 value=0.64";
178+
179+
const writeResponse = await axios.post(writeUrl, writeData, {
180+
headers: {
181+
"Content-Type": "text/plain",
182+
},
183+
});
184+
185+
expect(writeResponse.status).toBe(204);
186+
187+
// Query data
188+
const queryUrl = `${container.getUrl()}/query?db=testdb&q=SELECT * FROM cpu_usage`;
189+
const queryResponse = await axios.get(queryUrl);
190+
191+
expect(queryResponse.status).toBe(200);
192+
expect(queryResponse.data).toHaveProperty("results");
193+
});
194+
});
195+
196+
describe("Version Detection", { timeout: 240_000 }, () => {
197+
it("should correctly detect InfluxDB 2.x from image tag", async () => {
198+
// The default image in Dockerfile is 2.7
199+
const container = await new InfluxDBContainer(IMAGE).start();
200+
expect(container.isInfluxDB2()).toBe(true);
201+
await container.stop();
202+
});
203+
204+
it("should correctly detect InfluxDB 1.x when using 1.8 image", async () => {
205+
const container = await new InfluxDBContainer("influxdb:1.8").start();
206+
expect(container.isInfluxDB2()).toBe(false);
207+
await container.stop();
208+
});
209+
});
210+
});

0 commit comments

Comments
 (0)