n8n-bookstack-agent-tool
Version:
Comprehensive BookStack API integration tool for n8n AI Agent with MCP framework compatibility
210 lines ⢠10.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.N8nIntegrationTester = void 0;
const index_js_1 = require("../index.js");
const mcp_commands_js_1 = require("../commands/mcp-commands.js");
const gui_config_js_1 = require("../auth/gui-config.js");
class N8nIntegrationTester {
constructor() {
this.config = {
baseUrl: 'https://wiki.l7cloud.io',
authType: 'bearer',
token: 'EnRkbVwqzNSyLaVo7olU8Wx8umGznKuE',
tokenSecret: 'TyaJ0JHAenwRIgScmsffrCeSIlon4fZ2',
timeout: 30000,
retryAttempts: 3,
retryDelay: 1000
};
this.tool = new index_js_1.BookStackN8nTool(this.config);
}
async runN8nIntegrationTests() {
console.log('\nš§ N8N INTEGRATION TESTS');
console.log('========================');
await this.testMCPCommandRegistration();
await this.testGuiConfiguration();
await this.testAgentCommandDiscovery();
await this.testExecCommandInterface();
await this.testPolicyDrivenUsage();
console.log('\nā
N8n integration tests completed');
}
async testMCPCommandRegistration() {
console.log('\nš Testing MCP Command Registration...');
try {
console.log(' Testing command registry initialization...');
mcp_commands_js_1.MCPCommandRegistry.initialize();
const commands = mcp_commands_js_1.MCPCommandRegistry.getCommands();
console.log(` ā
Command registry: ${commands.length} commands registered`);
let validCommands = 0;
for (const command of commands) {
const hasName = typeof command.name === 'string' && command.name.length > 0;
const hasDescription = typeof command.description === 'string';
const hasInputSchema = command.inputSchema && typeof command.inputSchema === 'object';
if (hasName && hasDescription && hasInputSchema) {
validCommands++;
}
}
console.log(` ā
Valid command structures: ${validCommands}/${commands.length} (${(validCommands / commands.length * 100).toFixed(1)}%)`);
const bookCommands = commands.filter((cmd) => cmd.name.toLowerCase().includes('book'));
const pageCommands = commands.filter((cmd) => cmd.name.toLowerCase().includes('page'));
const chapterCommands = commands.filter((cmd) => cmd.name.toLowerCase().includes('chapter'));
console.log(` ā
Book commands: ${bookCommands.length}`);
console.log(` ā
Page commands: ${pageCommands.length}`);
console.log(` ā
Chapter commands: ${chapterCommands.length}`);
}
catch (error) {
console.log(` ā MCP command registration failed: ${error.message}`);
}
}
async testGuiConfiguration() {
console.log('\nš„ļø Testing GUI Configuration...');
try {
console.log(' Testing GUI config form generation...');
const configForm = gui_config_js_1.N8nConfigGenerator.generateBookStackConfig();
const hasFields = Array.isArray(configForm) && configForm.length > 0;
console.log(` ā
Config form fields: ${hasFields ? configForm.length : 0}`);
if (hasFields) {
const requiredFields = ['baseUrl', 'authType', 'token'];
let foundFields = 0;
for (const field of requiredFields) {
const fieldExists = configForm.some((f) => f.name === field);
if (fieldExists) {
foundFields++;
console.log(` ā
${field}: Present`);
}
else {
console.log(` ā ${field}: Missing`);
}
}
console.log(` š Required fields: ${foundFields}/${requiredFields.length} (${(foundFields / requiredFields.length * 100).toFixed(1)}%)`);
}
console.log(' Testing form validation...');
const configSchema = gui_config_js_1.N8nConfigGenerator.generateConfigSchema();
const hasValidSchema = configSchema && typeof configSchema === 'object';
console.log(` ā
Config schema generation: ${hasValidSchema ? 'Passed' : 'Failed'}`);
}
catch (error) {
console.log(` ā GUI configuration test failed: ${error.message}`);
}
}
async testAgentCommandDiscovery() {
console.log('\nš Testing Agent Command Discovery...');
try {
console.log(' Testing command introspection...');
const availableCommands = this.tool.getAvailableCommands();
console.log(` ā
Available commands: ${availableCommands.length}`);
let commandsWithMetadata = 0;
for (const command of availableCommands) {
const hasDescription = command.description && command.description.length > 0;
const hasParameters = command.parameters && typeof command.parameters === 'object';
if (hasDescription && hasParameters) {
commandsWithMetadata++;
}
}
console.log(` ā
Commands with metadata: ${commandsWithMetadata}/${availableCommands.length} (${(commandsWithMetadata / availableCommands.length * 100).toFixed(1)}%)`);
const resourceCategories = ['books', 'pages', 'chapters', 'shelves', 'users', 'roles', 'attachments', 'tags'];
let categoriesFound = 0;
for (const category of resourceCategories) {
const categoryCommands = availableCommands.filter((cmd) => cmd.name.toLowerCase().includes(category.slice(0, -1)) // Remove 's' for singular
);
if (categoryCommands.length > 0) {
categoriesFound++;
console.log(` ā
${category}: ${categoryCommands.length} commands`);
}
else {
console.log(` ā ${category}: No commands found`);
}
}
console.log(` š Resource categories: ${categoriesFound}/${resourceCategories.length} (${(categoriesFound / resourceCategories.length * 100).toFixed(1)}%)`);
}
catch (error) {
console.log(` ā Agent command discovery failed: ${error.message}`);
}
}
async testExecCommandInterface() {
console.log('\nā” Testing execCommand Interface...');
try {
console.log(' Testing execCommand with valid parameters...');
const result = await this.tool.execCommand('listBooks', { count: 1 });
const isValidResult = result && (typeof result === 'object' || Array.isArray(result));
console.log(` ā
execCommand result: ${isValidResult ? 'Valid' : 'Invalid'}`);
if (isValidResult) {
console.log(` ā
Result type: ${Array.isArray(result) ? 'Array' : 'Object'}`);
if (Array.isArray(result)) {
console.log(` ā
Result length: ${result.length}`);
}
}
}
catch (error) {
console.log(` ā execCommand test failed: ${error.message}`);
}
try {
console.log(' Testing execCommand with invalid command...');
await this.tool.execCommand('invalidCommand', {});
console.log(` ā ļø Invalid command: No error thrown`);
}
catch (error) {
console.log(` ā
Invalid command handling: Properly rejected`);
}
try {
console.log(' Testing execCommand with missing parameters...');
await this.tool.execCommand('createBook', {}); // Missing required 'name' parameter
console.log(` ā ļø Missing parameters: No error thrown`);
}
catch (error) {
console.log(` ā
Missing parameters handling: Properly rejected`);
}
}
async testPolicyDrivenUsage() {
console.log('\nš Testing Policy-Driven Usage...');
try {
console.log(' Testing command execution policies...');
const readOnlyCommands = ['listBooks', 'getBook', 'listPages', 'listChapters'];
let readOnlySuccess = 0;
for (const command of readOnlyCommands) {
try {
await this.tool.execCommand(command, command === 'getBook' ? { id: 4 } : {});
readOnlySuccess++;
console.log(` ā
${command}: Allowed`);
}
catch (error) {
console.log(` ā ${command}: Blocked - ${error.message}`);
}
}
console.log(` š Read-only operations: ${readOnlySuccess}/${readOnlyCommands.length} (${(readOnlySuccess / readOnlyCommands.length * 100).toFixed(1)}%)`);
console.log(' Testing write operation policies...');
const writeCommands = ['createBook', 'updateBook', 'deleteBook'];
let writeAttempts = 0;
let writeBlocked = 0;
for (const command of writeCommands) {
writeAttempts++;
try {
const params = command === 'createBook' ? { name: 'Test Policy Book' } :
command === 'updateBook' ? { id: 999999, name: 'Updated' } :
{ id: 999999 };
await this.tool.execCommand(command, params);
console.log(` ā ļø ${command}: Allowed (unexpected)`);
}
catch (error) {
writeBlocked++;
const errorMessage = error.message;
if (errorMessage.includes('403') || errorMessage.includes('permission') || errorMessage.includes('not found')) {
console.log(` ā
${command}: Properly restricted`);
}
else {
console.log(` ā ${command}: Unexpected error - ${errorMessage}`);
}
}
}
console.log(` š Write operations: ${writeBlocked}/${writeAttempts} properly restricted (${(writeBlocked / writeAttempts * 100).toFixed(1)}%)`);
}
catch (error) {
console.log(` ā Policy-driven usage test failed: ${error.message}`);
}
}
}
exports.N8nIntegrationTester = N8nIntegrationTester;
if (require.main === module) {
const tester = new N8nIntegrationTester();
tester.runN8nIntegrationTests().catch(console.error);
}
//# sourceMappingURL=n8n-integration-test.js.map