293 lines
8.0 KiB
C#
Executable File
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");
|
|
}
|
|
}
|
|
} |