Skip to content

chore: llm generated tests#121

Merged
infiniteregrets merged 8 commits intomainfrom
m/spec-tests
Feb 4, 2026
Merged

chore: llm generated tests#121
infiniteregrets merged 8 commits intomainfrom
m/spec-tests

Conversation

@infiniteregrets
Copy link
Member

@infiniteregrets infiniteregrets commented Feb 4, 2026

based on specs from https://github.com/s2-streamstore/s2-sdk-go/tree/main/docs

credits: claude, codex

@infiniteregrets infiniteregrets requested a review from a team as a code owner February 4, 2026 04:05
@greptile-apps
Copy link

greptile-apps bot commented Feb 4, 2026

Greptile Overview

Greptile Summary

This PR adds comprehensive E2E test coverage for the TypeScript SDK, including test suites for access tokens, basins, streams, metrics, and client lifecycle operations.

Key Changes:

  • Added 5 new test files covering all major SDK features (~4100 lines)
  • Created shared test helpers with utilities for basin/stream naming and retry logic
  • Added fencing token length validation (36 bytes max) in AppendInput.create
  • Updated CI workflow to exclude certain tests from S2-lite integration runs

Test Implementation Quality:

  • Proper cleanup guards in afterAll hooks checking if (!s2) return to prevent crashes when env parsing fails
  • Uses setupOk flag pattern in access token tests to skip tests requiring complex setup
  • Consistent use of TEST_TIMEOUT_MS and helper functions across all test files
  • Proper error handling for free tier limitations with isFreeTierLimitation helper

Confidence Score: 5/5

  • This PR is safe to merge - it adds comprehensive test coverage with proper cleanup patterns
  • All test files follow consistent patterns with proper initialization guards and cleanup logic. The fencing token validation is a straightforward bounds check. Previous review concerns about cleanup crashes have been addressed with if (!s2) return guards.
  • No files require special attention

Important Files Changed

Filename Overview
packages/streamstore/src/types.ts Added fencing token length validation (36 bytes max) in AppendInput.create
packages/streamstore/src/tests/accessTokens.spec.e2e.test.ts Added comprehensive access token tests with proper cleanup guards using setupOk flag
packages/streamstore/src/tests/basins.spec.e2e.test.ts Added basin operations tests with proper s2 initialization guards in afterAll
packages/streamstore/src/tests/streams.spec.e2e.test.ts Added extensive stream operations tests with proper cleanup guards checking both s2 and basinName
packages/streamstore/src/tests/spec.e2e.test.ts Added spec parity integration tests covering read/append semantics, sessions, and auto-prefixing

Sequence Diagram

sequenceDiagram
    participant Test as Test Suite
    participant Env as S2Environment
    participant S2 as S2 Client
    participant API as S2 API
    participant Cleanup as afterAll Hook

    Note over Test,Cleanup: E2E Test Execution Flow

    Test->>Env: parse() environment
    alt Has S2_ACCESS_TOKEN
        Env-->>Test: Returns config with accessToken
        Test->>S2: new S2(config)
        S2-->>Test: Client initialized
        
        Test->>S2: Create test resources (basins/streams/tokens)
        S2->>API: API calls
        API-->>S2: Resources created
        S2-->>Test: Success (setupOk = true)
        
        Test->>Test: Execute test cases
        Test->>S2: Perform operations
        S2->>API: API calls
        API-->>S2: Responses
        S2-->>Test: Results
        
        Test->>Cleanup: Trigger afterAll
        Cleanup->>Cleanup: Check if (!s2) return
        Cleanup->>S2: Delete resources
        S2->>API: Cleanup calls
        API-->>S2: Resources deleted
    else No Access Token
        Env-->>Test: Returns config without accessToken
        Test->>Test: Early return (skip tests)
        Test->>Cleanup: Trigger afterAll
        Cleanup->>Cleanup: Guard: if (!s2) return
        Cleanup-->>Test: Skip cleanup safely
    end
