|
2 | 2 | import { it, afterEach, vi, expect } from "vitest" |
3 | 3 | import { SSHConfig } from "./sshConfig" |
4 | 4 |
|
5 | | -const sshFilePath = "~/.config/ssh" |
| 5 | +// This is not the usual path to ~/.ssh/config, but |
| 6 | +// setting it to a different path makes it easier to test |
| 7 | +// and makes mistakes abundantly clear. |
| 8 | +const sshFilePath = "/Path/To/UserHomeDir/.sshConfigDir/sshConfigFile" |
| 9 | +const sshTempFilePathExpr = `^/Path/To/UserHomeDir/.sshConfigDir/.sshConfigFile.vscode-coder-tmp.[a-z0-9]+$` |
6 | 10 |
|
7 | 11 | const mockFileSystem = { |
8 | 12 | mkdir: vi.fn(), |
@@ -42,11 +46,14 @@ Host coder-vscode--* |
42 | 46 |
|
43 | 47 | expect(mockFileSystem.readFile).toBeCalledWith(sshFilePath, expect.anything()) |
44 | 48 | expect(mockFileSystem.writeFile).toBeCalledWith( |
45 | | - expect.stringContaining(sshFilePath), |
| 49 | + expect.stringMatching(sshTempFilePathExpr), |
46 | 50 | expectedOutput, |
47 | | - expect.anything(), |
| 51 | + expect.objectContaining({ |
| 52 | + encoding: "utf-8", |
| 53 | + mode: 0o600, // Default mode for new files. |
| 54 | + }), |
48 | 55 | ) |
49 | | - expect(mockFileSystem.rename).toBeCalledWith(expect.stringContaining(sshFilePath + "."), sshFilePath) |
| 56 | + expect(mockFileSystem.rename).toBeCalledWith(expect.stringMatching(sshTempFilePathExpr), sshFilePath) |
50 | 57 | }) |
51 | 58 |
|
52 | 59 | it("creates a new file and adds the config", async () => { |
@@ -75,11 +82,14 @@ Host coder-vscode.dev.coder.com--* |
75 | 82 |
|
76 | 83 | expect(mockFileSystem.readFile).toBeCalledWith(sshFilePath, expect.anything()) |
77 | 84 | expect(mockFileSystem.writeFile).toBeCalledWith( |
78 | | - expect.stringContaining(sshFilePath), |
| 85 | + expect.stringMatching(sshTempFilePathExpr), |
79 | 86 | expectedOutput, |
80 | | - expect.anything(), |
| 87 | + expect.objectContaining({ |
| 88 | + encoding: "utf-8", |
| 89 | + mode: 0o600, // Default mode for new files. |
| 90 | + }), |
81 | 91 | ) |
82 | | - expect(mockFileSystem.rename).toBeCalledWith(expect.stringContaining(sshFilePath + "."), sshFilePath) |
| 92 | + expect(mockFileSystem.rename).toBeCalledWith(expect.stringMatching(sshTempFilePathExpr), sshFilePath) |
83 | 93 | }) |
84 | 94 |
|
85 | 95 | it("adds a new coder config in an existent SSH configuration", async () => { |
@@ -115,11 +125,11 @@ Host coder-vscode.dev.coder.com--* |
115 | 125 | UserKnownHostsFile /dev/null |
116 | 126 | # --- END CODER VSCODE dev.coder.com ---` |
117 | 127 |
|
118 | | - expect(mockFileSystem.writeFile).toBeCalledWith(expect.stringContaining(sshFilePath), expectedOutput, { |
| 128 | + expect(mockFileSystem.writeFile).toBeCalledWith(expect.stringMatching(sshTempFilePathExpr), expectedOutput, { |
119 | 129 | encoding: "utf-8", |
120 | 130 | mode: 0o644, |
121 | 131 | }) |
122 | | - expect(mockFileSystem.rename).toBeCalledWith(expect.stringContaining(sshFilePath + "."), sshFilePath) |
| 132 | + expect(mockFileSystem.rename).toBeCalledWith(expect.stringMatching(sshTempFilePathExpr), sshFilePath) |
123 | 133 | }) |
124 | 134 |
|
125 | 135 | it("updates an existent coder config", async () => { |
@@ -181,11 +191,11 @@ Host coder-vscode.dev-updated.coder.com--* |
181 | 191 | Host * |
182 | 192 | SetEnv TEST=1` |
183 | 193 |
|
184 | | - expect(mockFileSystem.writeFile).toBeCalledWith(expect.stringContaining(sshFilePath), expectedOutput, { |
| 194 | + expect(mockFileSystem.writeFile).toBeCalledWith(expect.stringMatching(sshTempFilePathExpr), expectedOutput, { |
185 | 195 | encoding: "utf-8", |
186 | 196 | mode: 0o644, |
187 | 197 | }) |
188 | | - expect(mockFileSystem.rename).toBeCalledWith(expect.stringContaining(sshFilePath + "."), sshFilePath) |
| 198 | + expect(mockFileSystem.rename).toBeCalledWith(expect.stringMatching(sshTempFilePathExpr), sshFilePath) |
189 | 199 | }) |
190 | 200 |
|
191 | 201 | it("does not remove deployment-unaware SSH config and adds the new one", async () => { |
@@ -228,11 +238,11 @@ Host coder-vscode.dev.coder.com--* |
228 | 238 | UserKnownHostsFile /dev/null |
229 | 239 | # --- END CODER VSCODE dev.coder.com ---` |
230 | 240 |
|
231 | | - expect(mockFileSystem.writeFile).toBeCalledWith(expect.stringContaining(sshFilePath), expectedOutput, { |
| 241 | + expect(mockFileSystem.writeFile).toBeCalledWith(expect.stringMatching(sshTempFilePathExpr), expectedOutput, { |
232 | 242 | encoding: "utf-8", |
233 | 243 | mode: 0o644, |
234 | 244 | }) |
235 | | - expect(mockFileSystem.rename).toBeCalledWith(expect.stringContaining(sshFilePath + "."), sshFilePath) |
| 245 | + expect(mockFileSystem.rename).toBeCalledWith(expect.stringMatching(sshTempFilePathExpr), sshFilePath) |
236 | 246 | }) |
237 | 247 |
|
238 | 248 | it("it does not remove a user-added block that only matches the host of an old coder SSH config", async () => { |
@@ -264,11 +274,11 @@ Host coder-vscode.dev.coder.com--* |
264 | 274 | UserKnownHostsFile /dev/null |
265 | 275 | # --- END CODER VSCODE dev.coder.com ---` |
266 | 276 |
|
267 | | - expect(mockFileSystem.writeFile).toBeCalledWith(expect.stringContaining(sshFilePath), expectedOutput, { |
| 277 | + expect(mockFileSystem.writeFile).toBeCalledWith(expect.stringMatching(sshTempFilePathExpr), expectedOutput, { |
268 | 278 | encoding: "utf-8", |
269 | 279 | mode: 0o644, |
270 | 280 | }) |
271 | | - expect(mockFileSystem.rename).toBeCalledWith(expect.stringContaining(sshFilePath + "."), sshFilePath) |
| 281 | + expect(mockFileSystem.rename).toBeCalledWith(expect.stringMatching(sshTempFilePathExpr), sshFilePath) |
272 | 282 | }) |
273 | 283 |
|
274 | 284 | it("throws an error if there is a missing end block", async () => { |
@@ -540,11 +550,11 @@ Host afterconfig |
540 | 550 | LogLevel: "ERROR", |
541 | 551 | }) |
542 | 552 |
|
543 | | - expect(mockFileSystem.writeFile).toBeCalledWith(expect.stringContaining(sshFilePath), expectedOutput, { |
| 553 | + expect(mockFileSystem.writeFile).toBeCalledWith(expect.stringMatching(sshTempFilePathExpr), expectedOutput, { |
544 | 554 | encoding: "utf-8", |
545 | 555 | mode: 0o644, |
546 | 556 | }) |
547 | | - expect(mockFileSystem.rename).toBeCalledWith(expect.stringContaining(sshFilePath + "."), sshFilePath) |
| 557 | + expect(mockFileSystem.rename).toBeCalledWith(expect.stringMatching(sshTempFilePathExpr), sshFilePath) |
548 | 558 | }) |
549 | 559 |
|
550 | 560 | it("override values", async () => { |
@@ -588,9 +598,12 @@ Host coder-vscode.dev.coder.com--* |
588 | 598 |
|
589 | 599 | expect(mockFileSystem.readFile).toBeCalledWith(sshFilePath, expect.anything()) |
590 | 600 | expect(mockFileSystem.writeFile).toBeCalledWith( |
591 | | - expect.stringContaining(sshFilePath), |
| 601 | + expect.stringMatching(sshTempFilePathExpr), |
592 | 602 | expectedOutput, |
593 | | - expect.anything(), |
| 603 | + expect.objectContaining({ |
| 604 | + encoding: "utf-8", |
| 605 | + mode: 0o600, // Default mode for new files. |
| 606 | + }), |
594 | 607 | ) |
595 | | - expect(mockFileSystem.rename).toBeCalledWith(expect.stringContaining(sshFilePath + "."), sshFilePath) |
| 608 | + expect(mockFileSystem.rename).toBeCalledWith(expect.stringMatching(sshTempFilePathExpr), sshFilePath) |
596 | 609 | }) |
0 commit comments