Skip to main content
Glama
s3.test.ts10.3 kB
import { Readable } from "node:stream"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { S3Resource } from "../../src/resources/s3"; import { createMockBuckets, createMockObjects } from "../mocks/s3Client.mock"; // Mock pdf-parse module vi.mock("pdf-parse", () => { return { default: vi.fn().mockResolvedValue({ text: "Extracted PDF text content", numpages: 1, info: { Title: "Test PDF" }, metadata: {}, version: "1.0", }), }; }); // Create a mock implementation of S3Client const mockSend = vi.fn(); vi.mock("@aws-sdk/client-s3", async () => { const actual = await vi.importActual("@aws-sdk/client-s3"); return { ...actual, S3Client: vi.fn().mockImplementation(() => ({ send: mockSend, })), }; }); // Skip MinIO setup/teardown for unit tests vi.mock("../helpers/minio-setup", () => ({ setupTestBucket: vi.fn().mockResolvedValue({}), cleanupTestBucket: vi.fn().mockResolvedValue({}), uploadTestFile: vi.fn().mockResolvedValue({}), uploadTestPdf: vi.fn().mockResolvedValue({}), setupTestFiles: vi.fn().mockResolvedValue({}), })); describe("S3Resource from resources directory", () => { let s3Resource: S3Resource; beforeEach(() => { // Reset mocks vi.clearAllMocks(); mockSend.mockReset(); // Mock environment variables vi.stubEnv("S3_BUCKETS", "test-bucket-1,test-bucket-2"); vi.stubEnv("AWS_REGION", "us-east-1"); vi.stubEnv("AWS_ENDPOINT", "http://localhost:9000"); vi.stubEnv("AWS_ACCESS_KEY_ID", "minioadmin"); vi.stubEnv("AWS_SECRET_ACCESS_KEY", "minioadmin"); vi.stubEnv("AWS_S3_FORCE_PATH_STYLE", "true"); // Create S3Resource instance s3Resource = new S3Resource(); }); afterEach(() => { vi.unstubAllEnvs(); }); describe("listBuckets", () => { it("should return a list of buckets", async () => { // Setup mock data const mockBuckets = createMockBuckets(3); // Mock successful response mockSend.mockResolvedValueOnce({ Buckets: mockBuckets }); // Execute the method being tested const result = await s3Resource.listBuckets(); // Assertions expect(result).toHaveLength(2); // Should only return configured buckets expect(result[0].Name).toBe("test-bucket-1"); expect(result[1].Name).toBe("test-bucket-2"); }); it("should limit buckets to the max allowed", async () => { // Mock environment variable vi.stubEnv("S3_MAX_BUCKETS", "1"); s3Resource = new S3Resource(); // Setup mock data const mockBuckets = createMockBuckets(3); // Mock successful response mockSend.mockResolvedValueOnce({ Buckets: mockBuckets }); // Execute the method being tested const result = await s3Resource.listBuckets(); // Assertions expect(result).toHaveLength(1); }); it("should handle errors when listing buckets", async () => { // Mock a failure mockSend.mockRejectedValueOnce(new Error("Network error")); // Execute the method and verify error handling await expect(s3Resource.listBuckets()).rejects.toThrow("Network error"); }); }); describe("listObjects", () => { it("should return objects from a bucket", async () => { // Setup mock data const mockObjects = createMockObjects(5); // Mock successful response mockSend.mockResolvedValueOnce({ Contents: mockObjects }); // Execute the method being tested const result = await s3Resource.listObjects("test-bucket-1"); // Assertions expect(result).toHaveLength(5); expect(result[0].Key).toBe("test-file-1.txt"); }); it("should throw error if bucket is not in allowed list", async () => { // Execute the method being tested with an unauthorized bucket const testPromise = s3Resource.listObjects("unauthorized-bucket"); // Assertions await expect(testPromise).rejects.toThrow(); }); it("should filter objects based on prefix", async () => { // Setup mock data const mockObjects = [ { Key: "folder1/file1.txt" }, { Key: "folder1/file2.txt" }, { Key: "folder2/file3.txt" }, ]; // Mock successful response mockSend.mockResolvedValueOnce({ Contents: mockObjects }); // Execute the method with a prefix const result = await s3Resource.listObjects("test-bucket-1", "folder1/"); // Verify the correct prefix was used in the command expect(mockSend).toHaveBeenCalledWith( expect.objectContaining({ input: expect.objectContaining({ Bucket: "test-bucket-1", Prefix: "folder1/", }), }), ); // Assertions expect(result).toEqual(mockObjects); }); }); describe("getObject", () => { it("should retrieve a text object from a bucket", async () => { // Mock text content const textContent = "Hello, World!"; // Mock successful response mockSend.mockResolvedValueOnce({ ContentType: "text/plain", Body: Readable.from([Buffer.from(textContent)]), }); // Execute the method being tested const result = await s3Resource.getObject("test-bucket-1", "test.txt"); // Assertions expect(result.contentType).toBe("text/plain"); expect(result.data).toBe(textContent); }); it("should retrieve a binary object from a bucket", async () => { // Mock binary content const binaryContent = Buffer.from([0x01, 0x02, 0x03, 0x04]); // Mock successful response mockSend.mockResolvedValueOnce({ ContentType: "application/octet-stream", Body: Readable.from([binaryContent]), }); // Execute the method being tested const result = await s3Resource.getObject("test-bucket-1", "test.bin"); // Assertions expect(result.contentType).toBe("application/octet-stream"); expect(Buffer.isBuffer(result.data)).toBe(true); expect(result.data).toEqual(binaryContent); }); it("should throw error if bucket is not in allowed list", async () => { // Execute the method being tested with an unauthorized bucket const testPromise = s3Resource.getObject("unauthorized-bucket", "test.txt"); // Assertions await expect(testPromise).rejects.toThrow(); }); it("should handle non-readable body response", async () => { // Mock an invalid response with a non-readable body mockSend.mockResolvedValueOnce({ ContentType: "text/plain", Body: "not a readable stream", }); // Execute the method and expect it to throw await expect(s3Resource.getObject("test-bucket-1", "test.txt")).rejects.toThrow( "Unexpected response body type", ); }); }); describe("isTextFile", () => { it("should identify text files based on extension", () => { // Test various file extensions expect(s3Resource.isTextFile("file.txt")).toBe(true); expect(s3Resource.isTextFile("file.json")).toBe(true); expect(s3Resource.isTextFile("file.html")).toBe(true); expect(s3Resource.isTextFile("file.jpg")).toBe(false); expect(s3Resource.isTextFile("file.png")).toBe(false); expect(s3Resource.isTextFile("file.zip")).toBe(false); }); it("should identify text files based on content type", () => { // Test various content types expect(s3Resource.isTextFile("file", "text/plain")).toBe(true); expect(s3Resource.isTextFile("file", "application/json")).toBe(true); expect(s3Resource.isTextFile("file", "application/xml")).toBe(true); expect(s3Resource.isTextFile("file", "image/jpeg")).toBe(false); expect(s3Resource.isTextFile("file", "application/octet-stream")).toBe(false); }); }); describe("isPdfFile", () => { it("should identify PDF files based on extension", () => { // Test various file extensions expect(s3Resource.isPdfFile("file.pdf")).toBe(true); expect(s3Resource.isPdfFile("file.PDF")).toBe(true); expect(s3Resource.isPdfFile("file.txt")).toBe(false); expect(s3Resource.isPdfFile("file.jpg")).toBe(false); }); it("should identify PDF files based on content type", () => { // Test various content types expect(s3Resource.isPdfFile("file", "application/pdf")).toBe(true); expect(s3Resource.isPdfFile("file", "text/plain")).toBe(false); expect(s3Resource.isPdfFile("file", "image/jpeg")).toBe(false); }); }); describe("convertPdfToText", () => { it("should convert PDF buffer to text", async () => { // Create a mock PDF buffer const pdfBuffer = Buffer.from("mock pdf content"); // Execute the method const result = await s3Resource.convertPdfToText(pdfBuffer); // Assertion expect(result).toBe("Extracted PDF text content"); }); it("should handle errors during PDF conversion", async () => { // Import the actual pdf-parse module to mock it for this specific test const pdfParse = await import("pdf-parse"); // Mock the pdf-parse implementation to throw an error vi.spyOn(pdfParse, "default").mockImplementationOnce(() => { throw new Error("PDF parsing error"); }); // Create a mock PDF buffer const pdfBuffer = Buffer.from("corrupt pdf content"); // Execute the method const result = await s3Resource.convertPdfToText(pdfBuffer); // Assertion - should return error message expect(result).toBe("Error: Could not extract text from PDF file."); }); }); describe("getObject with PDF", () => { it("should extract text from PDF files", async () => { // Create a mock PDF buffer const pdfBuffer = Buffer.from("mock pdf content"); // Mock successful response for a PDF file mockSend.mockResolvedValueOnce({ ContentType: "application/pdf", Body: Readable.from([pdfBuffer]), }); // Execute the method const result = await s3Resource.getObject("test-bucket-1", "document.pdf"); // Assertions expect(result.contentType).toBe("application/pdf"); expect(result.data).toBe("Extracted PDF text content"); expect(typeof result.data).toBe("string"); }); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/samuraikun/aws-s3-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server