Loading

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

7 files reviewed, 6 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +45 to +48
createdBasins.push(basinA, basinB);
await waitForBasinReady(s2, basinA);
await waitForBasinReady(s2, basinB);
const basinClient = s2.basin(basinA);
Copy link

Choose a reason for hiding this comment

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

[P1] afterAll can throw if beforeAll returned early (no access token) and s2 was never initialized.

When S2Environment.parse() yields no accessToken, beforeAll returns without setting s2, but afterAll still runs and calls s2.accessTokens.revoke(...), which will crash the suite with Cannot read properties of undefined.

Consider guarding cleanup with if (!s2) return; (or set setupOk/a created flag only after s2 is constructed).

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/streamstore/src/tests/accessTokens.spec.e2e.test.ts
Line: 45:48

Comment:
[P1] `afterAll` can throw if `beforeAll` returned early (no access token) and `s2` was never initialized.

When `S2Environment.parse()` yields no `accessToken`, `beforeAll` returns without setting `s2`, but `afterAll` still runs and calls `s2.accessTokens.revoke(...)`, which will crash the suite with `Cannot read properties of undefined`.

Consider guarding cleanup with `if (!s2) return;` (or set `setupOk`/a `created` flag only after `s2` is constructed).

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +21 to +26

const trackBasin = (name: string) => {
createdBasins.push(name);
return name;
};

Copy link

Choose a reason for hiding this comment

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

[P1] afterAll can crash when env token is missing because s2 is uninitialized.

beforeAll returns early if S2Environment.parse() has no accessToken, but afterAll still iterates createdBasins and calls s2.basins.delete(...). If the env var is set but parse fails (or token is omitted), this turns into a runtime error rather than a skipped suite. Guard cleanup with if (!s2) return; or only register cleanup after init succeeds.

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/streamstore/src/tests/basins.spec.e2e.test.ts
Line: 21:26

Comment:
[P1] `afterAll` can crash when env token is missing because `s2` is uninitialized.

`beforeAll` returns early if `S2Environment.parse()` has no `accessToken`, but `afterAll` still iterates `createdBasins` and calls `s2.basins.delete(...)`. If the env var is set but parse fails (or token is omitted), this turns into a runtime error rather than a skipped suite. Guard cleanup with `if (!s2) return;` or only register cleanup after init succeeds.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +20 to +33
const end = Date.now();
const start = end - hours * 60 * 60 * 1000;
return { start, end };
};

beforeAll(async () => {
const env = S2Environment.parse();
if (!env.accessToken) return;
s2 = new S2(env as S2ClientOptions);
basinName = makeBasinName("ts-metrics");
await s2.basins.create({ basin: basinName });
await waitForBasinReady(s2, basinName);
const basin = s2.basin(basinName);
streamName = makeStreamName("metrics");
Copy link

Choose a reason for hiding this comment

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

[P1] afterAll can throw if beforeAll returned early (no access token) and s2 was never constructed.

This suite sets basinName/streamName after initializing s2, but afterAll only checks basinName and then calls s2.basins.delete(...). If env parsing returns no access token, s2 remains undefined and the cleanup will crash instead of no-op. Add if (!s2) return; or a created flag.

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/streamstore/src/tests/metrics.spec.e2e.test.ts
Line: 20:33

Comment:
[P1] `afterAll` can throw if `beforeAll` returned early (no access token) and `s2` was never constructed.

This suite sets `basinName`/`streamName` after initializing `s2`, but `afterAll` only checks `basinName` and then calls `s2.basins.delete(...)`. If env parsing returns no access token, `s2` remains undefined and the cleanup will crash instead of no-op. Add `if (!s2) return;` or a `created` flag.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines 42 to 55
await waitForBasinReady(s2, basinName);
basin = s2.basin(basinName);
}, TEST_TIMEOUT_MS);

