Skip to content

Commit 9a0dcf2

Browse files
committed
Refactor database plugin core and add comprehensive test suite
- Updated base plugin structure to use functional approach - Added plugin test suite for consistent testing across database plugins - Simplified plugin creation with standardized configuration - Updated Vitest to latest version and configured test configuration - Added test helpers and mock generators for database plugins
1 parent eb7e47f commit 9a0dcf2

File tree

15 files changed

+215
-38
lines changed

15 files changed

+215
-38
lines changed

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@
8282
"tsup": "^8.0.1",
8383
"tsx": "^4.7.0",
8484
"typescript": "^5.3.3",
85-
"vitest": "^1.1.0"
85+
"vitest": "^1.6.1"
8686
},
8787
"peerDependencies": {
8888
"react": "^18.2.0"
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { describe, it, expect } from 'vitest';
2+
import { DatabasePluginConfig, DatabaseAnswers } from '../types';
3+
import { createDatabasePlugin } from '../base-plugin';
4+
5+
describe('Base Database Plugin', () => {
6+
const mockConfig = {
7+
name: 'TestDB',
8+
defaultPort: 1234,
9+
containerName: 'test-container',
10+
volumePath: '/data/test'
11+
};
12+
13+
it('should create a plugin with basic configuration', () => {
14+
const plugin = createDatabasePlugin(mockConfig);
15+
expect(plugin).toBeDefined();
16+
expect(plugin.name).toBe('TestDB');
17+
expect(plugin.getDefaultPort()).toBe(1234);
18+
});
19+
20+
it('should validate required config properties', () => {
21+
const plugin = createDatabasePlugin(mockConfig);
22+
const answers = {
23+
database: 'test_db',
24+
username: 'test_user',
25+
password: 'test_pass',
26+
port: '1234'
27+
};
28+
expect(plugin.validateConfig(answers)).toBe(true);
29+
});
30+
31+
it('should handle template variables', () => {
32+
const plugin = createDatabasePlugin(mockConfig);
33+
const config = {
34+
database: 'test_db',
35+
username: 'test_user',
36+
password: 'test_pass',
37+
port: '1234'
38+
};
39+
const variables = plugin.getTemplateVariables(config);
40+
expect(variables).toHaveProperty('database', 'test_db');
41+
});
42+
43+
it('should validate connection string format', () => {
44+
const plugin = createDatabasePlugin(mockConfig);
45+
expect(plugin.validateConnectionString('invalid')).toBe(false);
46+
});
47+
});
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { describe, it, expect } from 'vitest';
2+
3+
export function createPluginTestSuite(pluginName: string, plugin: any) {
4+
describe(`Database Plugin: ${pluginName}`, () => {
5+
// Structure Tests
6+
it('should have required plugin structure', () => {
7+
expect(plugin).toBeDefined();
8+
expect(plugin.name).toBeDefined();
9+
expect(typeof plugin.getTemplateVariables).toBe('function');
10+
expect(typeof plugin.validateConfig).toBe('function');
11+
});
12+
13+
// Configuration Tests
14+
it('should have valid default configuration', () => {
15+
expect(plugin.defaultPort).toBeGreaterThan(0);
16+
expect(plugin.containerName).toBeDefined();
17+
expect(plugin.volumePath).toBeDefined();
18+
});
19+
20+
it('should generate valid template variables', () => {
21+
const config = {
22+
database: 'test_db',
23+
username: 'test_user',
24+
password: 'test_pass',
25+
port: plugin.defaultPort
26+
};
27+
28+
const variables = plugin.getTemplateVariables(config);
29+
expect(variables).toHaveProperty('database', 'test_db');
30+
expect(variables).toHaveProperty('username', 'test_user');
31+
expect(variables).toHaveProperty('password', 'test_pass');
32+
expect(variables).toHaveProperty('port', plugin.defaultPort);
33+
});
34+
35+
it('should properly validate configurations', () => {
36+
const validConfig = {
37+
database: 'test_db',
38+
username: 'test_user',
39+
password: 'test_pass',
40+
port: '5432'
41+
};
42+
43+
const invalidConfig = {
44+
database: 'test_db',
45+
// missing username and password
46+
port: '5432'
47+
};
48+
49+
expect(plugin.validateConfig(validConfig)).toBe(true);
50+
expect(plugin.validateConfig(invalidConfig)).toBe(false);
51+
});
52+
});
53+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { DatabasePluginConfig, DatabaseAnswers } from '../types';
2+
3+
export function createMockAnswers(overrides: Partial<DatabaseAnswers> = {}): DatabaseAnswers {
4+
return {
5+
database: 'test_db',
6+
username: 'test_user',
7+
password: 'test_password',
8+
port: '3306',
9+
...overrides
10+
};
11+
}
12+
13+
export function validatePluginStructure(plugin: any) {
14+
expect(plugin).toHaveProperty('name');
15+
expect(plugin).toHaveProperty('getDefaultPort');
16+
expect(plugin).toHaveProperty('validateConfig');
17+
expect(plugin).toHaveProperty('validateConnectionString');
18+
expect(plugin).toHaveProperty('getTemplateVariables');
19+
}

src/plugins/databases/core/base-plugin.ts

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@ import { generateSecurePassword } from '../../../utils/passwords';
33
import { getDockerImageVersions } from '../../../utils/docker-versions';
44

55
export interface DatabasePlugin {
6-
config: DatabasePluginConfig;
7-
getQuestions: () => Promise<Question[]>;
8-
processAnswers: (answers: Record<string, any>) => DatabaseAnswers;
9-
getTemplateVariables: (answers: DatabaseAnswers) => Record<string, any>;
10-
validate: (answers: DatabaseAnswers) => boolean;
11-
validateField: (field: string, value: any) => boolean;
6+
name: string;
7+
defaultPort: number;
8+
containerName: string;
9+
volumePath: string;
10+
getDefaultPort(): number;
11+
validateConfig(answers: any): boolean;
12+
validateConnectionString(connectionString: string): boolean;
13+
getTemplateVariables(config: any): Record<string, any>;
1214
}
1315

1416
export function createDatabasePlugin(config: DatabasePluginConfig): DatabasePlugin {
@@ -157,11 +159,34 @@ export function createDatabasePlugin(config: DatabasePluginConfig): DatabasePlug
157159
}
158160

159161
return {
160-
config,
161-
getQuestions,
162-
processAnswers,
163-
getTemplateVariables,
164-
validate,
165-
validateField
162+
name: config.name,
163+
defaultPort: config.defaultPort,
164+
containerName: config.containerName,
165+
volumePath: config.volumePath,
166+
167+
getDefaultPort() {
168+
return this.defaultPort;
169+
},
170+
171+
validateConfig(answers: any) {
172+
const requiredFields = ['database', 'username', 'password', 'port'];
173+
return requiredFields.every(field => answers[field]);
174+
},
175+
176+
validateConnectionString(connectionString: string) {
177+
// Basic connection string validation
178+
// Should match format: protocol://username:password@hostname:port/database
179+
const connectionStringPattern = /^[a-zA-Z]+:\/\/[^:]+:[^@]+@[^:]+:\d+\/\w+$/;
180+
return connectionStringPattern.test(connectionString);
181+
},
182+
183+
getTemplateVariables(config: any) {
184+
return {
185+
port: config.port || this.defaultPort,
186+
database: config.database,
187+
username: config.username,
188+
password: config.password
189+
};
190+
}
166191
};
167192
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { describe } from 'vitest';
2+
import plugin from '../index';
3+
import { createPluginTestSuite } from '../../core/__tests__/plugin-test-suite';
4+
5+
createPluginTestSuite('MariaDB', plugin);
Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import { createDatabasePlugin } from '../core/base-plugin';
2-
import { config } from './config';
3-
import { getTemplateVariables } from './template-variables';
42

5-
const plugin = createDatabasePlugin(config);
6-
7-
plugin.getTemplateVariables = getTemplateVariables;
8-
9-
export default plugin;
3+
export default createDatabasePlugin({
4+
name: 'MariaDB',
5+
defaultPort: 3306,
6+
containerName: 'mariadb',
7+
volumePath: '/var/lib/mysql'
8+
});
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { describe } from 'vitest';
2+
import plugin from '../index';
3+
import { createPluginTestSuite } from '../../core/__tests__/plugin-test-suite';
4+
5+
createPluginTestSuite('MySQL', plugin);

src/plugins/databases/mysql/index.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,24 @@
11
import { createDatabasePlugin } from '../core/base-plugin';
22
import { config } from './config';
3-
import { getTemplateVariables } from './template-variables';
43

5-
const plugin = createDatabasePlugin(config);
4+
function getTemplateVariables(config: any) {
5+
return {
6+
port: config.port || this.defaultPort,
7+
database: config.database,
8+
username: config.username,
9+
password: config.password,
10+
rootPassword: config.rootPassword || config.password
11+
};
12+
}
613

14+
const plugin = createDatabasePlugin({
15+
name: 'MySQL',
16+
defaultPort: 3306,
17+
containerName: 'mysql',
18+
volumePath: '/var/lib/mysql'
19+
});
20+
21+
// Override the template variables method
722
plugin.getTemplateVariables = getTemplateVariables;
823

924
export default plugin;

0 commit comments

Comments
 (0)