Skip to content

Commit 4f4eb98

Browse files
authored
fix(tests): "Unable to read file 's3-read-test:..." #4252
Problem: Lots of "Unable to read file" noise in the test logs: FileViewerManager ✔ prompts if file size is greater than 4MB ✔ throws if the user cancels a download opens text files No file system provider found for resource 's3-edit-test:/us-west-2/bucket-name/big-image.jpg' ✔ opens a new editor if no document exists ✔ closes the read-only tab when opening in edit mode (70ms) Unable to read file 's3-read-test:/us-west-2/bucket-name/test1.txt' (Error): Error: Unable to read file 's3-read-test:/us-west-2/bucket-name/test1.txt' (Error) at h.doReadFileStream (vscode-file://…) at async p.doRead (vscode-file://…) at async p.readStream (vscode-file://…) at async wr.resolveFromFile (vscode-file://…) ✔ re-uses tabs in edit mode when opening as read-only ✔ can open in edit mode, showing a warning with two options Unable to read file 's3-edit-test:/us-west-2/bucket-name/test1.txt' (Error): Error: Unable to read file 's3-edit-test:/us-west-2/bucket-name/test1.txt' (Error) at h.doReadFileStream (vscode-file://…) at async p.doRead (vscode-file://…) at async p.readStream (vscode-file://…) at async wr.resolveFromFile (vscode-file://…) ✔ re-uses an editor if already opened, focusing it (75ms) Unable to read file 's3-read-test:/us-west-2/bucket-name/test1.txt' (Error): Error: Unable to read file 's3-read-test:/us-west-2/bucket-name/test1.txt' (Error) at h.doReadFileStream (vscode-file://…) at async p.doRead (vscode-file://…) at async p.readStream (vscode-file://…) at async wr.resolveFromFile (vscode-file://…) Solution: - Use one VirualFileSystem provider instead of re-creating for each test. - Use `fileViewerManager.closeEditors()` instead of `closeAllEditors()` (which is unreliable). - Remove the "case-insensitive" test because it's a vscode feature, we don't enhance it.
1 parent 3dba25e commit 4f4eb98

File tree

3 files changed

+44
-48
lines changed

3 files changed

+44
-48
lines changed

src/s3/commands/openFile.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,25 @@
66
import * as vscode from 'vscode'
77
import { localize } from '../../shared/utilities/vsCodeUtils'
88
import { S3FileNode } from '../explorer/s3FileNode'
9-
import { S3FileViewerManager } from '../fileViewerManager'
9+
import { S3FileViewerManager, S3Tab } from '../fileViewerManager'
1010
import { downloadFileAsCommand } from './downloadFileAs'
1111
import { telemetry } from '../../shared/telemetry/telemetry'
1212

1313
const sizeLimit = 50 * Math.pow(10, 6)
1414

15-
export async function openFileReadModeCommand(node: S3FileNode, manager: S3FileViewerManager): Promise<void> {
15+
export async function openFileReadModeCommand(
16+
node: S3FileNode,
17+
manager: S3FileViewerManager
18+
): Promise<S3Tab | undefined> {
1619
if (await isFileSizeValid(node.file.sizeBytes, node)) {
1720
return telemetry.s3_openEditor.run(() => manager.openInReadMode({ bucket: node.bucket, ...node.file }))
1821
}
1922
}
2023

21-
export async function editFileCommand(uriOrNode: vscode.Uri | S3FileNode, manager: S3FileViewerManager): Promise<void> {
24+
export async function editFileCommand(
25+
uriOrNode: vscode.Uri | S3FileNode,
26+
manager: S3FileViewerManager
27+
): Promise<S3Tab | undefined> {
2228
if (uriOrNode instanceof S3FileNode) {
2329
const size = uriOrNode.file.sizeBytes
2430

src/s3/fileViewerManager.ts

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,12 @@ export class S3FileViewerManager {
130130
this.disposables.push(this.registerTabCleanup())
131131
}
132132

133-
/**
134-
* Removes all active editors as well as any underlying files
135-
*/
133+
/** Disposes all active editors and underlying files. */
134+
public async closeEditors(): Promise<void> {
135+
await Promise.all([...Object.values(this.activeTabs).map(v => v?.dispose())])
136+
}
137+
138+
/** Disposes all active editors, underlying files, providers, and other resources. */
136139
public async dispose(): Promise<void> {
137140
await Promise.all([
138141
...Object.values(this.activeTabs).map(v => v?.dispose()),
@@ -177,8 +180,12 @@ export class S3FileViewerManager {
177180

178181
private async closeEditor(editor: vscode.TextEditor | undefined): Promise<void> {
179182
if (editor && !editor.document.isClosed) {
180-
await vscode.window.showTextDocument(editor.document, { preserveFocus: false })
181-
await vscode.commands.executeCommand('workbench.action.closeActiveEditor')
183+
await vscode.window.showTextDocument(editor.document, { preserveFocus: false }).then(
184+
r => vscode.commands.executeCommand('workbench.action.closeActiveEditor'),
185+
e => {
186+
getLogger().warn('S3FileViewer: showTextDocument failed to open: "%s"', editor.document.uri)
187+
}
188+
)
182189
}
183190
}
184191

@@ -209,7 +216,7 @@ export class S3FileViewerManager {
209216
*
210217
* @param file
211218
*/
212-
public async openInReadMode(file: S3File): Promise<void> {
219+
public async openInReadMode(file: S3File): Promise<S3Tab | undefined> {
213220
const contentType = mime.contentType(path.extname(file.name))
214221
const isTextDocument = contentType && mime.charset(contentType) === 'UTF-8'
215222

@@ -223,7 +230,7 @@ export class S3FileViewerManager {
223230
return this.openInEditMode(file)
224231
}
225232

226-
await this.createTab(file, TabMode.Read)
233+
return this.createTab(file, TabMode.Read)
227234
}
228235

229236
/**
@@ -232,7 +239,7 @@ export class S3FileViewerManager {
232239
*
233240
* @param uriOrFile to be opened
234241
*/
235-
public async openInEditMode(uriOrFile: vscode.Uri | S3File): Promise<void> {
242+
public async openInEditMode(uriOrFile: vscode.Uri | S3File): Promise<S3Tab | undefined> {
236243
const uri = uriOrFile instanceof vscode.Uri ? uriOrFile : this.fileToUri(uriOrFile, TabMode.Edit)
237244
const activeTab = await this.tryFocusTab(uri, uri.with({ scheme: this.schemes.read }))
238245
const file = activeTab?.file ?? uriOrFile
@@ -248,7 +255,7 @@ export class S3FileViewerManager {
248255
await activeTab?.dispose()
249256
void this.showEditNotification()
250257

251-
await this.createTab(file, TabMode.Edit)
258+
return this.createTab(file, TabMode.Edit)
252259
}
253260

254261
private registerProvider(file: S3File, uri: vscode.Uri): vscode.Disposable {
@@ -266,7 +273,7 @@ export class S3FileViewerManager {
266273
/**
267274
* Creates a new tab based on the mode
268275
*/
269-
private async createTab(file: S3File, mode: TabMode): Promise<void> {
276+
private async createTab(file: S3File, mode: TabMode): Promise<S3Tab | undefined> {
270277
if (!(await this.canContinueDownload(file))) {
271278
throw new CancellationError('user')
272279
}
@@ -291,6 +298,8 @@ export class S3FileViewerManager {
291298
}
292299
},
293300
}
301+
302+
return this.activeTabs[key]
294303
}
295304

296305
private async canContinueDownload(file: S3File): Promise<boolean> {

src/test/s3/util/fileViewerManager.test.ts

Lines changed: 16 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { VirtualFileSystem } from '../../../shared/virtualFilesystem'
1313
import { bufferToStream } from '../../../shared/utilities/streamUtilities'
1414
import { MockOutputChannel } from '../../mockOutputChannel'
1515
import { SeverityLevel } from '../../shared/vscode/message'
16-
import { assertTelemetry, assertTextEditorContains, closeAllEditors } from '../../testUtil'
16+
import { assertTelemetry, assertTextEditorContains } from '../../testUtil'
1717
import { PromptSettings } from '../../../shared/settings'
1818
import { stub } from '../../utilities/stubber'
1919
import { assertHasProps } from '../../../shared/utilities/tsUtils'
@@ -187,14 +187,14 @@ describe('FileViewerManager', function () {
187187
return window.visibleTextEditors.filter(e => e.document.fileName.endsWith(documentName))
188188
}
189189

190-
function registerFileSystemProviders(isCaseSensitive: boolean = true): vscode.Disposable[] {
190+
function registerFileSystemProviders(): vscode.Disposable[] {
191191
return [
192-
vscode.workspace.registerFileSystemProvider(editScheme, fs, { isCaseSensitive }),
193-
vscode.workspace.registerFileSystemProvider(readScheme, fs, { isReadonly: true, isCaseSensitive }),
192+
vscode.workspace.registerFileSystemProvider(editScheme, fs, { isCaseSensitive: true }),
193+
vscode.workspace.registerFileSystemProvider(readScheme, fs, { isReadonly: true, isCaseSensitive: true }),
194194
]
195195
}
196196

197-
beforeEach(function () {
197+
before(function () {
198198
s3 = createS3()
199199
fs = new VirtualFileSystem()
200200

@@ -207,18 +207,25 @@ describe('FileViewerManager', function () {
207207
})
208208

209209
afterEach(async function () {
210-
await closeAllEditors()
211-
vscode.Disposable.from(...disposables).dispose()
210+
await fileViewerManager.closeEditors()
211+
})
212+
213+
after(async function () {
214+
await vscode.Disposable.from(...disposables).dispose()
215+
await fileViewerManager.dispose()
212216
})
213217

214218
it('prompts if file size is greater than 4MB', async function () {
215-
void fileViewerManager.openInReadMode({ ...bigImage, bucket })
219+
// User can "Continue".
220+
const didOpen = fileViewerManager.openInReadMode({ ...bigImage, bucket })
216221
await getTestWindow()
217222
.waitForMessage(/File size is more than 4MB/)
218223
.then(message => message.selectItem(/Continue/))
224+
await (await didOpen)?.dispose()
219225
})
220226

221227
it('throws if the user cancels a download', async function () {
228+
// User can "Cancel".
222229
const didOpen = fileViewerManager.openInReadMode({ ...bigImage, bucket })
223230
await getTestWindow()
224231
.waitForMessage(/File size is more than 4MB/)
@@ -232,7 +239,7 @@ describe('FileViewerManager', function () {
232239
const textFile2Contents = Buffer.from('test2 contents', 'utf-8')
233240
const textFile2 = makeFile('test2.txt', textFile2Contents)
234241

235-
beforeEach(function () {
242+
before(function () {
236243
s3.addFile(textFile1)
237244
s3.addFile(textFile2)
238245
})
@@ -324,30 +331,4 @@ describe('FileViewerManager', function () {
324331
await assertTextEditorContains(upperCaseFileContent)
325332
})
326333
})
327-
328-
describe('file uri case insensitivity', function () {
329-
beforeEach(function () {
330-
vscode.Disposable.from(...disposables).dispose()
331-
// Case insensitive file system providers
332-
disposables = registerFileSystemProviders(false)
333-
})
334-
335-
it('opens an existing file since names are the same', async function () {
336-
// Create and assert content of file with lowercase name
337-
const lowerCaseFileContent = 'lowercaseContent'
338-
const lowerCaseFile = makeFile('file.txt', Buffer.from(lowerCaseFileContent, 'utf-8'))
339-
s3.addFile(lowerCaseFile)
340-
await fileViewerManager.openInReadMode({ ...lowerCaseFile, bucket })
341-
await assertTextEditorContains(lowerCaseFileContent)
342-
343-
// Create similarily named file, but with uppercase character
344-
const upperCaseFileContent = 'uppercaseContent'
345-
const upperCaseFile = makeFile('File.txt', Buffer.from(upperCaseFileContent, 'utf-8'))
346-
s3.addFile(upperCaseFile)
347-
348-
// Attempt to open uppercase file opens existing lowercase file instead
349-
await fileViewerManager.openInReadMode({ ...upperCaseFile, bucket })
350-
await assertTextEditorContains(lowerCaseFileContent)
351-
})
352-
})
353334
})

0 commit comments

Comments
 (0)