Skip to content

Commit b9f4695

Browse files
Fix Tests to run properly on Windows (RooCodeInc#1963)
* fix: remove -p flag from test script to prevent git operation errors The -p flag in npm-run-all was causing tests to run in parallel, which led to 'Cannot log after tests are done' errors with git operations. These errors don't appear when running test:extension alone. The issue occurs because git-based tests create temporary directories and run async operations that can interfere with each other when executed in parallel. Running tests sequentially resolves this cleanly. While it might increase total test time slightly, it ensures more reliable and consistent test results. * refactor(terminal): improve mock streams and fix test issues - Create shell-specific mock streams (bash, cmd, pwsh) with proper line ending handling - Fix open handles in tests by properly managing timeouts - Standardize stderr redirection across all shell implementations using stdio option - Improve test reliability and output cleanliness * fix(tests): add skipVerification option to PowerShell tests to debug Linux issues * fix(tests): use explicit variable name in PowerShell test to fix Linux compatibility * Refactor terminal tests to use purpose-based approach instead of command mapping * Remove reference to non-existent test file * fix: use printf instead of echo -e for more consistent behavior across platforms * fix: use single quotes for PowerShell commands to preserve variables on Linux * Update code-qa workflow to run tests on both Windows and Ubuntu * fix: use platform-specific PowerShell command execution for Linux and Windows * Fix toggleToolAlwaysAllow to handle path normalization for cross-platform compatibility * Fix McpHub tests to handle normalized paths on Windows * Suppress console.error messages in McpHub tests * fix: make Bedrock ARN regex patterns Windows-compatible Fixed an issue where AWS Bedrock tests were timing out on Windows but passing on Linux. The root cause was path separator handling in regex patterns used for model ID extraction from ARNs. 1. Updated model ID extraction regex to handle both forward slashes (Linux) and backslashes (Windows) 2. Modified ARN matching regex to be platform-independent 3. Ensured consistent region prefix handling for all supported regions This change maintains functionality while ensuring cross-platform compatibility. * fix: make WorkspaceTracker test cross-platform compatible Fixed an issue where the WorkspaceTracker test 'should initialize with workspace files' was failing on Windows but passing on Linux. The problem was in the mock implementation of toRelativePath that only handled forward slashes. - Updated the toRelativePath mock to use path.relative which properly handles platform-specific path separators - Ensured all paths are converted to forward slashes for consistency in test assertions - The fix maintains cross-platform compatibility while preserving the test's intent * fix: make WorkspaceTracker tests cross-platform compatible Fixed cross-platform compatibility issues in the WorkspaceTracker tests that were causing failures on Windows but passing on Linux: 1. Updated the toRelativePath mock implementation to: - Use path.relative which properly handles platform-specific path separators - Convert paths to forward slashes for consistency in test assertions 2. Enhanced the 'should not update file paths' test to be platform-agnostic by: - Using more flexible assertions that don't depend on specific path formats - Checking file path length and content rather than exact string matches - Properly typed the test assertions to fix TypeScript errors These changes preserve the test intent while ensuring they run successfully across different operating systems. * fix: make McpHub tests cross-platform compatible Fixed cross-platform compatibility issues in the McpHub tests that were causing failures on Windows but passing on Linux: 1. Made the toggleToolAlwaysAllow tests more platform-agnostic by: - No longer relying on specific path formats which differ between Windows and Linux - Using the last write call instead of searching for a specific path string - Adding more robust assertions that verify structure instead of exact path matches - Properly handling array existence checks 2. These tests would fail on Windows because paths are formatted with backslashes instead of forward slashes, causing path equality checks to fail. The changes maintain test intent while ensuring cross-platform compatibility. * handle escaping of slash and quote * fix: ensure consistent line endings in git fallback strategy Fixed an issue where tests would fail on GitHub Windows runners but pass on local Windows machines due to line ending differences. The fix ensures consistent line ending handling by: 1. Normalizing CRLF to LF when reading files in the git fallback strategy 2. Disabling Git's automatic line ending conversion 3. Maintaining consistent line ending usage throughout text operations * feat: run tests sequentially on Windows, parallel otherwise
1 parent 5d99384 commit b9f4695

File tree

22 files changed

+1424
-103
lines changed

22 files changed

+1424
-103
lines changed

.changeset/curvy-cows-cry.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
"roo-cline": patch
3+
---
4+
5+
fix: ensure consistent line endings in git fallback strategy
6+
7+
Fixed a cross-platform issue where tests would fail on GitHub Windows runners but pass on local Windows machines due to line ending differences. The fix ensures consistent line ending handling by:
8+
9+
1. Normalizing CRLF to LF when reading files in the git fallback strategy
10+
2. Disabling Git's automatic line ending conversion using core.autocrlf setting
11+
3. Maintaining consistent line ending usage throughout the text operations

.github/workflows/code-qa.yml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,10 @@ jobs:
6262
run: npm run knip
6363

6464
test-extension:
65-
runs-on: ubuntu-latest
65+
runs-on: ${{ matrix.os }}
66+
strategy:
67+
matrix:
68+
os: [ubuntu-latest, windows-latest]
6669
steps:
6770
- name: Checkout code
6871
uses: actions/checkout@v4
@@ -77,7 +80,10 @@ jobs:
7780
run: npx jest --silent
7881

7982
test-webview:
80-
runs-on: ubuntu-latest
83+
runs-on: ${{ matrix.os }}
84+
strategy:
85+
matrix:
86+
os: [ubuntu-latest, windows-latest]
8187
steps:
8288
- name: Checkout code
8389
uses: actions/checkout@v4

jest.config.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ module.exports = {
1919
],
2020
},
2121
testMatch: ["**/__tests__/**/*.test.ts"],
22+
// Platform-specific test configuration
23+
testPathIgnorePatterns: [
24+
// Skip platform-specific tests based on environment
25+
...(process.platform === "win32" ? [".*\\.bash\\.test\\.ts$"] : [".*\\.cmd\\.test\\.ts$"]),
26+
// PowerShell tests are conditionally skipped in the test files themselves using the setupFilesAfterEnv
27+
],
2228
moduleNameMapper: {
2329
"^vscode$": "<rootDir>/src/__mocks__/vscode.js",
2430
"@modelcontextprotocol/sdk$": "<rootDir>/src/__mocks__/@modelcontextprotocol/sdk/index.js",
@@ -39,4 +45,5 @@ module.exports = {
3945
modulePathIgnorePatterns: [".vscode-test"],
4046
reporters: [["jest-simple-dot-reporter", {}]],
4147
setupFiles: ["<rootDir>/src/__mocks__/jest.setup.ts"],
48+
setupFilesAfterEnv: ["<rootDir>/src/integrations/terminal/__tests__/setupTerminalTests.ts"],
4249
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@
331331
"package": "npm-run-all -p build:webview build:esbuild check-types lint",
332332
"pretest": "npm run compile",
333333
"dev": "cd webview-ui && npm run dev",
334-
"test": "npm-run-all -p test:*",
334+
"test": "node scripts/run-tests.js",
335335
"test:extension": "jest",
336336
"test:webview": "cd webview-ui && npm run test",
337337
"prepare": "husky",

scripts/run-tests.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// run-tests.js
2+
const { execSync } = require("child_process")
3+
4+
if (process.platform === "win32") {
5+
execSync("npm-run-all test:*", { stdio: "inherit" })
6+
} else {
7+
execSync("npm-run-all -p test:*", { stdio: "inherit" })
8+
}

src/api/providers/__tests__/bedrock.test.ts

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -736,15 +736,39 @@ describe("AwsBedrockHandler", () => {
736736
awsRegion: "us-east-1",
737737
})
738738

739-
const mockStreamEvent = {
740-
trace: {
741-
promptRouter: {
742-
invokedModelId: "arn:aws:bedrock:us-east-1:123456789:foundation-model/default-model:0",
739+
// Create a spy on the getModelByName method
740+
const getModelByNameSpy = jest.spyOn(handler, "getModelByName")
741+
742+
// Mock the BedrockRuntimeClient.prototype.send method
743+
const mockSend = jest.spyOn(BedrockRuntimeClient.prototype, "send").mockImplementationOnce(async () => {
744+
return {
745+
stream: {
746+
[Symbol.asyncIterator]: async function* () {
747+
// First yield a trace event with invokedModelId
748+
yield {
749+
trace: {
750+
promptRouter: {
751+
invokedModelId:
752+
"arn:aws:bedrock:us-east-1:123456789:foundation-model/default-model:0",
753+
},
754+
},
755+
}
756+
// Then yield the metadata event (required to finish the stream processing)
757+
yield {
758+
metadata: {
759+
usage: {
760+
inputTokens: 10,
761+
outputTokens: 20,
762+
},
763+
},
764+
}
765+
},
743766
},
744-
},
745-
}
767+
}
768+
})
746769

747-
jest.spyOn(handler, "getModel").mockReturnValue({
770+
// Mock getModel to provide a test model config
771+
const getModelSpy = jest.spyOn(handler, "getModel").mockReturnValue({
748772
id: "default-model",
749773
info: {
750774
maxTokens: 4096,
@@ -754,7 +778,24 @@ describe("AwsBedrockHandler", () => {
754778
},
755779
})
756780

757-
await handler.createMessage("system prompt", [{ role: "user", content: "user message" }]).next()
781+
// Collect all yielded events to ensure completion
782+
const events = []
783+
const messageGenerator = handler.createMessage("system prompt", [{ role: "user", content: "user message" }])
784+
785+
// Use a timeout to prevent test hanging
786+
const timeout = 1000
787+
const startTime = Date.now()
788+
789+
while (true) {
790+
if (Date.now() - startTime > timeout) {
791+
throw new Error("Test timed out waiting for stream to complete")
792+
}
793+
794+
const result = await messageGenerator.next()
795+
events.push(result.value)
796+
797+
if (result.done) break
798+
}
758799

759800
expect(handler.getModel()).toEqual({
760801
id: "default-model",

src/api/providers/bedrock.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -289,15 +289,25 @@ export class AwsBedrockHandler extends BaseProvider implements SingleCompletionH
289289
if (streamEvent?.trace?.promptRouter?.invokedModelId) {
290290
try {
291291
const invokedModelId = streamEvent.trace.promptRouter.invokedModelId
292-
const modelMatch = invokedModelId.match(/\/([^\/]+)(?::|$)/)
292+
// Create a platform-independent regex that doesn't use forward slash as both delimiter and matcher
293+
const modelMatch = invokedModelId.match(new RegExp("[\\/\\\\]([^\\/\\\\]+)(?::|$)"))
293294
if (modelMatch && modelMatch[1]) {
294295
let modelName = modelMatch[1]
295296

296297
// Get a new modelConfig from getModel() using invokedModelId.. remove the region first
297298
let region = modelName.slice(0, 3)
298299

300+
// Check for all region prefixes (us., eu., and apac prefix)
299301
if (region === "us." || region === "eu.") modelName = modelName.slice(3)
302+
else if (modelName.startsWith("apac.")) modelName = modelName.slice(5)
300303
this.costModelConfig = this.getModelByName(modelName)
304+
305+
// Log successful model extraction to help with debugging
306+
logger.debug("Successfully extracted model from invokedModelId", {
307+
ctx: "bedrock",
308+
invokedModelId,
309+
extractedModelName: modelName,
310+
})
301311
}
302312

303313
// Handle metadata events for the promptRouter.
@@ -513,15 +523,19 @@ Please check:
513523

514524
// If custom ARN is provided, use it
515525
if (this.options.awsCustomArn) {
516-
// Extract the model name from the ARN
526+
// Extract the model name from the ARN using platform-independent regex
517527
const arnMatch = this.options.awsCustomArn.match(
518-
/^arn:aws:bedrock:([^:]+):(\d+):(inference-profile|foundation-model|provisioned-model)\/(.+)$/,
528+
new RegExp(
529+
"^arn:aws:bedrock:([^:]+):(\\d+):(inference-profile|foundation-model|provisioned-model|default-prompt-router|prompt-router)[/\\\\](.+)$",
530+
),
519531
)
520532

521533
let modelName = arnMatch ? arnMatch[4] : ""
522534
if (modelName) {
523535
let region = modelName.slice(0, 3)
536+
// Check for all region prefixes (us., eu., and apac prefix)
524537
if (region === "us." || region === "eu.") modelName = modelName.slice(3)
538+
else if (modelName.startsWith("apac.")) modelName = modelName.slice(5)
525539

526540
let modelData = this.getModelByName(modelName)
527541
modelData.id = this.options.awsCustomArn

src/core/diff/strategies/new-unified/edit-strategies.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,8 @@ export async function applyGitFallback(hunk: Hunk, content: string[]): Promise<E
157157
await git.init()
158158
await git.addConfig("user.name", "Temp")
159159
await git.addConfig("user.email", "[email protected]")
160+
// Prevent Git from automatically converting line endings
161+
await git.addConfig("core.autocrlf", "false")
160162

161163
const filePath = path.join(tmpDir.name, "file.txt")
162164

@@ -168,6 +170,7 @@ export async function applyGitFallback(hunk: Hunk, content: string[]): Promise<E
168170
.filter((change) => change.type === "context" || change.type === "add")
169171
.map((change) => change.originalLine || change.indent + change.content)
170172

173+
// Ensure consistent line endings (LF only) in all text operations
171174
const searchText = searchLines.join("\n")
172175
const replaceText = replaceLines.join("\n")
173176
const originalText = content.join("\n")
@@ -195,7 +198,9 @@ export async function applyGitFallback(hunk: Hunk, content: string[]): Promise<E
195198
await git.raw(["cherry-pick", "--minimal", replaceCommit.commit])
196199

197200
const newText = fs.readFileSync(filePath, "utf-8")
198-
const newLines = newText.split("\n")
201+
// Normalize line endings to LF before splitting
202+
const normalizedText = newText.replace(/\r\n/g, "\n")
203+
const newLines = normalizedText.split("\n")
199204
return {
200205
confidence: 1,
201206
result: newLines,
@@ -212,6 +217,8 @@ export async function applyGitFallback(hunk: Hunk, content: string[]): Promise<E
212217
await git.init()
213218
await git.addConfig("user.name", "Temp")
214219
await git.addConfig("user.email", "[email protected]")
220+
// Prevent Git from automatically converting line endings
221+
await git.addConfig("core.autocrlf", "false")
215222

216223
fs.writeFileSync(filePath, searchText)
217224
await git.add("file.txt")
@@ -237,7 +244,9 @@ export async function applyGitFallback(hunk: Hunk, content: string[]): Promise<E
237244
await git.raw(["cherry-pick", "--minimal", replaceHash])
238245

239246
const newText = fs.readFileSync(filePath, "utf-8")
240-
const newLines = newText.split("\n")
247+
// Normalize line endings to LF before splitting
248+
const normalizedText = newText.replace(/\r\n/g, "\n")
249+
const newLines = normalizedText.split("\n")
241250
return {
242251
confidence: 1,
243252
result: newLines,

src/extension.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ export async function activate(context: vscode.ExtensionContext) {
116116
registerTerminalActions(context)
117117

118118
// Allows other extensions to activate once Roo is ready.
119-
vscode.commands.executeCommand('roo-cline.activationCompleted');
119+
vscode.commands.executeCommand("roo-cline.activationCompleted")
120120

121121
// Implements the `RooCodeAPI` interface.
122122
return new API(outputChannel, provider)

0 commit comments

Comments
 (0)