Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit68fa375

Browse files
committed
Add tests
1 parente120cb5 commit68fa375

File tree

4 files changed

+531
-102
lines changed

4 files changed

+531
-102
lines changed

‎src/remote/sshProcess.ts‎

Lines changed: 15 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,6 @@ export interface NetworkInfo {
2020
using_coder_connect:boolean;
2121
}
2222

23-
/**
24-
* Process information from find-process.
25-
*/
26-
interfaceProcessInfo{
27-
pid:number;
28-
name:string;
29-
cmd:string;
30-
}
31-
3223
/**
3324
* Options for creating an SshProcessMonitor.
3425
*/
@@ -44,27 +35,6 @@ export interface SshProcessMonitorOptions {
4435
remoteSshExtensionId:string;
4536
}
4637

47-
/**
48-
* Checks if a process is an actual SSH process (not a shell wrapper).
49-
* Filters out processes like "sh -c ... | ssh ..." where ssh appears mid-command.
50-
*/
51-
functionisActualSshProcess(p:ProcessInfo):boolean{
52-
// Process name is exactly "ssh" or "ssh.exe"
53-
if(p.name==="ssh"||p.name==="ssh.exe"){
54-
returntrue;
55-
}
56-
// Command starts with ssh binary (not piped through shell)
57-
if(/^(ssh|ssh\.exe)\s/i.test(p.cmd)){
58-
returntrue;
59-
}
60-
// Command starts with full path to ssh (Unix or Windows)
61-
// e.g., "/usr/bin/ssh " or "C:\Program Files\OpenSSH\ssh.exe "
62-
if(/^[\w/\\:.-]+([/\\])ssh(\.exe)?\s/i.test(p.cmd)){
63-
returntrue;
64-
}
65-
returnfalse;
66-
}
67-
6838
/**
6939
* Finds the Remote SSH extension's log file path.
7040
*/
@@ -139,6 +109,7 @@ export class SshProcessMonitor implements vscode.Disposable {
139109
privatecurrentPid:number|undefined;
140110
privatelogFilePath:string|undefined;
141111
privatependingTimeout:NodeJS.Timeout|undefined;
112+
privatelastStaleSearchTime=0;
142113

143114
privateconstructor(options:SshProcessMonitorOptions){
144115
this.options={
@@ -216,7 +187,7 @@ export class SshProcessMonitor implements vscode.Disposable {
216187
while(!this.disposed){
217188
attempt++;
218189

219-
if(attempt%5===0){
190+
if(attempt%10===0){
220191
logger.debug(
221192
`SSH process search attempt${attempt} for host:${sshHost}`,
222193
);
@@ -231,15 +202,6 @@ export class SshProcessMonitor implements vscode.Disposable {
231202
return;
232203
}
233204

234-
// Fall back to hostname-based search
235-
// const pidByHost = await this.findSshProcessByHost();
236-
// if (pidByHost !== undefined) {
237-
// logger.info(`Found SSH process by hostname (PID: ${pidByHost})`);
238-
// this.setCurrentPid(pidByHost);
239-
// this.startMonitoring();
240-
// return;
241-
// }
242-
243205
awaitthis.delay(pollInterval);
244206
}
245207
}
@@ -262,6 +224,7 @@ export class SshProcessMonitor implements vscode.Disposable {
262224

263225
constlogContent=awaitfs.readFile(logPath,"utf8");
264226
this.options.logger.debug(`Read Remote SSH log file:${logPath}`);
227+
265228
constport=findPort(logContent);
266229
if(!port){
267230
returnundefined;
@@ -280,45 +243,6 @@ export class SshProcessMonitor implements vscode.Disposable {
280243
}
281244
}
282245

283-
/**
284-
* Attempts to find an SSH process by hostname.
285-
* Less accurate than port-based as multiple windows may connect to same host.
286-
* Returns the PID if found, undefined otherwise.
287-
*/
288-
privateasyncfindSshProcessByHost():Promise<number|undefined>{
289-
const{ sshHost, logger}=this.options;
290-
291-
try{
292-
// Find all processes with "ssh" in name
293-
constprocesses=awaitfind("name","ssh");
294-
constmatches=processes.filter(
295-
(p)=>p.cmd.includes(sshHost)&&isActualSshProcess(p),
296-
);
297-
298-
if(matches.length===0){
299-
returnundefined;
300-
}
301-
302-
constpreferred=matches.find(
303-
(p)=>p.name==="ssh"||p.name==="ssh.exe",
304-
);
305-
if(preferred){
306-
returnpreferred.pid;
307-
}
308-
309-
if(matches.length>1){
310-
logger.warn(
311-
`Found${matches.length} SSH processes for host, using first`,
312-
);
313-
}
314-
315-
returnmatches[0].pid;
316-
}catch(error){
317-
logger.debug(`Error searching for SSH process:${error}`);
318-
returnundefined;
319-
}
320-
}
321-
322246
/**
323247
* Updates the current PID and fires change events.
324248
*/
@@ -406,15 +330,20 @@ export class SshProcessMonitor implements vscode.Disposable {
406330
constageMs=Date.now()-stats.mtime.getTime();
407331

408332
if(ageMs>staleThreshold){
409-
logger.info(
333+
// Prevent tight loop: if we just searched due to stale, wait before searching again
334+
consttimeSinceLastSearch=Date.now()-this.lastStaleSearchTime;
335+
if(timeSinceLastSearch<staleThreshold){
336+
awaitthis.delay(staleThreshold-timeSinceLastSearch);
337+
continue;
338+
}
339+
340+
logger.debug(
410341
`Network info stale (${Math.round(ageMs/1000)}s old), searching for new SSH process`,
411342
);
412-
this.currentPid=undefined;
413-
this.statusBarItem.hide();
414-
this._onPidChange.fire(undefined);
415-
this.searchForProcess().catch((err)=>{
416-
logger.error("Error restarting SSH process search",err);
417-
});
343+
344+
// searchForProcess will update PID if a different process is found
345+
this.lastStaleSearchTime=Date.now();
346+
awaitthis.searchForProcess();
418347
return;
419348
}
420349

‎test/mocks/testHelpers.ts‎

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export class MockConfigurationProvider {
2929
get<T>(key:string,defaultValue:T):T;
3030
get<T>(key:string,defaultValue?:T):T|undefined{
3131
constvalue=this.config.get(key);
32-
returnvalue!==undefined ?(valueasT) :defaultValue;
32+
returnvalue===undefined ?defaultValue :(valueasT);
3333
}
3434

3535
/**
@@ -53,7 +53,7 @@ export class MockConfigurationProvider {
5353
return{
5454
get:vi.fn((key:string,defaultValue?:unknown)=>{
5555
constvalue=snapshot.get(getFullKey(key));
56-
returnvalue!==undefined ?value :defaultValue;
56+
returnvalue===undefined ?defaultValue :value;
5757
}),
5858
has:vi.fn((key:string)=>{
5959
returnsnapshot.has(getFullKey(key));
@@ -141,7 +141,7 @@ export class MockProgressReporter {
141141
* Use this to control user responses in tests.
142142
*/
143143
exportclassMockUserInteraction{
144-
privateresponses=newMap<string,string|undefined>();
144+
privatereadonlyresponses=newMap<string,string|undefined>();
145145
privateexternalUrls:string[]=[];
146146

147147
constructor(){
@@ -211,7 +211,7 @@ export class MockUserInteraction {
211211

212212
// Simple in-memory implementation of Memento
213213
exportclassInMemoryMementoimplementsvscode.Memento{
214-
privatestorage=newMap<string,unknown>();
214+
privatereadonlystorage=newMap<string,unknown>();
215215

216216
get<T>(key:string):T|undefined;
217217
get<T>(key:string,defaultValue:T):T;
@@ -235,9 +235,11 @@ export class InMemoryMemento implements vscode.Memento {
235235

236236
// Simple in-memory implementation of SecretStorage
237237
exportclassInMemorySecretStorageimplementsvscode.SecretStorage{
238-
privatesecrets=newMap<string,string>();
238+
privatereadonlysecrets=newMap<string,string>();
239239
privateisCorrupted=false;
240-
privatelisteners:Array<(e:vscode.SecretStorageChangeEvent)=>void>=[];
240+
privatereadonlylisteners:Array<
241+
(e:vscode.SecretStorageChangeEvent)=>void
242+
>=[];
241243

242244
onDidChange:vscode.Event<vscode.SecretStorageChangeEvent>=(listener)=>{
243245
this.listeners.push(listener);
@@ -350,3 +352,50 @@ export function createMockStream(
350352
destroy:vi.fn(),
351353
}asunknownasIncomingMessage;
352354
}
355+
356+
/**
357+
* Mock status bar that integrates with vscode.window.createStatusBarItem.
358+
* Use this to inspect status bar state in tests.
359+
*/
360+
exportclassMockStatusBar{
361+
text="";
362+
tooltip:string|vscode.MarkdownString="";
363+
backgroundColor:vscode.ThemeColor|undefined;
364+
color:string|vscode.ThemeColor|undefined;
365+
command:string|vscode.Command|undefined;
366+
accessibilityInformation:vscode.AccessibilityInformation|undefined;
367+
name:string|undefined;
368+
priority:number|undefined;
369+
alignment:vscode.StatusBarAlignment=vscode.StatusBarAlignment.Left;
370+
371+
readonlyshow=vi.fn();
372+
readonlyhide=vi.fn();
373+
readonlydispose=vi.fn();
374+
375+
constructor(){
376+
this.setupVSCodeMock();
377+
}
378+
379+
/**
380+
* Reset all status bar state
381+
*/
382+
reset():void{
383+
this.text="";
384+
this.tooltip="";
385+
this.backgroundColor=undefined;
386+
this.color=undefined;
387+
this.command=undefined;
388+
this.show.mockClear();
389+
this.hide.mockClear();
390+
this.dispose.mockClear();
391+
}
392+
393+
/**
394+
* Setup the vscode.window.createStatusBarItem mock
395+
*/
396+
privatesetupVSCodeMock():void{
397+
vi.mocked(vscode.window.createStatusBarItem).mockReturnValue(
398+
thisasunknownasvscode.StatusBarItem,
399+
);
400+
}
401+
}

‎test/mocks/vscode.runtime.ts‎

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -55,18 +55,28 @@ export class Uri {
5555
}
5656
}
5757

58-
// mini event
59-
constmakeEvent=<T>()=>{
60-
constlisteners=newSet<(e:T)=>void>();
61-
constevent=(listener:(e:T)=>void)=>{
62-
listeners.add(listener);
63-
return{dispose:()=>listeners.delete(listener)};
58+
/**
59+
* Mock EventEmitter that matches vscode.EventEmitter interface.
60+
*/
61+
exportclassEventEmitter<T>{
62+
privatereadonlylisteners=newSet<(e:T)=>void>();
63+
64+
event=(listener:(e:T)=>void)=>{
65+
this.listeners.add(listener);
66+
return{dispose:()=>this.listeners.delete(listener)};
6467
};
65-
return{ event,fire:(e:T)=>listeners.forEach((l)=>l(e))};
66-
};
6768

68-
constonDidChangeConfiguration=makeEvent<unknown>();
69-
constonDidChangeWorkspaceFolders=makeEvent<unknown>();
69+
fire(data:T):void{
70+
this.listeners.forEach((l)=>l(data));
71+
}
72+
73+
dispose():void{
74+
this.listeners.clear();
75+
}
76+
}
77+
78+
constonDidChangeConfiguration=newEventEmitter<unknown>();
79+
constonDidChangeWorkspaceFolders=newEventEmitter<unknown>();
7080

7181
exportconstwindow={
7282
showInformationMessage:vi.fn(),
@@ -83,6 +93,7 @@ export const window = {
8393
dispose:vi.fn(),
8494
clear:vi.fn(),
8595
})),
96+
createStatusBarItem:vi.fn(),
8697
};
8798

8899
exportconstcommands={
@@ -132,6 +143,7 @@ const vscode = {
132143
ExtensionMode,
133144
UIKind,
134145
Uri,
146+
EventEmitter,
135147
window,
136148
commands,
137149
workspace,

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp