Skip to content

Conversation

@joehan
Copy link
Contributor

@joehan joehan commented Nov 26, 2025

Description

Going through my usual exercise of trying out new AI by having it write unit tests - this time, AGY wrote tests for the file uploader used for hosting deploy.

This is part of a larger effort to increase the test coverage for this repo.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @joehan, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a new unit test file for the uploader.ts module, which is a critical component for handling file uploads during hosting deployments. The primary goal is to enhance test coverage by validating the Uploader's core functionalities, such as initialization, file hashing, and the process of populating file versions. The tests were generated with the assistance of an AI, contributing to a broader initiative to improve the repository's overall test coverage.

Highlights

  • New Unit Test File: A new unit test file, uploader.spec.ts, has been added to test the Uploader class responsible for hosting deployments.
  • Uploader Initialization Test: The new test suite includes a test case to ensure the Uploader class initializes correctly with provided configuration.
  • File Hashing and Population Logic: Comprehensive tests have been added to verify the Uploader's functionality for hashing files and populating file versions, including interactions with the Client API and file system operations.
  • Testing Frameworks: The tests utilize chai for assertions and sinon for robust mocking of dependencies like fs, zlib, and the internal Client.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds unit tests for the Uploader class, which is a great step towards increasing test coverage. The tests cover the initialization and the main file processing logic, including hashing, populating, and uploading. My review includes a few suggestions to improve the test code's quality and maintainability, such as improving typings in the mock queue, removing unused code, and refactoring duplicated logic in the stream mocks. Overall, this is a solid contribution.

Comment on lines +13 to +32
class MockQueue {
public handler: any;
private promises: Promise<void>[] = [];
constructor(options: any) {
this.handler = options.handler;
}
add(item: any) {
const p = Promise.resolve(this.handler(item));
this.promises.push(p);
}
process() { }
async wait() {
await Promise.all(this.promises);
return Promise.resolve();
}
close() { }
stats() {
return { total: 0, complete: 0, cursor: 0 };
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The MockQueue class uses any in its constructor and methods. It could be made more type-safe by using generics, similar to the actual Queue implementation it's mocking. This would improve the robustness and readability of the test setup. After applying this change, you'll also need to update the instantiation of MockQueue to provide the generic type, for example: new MockQueue<string>({ ... }).

Suggested change
class MockQueue {
public handler: any;
private promises: Promise<void>[] = [];
constructor(options: any) {
this.handler = options.handler;
}
add(item: any) {
const p = Promise.resolve(this.handler(item));
this.promises.push(p);
}
process() { }
async wait() {
await Promise.all(this.promises);
return Promise.resolve();
}
close() { }
stats() {
return { total: 0, complete: 0, cursor: 0 };
}
}
class MockQueue<T> {
public handler: (item: T) => Promise<void>;
private promises: Promise<void>[] = [];
constructor(options: { handler: (item: T) => Promise<void> }) {
this.handler = options.handler;
}
add(item: T) {
const p = Promise.resolve(this.handler(item));
this.promises.push(p);
}
process() { }
async wait() {
await Promise.all(this.promises);
return Promise.resolve();
}
close() { }
stats() {
return { total: 0, complete: 0, cursor: 0 };
}
}

(uploader as any).uploadQueue = new MockQueue({ handler: (uploader as any).uploadHandler.bind(uploader) });

(fs.statSync as sinon.SinonStub).returns({ mtime: new Date(), size: 100 });
const { PassThrough, Readable } = require("stream");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

For consistency with other imports and better code organization, please use an import statement at the top of the file instead of require() within the test. You can remove this line and add import { PassThrough, Readable } from "stream"; to the top of the file.

Comment on lines +72 to +106
// Mock stream for file1.txt
const mockStream1 = new Readable({
read() {
this.push(Buffer.from("hash1"));
this.push(null);
},
});
// Mock stream for file2.txt
const mockStream2 = new Readable({
read() {
this.push(Buffer.from("hash2"));
this.push(null);
},
});

(zlib.createGzip as sinon.SinonStub).callsFake(() => new PassThrough());
(fs.createReadStream as sinon.SinonStub).callsFake((filePath: string) => {
if (filePath.includes("file1.txt")) {
return new Readable({
read() {
this.push(Buffer.from("hash1"));
this.push(null);
},
});
}
if (filePath.includes("file2.txt")) {
return new Readable({
read() {
this.push(Buffer.from("hash2"));
this.push(null);
},
});
}
return new PassThrough();
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This section for mocking streams can be simplified. The mockStream1 and mockStream2 variables are declared but never used and can be removed. Additionally, the Readable stream creation logic is duplicated inside fs.createReadStream.callsFake. This can be extracted to a helper function to make the code cleaner and more maintainable.

    const createMockStream = (content: string) =>
      new Readable({
        read() {
          this.push(Buffer.from(content));
          this.push(null);
        },
      });

    (zlib.createGzip as sinon.SinonStub).callsFake(() => new PassThrough());
    (fs.createReadStream as sinon.SinonStub).callsFake((filePath: string) => {
      if (filePath.includes("file1.txt")) {
        return createMockStream("hash1");
      }
      if (filePath.includes("file2.txt")) {
        return createMockStream("hash2");
      }
      return new PassThrough();
    });

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant