Skip to content

Commit 53c4caf

Browse files
committed
allow state insertion into empty documents
1 parent 897612e commit 53c4caf

File tree

2 files changed

+40
-23
lines changed

2 files changed

+40
-23
lines changed

src/handlers/ResourceHandler.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { ResponseError, ServerRequestHandler } from 'vscode-languageserver';
33
import { RequestHandler } from 'vscode-languageserver/node';
44
import { TopLevelSection } from '../context/ContextType';
55
import { getEntityMap } from '../context/SectionContextBuilder';
6+
import { CloudFormationFileType } from '../document/Document';
67
import { parseResourceTypeName } from '../resourceState/ResourceStateParser';
78
import {
89
ResourceTypesResult,
@@ -82,8 +83,18 @@ export function importResourceStateHandler(
8283
): RequestHandler<ResourceStateParams, ResourceStateResult, void> {
8384
return async (params: ResourceStateParams): Promise<ResourceStateResult> => {
8485
components.usageTracker.track(EventType.DidImportResources);
85-
if (!components.documentManager.get(params.textDocument.uri)?.isTemplate()) {
86-
throw new ResponseError(400, 'Must open CloudFormation template to import or clone resource state');
86+
const doc = components.documentManager.get(params.textDocument.uri);
87+
if (!doc) {
88+
const msg = `${params.purpose} failed: ${params.textDocument.uri} not found`;
89+
log.error(msg);
90+
throw new ResponseError(500, msg); // all open TextDocuments should be registered by protocol
91+
}
92+
93+
if (!doc.isTemplate() && doc.cfnFileType !== CloudFormationFileType.Empty) {
94+
throw new ResponseError(
95+
400,
96+
`${params.purpose} failed: ${params.textDocument.uri} is not a valid CloudFormation template`,
97+
);
8798
}
8899
return await components.resourceStateImporter.importResourceState(params);
89100
};

tst/unit/handlers/ResourceHandler.test.ts

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1+
import { stubInterface } from 'ts-sinon';
12
import { describe, it, expect, beforeEach, vi } from 'vitest';
23
import { CancellationToken, RequestHandler } from 'vscode-languageserver-protocol';
3-
import { TextDocument } from 'vscode-languageserver-textdocument';
44
import { getEntityMap } from '../../../src/context/SectionContextBuilder';
5-
import { Document } from '../../../src/document/Document';
5+
import { CloudFormationFileType, Document } from '../../../src/document/Document';
66
import {
77
getManagedResourceStackTemplateHandler,
88
importResourceStateHandler,
@@ -168,33 +168,39 @@ describe('ResourceHandler - removeResourceTypeHandler', () => {
168168
describe('ResourceHandler - importResourceStateHandler', () => {
169169
let mockComponents: ReturnType<typeof createMockComponents>;
170170
let handler: RequestHandler<ResourceStateParams, ResourceStateResult, void>;
171+
const params = {
172+
textDocument: { uri: 'docUri' },
173+
resourceSelections: [
174+
{
175+
resourceType: 'AWS::S3::Bucket',
176+
resourceIdentifiers: ['bucket1234'],
177+
},
178+
],
179+
purpose: ResourceStatePurpose.IMPORT,
180+
};
171181

172182
beforeEach(() => {
173183
vi.clearAllMocks();
174184
mockComponents = createMockComponents();
175185
handler = importResourceStateHandler(mockComponents);
176186
});
177187

178-
it('should throw error if template file is not open', async () => {
179-
mockComponents.documentManager.get.returns(
180-
new Document(TextDocument.create('sample.yaml', 'yaml', 1, 'Hello:')),
181-
);
182-
mockComponents.documentManager.isTemplate.resolves(false);
188+
it('should throw error if document not found', async () => {
189+
mockComponents.documentManager.get.returns(undefined);
183190

184191
await expect(async () => {
185-
await handler(
186-
{
187-
textDocument: { uri: 'docUri' },
188-
resourceSelections: [
189-
{
190-
resourceType: 'AWS::S3::Bucket',
191-
resourceIdentifiers: ['bucket1234'],
192-
},
193-
],
194-
purpose: ResourceStatePurpose.IMPORT,
195-
},
196-
CancellationToken.None,
197-
);
198-
}).rejects.toThrow('Must open CloudFormation template to import or clone resource state');
192+
await handler(params, CancellationToken.None);
193+
}).rejects.toThrow('Import failed: docUri not found');
194+
});
195+
196+
it('should throw error if document is not a valid CloudFormation template', async () => {
197+
const mockDoc = stubInterface<Document>();
198+
mockDoc.isTemplate.returns(false);
199+
Object.defineProperty(mockDoc, 'cfnFileType', { value: CloudFormationFileType.Other });
200+
mockComponents.documentManager.get.returns(mockDoc);
201+
202+
await expect(async () => {
203+
await handler(params, CancellationToken.None);
204+
}).rejects.toThrow('Import failed: docUri is not a valid CloudFormation template');
199205
});
200206
});

0 commit comments

Comments
 (0)