afterAll(async () => {
if (basinName) {
await s2.basins.delete({ basin: basinName }).catch(() => {});
}
}, TEST_TIMEOUT_MS);

describe("List streams", () => {
const listStreams: string[] = [];
let listPrefix = "";

Copy link

Choose a reason for hiding this comment

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

[P1] afterAll can crash if env parsing returns no access token and s2/basinName were never initialized.

beforeAll returns early on missing env.accessToken, but afterAll checks only basinName (declared but not initialized) and then uses s2.basins.delete(...). In that early-return scenario, s2 is undefined, so cleanup can throw. Guard with if (!s2) return; (or initialize basinName = "" like other suites).

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/streamstore/src/tests/streams.spec.e2e.test.ts
Line: 42:55

Comment:
[P1] `afterAll` can crash if env parsing returns no access token and `s2`/`basinName` were never initialized.

`beforeAll` returns early on missing `env.accessToken`, but `afterAll` checks only `basinName` (declared but not initialized) and then uses `s2.basins.delete(...)`. In that early-return scenario, `s2` is undefined, so cleanup can throw. Guard with `if (!s2) return;` (or initialize `basinName = ""` like other suites).

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +123 to +131
} finally {
await basin.streams.delete({ stream: streamName }).catch(() => {});
}
},
TEST_TIMEOUT_MS,
);

it(
"clamps count to 1000 on unary read",
Copy link

Choose a reason for hiding this comment

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

[P1] limited client may be constructed with endpoints: undefined, causing runtime failures unrelated to the behavior under test.

In the auto-prefix test, endpoints: S2Environment.parse().endpoints can be undefined (e.g., if endpoints are not set in the environment), which will likely throw inside new S2(...) or on first request. Since this suite already parsed env in beforeAll, reuse the stored env.endpoints (and/or assert it exists before running).

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/streamstore/src/tests/spec.e2e.test.ts
Line: 123:131

Comment:
[P1] `limited` client may be constructed with `endpoints: undefined`, causing runtime failures unrelated to the behavior under test.

In the auto-prefix test, `endpoints: S2Environment.parse().endpoints` can be `undefined` (e.g., if endpoints are not set in the environment), which will likely throw inside `new S2(...)` or on first request. Since this suite already parsed env in `beforeAll`, reuse the stored `env.endpoints` (and/or assert it exists before running).

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines 18 to 31
`${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;

describeIf("Spec Integration Tests", () => {
let s2: S2;
let basinName: string;
let autoBasinName: string;
let basin: S2Basin;
let autoBasin: S2Basin;
let metricsStreamName: string;

const createStream = async (target: S2Basin, prefix: string) => {
const streamName = makeStreamName(prefix);
await target.streams.create({ stream: streamName });
return streamName;
Copy link

Choose a reason for hiding this comment

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

[P3] Duplicated helper logic and constants here drift from tests/helpers.ts.

This file redefines TEST_TIMEOUT_MS, makeBasinName, and makeStreamName instead of importing from ./helpers.js. That makes it easy for future changes (naming constraints/timeouts) to get out of sync across suites. Consider using the shared helpers to keep behavior consistent.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/streamstore/src/tests/spec.e2e.test.ts
Line: 18:31

Comment:
[P3] Duplicated helper logic and constants here drift from `tests/helpers.ts`.

This file redefines `TEST_TIMEOUT_MS`, `makeBasinName`, and `makeStreamName` instead of importing from `./helpers.js`. That makes it easy for future changes (naming constraints/timeouts) to get out of sync across suites. Consider using the shared helpers to keep behavior consistent.

<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>

How can I resolve this? If you propose a fix, please make it concise.

@infiniteregrets
Copy link
Member Author

@greptile-apps review pls

@infiniteregrets infiniteregrets changed the title test chore: llm generated tests Feb 4, 2026
@infiniteregrets infiniteregrets merged commit a141ed9 into main Feb 4, 2026
6 checks passed
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

Comments