Skip to content

Commit cc027e4

Browse files
authored
Merge pull request #40 from Relwave/develop
v0.1.0-beta.5
2 parents e771ea9 + 888c97f commit cc027e4

File tree

16 files changed

+1008
-13
lines changed

16 files changed

+1008
-13
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
</p>
1818

1919
<p align="center">
20-
<a href="https://github.com/Yashh56/RelWave/releases"><strong>Download</strong></a> |
20+
<a href="https://github.com/Relwave/relwave-app/releases"><strong>Download</strong></a> |
2121
<a href="#Features"><strong>Features</strong></a> |
2222
<a href="#Installation"><strong>Installation</strong></a> |
2323
<a href="#Contributing"><strong>Contributing</strong></a>
@@ -103,7 +103,7 @@ Before building from source, ensure you have:
103103

104104
### From Releases (Recommended)
105105

106-
Download the latest release for your platform from the [**Releases**](https://github.com/Yashh56/RelWave/releases) page:
106+
Download the latest release for your platform from the [**Releases**](https://github.com/Relwave/relwave-app/releases) page:
107107

108108
| Platform | File Type | Description |
109109
|----------|----------|-------------|
@@ -116,7 +116,7 @@ Download the latest release for your platform from the [**Releases**](https://gi
116116

117117
1. Clone the repository:
118118
```bash
119-
git clone https://github.com/Yashh56/RelWave.git
119+
git clone https://github.com/Relwave/relwave-app.git
120120
cd RelWave
121121
```
122122

Lines changed: 360 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,360 @@
1+
import { describe, expect, test, beforeEach } from "@jest/globals";
2+
import { DiscoveryService, DiscoveredDatabase } from "../src/services/discoveryService";
3+
4+
describe("DiscoveryService", () => {
5+
let service: DiscoveryService;
6+
7+
beforeEach(() => {
8+
service = new DiscoveryService();
9+
});
10+
11+
describe("generateFunName", () => {
12+
test("should generate a name in format adjective-noun", () => {
13+
const name = service.generateFunName("postgresql", 5432);
14+
expect(name).toMatch(/^[a-z]+-[a-z]+$/);
15+
});
16+
17+
test("should add port suffix for non-default PostgreSQL port", () => {
18+
const name = service.generateFunName("postgresql", 5433);
19+
expect(name).toMatch(/^[a-z]+-[a-z]+-5433$/);
20+
});
21+
22+
test("should not add port suffix for default PostgreSQL port", () => {
23+
const name = service.generateFunName("postgresql", 5432);
24+
expect(name).not.toContain("-5432");
25+
});
26+
27+
test("should not add port suffix for default MySQL port", () => {
28+
const name = service.generateFunName("mysql", 3306);
29+
expect(name).not.toContain("-3306");
30+
});
31+
32+
test("should not add port suffix for default MariaDB port", () => {
33+
const name = service.generateFunName("mariadb", 3306);
34+
expect(name).not.toContain("-3306");
35+
});
36+
37+
test("should add port suffix for non-default MySQL port", () => {
38+
const name = service.generateFunName("mysql", 3307);
39+
expect(name).toMatch(/^[a-z]+-[a-z]+-3307$/);
40+
});
41+
42+
test("should generate different names on multiple calls", () => {
43+
// Given the randomness, most calls should produce different names
44+
const names = new Set<string>();
45+
for (let i = 0; i < 20; i++) {
46+
names.add(service.generateFunName("postgresql", 5432));
47+
}
48+
// At least some variety expected (not all same)
49+
expect(names.size).toBeGreaterThan(1);
50+
});
51+
});
52+
53+
describe("extractCredentialsFromEnv (via reflection)", () => {
54+
// Access private method via prototype for testing
55+
const extractCredentials = (
56+
svc: DiscoveryService,
57+
dbType: "postgresql" | "mysql" | "mariadb",
58+
envVars: Map<string, string>
59+
) => {
60+
return (svc as any).extractCredentialsFromEnv(dbType, envVars);
61+
};
62+
63+
describe("PostgreSQL", () => {
64+
test("should extract PostgreSQL credentials from env vars", () => {
65+
const envVars = new Map<string, string>([
66+
["POSTGRES_USER", "testuser"],
67+
["POSTGRES_PASSWORD", "testpass"],
68+
["POSTGRES_DB", "testdb"],
69+
]);
70+
71+
const result = extractCredentials(service, "postgresql", envVars);
72+
73+
expect(result.user).toBe("testuser");
74+
expect(result.password).toBe("testpass");
75+
expect(result.database).toBe("testdb");
76+
});
77+
78+
test("should use defaults when PostgreSQL env vars are missing", () => {
79+
const envVars = new Map<string, string>();
80+
81+
const result = extractCredentials(service, "postgresql", envVars);
82+
83+
expect(result.user).toBe("postgres");
84+
expect(result.password).toBe("");
85+
expect(result.database).toBe("postgres");
86+
});
87+
88+
test("should use POSTGRES_USER as database when POSTGRES_DB is missing", () => {
89+
const envVars = new Map<string, string>([
90+
["POSTGRES_USER", "customuser"],
91+
]);
92+
93+
const result = extractCredentials(service, "postgresql", envVars);
94+
95+
expect(result.user).toBe("customuser");
96+
expect(result.database).toBe("customuser");
97+
});
98+
});
99+
100+
describe("MySQL", () => {
101+
test("should extract MySQL credentials with custom user", () => {
102+
const envVars = new Map<string, string>([
103+
["MYSQL_USER", "myuser"],
104+
["MYSQL_PASSWORD", "mypass"],
105+
["MYSQL_DATABASE", "mydb"],
106+
]);
107+
108+
const result = extractCredentials(service, "mysql", envVars);
109+
110+
expect(result.user).toBe("myuser");
111+
expect(result.password).toBe("mypass");
112+
expect(result.database).toBe("mydb");
113+
});
114+
115+
test("should use root password when user is root", () => {
116+
const envVars = new Map<string, string>([
117+
["MYSQL_ROOT_PASSWORD", "rootpass"],
118+
["MYSQL_DATABASE", "mydb"],
119+
]);
120+
121+
const result = extractCredentials(service, "mysql", envVars);
122+
123+
expect(result.user).toBe("root");
124+
expect(result.password).toBe("rootpass");
125+
expect(result.database).toBe("mydb");
126+
});
127+
128+
test("should use defaults when MySQL env vars are missing", () => {
129+
const envVars = new Map<string, string>();
130+
131+
const result = extractCredentials(service, "mysql", envVars);
132+
133+
expect(result.user).toBe("root");
134+
expect(result.password).toBe("");
135+
expect(result.database).toBe("mysql");
136+
});
137+
});
138+
139+
describe("MariaDB", () => {
140+
test("should extract MariaDB credentials with MARIADB_ prefix", () => {
141+
const envVars = new Map<string, string>([
142+
["MARIADB_USER", "mariauser"],
143+
["MARIADB_PASSWORD", "mariapass"],
144+
["MARIADB_DATABASE", "mariadb"],
145+
]);
146+
147+
const result = extractCredentials(service, "mariadb", envVars);
148+
149+
expect(result.user).toBe("mariauser");
150+
expect(result.password).toBe("mariapass");
151+
expect(result.database).toBe("mariadb");
152+
});
153+
154+
test("should fall back to MYSQL_ prefix for MariaDB", () => {
155+
const envVars = new Map<string, string>([
156+
["MYSQL_USER", "fallbackuser"],
157+
["MYSQL_PASSWORD", "fallbackpass"],
158+
["MYSQL_DATABASE", "fallbackdb"],
159+
]);
160+
161+
const result = extractCredentials(service, "mariadb", envVars);
162+
163+
expect(result.user).toBe("fallbackuser");
164+
expect(result.password).toBe("fallbackpass");
165+
expect(result.database).toBe("fallbackdb");
166+
});
167+
168+
test("should use MARIADB_ROOT_PASSWORD for root user", () => {
169+
const envVars = new Map<string, string>([
170+
["MARIADB_ROOT_PASSWORD", "mariarootpass"],
171+
]);
172+
173+
const result = extractCredentials(service, "mariadb", envVars);
174+
175+
expect(result.user).toBe("root");
176+
expect(result.password).toBe("mariarootpass");
177+
});
178+
179+
test("should fall back to MYSQL_ROOT_PASSWORD for root user", () => {
180+
const envVars = new Map<string, string>([
181+
["MYSQL_ROOT_PASSWORD", "mysqlrootpass"],
182+
]);
183+
184+
const result = extractCredentials(service, "mariadb", envVars);
185+
186+
expect(result.user).toBe("root");
187+
expect(result.password).toBe("mysqlrootpass");
188+
});
189+
});
190+
});
191+
192+
describe("getDefaultPort (private)", () => {
193+
const getDefaultPort = (svc: DiscoveryService, type: string) => {
194+
return (svc as any).getDefaultPort(type);
195+
};
196+
197+
test("should return 5432 for postgresql", () => {
198+
expect(getDefaultPort(service, "postgresql")).toBe(5432);
199+
});
200+
201+
test("should return 3306 for mysql", () => {
202+
expect(getDefaultPort(service, "mysql")).toBe(3306);
203+
});
204+
205+
test("should return 3306 for mariadb", () => {
206+
expect(getDefaultPort(service, "mariadb")).toBe(3306);
207+
});
208+
209+
test("should return 0 for unknown type", () => {
210+
expect(getDefaultPort(service, "unknown")).toBe(0);
211+
});
212+
});
213+
214+
describe("getDefaultUser (private)", () => {
215+
const getDefaultUser = (svc: DiscoveryService, type: string) => {
216+
return (svc as any).getDefaultUser(type);
217+
};
218+
219+
test("should return postgres for postgresql", () => {
220+
expect(getDefaultUser(service, "postgresql")).toBe("postgres");
221+
});
222+
223+
test("should return root for mysql", () => {
224+
expect(getDefaultUser(service, "mysql")).toBe("root");
225+
});
226+
227+
test("should return root for mariadb", () => {
228+
expect(getDefaultUser(service, "mariadb")).toBe("root");
229+
});
230+
231+
test("should return empty string for unknown type", () => {
232+
expect(getDefaultUser(service, "unknown")).toBe("");
233+
});
234+
});
235+
236+
describe("getDefaultDatabase (private)", () => {
237+
const getDefaultDatabase = (svc: DiscoveryService, type: string) => {
238+
return (svc as any).getDefaultDatabase(type);
239+
};
240+
241+
test("should return postgres for postgresql", () => {
242+
expect(getDefaultDatabase(service, "postgresql")).toBe("postgres");
243+
});
244+
245+
test("should return mysql for mysql", () => {
246+
expect(getDefaultDatabase(service, "mysql")).toBe("mysql");
247+
});
248+
249+
test("should return mysql for mariadb", () => {
250+
expect(getDefaultDatabase(service, "mariadb")).toBe("mysql");
251+
});
252+
253+
test("should return empty string for unknown type", () => {
254+
expect(getDefaultDatabase(service, "unknown")).toBe("");
255+
});
256+
});
257+
258+
describe("DiscoveredDatabase interface", () => {
259+
test("should have all required properties for local source", () => {
260+
const db: DiscoveredDatabase = {
261+
type: "postgresql",
262+
host: "localhost",
263+
port: 5432,
264+
source: "local",
265+
suggestedName: "test-db",
266+
defaultUser: "postgres",
267+
defaultDatabase: "postgres",
268+
};
269+
270+
expect(db.type).toBe("postgresql");
271+
expect(db.host).toBe("localhost");
272+
expect(db.port).toBe(5432);
273+
expect(db.source).toBe("local");
274+
expect(db.suggestedName).toBe("test-db");
275+
expect(db.defaultUser).toBe("postgres");
276+
expect(db.defaultDatabase).toBe("postgres");
277+
expect(db.containerName).toBeUndefined();
278+
expect(db.defaultPassword).toBeUndefined();
279+
});
280+
281+
test("should accept optional properties for Docker containers", () => {
282+
const db: DiscoveredDatabase = {
283+
type: "mysql",
284+
host: "localhost",
285+
port: 3306,
286+
source: "docker",
287+
containerName: "mysql-container",
288+
suggestedName: "test-mysql",
289+
defaultUser: "root",
290+
defaultDatabase: "mydb",
291+
defaultPassword: "secret123",
292+
};
293+
294+
expect(db.source).toBe("docker");
295+
expect(db.containerName).toBe("mysql-container");
296+
expect(db.defaultPassword).toBe("secret123");
297+
});
298+
299+
test("should accept all database types", () => {
300+
const pgDb: DiscoveredDatabase = {
301+
type: "postgresql",
302+
host: "localhost",
303+
port: 5432,
304+
source: "local",
305+
suggestedName: "pg-db",
306+
defaultUser: "postgres",
307+
defaultDatabase: "postgres",
308+
};
309+
310+
const mysqlDb: DiscoveredDatabase = {
311+
type: "mysql",
312+
host: "localhost",
313+
port: 3306,
314+
source: "local",
315+
suggestedName: "mysql-db",
316+
defaultUser: "root",
317+
defaultDatabase: "mysql",
318+
};
319+
320+
const mariaDb: DiscoveredDatabase = {
321+
type: "mariadb",
322+
host: "localhost",
323+
port: 3306,
324+
source: "docker",
325+
suggestedName: "maria-db",
326+
defaultUser: "root",
327+
defaultDatabase: "mysql",
328+
};
329+
330+
expect(pgDb.type).toBe("postgresql");
331+
expect(mysqlDb.type).toBe("mysql");
332+
expect(mariaDb.type).toBe("mariadb");
333+
});
334+
});
335+
336+
describe("discoverLocalDatabases", () => {
337+
test("should return an array", async () => {
338+
// This test just verifies the method exists and returns an array
339+
// Actual discovery depends on system state
340+
const result = await service.discoverLocalDatabases();
341+
expect(Array.isArray(result)).toBe(true);
342+
});
343+
344+
test("each discovered database should have required fields", async () => {
345+
const result = await service.discoverLocalDatabases();
346+
347+
for (const db of result) {
348+
expect(db.type).toBeDefined();
349+
expect(["postgresql", "mysql", "mariadb"]).toContain(db.type);
350+
expect(db.host).toBeDefined();
351+
expect(typeof db.port).toBe("number");
352+
expect(db.source).toBeDefined();
353+
expect(["local", "docker"]).toContain(db.source);
354+
expect(db.suggestedName).toBeDefined();
355+
expect(db.defaultUser).toBeDefined();
356+
expect(db.defaultDatabase).toBeDefined();
357+
}
358+
});
359+
});
360+
});

bridge/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "db-visualizer-bridge",
3-
"version": "0.1.0",
3+
"version": "0.1.0-beta.5",
44
"type": "commonjs",
55
"main": "dist/index.cjs",
66
"scripts": {

0 commit comments

Comments
 (0)