MarketAlly.AIPlugin.Extensions/MarketAlly.AIPlugin.Tests/Plugins/SecureFileOperationsPluginT...

293 lines
8.0 KiB
C#
Executable File

using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.Extensions.Logging;
using MarketAlly.AIPlugin.Plugins;
using MarketAlly.AIPlugin.Security;
using MarketAlly.AIPlugin.Exceptions;
using Moq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
namespace MarketAlly.AIPlugin.Tests.Plugins
{
[TestClass]
public class SecureFileOperationsPluginTests
{
private SecureFileOperationsPlugin _plugin;
private SecurityConfiguration _securityConfig;
private Mock<ILogger<SecureFileOperationsPlugin>> _mockLogger;
private string _testDirectory;
[TestInitialize]
public void Setup()
{
_testDirectory = Path.Combine(Path.GetTempPath(), "AIPlugin_Tests", Guid.NewGuid().ToString());
Directory.CreateDirectory(_testDirectory);
_securityConfig = new SecurityConfiguration
{
AllowedDirectories = new List<string> { _testDirectory },
AllowedFileExtensions = new List<string> { ".txt", ".json", ".log" },
MaxFileSizeBytes = 1024 * 1024 // 1MB
};
_mockLogger = new Mock<ILogger<SecureFileOperationsPlugin>>();
_plugin = new SecureFileOperationsPlugin(_securityConfig, _mockLogger.Object);
}
[TestCleanup]
public void Cleanup()
{
if (Directory.Exists(_testDirectory))
{
Directory.Delete(_testDirectory, true);
}
}
[TestMethod]
public async Task ExecuteAsync_CreateFile_ValidParameters_Success()
{
// Arrange
var filePath = Path.Combine(_testDirectory, "test.txt");
var parameters = new Dictionary<string, object>
{
["operation"] = "create",
["filePath"] = filePath,
["content"] = "Test content",
["overwrite"] = false
};
// Act
var result = await _plugin.ExecuteAsync(parameters);
// Assert
Assert.IsTrue(result.Success);
Assert.IsTrue(File.Exists(filePath));
Assert.AreEqual("Test content", File.ReadAllText(filePath));
}
[TestMethod]
public async Task ExecuteAsync_CreateFile_PathTraversal_SecurityException()
{
// Arrange
var maliciousPath = Path.Combine(_testDirectory, "..", "..", "malicious.txt");
var parameters = new Dictionary<string, object>
{
["operation"] = "create",
["filePath"] = maliciousPath,
["content"] = "Malicious content"
};
// Act
var result = await _plugin.ExecuteAsync(parameters);
// Assert
Assert.IsFalse(result.Success);
Assert.IsInstanceOfType(result.Error, typeof(SecurityValidationException));
}
[TestMethod]
public async Task ExecuteAsync_CreateFile_DisallowedExtension_SecurityException()
{
// Arrange
var executablePath = Path.Combine(_testDirectory, "malware.exe");
var parameters = new Dictionary<string, object>
{
["operation"] = "create",
["filePath"] = executablePath,
["content"] = "Executable content"
};
// Act
var result = await _plugin.ExecuteAsync(parameters);
// Assert
Assert.IsFalse(result.Success);
Assert.IsInstanceOfType(result.Error, typeof(SecurityValidationException));
}
[TestMethod]
public async Task ExecuteAsync_CreateFile_ContentTooLarge_SecurityException()
{
// Arrange
var filePath = Path.Combine(_testDirectory, "large.txt");
var largeContent = new string('A', (int)(_securityConfig.MaxFileSizeBytes + 1));
var parameters = new Dictionary<string, object>
{
["operation"] = "create",
["filePath"] = filePath,
["content"] = largeContent
};
// Act
var result = await _plugin.ExecuteAsync(parameters);
// Assert
Assert.IsFalse(result.Success);
Assert.IsInstanceOfType(result.Error, typeof(SecurityValidationException));
}
[TestMethod]
public async Task ExecuteAsync_UpdateFile_FileExists_Success()
{
// Arrange
var filePath = Path.Combine(_testDirectory, "update.txt");
File.WriteAllText(filePath, "Original content");
var parameters = new Dictionary<string, object>
{
["operation"] = "update",
["filePath"] = filePath,
["content"] = "Updated content"
};
// Act
var result = await _plugin.ExecuteAsync(parameters);
// Assert
Assert.IsTrue(result.Success);
Assert.AreEqual("Updated content", File.ReadAllText(filePath));
}
[TestMethod]
public async Task ExecuteAsync_UpdateFile_FileNotExists_FileNotFoundException()
{
// Arrange
var filePath = Path.Combine(_testDirectory, "nonexistent.txt");
var parameters = new Dictionary<string, object>
{
["operation"] = "update",
["filePath"] = filePath,
["content"] = "Content"
};
// Act
var result = await _plugin.ExecuteAsync(parameters);
// Assert
Assert.IsFalse(result.Success);
Assert.IsInstanceOfType(result.Error, typeof(FileNotFoundException));
}
[TestMethod]
public async Task ExecuteAsync_DeleteFile_FileExists_Success()
{
// Arrange
var filePath = Path.Combine(_testDirectory, "delete.txt");
File.WriteAllText(filePath, "Content to delete");
var parameters = new Dictionary<string, object>
{
["operation"] = "delete",
["filePath"] = filePath
};
// Act
var result = await _plugin.ExecuteAsync(parameters);
// Assert
Assert.IsTrue(result.Success);
Assert.IsFalse(File.Exists(filePath));
}
[TestMethod]
public async Task ExecuteAsync_InvalidOperation_ArgumentException()
{
// Arrange
var parameters = new Dictionary<string, object>
{
["operation"] = "invalid",
["filePath"] = Path.Combine(_testDirectory, "test.txt")
};
// Act
var result = await _plugin.ExecuteAsync(parameters);
// Assert
Assert.IsFalse(result.Success);
Assert.IsInstanceOfType(result.Error, typeof(ArgumentException));
}
[TestMethod]
public async Task ExecuteAsync_MissingRequiredParameter_ParameterValidationException()
{
// Arrange
var parameters = new Dictionary<string, object>
{
["filePath"] = Path.Combine(_testDirectory, "test.txt")
// Missing "operation" parameter
};
// Act
var result = await _plugin.ExecuteAsync(parameters);
// Assert
Assert.IsFalse(result.Success);
Assert.IsInstanceOfType(result.Error, typeof(ParameterValidationException));
}
[TestMethod]
public async Task ExecuteAsync_CreateFileWithBackup_BackupCreated()
{
// Arrange
var filePath = Path.Combine(_testDirectory, "backup_test.txt");
File.WriteAllText(filePath, "Original content");
var parameters = new Dictionary<string, object>
{
["operation"] = "update",
["filePath"] = filePath,
["content"] = "New content",
["makeBackup"] = true
};
// Act
var result = await _plugin.ExecuteAsync(parameters);
// Assert
Assert.IsTrue(result.Success);
Assert.AreEqual("New content", File.ReadAllText(filePath));
// Check that backup was created
var backupFiles = Directory.GetFiles(_testDirectory, "backup_test*.bak*");
Assert.IsTrue(backupFiles.Length > 0);
}
[TestMethod]
public async Task ExecuteAsync_CreateDirectories_DirectoryCreated()
{
// Arrange
var subDirectory = Path.Combine(_testDirectory, "subdir");
var filePath = Path.Combine(subDirectory, "test.txt");
var parameters = new Dictionary<string, object>
{
["operation"] = "create",
["filePath"] = filePath,
["content"] = "Test content",
["createDirectories"] = true
};
// Act
var result = await _plugin.ExecuteAsync(parameters);
// Assert
if (!result.Success)
{
// Log detailed error information for debugging
Console.WriteLine($"Plugin execution failed: {result.Message}");
Console.WriteLine($"Error type: {result.Error?.GetType().Name}");
Console.WriteLine($"Error details: {result.Error?.Message}");
Console.WriteLine($"Test directory: {_testDirectory}");
Console.WriteLine($"Sub directory: {subDirectory}");
Console.WriteLine($"File path: {filePath}");
Console.WriteLine($"Allowed directories: {string.Join(", ", _securityConfig.AllowedDirectories)}");
}
Assert.IsTrue(result.Success, $"Plugin execution failed: {result.Message} (Error: {result.Error?.Message})");
Assert.IsTrue(Directory.Exists(subDirectory), "Subdirectory was not created");
Assert.IsTrue(File.Exists(filePath), "File was not created in subdirectory");
}
}
}