Skip to content

Conversation

@cloud-j-luna
Copy link
Member

@cloud-j-luna cloud-j-luna commented Sep 24, 2025

🌟 PR Title

[Use a clear, concise title that reflects the change]

📝 Description

[Explain what this PR does in 2-3 sentences. Include context about the feature or problem being solved]

🔧 Purpose of the Change

  • [ x] Other: Tests

✅ Checklist

  • I've updated relevant documentation
  • Code follows Akash Network's style guide
  • I've added/updated relevant unit tests
  • Dependencies have been properly updated
  • I agree and adhered to the Contribution Guidelines

📎 Notes for Reviewers

Follow up issues:

Critical Compatibility Issues

Integer DecCoin encoding incompatibility between TypeScript and Go

Description: When a bid price is sent as an integer string (e.g., "2500") in a DecCoin field from TypeScript, Go decodes it incorrectly with a factor difference of ~10^15 (receives "0.0000000000000025" instead of "2500").
Impact: High - affects all market pricing operations
Workaround: Use explicit decimal format with .0 suffix (e.g., "2500.0")
Location: TypeScript protobuf encoding → Go DecCoin decoding
Test Evidence: Multi-message tx test initially failed with this issue (lines 683-750 in deployments.spec.ts)

Multi-message transaction encoding fails with DecCoin fields

Description: When using createGatewayTxClient.estimateFee() to build a transaction containing multiple messages where one or more have DecCoin fields (like MsgCreateBid), the tx encoding fails with: math/big: cannot unmarshal "0.0025" into a *big.Int: tx parse error
Impact: High - prevents atomic multi-message transactions involving market operations
Workaround: Send messages in separate transactions
Location: ts/test/util/createGatewayTxClient.ts - estimateFee() function
Test Evidence: Multi-message tx test had to revert to separate SDK calls (lines 745-752 in deployments.spec.ts)

Missing Test Coverage

Query echo endpoints for market operations
Description: Add positive query assertions for bids, leases, and other market queries once mock server responds with data or echo fixtures
Impact: Medium - limits query path testing
Scope: Add query endpoints like /akash/market/v1beta5/bids/list, /akash/market/v1beta5/leases/list to the mock server and corresponding tests
Location: go/testutil/mock/server.go and ts/test/functional/deployments.spec.ts

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 24, 2025

Walkthrough

Adds a Go mock gRPC server with HTTP gateway, new Go query/tx mocks and CLI, TypeScript helpers (mock server launcher and gateway Tx client), functional TS tests and docs, Make/CICD targets to run guarded functional tests, tooling adjustments (tsconfig/jest/npm), and small infra changes (BUF runtime guard, .gitignore).

Changes

Cohort / File(s) Summary
Mock Server Core (Go)
go/testutil/mock/server.go, go/testutil/mock/cmd/server/main.go, go/testutil/mock/server_test.go
New exported Server/Config types with Start/Stop and address accessors; CLI binary prints gateway/grpc addresses; integration test exercises HTTP gateway endpoint.
Mock Query & TX Services (Go)
go/testutil/mock/query/*, go/testutil/mock/tx/service.go
Added mock query implementations (DeploymentQuery, MarketQuery) returning empty/mocked responses, and tx service implementing Simulate and BroadcastTx (other RPCs return Unimplemented).
TypeScript Mock Integration
ts/test/util/mockServer.ts
New MockServer interface and startMockServer() that spawns/selects a binary, parses stdout for addresses, polls for readiness, captures stderr, and exposes stop() cleanup and timeout error paths.
Gateway Tx Client (TypeScript)
ts/test/util/createGatewayTxClient.ts
New GatewayTxClientOptions and createGatewayTxClient() implementing estimateFee (simulate), sign (signDirect flow), and broadcast through HTTP gateway endpoints with encoding/decoding and error handling.
Functional Tests & Docs (TypeScript)
ts/test/functional/*.spec.ts, ts/test/functional/README.md
New functional suites (deployments, protoc-gen tests) that run against mock server, use vendored buf flows, snapshot checks, and a README describing execution and architecture.
Test Orchestration & Make/CICD
ts/package.json, make/test.mk, .github/workflows/tests.yaml, make/setup-cache.mk
Split npm test scripts (unit vs guarded functional), added test-functional-ts and mock-server-bin Make targets, CI job test-functional-ts, and BUF runtime guard to reinstall BUF if missing.
TS Config & Tooling
ts/jest.config.ts, ts/tsconfig.json, ts/.npmrc
Exclude functional tests from coverage, set Jest timeout to 120s, narrow TS include to src/**/*.ts and exclude test/**/script/**, add engine-strict=true.
Protoc Scripts Polyfills
ts/script/protoc-gen-sdk-object.ts, ts/script/protoc-gen-customtype-patches.ts
Add localStorage polyfill for Node/non-browser execution in protoc-generation scripts.
Protoc/Buf Test Adjustments (TS)
ts/test/functional/protoc-gen-*.spec.ts
Tests now validate vendored proto & buf binary presence, run buf generate with config, and snapshot additional generated files.
Makefile/NPM script tweaks
make/test.mk, ts/package.json
Adjusted npm test orchestration, removed subshell usage in recipes, functional test runner guarded by env check.
Misc
.gitignore
Added macOS .DS_Store ignore entry.

Sequence Diagram(s)

sequenceDiagram
    participant TS as TypeScript tests
    participant Launcher as startMockServer (TS)
    participant Proc as Mock Server Process
    participant GW as HTTP Gateway
    participant GRPC as gRPC Server
    participant Query as Query Service
    participant TX as TX Service

    TS->>Launcher: startMockServer()
    Launcher->>Proc: spawn mock-server binary/process
    Proc->>GRPC: register services (Query, TX)
    Proc->>GW: register HTTP gateway handlers
    Proc-->>Launcher: stdout: gateway URL, grpc addr

    rect rgb(235,245,255)
      Note over TS,GW: Query flow (HTTP → gRPC → response)
      TS->>GW: GET /akash/deployment/v1beta4/deployments/list
      GW->>GRPC: forward request
      GRPC->>Query: Deployments()
      Query-->>GRPC: empty/mocked response
      GRPC-->>GW: response
      GW-->>TS: 200 JSON
    end

    rect rgb(245,255,235)
      Note over TS,TX: Tx flow (simulate / broadcast)
      TS->>GW: POST /cosmos/tx/v1beta1/simulate (tx_bytes)
      GW->>GRPC: Simulate RPC
      GRPC->>TX: Simulate()
      TX-->>GRPC: gas estimate
      GRPC-->>GW: simulation response
      GW-->>TS: simulation result
      TS->>GW: POST /cosmos/tx/v1beta1/txs (broadcast)
      GW->>GRPC: BroadcastTx RPC
      GRPC->>TX: BroadcastTx()
      TX-->>GRPC: TxResponse
      GRPC-->>GW: response
      GW-->>TS: broadcast result
    end

    TS->>Launcher: stop()
    Launcher->>Proc: SIGTERM → graceful shutdown
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Suggested reviewers

  • stalniy
  • troian
  • ygrishajev

Poem

🐰 I hopped a server, pipe and wire,
Go builds the gate, TS sparks the fire.
Tests parade, mocks hum along,
CI nods, the logs grow strong—
Carrots for passing suites, hop on, admire! 🥕

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 27.59% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Description check ⚠️ Warning PR description is incomplete and uses the template format without providing actual content for most sections. Provide a clear PR title, 2-3 sentence description explaining the feature/fix, select the appropriate purpose checkbox, fill in related issues, complete the checklist items, and add reviewer notes with architectural context.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately reflects the main change: adding functional tests for deployments with a Go mock server and TypeScript test suite.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch luna/functional-tests

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

♻️ Duplicate comments (1)
go/testutil/mock/server.go (1)

279-295: Remove non-standard "BROADCAST_MODE_UNSPECIFIED_VALUE" case.

As noted in a previous review, "BROADCAST_MODE_UNSPECIFIED_VALUE" is not a valid protobuf enum string. Only "BROADCAST_MODE_UNSPECIFIED" is standard. This case should be removed.

🔎 Proposed fix
 		if modeStr, ok := jsonReq["mode"].(string); ok {
 			modeStr = strings.ToUpper(modeStr)
 			switch modeStr {
-			case "BROADCAST_MODE_UNSPECIFIED", "BROADCAST_MODE_UNSPECIFIED_VALUE":
+			case "BROADCAST_MODE_UNSPECIFIED":
 				req.Mode = txv1beta1.BroadcastMode_BROADCAST_MODE_UNSPECIFIED
 			case "BROADCAST_MODE_BLOCK":
🧹 Nitpick comments (7)
ts/script/protoc-gen-sdk-object.ts (1)

3-25: Consider extracting shared localStorage polyfill.

This localStorage polyfill is duplicated in protoc-gen-customtype-patches.ts. Since both scripts need the same polyfill, consider importing from a shared module (e.g., the existing localStorage-polyfill.js mentioned in the AI summary) instead of duplicating inline.

🔎 Suggested approach
-const localStoragePolyfill = {
-  getItem: () => null,
-  setItem: () => {},
-  removeItem: () => {},
-  clear: () => {},
-  length: 0,
-  key: () => null,
-};
-
-if (typeof globalThis.localStorage === "undefined" || typeof globalThis.localStorage.getItem !== "function") {
-  Object.defineProperty(globalThis, "localStorage", {
-    value: localStoragePolyfill,
-    writable: true,
-    configurable: true,
-  });
-}
-if (typeof global !== "undefined" && (typeof global.localStorage === "undefined" || typeof global.localStorage.getItem !== "function")) {
-  Object.defineProperty(global, "localStorage", {
-    value: localStoragePolyfill,
-    writable: true,
-    configurable: true,
-  });
-}
+import "./localStorage-polyfill.js";
go/testutil/mock/helper.go (1)

8-29: Register cleanup to stop the server and consider removing redundant sleep.

  1. The server should be stopped when the test completes. Use t.Cleanup() to ensure proper resource cleanup.
  2. Since server.Start() already calls waitForGRPCReady() with retry logic, the additional 100ms sleep may be unnecessary.
🔎 Proposed fix
 func StartMockServer(t testing.TB, dataDir string) *Server {
 	t.Helper()

 	cfg := Config{
 		GRPCAddr:    "127.0.0.1:0",
 		GatewayAddr: "127.0.0.1:0",
 		DataDir:     dataDir,
 	}

 	server, err := NewServer(cfg)
 	if err != nil {
 		t.Fatalf("failed to create mock server: %v", err)
 	}

 	if err := server.Start(); err != nil {
 		t.Fatalf("failed to start mock server: %v", err)
 	}

-	time.Sleep(100 * time.Millisecond)
+	t.Cleanup(func() {
+		if err := server.Stop(); err != nil {
+			t.Logf("failed to stop mock server: %v", err)
+		}
+	})

 	return server
 }
go/testutil/mock/query/deployment.go (1)

34-56: Consider thread-safety for loadData().

The loadData() method is not thread-safe. If multiple goroutines call Deployments() concurrently before data is loaded, they may race on reading/writing q.data. For test utilities this is typically acceptable, but worth noting if concurrent test execution is planned.

ts/test/util/createGatewayTxClient.ts (1)

114-119: Hardcoded chain ID limits reusability.

The chain ID "akashnet-2" is hardcoded. Consider making it configurable via GatewayTxClientOptions.

 export interface GatewayTxClientOptions {
   gatewayUrl: string;
   signer: OfflineSigner;
   gasMultiplier?: number;
   defaultGasPrice?: string;
+  chainId?: string;
   getMessageType: (typeUrl: string) => any;
 }
go/testutil/mock/server_test.go (2)

14-16: Consider validating the data directory exists.

The test uses a relative path to the data directory. If the test file is moved or the directory structure changes, this could silently fail. Consider adding an explicit check that the data directory exists before starting the server, or use a more robust path resolution.

🔎 Optional improvement
 func TestServer(t *testing.T) {
+	dataDir := "../../testutil/mock/data"
+	if _, err := os.Stat(dataDir); os.IsNotExist(err) {
+		t.Fatalf("data directory does not exist: %s", dataDir)
+	}
-	server := StartMockServer(t, "../../testutil/mock/data")
+	server := StartMockServer(t, dataDir)
 	defer server.Stop()

40-46: Simplify the deployments validation logic.

The current logic uses a type assertion with an else branch that always passes. Since the mock server should return a consistent JSON structure, consider asserting the expected structure more strictly or simplifying the conditional logic.

🔎 Proposed simplification
-	if deployments, ok := response["deployments"].([]interface{}); ok {
-		t.Logf("Deployments array length: %d", len(deployments))
-		require.GreaterOrEqual(t, len(deployments), 0)
-	} else {
-		t.Logf("Deployments field type: %T, value: %+v", response["deployments"], response["deployments"])
-		require.Contains(t, response, "deployments", "Response should contain 'deployments' field")
-	}
+	require.Contains(t, response, "deployments", "Response should contain 'deployments' field")
+	deployments, ok := response["deployments"].([]interface{})
+	require.True(t, ok, "deployments field should be an array, got %T", response["deployments"])
+	t.Logf("Deployments array length: %d", len(deployments))
+	require.GreaterOrEqual(t, len(deployments), 0)
ts/test/functional/deployments.spec.ts (1)

28-28: Consider using environment variable for test mnemonic.

The test uses a hardcoded mnemonic. While this is fine for mock server tests, past review comments suggested using process.env.TEST_MNEMONIC with proper validation for more flexibility when running against real networks.

For the current mock-only setup, the hardcoded mnemonic is acceptable.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 00530d1 and bd136a8.

⛔ Files ignored due to path filters (2)
  • ts/package-lock.json is excluded by !**/package-lock.json
  • ts/test/functional/__snapshots__/protoc-gen-sdk-object.spec.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (31)
  • .github/workflows/tests.yaml
  • .gitignore
  • README.md
  • go/testutil/mock/cmd/generate-fixtures/main.go
  • go/testutil/mock/cmd/server/main.go
  • go/testutil/mock/data/deployments.json
  • go/testutil/mock/data/market.json
  • go/testutil/mock/helper.go
  • go/testutil/mock/query/deployment.go
  • go/testutil/mock/query/market.go
  • go/testutil/mock/server.go
  • go/testutil/mock/server_test.go
  • go/testutil/mock/tx/service.go
  • make/setup-cache.mk
  • make/test.mk
  • ts/.npmrc
  • ts/README.md
  • ts/jest.config.ts
  • ts/package.json
  • ts/script/localStorage-polyfill.js
  • ts/script/protoc-gen-customtype-patches-wrapper.sh
  • ts/script/protoc-gen-customtype-patches.ts
  • ts/script/protoc-gen-sdk-object-wrapper.sh
  • ts/script/protoc-gen-sdk-object.ts
  • ts/test/functional/README.md
  • ts/test/functional/deployments.spec.ts
  • ts/test/functional/protoc-gen-customtype-patches.spec.ts
  • ts/test/functional/protoc-gen-sdk-object.spec.ts
  • ts/test/util/createGatewayTxClient.ts
  • ts/test/util/mockServer.ts
  • ts/tsconfig.json
✅ Files skipped from review due to trivial changes (1)
  • ts/test/functional/README.md
🚧 Files skipped from review as they are similar to previous changes (13)
  • .gitignore
  • ts/package.json
  • go/testutil/mock/data/market.json
  • ts/tsconfig.json
  • README.md
  • ts/jest.config.ts
  • go/testutil/mock/cmd/server/main.go
  • go/testutil/mock/cmd/generate-fixtures/main.go
  • ts/script/protoc-gen-customtype-patches-wrapper.sh
  • make/test.mk
  • go/testutil/mock/query/market.go
  • ts/README.md
  • ts/test/functional/protoc-gen-customtype-patches.spec.ts
🧰 Additional context used
🧬 Code graph analysis (4)
go/testutil/mock/server_test.go (1)
go/testutil/mock/helper.go (1)
  • StartMockServer (8-29)
go/testutil/mock/server.go (4)
go/sdkutil/encoding.go (2)
  • EncodingConfig (17-23)
  • MakeEncodingConfig (26-68)
go/testutil/mock/query/deployment.go (1)
  • NewDeploymentQuery (27-32)
go/testutil/mock/query/market.go (1)
  • NewMarketQuery (29-34)
go/testutil/mock/tx/service.go (1)
  • NewService (19-21)
go/testutil/mock/helper.go (1)
go/testutil/mock/server.go (3)
  • Server (29-41)
  • Config (43-47)
  • NewServer (49-120)
ts/test/functional/deployments.spec.ts (2)
ts/test/util/mockServer.ts (1)
  • startMockServer (11-211)
ts/test/util/createGatewayTxClient.ts (1)
  • createGatewayTxClient (31-180)
🪛 actionlint (1.7.9)
.github/workflows/tests.yaml

65-65: shellcheck reported issue in this script: SC2086:info:2:34: Double quote to prevent globbing and word splitting

(shellcheck)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: test
  • GitHub Check: coverage
  • GitHub Check: go
🔇 Additional comments (19)
go/testutil/mock/data/deployments.json (1)

1-6: LGTM!

Valid JSON fixture for mock deployment data. The nested structure with deployments.deployments array and pagination object aligns with the expected QueryDeploymentsResponse format consumed by DeploymentQuery.

go/testutil/mock/tx/service.go (1)

23-59: LGTM!

The mock tx service implementation is well-structured for testing purposes:

  • Simulate returns consistent gas estimates
  • BroadcastTx generates deterministic transaction hashes from input bytes
  • Unimplemented methods properly return gRPC status codes
go/testutil/mock/server.go (2)

49-120: LGTM on server initialization.

The NewServer function properly:

  • Sets sensible defaults for addresses and data directory
  • Registers query handlers and tx service
  • Configures JSON marshaling with OrigName: true and EmitDefaults: true for consistent output
  • Handles errors with context cancellation on failure

166-195: Good implementation of readiness check with exponential backoff.

The waitForGRPCReady() method properly addresses the race condition flagged in previous reviews by using exponential backoff with a cap, context timeout, and proper cleanup of dial contexts.

ts/script/protoc-gen-customtype-patches.ts (1)

3-25: Duplicate localStorage polyfill.

This is identical to the polyfill in protoc-gen-sdk-object.ts. See the refactoring suggestion there to extract this to a shared module.

ts/.npmrc (1)

1-1: LGTM! Appropriate engine enforcement.

Setting engine-strict=true is a good practice to enforce Node.js version requirements at install time, especially given the use of --experimental-strip-types which requires Node.js v22.6.0+.

ts/script/protoc-gen-sdk-object-wrapper.sh (1)

1-8: LGTM! Well-structured wrapper script.

The wrapper correctly sets up the localStorage polyfill via NODE_OPTIONS and executes the TypeScript plugin with appropriate experimental flags. The use of --experimental-strip-types aligns with the Node.js v22.6+ requirement enforced elsewhere in the PR.

.github/workflows/tests.yaml (1)

77-79: Verify necessity of Go dependency download step.

A previous review comment (marked as "✅ Addressed in commit 7c7428e") indicated that this explicit "Download Go dependencies" step is unnecessary for the test-functional-ts job, as it only runs TypeScript tests. However, the step still appears in the current code.

If the functional tests do require Go dependencies (e.g., for building the mock server), this step is correct. Otherwise, consider removing it to speed up CI runs.

Based on learnings from past reviews, this was flagged as unnecessary. Can you confirm whether the mock server binary is pre-built via the make target dependencies, or if this Go download step is actually needed?

ts/script/localStorage-polyfill.js (1)

1-11: LGTM! Clean localStorage polyfill implementation.

The polyfill properly checks for both the existence of globalThis.localStorage and its getItem method, providing safe no-op stubs for all localStorage APIs. This ensures TypeScript plugins can run in non-browser environments without errors.

ts/test/functional/protoc-gen-sdk-object.spec.ts (2)

11-11: LGTM! Test suite properly structured.

The test suite has been correctly updated based on previous review feedback:

  • Typo in describe block was fixed
  • Silent test skipping replaced with explicit error throwing (lines 35-40)
  • Node.js version requirements properly enforced via engine-strict

35-40: Good improvement! Proper error handling prevents silent failures.

Throwing explicit errors when prerequisites are missing (vendor directory or buf binary) is much better than the previous silent skip approach. This ensures CI will fail loudly if the environment is misconfigured.

ts/test/functional/deployments.spec.ts (3)

68-97: LGTM! Well-structured SDK factory pattern.

The createTestSDK helper correctly:

  • Conditionally creates the transaction client only when a wallet is provided
  • Uses the mock server's gateway URL for both query and transaction operations
  • Properly integrates with the gateway transaction client

This addresses previous concerns about null signer issues.


148-201: Good serialization test with deterministic validation.

The test properly validates:

  • Deterministic encoding by comparing against a fixed base64 string
  • Round-trip decoding to ensure data integrity
  • Message structure preservation

This is a valuable test for ensuring TypeScript-Go protobuf compatibility.


204-285: Excellent negative test coverage.

The transaction validation tests comprehensively cover error cases:

  • Empty groups (lines 205-219)
  • Empty hash (lines 221-235)
  • Invalid hash length (lines 237-251)
  • Negative price (lines 253-284)

Each test properly validates that the Go-side ValidateBasic() logic is triggered and returns appropriate error messages.

ts/test/util/mockServer.ts (5)

11-43: LGTM! Robust server startup logic with proper fallbacks.

The implementation correctly:

  • Prefers pre-built binary via MOCK_SERVER_BIN environment variable
  • Falls back to go run with automatic vendor detection
  • Configures appropriate working directory and environment variables
  • Uses proper spawn options (detached: false, proper signal handling)

70-79: Good improvement! Comprehensive error keyword filtering.

The stderr filtering now catches a broad range of error types (error, fail, panic, fatal, exception, cannot, unable), addressing previous review feedback. This ensures critical messages are logged while reducing noise from debug output.


81-92: Excellent error handling! Proper async error propagation.

The error and exit handlers correctly:

  • Store spawn errors for checking in the polling loop (lines 81-83)
  • Log exit codes with context (lines 85-92)
  • Avoid synchronous throws that would crash Node.js

This addresses critical issues from previous reviews.


94-210: Outstanding cleanup logic! Comprehensive resource management.

The finally block (lines 191-210) ensures proper cleanup in all error paths:

  • Kills process only if still running (lines 193-198)
  • Removes all event listeners (line 201)
  • Destroys stdout/stderr streams (lines 203-208)
  • Uses cleanupOnError flag to avoid double cleanup on success

The stop() method (lines 114-180) also handles shutdown gracefully with SIGTERM → SIGKILL escalation and timeout. This prevents resource leaks and orphaned processes.


149-150: Typo in stream destroy logic.

Line 149 has .destroyed instead of .destroy() - this won't actually destroy the stderr stream.

🔎 Proposed fix
                 if (proc.stderr && !proc.stderr.destroyed) {
-                  proc.stderr.destroyed;
+                  proc.stderr.destroy();
                 }

Likely an incorrect or invalid review comment.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
ts/test/functional/protoc-gen-sdk-object.spec.ts (1)

79-83: Bug: Cleanup never executes due to incorrect access check logic.

access() returns Promise<void> (resolves to undefined on success), and the catch returns false on error. Since both undefined and false are falsy, the condition if (await access(...)) is never true, so the cleanup is never performed.

Also, rmdir with { recursive: true } is deprecated in favor of rm.

🔎 Proposed fix
     } finally {
-      if (await access(outputDir, fsConst.W_OK).catch(() => false)) {
-        await rmdir(outputDir, { recursive: true });
-      }
+      await access(outputDir, fsConst.W_OK)
+        .then(() => rm(outputDir, { recursive: true }))
+        .catch(() => {});
     }

Don't forget to update the import:

-import { access, constants as fsConst, readFile, rmdir } from "fs/promises";
+import { access, constants as fsConst, readFile, rm } from "fs/promises";
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bd136a8 and b7c7b0e.

📒 Files selected for processing (2)
  • ts/test/functional/protoc-gen-customtype-patches.spec.ts
  • ts/test/functional/protoc-gen-sdk-object.spec.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • ts/test/functional/protoc-gen-customtype-patches.spec.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: test-functional-ts
  • GitHub Check: coverage
  • GitHub Check: test
  • GitHub Check: go
  • GitHub Check: proto
🔇 Additional comments (2)
ts/test/functional/protoc-gen-sdk-object.spec.ts (2)

11-32: LGTM! Setup and configuration are well-structured.

The describe block name typo has been fixed, and the configuration with path resolution for vendor and buf binary is appropriate.


34-64: LGTM! Pre-condition checks and command construction are solid.

The error messages are clear and actionable, helping developers understand what's missing and how to fix it. This addresses the past review feedback about silent test skipping.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
go/testutil/mock/query/market.go (1)

102-120: Nil pointer dereference risk on req.Filters.

While line 102 checks req != nil, lines 105-114 access req.Filters.Owner, req.Filters.DSeq, etc. without verifying that req.Filters is non-nil. This will panic if a request is sent with nil filters.

🔎 Proposed fix
-	if req != nil && len(resp.Bids) > 0 {
+	if req != nil && req.Filters != nil && len(resp.Bids) > 0 {
 		var filtered []mv1beta5.QueryBidResponse
 		for _, bidResp := range resp.Bids {
 			if req.Filters.Owner != "" && bidResp.Bid.ID.Owner != req.Filters.Owner {
🧹 Nitpick comments (4)
go/testutil/mock/query/market.go (1)

29-34: Consider adding input validation in the constructor.

For robustness, you could validate that dataDir is non-empty and codec is non-nil, though for test utilities this may be acceptable as-is.

ts/test/util/createGatewayTxClient.ts (3)

23-29: Consider stricter typing for getMessageType.

The interface is well-designed. The any return type for getMessageType is pragmatic for a test utility but could be typed more strictly if message types share a common interface.

🔎 Optional: Stricter typing example

If your message types share a common encoder interface, you could type it as:

-  getMessageType: (typeUrl: string) => any;
+  getMessageType: (typeUrl: string) => { encode(message: any, writer: BinaryWriter): BinaryWriter };

This provides better type safety while maintaining flexibility.


36-118: Consider making the simulation fee denom configurable.

The estimateFee method correctly encodes messages for simulation (addressing the past review comment). However, the hardcoded "uakt" denom on line 74 limits portability to Akash network.

🔎 Proposed enhancement for multi-chain support

Extract the denom from the gasPrice or add it to options:

  const authInfo: AuthInfo = {
    signerInfos: [{
      // ...
    }],
    fee: {
      amount: [{
-       denom: "uakt",
+       denom: gasPrice.denom,
        amount: "1",
      }],
      // ...
    },
  };

This would allow the client to work with any Cosmos chain.


127-137: Refactor duplicated message encoding logic.

The message encoding logic here duplicates lines 37-47 in estimateFee. Extract this into a helper function to improve maintainability.

🔎 Proposed refactor

Add a helper function at the module level:

function encodeMessages(messages: EncodeObject[], getMessageType: (typeUrl: string) => any): Any[] {
  return messages.map(msg => {
    const MessageType = getMessageType(msg.typeUrl);
    if (!MessageType) {
      throw new Error(`Message type ${msg.typeUrl} not found in registry`);
    }
    const value = MessageType.encode(msg.value, new BinaryWriter()).finish();
    return {
      typeUrl: msg.typeUrl,
      value: value,
    };
  });
}

Then use it in both methods:

  async estimateFee(messages: EncodeObject[], memo?: string): Promise<StdFee> {
-   const messageAnys: Any[] = messages.map(msg => {
-     const MessageType = options.getMessageType(msg.typeUrl);
-     if (!MessageType) {
-       throw new Error(`Message type ${msg.typeUrl} not found in registry`);
-     }
-     const value = MessageType.encode(msg.value, new BinaryWriter()).finish();
-     return {
-       typeUrl: msg.typeUrl,
-       value: value,
-     };
-   });
+   const messageAnys = encodeMessages(messages, options.getMessageType);
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b7c7b0e and 536493d.

📒 Files selected for processing (5)
  • .github/workflows/tests.yaml
  • go/testutil/mock/query/deployment.go
  • go/testutil/mock/query/market.go
  • make/setup-cache.mk
  • ts/test/util/createGatewayTxClient.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • .github/workflows/tests.yaml
  • go/testutil/mock/query/deployment.go
🧰 Additional context used
🧬 Code graph analysis (1)
ts/test/util/createGatewayTxClient.ts (3)
ts/src/sdk/transport/tx/TxClient.ts (3)
  • EncodeObject (7-7)
  • StdFee (7-7)
  • DeliverTxResponse (7-7)
ts/src/generated/protos/index.cosmos.v1beta1.ts (1)
  • SignMode (253-253)
ts/esbuild.config.mjs (1)
  • code (64-64)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: test-functional-ts
  • GitHub Check: coverage
  • GitHub Check: test
  • GitHub Check: proto
  • GitHub Check: go
🔇 Additional comments (5)
make/setup-cache.mk (1)

34-43: LGTM! Previous concern properly addressed.

The explanatory comment clearly documents why BUF requires runtime verification as a direct test dependency, and the implementation correctly handles the case where the binary is missing while the version file exists. The check-and-reinstall pattern is sound and prevents silent test failures as intended.

go/testutil/mock/query/market.go (2)

36-61: LGTM!

The data loading logic is well-structured with appropriate caching, error handling, and nil slice initialization.


63-80: LGTM!

The Leases method follows a safe pattern with proper error handling and nil-safe initialization.

ts/test/util/createGatewayTxClient.ts (2)

1-22: LGTM! Clear documentation and appropriate imports.

The file header clearly explains this is a gateway-based client for Node.js environments using REST endpoints, and the imports are well-organized.


206-246: Robust broadcast implementation with good error handling.

The broadcast method correctly:

  • Encodes the signed transaction to bytes
  • Uses BROADCAST_MODE_SYNC for synchronous broadcasting
  • Handles response variations with multiple field name fallbacks (lines 229-242)
  • Validates the transaction code and throws descriptive errors

The defensive field name handling (snake_case, camelCase, PascalCase) is excellent for compatibility across different gateway implementations.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
ts/test/functional/deployments.spec.ts (1)

69-69: Consider reducing the global timeout for mock server tests.

The 180-second (3-minute) timeout seems excessive for tests running against an in-memory mock server. Mock server operations should complete much faster than tests against a real network. Consider using a shorter timeout (e.g., 30-60 seconds) to catch hanging tests more quickly, unless CI environment constraints require this duration.

Proposed timeout reduction

Based on the search results, global timeouts can mask slow tests and increase overall test runtime, and per-test or per-suite timeouts are preferred for specific slow tests. For mock server tests that don't involve real network delays, a 180-second timeout is likely excessive.

-  jest.setTimeout(180000);
+  jest.setTimeout(30000); // 30 seconds should be sufficient for mock server operations
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 536493d and 58d578a.

📒 Files selected for processing (2)
  • ts/test/functional/deployments.spec.ts
  • ts/test/util/createGatewayTxClient.ts
🧰 Additional context used
🧬 Code graph analysis (1)
ts/test/util/createGatewayTxClient.ts (3)
ts/src/sdk/transport/tx/TxClient.ts (3)
  • EncodeObject (7-7)
  • StdFee (7-7)
  • DeliverTxResponse (7-7)
ts/src/generated/protos/index.cosmos.v1beta1.ts (1)
  • SignMode (253-253)
ts/esbuild.config.mjs (1)
  • code (64-64)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: coverage
  • GitHub Check: test
  • GitHub Check: test-functional-ts
  • GitHub Check: proto
  • GitHub Check: go
🔇 Additional comments (3)
ts/test/util/createGatewayTxClient.ts (1)

1-250: Gateway TxClient implementation looks solid.

The implementation correctly handles all three transaction lifecycle operations (estimate, sign, broadcast) via HTTP gateway endpoints. All previously flagged issues have been addressed:

  • Empty accounts guard is in place (line 125-127)
  • Chain ID and account number are configurable (lines 26-27, 187-188)
  • Hardcoded sequence has explanatory comment (line 173)
  • Error handling is comprehensive throughout
  • signDirect capability is verified before use (line 191-193)

The code is well-structured for its intended use as a test utility against a mock gateway server.

ts/test/functional/deployments.spec.ts (2)

11-11: BinaryWriter import is correct for @bufbuild/protobuf-generated code.

The past review comment flagged this as potentially incompatible with ts-proto, but that concern doesn't apply here. The generated protobuf code (line 18) uses @bufbuild/protobuf (version 2.2.3 per library context), which expects BinaryWriter from @bufbuild/protobuf/wire. This is the correct writer for the serialization test on lines 189-191.


101-286: Functional test suite is well-structured and comprehensive.

The test suite effectively validates:

  • Protobuf encoding/decoding compatibility between TypeScript and Go
  • Query endpoints with proper response structure assertions
  • SDK module availability and structure
  • Deterministic message serialization with round-trip verification (lines 149-202)
  • Transaction validation with specific error message checks (lines 206-286)

The use of the mock server lifecycle in beforeAll/afterAll is clean, and the conditional SDK setup (lines 82-98) appropriately handles wallet-backed vs. query-only scenarios. All previously flagged issues (debug logs, duplicates, dead code branches) have been addressed.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
go/testutil/mock/server.go (1)

275-291: Remove non-existent "BROADCAST_MODE_UNSPECIFIED_VALUE" from switch.

A past review comment (currently unresolved) correctly identified that "BROADCAST_MODE_UNSPECIFIED_VALUE" is not a valid protobuf enum string. The standard naming convention uses "BROADCAST_MODE_UNSPECIFIED" for the zero value without a _VALUE suffix. Since both would map to the same enum anyway, this case should be removed.

🔎 Proposed fix
 		if modeStr, ok := jsonReq["mode"].(string); ok {
 			modeStr = strings.ToUpper(modeStr)
 			switch modeStr {
-			case "BROADCAST_MODE_UNSPECIFIED", "BROADCAST_MODE_UNSPECIFIED_VALUE":
+			case "BROADCAST_MODE_UNSPECIFIED":
 				req.Mode = txv1beta1.BroadcastMode_BROADCAST_MODE_UNSPECIFIED
 			case "BROADCAST_MODE_BLOCK":
 				req.Mode = txv1beta1.BroadcastMode_BROADCAST_MODE_BLOCK
🧹 Nitpick comments (4)
go/testutil/mock/query/market.go (1)

14-16: Unused field: codec is never referenced.

The codec field is stored but never used in any of the query methods. Either remove it or document why it's retained for future use.

🔎 Proposed fix to remove unused field
 type MarketQuery struct {
-	codec codec.Codec
 }
 
-func NewMarketQuery(codec codec.Codec) *MarketQuery {
-	return &MarketQuery{
-		codec: codec,
-	}
+func NewMarketQuery(codec codec.Codec) *MarketQuery {
+	return &MarketQuery{}
 }
ts/test/functional/deployments.spec.ts (1)

147-200: Test appears to verify deterministic serialization, but expected base64 may be brittle.

The test at line 192 compares the base64-encoded result against a hardcoded expected value. This is a snapshot-style test that will break if protobuf serialization changes (field ordering, varint encoding optimizations, etc.), even when the logical content is identical.

While this validates TS-Go encoding compatibility, consider whether the brittleness is acceptable or if a round-trip encode/decode check would be more maintainable.

go/testutil/mock/query/deployment.go (1)

14-16: Unused field: codec is never referenced.

Similar to MarketQuery, the codec field is stored but never used. Consider removing it or documenting its intended future use.

🔎 Proposed fix to remove unused field
 type DeploymentQuery struct {
-	codec codec.Codec
 }
 
-func NewDeploymentQuery(codec codec.Codec) *DeploymentQuery {
-	return &DeploymentQuery{
-		codec: codec,
-	}
+func NewDeploymentQuery(codec codec.Codec) *DeploymentQuery {
+	return &DeploymentQuery{}
 }
ts/test/util/mockServer.ts (1)

111-177: Complex cleanup logic in stop() function.

The stop() implementation handles multiple edge cases (already exited, timeout, kill failures) with proper stream cleanup. While comprehensive, the nested promise construction and multiple state checks add complexity.

The implementation appears correct, but consider adding inline comments explaining the timeout/SIGKILL escalation pattern for future maintainers.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 58d578a and 0a33fbf.

📒 Files selected for processing (8)
  • go/testutil/mock/cmd/server/main.go
  • go/testutil/mock/helper.go
  • go/testutil/mock/query/deployment.go
  • go/testutil/mock/query/market.go
  • go/testutil/mock/server.go
  • go/testutil/mock/server_test.go
  • ts/test/functional/deployments.spec.ts
  • ts/test/util/mockServer.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • go/testutil/mock/helper.go
🧰 Additional context used
🧬 Code graph analysis (4)
ts/test/functional/deployments.spec.ts (2)
ts/test/util/mockServer.ts (1)
  • startMockServer (11-208)
ts/test/util/createGatewayTxClient.ts (1)
  • createGatewayTxClient (33-250)
go/testutil/mock/server.go (4)
go/sdkutil/encoding.go (2)
  • EncodingConfig (17-23)
  • MakeEncodingConfig (26-68)
go/testutil/mock/query/deployment.go (1)
  • NewDeploymentQuery (18-22)
go/testutil/mock/query/market.go (1)
  • NewMarketQuery (18-22)
go/testutil/mock/tx/service.go (1)
  • NewService (19-21)
go/testutil/mock/cmd/server/main.go (1)
go/testutil/mock/server.go (2)
  • NewServer (48-116)
  • Config (43-46)
go/testutil/mock/server_test.go (1)
go/testutil/mock/helper.go (1)
  • StartMockServer (8-28)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: test-functional-ts
  • GitHub Check: coverage
  • GitHub Check: test
  • GitHub Check: proto
  • GitHub Check: go
🔇 Additional comments (7)
go/testutil/mock/cmd/server/main.go (1)

14-36: LGTM!

The CLI implementation is straightforward and handles the server lifecycle correctly with proper signal handling and error propagation.

go/testutil/mock/server_test.go (1)

14-47: LGTM!

The test provides solid coverage of the mock server's basic HTTP gateway functionality, including response parsing and structure validation.

ts/test/functional/deployments.spec.ts (2)

80-96: LGTM: Conditional tx client construction.

The SDK construction now properly handles the optional wallet by only creating a tx client when a wallet is provided, avoiding the null signer hazard flagged in previous reviews.


187-189: No action needed—BinaryWriter from @bufbuild/protobuf/wire is the correct type for this ts-proto generated encode API.

The current usage is compatible and idiomatic. The ts-proto generated code explicitly accepts BinaryWriter as the writer parameter and this integration is working correctly as evidenced by the test validation logic.

Likely an incorrect or invalid review comment.

ts/test/util/mockServer.ts (3)

11-40: LGTM: Server spawning logic with environment-based binary selection.

The implementation correctly determines whether to use a pre-built binary (via MOCK_SERVER_BIN) or fall back to go run, with appropriate vendor mode detection.


78-98: LGTM: Proper async error handling.

The error handler now correctly stores the error in spawnError instead of throwing synchronously, and the polling loop checks for this error and propagates it through the async flow. This addresses the critical issue from previous reviews.


189-206: LGTM: Proper cleanup in error paths.

The finally block ensures that the process is terminated and resources are cleaned up even when errors occur during startup, preventing resource leaks.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
go/testutil/mock/server.go (1)

319-319: Remove "BROADCAST_MODE_UNSPECIFIED_VALUE" as previously requested.

This case was flagged in a previous review as non-existent. The correct enum value is "BROADCAST_MODE_UNSPECIFIED" without the "_VALUE" suffix. Since both map to the same enum value, this case should be removed.

🔎 Proposed fix
 	switch strings.ToUpper(modeStr) {
-	case "BROADCAST_MODE_UNSPECIFIED", "BROADCAST_MODE_UNSPECIFIED_VALUE":
+	case "BROADCAST_MODE_UNSPECIFIED":
 		return txv1beta1.BroadcastMode_BROADCAST_MODE_UNSPECIFIED
 	case "BROADCAST_MODE_BLOCK":
 		return txv1beta1.BroadcastMode_BROADCAST_MODE_BLOCK

Based on learnings, this issue was identified in a previous review but not yet addressed.

🧹 Nitpick comments (3)
go/testutil/mock/server_test.go (2)

22-22: Consider removing the sleep or adding explicit gateway readiness check.

The time.Sleep(100 * time.Millisecond) after server.Start() appears to be waiting for the gateway to be ready. While Start() already waits for gRPC readiness via waitForGRPCReady(), the gateway server starts non-blocking. Consider either:

  1. Removing the sleep if Start() guarantees both servers are ready
  2. Adding an explicit gateway readiness check (e.g., retry loop) instead of a fixed sleep
🔎 Option 2: Replace sleep with readiness check
-	time.Sleep(100 * time.Millisecond)
-
 	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
 	defer cancel()

 	url := server.GatewayURL() + "/akash/deployment/v1beta4/deployments/list"
-	req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
-	require.NoError(t, err)
-
-	resp, err := http.DefaultClient.Do(req)
-	require.NoError(t, err)
+	
+	// Retry until gateway is ready or timeout
+	var resp *http.Response
+	var err error
+	for i := 0; i < 10; i++ {
+		req, reqErr := http.NewRequestWithContext(ctx, "GET", url, nil)
+		require.NoError(t, reqErr)
+		
+		resp, err = http.DefaultClient.Do(req)
+		if err == nil {
+			break
+		}
+		time.Sleep(50 * time.Millisecond)
+	}
+	require.NoError(t, err)
 	defer resp.Body.Close()

46-52: Simplify the deployments field validation.

The validation logic is functional but can be simplified. The require.GreaterOrEqual(t, len(deployments), 0) assertion is always true for a slice, and the conditional logic is more complex than necessary.

🔎 Simplified validation
-	if deployments, ok := response["deployments"].([]interface{}); ok {
-		t.Logf("Deployments array length: %d", len(deployments))
-		require.GreaterOrEqual(t, len(deployments), 0)
-	} else {
-		t.Logf("Deployments field type: %T, value: %+v", response["deployments"], response["deployments"])
-		require.Contains(t, response, "deployments", "Response should contain 'deployments' field")
-	}
+	require.Contains(t, response, "deployments", "Response should contain 'deployments' field")
+	t.Logf("Deployments field type: %T, value: %+v", response["deployments"], response["deployments"])
go/testutil/mock/server.go (1)

367-367: Consider using GracefulStop() instead of Stop().

A previous review suggested using GracefulStop() for graceful server shutdown. The current code uses Stop(), which forcefully terminates active RPCs. While Stop() may be faster for test teardown, GracefulStop() is generally preferred for proper cleanup, allowing in-flight RPCs to complete.

🔎 Use GracefulStop()
 	if s.grpcSrv != nil {
-		s.grpcSrv.Stop()
+		s.grpcSrv.GracefulStop()
 	}

Based on learnings, a previous review recommended this change for proper graceful shutdown.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0a33fbf and f7bd889.

📒 Files selected for processing (2)
  • go/testutil/mock/server.go
  • go/testutil/mock/server_test.go
🧰 Additional context used
🧬 Code graph analysis (2)
go/testutil/mock/server_test.go (1)
go/testutil/mock/server.go (2)
  • NewServer (47-85)
  • Config (42-45)
go/testutil/mock/server.go (4)
go/sdkutil/encoding.go (2)
  • EncodingConfig (17-23)
  • MakeEncodingConfig (26-68)
go/testutil/mock/query/deployment.go (2)
  • DeploymentQuery (14-16)
  • NewDeploymentQuery (18-22)
go/testutil/mock/query/market.go (2)
  • MarketQuery (14-16)
  • NewMarketQuery (18-22)
go/testutil/mock/tx/service.go (1)
  • NewService (19-21)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: test
  • GitHub Check: test-functional-ts
  • GitHub Check: coverage
  • GitHub Check: go
  • GitHub Check: proto
🔇 Additional comments (3)
go/testutil/mock/server.go (3)

173-202: LGTM! Solid implementation of readiness check.

The exponential backoff with timeout and blocking dial effectively addresses the race condition concern from previous reviews. The implementation properly waits for the gRPC server to be ready before proceeding.


211-254: LGTM! Consistent response serialization.

The simulate handler correctly uses runtime.ForwardResponseMessage for response serialization, addressing the serialization consistency concern from previous reviews. Error handling is also consistent throughout.


256-303: LGTM! Consistent with simulate handler.

The broadcast handler uses the same runtime.ForwardResponseMessage pattern as the simulate handler, ensuring consistent JSON serialization across both endpoints.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
go/testutil/mock/server.go (1)

380-382: Remove non-standard "BROADCAST_MODE_UNSPECIFIED_VALUE" from switch case.

As noted in a previous review, "BROADCAST_MODE_UNSPECIFIED_VALUE" is not a valid protobuf enum string. The standard naming uses just "BROADCAST_MODE_UNSPECIFIED" without the "_VALUE" suffix. Since both map to the same enum value anyway, the extra case is unnecessary.

🔎 Proposed fix
 switch strings.ToUpper(modeStr) {
-case "BROADCAST_MODE_UNSPECIFIED", "BROADCAST_MODE_UNSPECIFIED_VALUE":
+case "BROADCAST_MODE_UNSPECIFIED":
 	return txv1beta1.BroadcastMode_BROADCAST_MODE_UNSPECIFIED
🧹 Nitpick comments (2)
go/testutil/mock/server.go (2)

284-285: Consider removing redundant context wrapping.

The context.WithCancel(r.Context()) is unnecessary since r.Context() already handles request lifecycle and cancellation. While the defer cancel() follows best practice for avoiding leaks, the wrapping adds no value here.

🔎 Proposed simplification
 s.gatewayMux.Handle("POST", broadcastPattern, func(w http.ResponseWriter, r *http.Request, pathParams map[string]string) {
-	ctx, cancel := context.WithCancel(r.Context())
-	defer cancel()
+	ctx := r.Context()

 	var jsonReq map[string]interface{}

Then use ctx throughout the handler as before.


341-356: Debug endpoint uses different marshaler than other handlers.

This handler uses jsonpb.Marshaler directly while other handlers use runtime.ForwardResponseMessage. For a debug endpoint this is acceptable, but for consistency you could use the same pattern. This is optional since it's only used for debugging.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 21d78f3 and 35a2be5.

📒 Files selected for processing (2)
  • go/testutil/mock/server.go
  • ts/test/functional/deployments.spec.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • ts/test/functional/deployments.spec.ts
🧰 Additional context used
🧬 Code graph analysis (1)
go/testutil/mock/server.go (4)
go/sdkutil/encoding.go (2)
  • EncodingConfig (17-23)
  • MakeEncodingConfig (26-68)
go/testutil/mock/query/deployment.go (2)
  • DeploymentQuery (14-16)
  • NewDeploymentQuery (18-22)
go/testutil/mock/query/market.go (2)
  • MarketQuery (14-16)
  • NewMarketQuery (18-22)
go/testutil/mock/tx/service.go (1)
  • NewService (19-21)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: test
  • GitHub Check: coverage
  • GitHub Check: test-functional-ts
  • GitHub Check: proto
  • GitHub Check: go
🔇 Additional comments (7)
go/testutil/mock/server.go (7)

52-94: LGTM!

Constructor properly initializes the server with sensible defaults, sets up the encoding configuration, registers gRPC services, and handles errors appropriately with context cleanup.


96-136: LGTM!

Good separation of concerns with dedicated functions for codec setup, gRPC service registration, and gateway handler registration. The JSONPb marshaler configuration with OrigName: true and EmitDefaults: true ensures consistent JSON output.


198-227: LGTM!

The readiness check with exponential backoff (10ms to 500ms) and an overall 5-second timeout is a robust approach that addresses timing variability across different systems.


236-279: LGTM!

The simulate handler correctly uses runtime.ForwardResponseMessage for consistent response serialization across all gateway handlers. Transaction validation is properly integrated.


394-419: LGTM!

The validation logic properly decodes transactions, validates messages that implement HasValidateBasic, and captures deployment messages for the debug endpoint. The empty tx_bytes check is appropriate for a mock server context.


429-447: LGTM!

The Stop() method properly implements shutdown with context cancellation, gRPC server stop, gateway shutdown with timeout, connection cleanup, and errgroup wait. This addresses the previous graceful shutdown concern.


364-372: Use RLock() for read operations and consider deep copying or using proto.Clone().

The shallow copy at line 370 creates a surface-level copy, but MsgCreateDeployment contains slices (Groups and Hash) that will still reference the same backing arrays as the original. If the returned value is ever modified, it will affect the internal state of s.lastDeployment.

Additionally, since this is a read-only operation, use RLock() instead of Lock() to allow concurrent readers and improve performance.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (3)
ts/test/functional/deployments.spec.ts (3)

11-11: Verify BinaryWriter compatibility with ts-proto encode APIs.

A past review flagged that BinaryWriter from @bufbuild/protobuf/wire may be incompatible with ts-proto style encode methods. However, the same pattern is used in createGatewayTxClient.ts, suggesting this is intentional. Please confirm this works correctly with the generated proto types in use.

Also applies to: 223-226


228-229: Consider snapshot testing for encoding verification.

Per past review feedback, hardcoded base64 expectations are brittle. Jest's toMatchSnapshot() would be more maintainable while still catching unintended changes.

🔎 Suggested approach
-    const expectedBase64 = "CjIKLWFrYXNoMXRlc3QxMjM0NTY3ODlhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ehDSCRJcCgp0ZXN0LWdyb3VwEgIKABpKCjcIARIHCgUKAzEwMBoNCgsKCTEzNDIxNzcyOCIUCgRtYWluEgwKCjIxNDc0ODM2NDgqBQoDCgEwEAEaDQoEdWFrdBIFMTAwMDAaBAECAwQiEQoPCgR1YWt0Egc1MDAwMDAw";
-    expect(base64Encoded).toBe(expectedBase64);
+    expect(base64Encoded).toMatchSnapshot();

163-165: Conditional assertion reduces test reliability.

The if (response?.pagination) makes this assertion optional. Per past review feedback, conditional assertions should be avoided. Either expect pagination to always be present or remove this check entirely.

🔎 Suggested fix
-    if (response?.pagination) {
-      expect(response.pagination).toHaveProperty("total");
-    }
+    // Mock server may not return pagination - if this is expected behavior, remove this block
+    // Otherwise, always assert: expect(response.pagination).toBeDefined();
🧹 Nitpick comments (3)
ts/test/functional/deployments.spec.ts (3)

88-101: Misleading function name: createInvalidDeployment creates a valid deployment by default.

The function creates a structurally valid deployment message. The "invalid" aspect only applies when specific overrides are passed (e.g., empty groups, empty hash). Consider renaming to createTestDeployment for clarity.

🔎 Suggested rename
-const createInvalidDeployment = (
+const createTestDeployment = (
   owner: string,
   dseq: number,
   overrides: Partial<MsgCreateDeployment> = {}
 ): MsgCreateDeployment => ({

Then update all usages accordingly.


375-375: Provider fallback to owner may mask HD path issues.

Using accounts[1] ?? accounts[0] silently falls back to the same account if the second HD path fails. This could hide wallet configuration issues. Consider asserting accounts[1] is defined.

🔎 Suggested assertion
       const owner = accounts[0];
-      const provider = accounts[1] ?? accounts[0];
+      const provider = accounts[1];
+      if (!provider) {
+        throw new Error("Expected second account from HD wallet");
+      }

42-66: Unused helper functions: toSnake and normalizeValue.

These functions are defined but never used in the file. Consider removing them to reduce dead code, or if they're intended for future use, add a TODO comment.

🔎 Verification script
#!/bin/bash
# Verify these functions are not used elsewhere
rg -n "toSnake|normalizeValue" ts/test/functional/deployments.spec.ts | head -20
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 35a2be5 and a62a553.

📒 Files selected for processing (2)
  • go/testutil/mock/server.go
  • ts/test/functional/deployments.spec.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • go/testutil/mock/server.go
🧰 Additional context used
🧬 Code graph analysis (1)
ts/test/functional/deployments.spec.ts (2)
ts/test/util/mockServer.ts (1)
  • startMockServer (11-208)
ts/test/util/createGatewayTxClient.ts (1)
  • createGatewayTxClient (33-250)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: test-functional-ts
  • GitHub Check: coverage
  • GitHub Check: test
  • GitHub Check: proto
  • GitHub Check: go
🔇 Additional comments (5)
ts/test/functional/deployments.spec.ts (5)

31-34: LGTM - Standard test mnemonic usage.

Using the well-known BIP39 test mnemonic is appropriate for functional tests against a mock server.


116-132: LGTM - Clean SDK factory implementation.

The createTestSDK function properly handles the optional wallet case, only attaching txClient when a wallet is provided. This addresses previous review feedback about avoiding null as any for the signer.


239-319: LGTM - Comprehensive validation test coverage.

Good test coverage for deployment validation edge cases: empty groups, empty hash, invalid hash length, and negative price. The use of rejects.toThrow() with regex patterns is appropriate.


564-611: LGTM - Thorough broadcast verification.

Good test coverage for the SYNC broadcast flow: fee estimation, signing, broadcasting, and verifying the response structure including tx hash, height, and gas metrics.


613-681: LGTM - Good market operations coverage.

Tests for lease creation and bid closing properly verify Go-decoded responses. The snake_case field expectations (bid_id, dseq) correctly match Go's JSON serialization.

Comment on lines 683 to 750
it("handles multi-message tx with deployment and bid", async () => {
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(TEST_MNEMONIC, {
prefix: "akash",
hdPaths: [makeCosmoshubPath(0), makeCosmoshubPath(1)],
});
const accounts = await wallet.getAccounts();
const owner = accounts[0];
const provider = accounts[1] ?? accounts[0];
const sdk = createTestSDK(wallet);

const deployment = createInvalidDeployment(owner.address, 111111, {
hash: new Uint8Array(Array.from({ length: 32 }, (_, i) => i + 50)),
groups: [{
name: "multi-msg-test",
requirements: { signedBy: { allOf: [], anyOf: [] }, attributes: [] },
resources: [{
resource: {
id: 1,
cpu: { units: { val: new TextEncoder().encode("100") }, attributes: [] },
memory: { quantity: { val: new TextEncoder().encode("134217728") }, attributes: [] },
storage: [{ name: "main", quantity: { val: new TextEncoder().encode("1073741824") }, attributes: [] }],
gpu: { units: { val: new TextEncoder().encode("0") }, attributes: [] },
endpoints: [],
},
count: 1,
price: { denom: "uakt", amount: "2000" },
}],
}],
});

await sdk.akash.deployment.v1beta4.createDeployment(deployment, { memo: "deployment in multi-msg" });

const baseGroup = createBaseResourceGroup();
const resources = baseGroup.resources[0]?.resource;
if (!resources) throw new Error("missing base resources");

const bid: MsgCreateBid = {
id: {
owner: owner.address,
provider: provider.address,
dseq: Long.fromNumber(111111),
gseq: 1,
oseq: 1,
bseq: 0,
},
price: { denom: "uakt", amount: "0.0015" },
deposit: {
amount: { denom: "uakt", amount: "5000000" },
sources: [Source.balance],
},
resourcesOffer: [{ resources, count: 1 }],
};

await sdk.akash.market.v1beta5.createBid(bid, { memo: "bid in multi-msg" });

const deploymentRes = await fetch(`${mockServer.gatewayUrl}/mock/last-deployment`);
expect(deploymentRes.ok).toBe(true);
const decodedDeployment = await deploymentRes.json();
expect(decodedDeployment?.id?.owner).toBe(owner.address);
expect(decodedDeployment?.id?.dseq).toBe("111111");

const bidRes = await fetch(`${mockServer.gatewayUrl}/mock/last-bid`);
expect(bidRes.ok).toBe(true);
const decodedBid = await bidRes.json();
expect(decodedBid?.id?.owner).toBe(owner.address);
expect(decodedBid?.id?.dseq).toBe("111111");
expect(normalizeDec(decodedBid?.price?.amount as string)).toBe("0.0015");
});
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Test doesn't actually verify multi-message transaction batching.

The test name claims "handles multi-message tx with deployment and bid" but sends two separate transactions (lines 713 and 736) rather than batching both messages into a single transaction. For true multi-message testing, use txClient.sign() and txClient.broadcast() directly with an array containing both messages.

🔎 Suggested approach for true multi-message test
const messages = [
  { typeUrl: "/akash.deployment.v1beta4.MsgCreateDeployment", value: deployment },
  { typeUrl: "/akash.market.v1beta5.MsgCreateBid", value: bid },
];

const fee = await txClient.estimateFee(messages, "multi-msg test");
const signed = await txClient.sign(messages, fee, "multi-msg test");
const result = await txClient.broadcast(signed);

// Verify both messages were processed in single tx
expect(result.code).toBe(0);
🤖 Prompt for AI Agents
In ts/test/functional/deployments.spec.ts around lines 683 to 750 the test name
claims a multi-message transaction but the code sends two separate txs; replace
the two separate createDeployment/createBid calls with a single tx flow: build
an array of two messages (deployment and bid) using the correct typeUrls, use
the tx client to estimate fee, call txClient.sign(...) with the messages and
memo, then txClient.broadcast(...) to send them in one transaction, assert the
broadcast result indicates success (code 0) and then verify the deployment and
bid effects (mock endpoints) as before.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (3)
ts/test/functional/deployments.spec.ts (3)

11-11: Remove incompatible BinaryWriter import.

BinaryWriter from @bufbuild/protobuf/wire is incompatible with ts-proto's encode/decode methods (which expect protobufjs Writer or create their own). Lines 223-225 use this writer incorrectly.

Based on past review comments, the fix is to remove this import and let ts-proto manage its own writer internally.


223-229: Fix BinaryWriter usage and hardcoded base64 expectation.

Lines 223-225 use the incompatible BinaryWriter (see line 11 comment). Additionally, the hardcoded base64 string at line 228 makes the test brittle.

As noted in past reviews, ts-proto's encode should be called without an external writer, or use jest snapshots: expect(base64Encoded).toMatchSnapshot().


683-750: Test doesn't verify true multi-message transaction batching.

Despite the test name claiming "handles multi-message tx", lines 735-736 send two separate transactions rather than batching both messages into a single transaction. The comment at line 734 acknowledges this workaround.

As noted in past reviews, true multi-message testing would require:

const messages = [
  { typeUrl: "/akash.deployment.v1beta4.MsgCreateDeployment", value: deployment },
  { typeUrl: "/akash.market.v1beta5.MsgCreateBid", value: bid },
];
const fee = await txClient.estimateFee(messages, "multi-msg test");
const signed = await txClient.sign(messages, fee, "multi-msg test");
const result = await txClient.broadcast(signed);

If DecCoin encoding issues prevent this, consider renaming the test to reflect the actual behavior (e.g., "handles deployment and bid in separate transactions") or add a separate multi-message test with compatible message types.

🧹 Nitpick comments (1)
ts/test/functional/deployments.spec.ts (1)

88-101: Consider renaming createInvalidDeployment to createTestDeployment.

The function name implies the deployment is always invalid, but it actually creates deployments that may be valid or invalid depending on the overrides parameter. A more accurate name would be createTestDeployment or createDeployment.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a62a553 and 7485579.

📒 Files selected for processing (1)
  • ts/test/functional/deployments.spec.ts
🧰 Additional context used
🧬 Code graph analysis (1)
ts/test/functional/deployments.spec.ts (2)
ts/test/util/mockServer.ts (1)
  • startMockServer (11-208)
ts/test/util/createGatewayTxClient.ts (1)
  • createGatewayTxClient (33-250)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: coverage
  • GitHub Check: go
  • GitHub Check: proto
  • GitHub Check: test-functional-ts
  • GitHub Check: test
🔇 Additional comments (4)
ts/test/functional/deployments.spec.ts (4)

135-181: LGTM: Query tests are well-structured.

The query tests properly verify response structure, handle optional pagination, and confirm SDK module availability.


239-562: LGTM: Comprehensive transaction validation coverage.

The validation tests thoroughly cover error conditions (empty groups, invalid hash, negative price) and decimal price precision edge cases (fractional, 18-decimal, zero, very small). The Go interop verification via mock endpoints is appropriate.


564-611: LGTM: Broadcast test correctly verifies SYNC mode transaction flow.

The test properly demonstrates the sign-and-broadcast flow with appropriate assertions on transaction hash, height, and gas metrics.


613-681: LGTM: Lease and bid operations properly verified.

Both tests correctly construct multi-account messages and verify Go interop via mock endpoints.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants