-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Infrastructure for remote configuration
- Loading branch information
1 parent
98da01d
commit 818881d
Showing
41 changed files
with
1,259 additions
and
138 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
96 changes: 96 additions & 0 deletions
96
clients/vscode-hlasmplugin/src/hlasmExternalConfigurationProvider.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
/* | ||
* Copyright (c) 2023 Broadcom. | ||
* The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. | ||
* | ||
* This program and the accompanying materials are made | ||
* available under the terms of the Eclipse Public License 2.0 | ||
* which is available at https://www.eclipse.org/legal/epl-2.0/ | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
* | ||
* Contributors: | ||
* Broadcom, Inc. - initial API and implementation | ||
*/ | ||
|
||
import * as vscode from 'vscode'; | ||
import * as vscodelc from 'vscode-languageclient'; | ||
|
||
interface ExternalConfigurationRequest { | ||
uri: string; | ||
}; | ||
interface ProcGrpsSchemaJson { }; | ||
interface ExternalConfigurationResponse { | ||
configuration: string | ProcGrpsSchemaJson; | ||
}; | ||
|
||
export type HLASMExternalConfigurationProviderHandler = (uri: vscode.Uri) => PromiseLike<ExternalConfigurationResponse | null> | ExternalConfigurationResponse | null; | ||
|
||
function isExternalConfigurationRequest(p: any): p is ExternalConfigurationRequest { | ||
return typeof p === 'object' && ('uri' in p); | ||
} | ||
|
||
function isError(e: any): e is Error { | ||
return e instanceof Error; | ||
} | ||
|
||
export class HLASMExternalConfigurationProvider { | ||
private toDispose: vscode.Disposable[] = []; | ||
private requestHandlers: HLASMExternalConfigurationProviderHandler[] = []; | ||
|
||
constructor( | ||
private channel: { | ||
onRequest<R, E>(method: string, handler: vscodelc.GenericRequestHandler<R, E>): vscode.Disposable; | ||
sendNotification(method: string, params: any): Promise<void>; | ||
}) { | ||
this.toDispose.push(this.channel.onRequest('external_configuration_request', (...params: any[]) => this.handleRawMessage(...params))); | ||
} | ||
|
||
dispose() { | ||
this.toDispose.forEach(x => x.dispose()); | ||
} | ||
|
||
private async handleRequest(uri: vscode.Uri): Promise<ExternalConfigurationResponse | vscodelc.ResponseError> { | ||
for (const h of this.requestHandlers) { | ||
try { | ||
const resp = await h(uri); | ||
if (resp) | ||
return resp; | ||
} | ||
catch (e) { | ||
return new vscodelc.ResponseError(-106, isError(e) ? e.message : 'Unknown error'); | ||
} | ||
} | ||
|
||
return new vscodelc.ResponseError(0, 'Not found'); | ||
} | ||
|
||
public async handleRawMessage(...params: any[]): Promise<ExternalConfigurationResponse | vscodelc.ResponseError> { | ||
if (params.length < 1 || !isExternalConfigurationRequest(params[0])) | ||
return new vscodelc.ResponseError(-5, 'Invalid request'); | ||
|
||
try { | ||
const uri = vscode.Uri.parse(params[0].uri); | ||
return this.handleRequest(uri); | ||
} catch (e) { | ||
return new vscodelc.ResponseError(-5, 'Invalid request'); | ||
} | ||
} | ||
|
||
private invalidateConfiguration(uri: vscode.Uri | null) { | ||
return this.channel.sendNotification('invalidate_external_configuration', uri ? { uri: uri.toString() } : {}); | ||
} | ||
|
||
public addHandler(h: HLASMExternalConfigurationProviderHandler) { | ||
this.requestHandlers.push(h); | ||
|
||
return { | ||
dispose: () => { | ||
const idx = this.requestHandlers.indexOf(h); | ||
if (idx >= 0) | ||
this.requestHandlers.splice(idx, 1); | ||
return this.invalidateConfiguration(null); | ||
}, | ||
invalidate: (uri: vscode.Uri | null) => this.invalidateConfiguration(uri) | ||
}; | ||
} | ||
} |
141 changes: 141 additions & 0 deletions
141
clients/vscode-hlasmplugin/src/test/suite/hlasmExternalConfigurationProvider.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
/* | ||
* Copyright (c) 2023 Broadcom. | ||
* The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. | ||
* | ||
* This program and the accompanying materials are made | ||
* available under the terms of the Eclipse Public License 2.0 | ||
* which is available at https://www.eclipse.org/legal/epl-2.0/ | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
* | ||
* Contributors: | ||
* Broadcom, Inc. - initial API and implementation | ||
*/ | ||
|
||
import * as vscode from 'vscode'; | ||
import * as vscodelc from 'vscode-languageclient'; | ||
import * as assert from 'assert'; | ||
import { HLASMExternalConfigurationProvider } from '../../hlasmExternalConfigurationProvider'; | ||
|
||
suite('External configuration provider', () => { | ||
test('Dispose', async () => { | ||
let disposeCalled = 0; | ||
const c = new HLASMExternalConfigurationProvider({ | ||
onRequest: <R, E>(method: string, handler: vscodelc.GenericRequestHandler<R, E>): vscode.Disposable => { | ||
return { dispose: () => { ++disposeCalled; } }; | ||
}, | ||
sendNotification: async (method: string, params: any): Promise<void> => { } | ||
}); | ||
|
||
const h = c.addHandler(async (uri) => null); | ||
|
||
assert.ok(h); | ||
assert.strictEqual(typeof h, 'object'); | ||
|
||
c.dispose(); | ||
|
||
assert.strictEqual(disposeCalled, 1); | ||
}); | ||
|
||
test('Query after dispose', async () => { | ||
const c = new HLASMExternalConfigurationProvider({ | ||
onRequest: <R, E>(method: string, handler: vscodelc.GenericRequestHandler<R, E>): vscode.Disposable => { | ||
return { dispose: () => { } }; | ||
}, | ||
sendNotification: async (method: string, params: any): Promise<void> => { } | ||
}); | ||
|
||
const h = c.addHandler(async (uri) => { throw Error('Should not be called'); }); | ||
|
||
assert.ok(h); | ||
assert.strictEqual(typeof h, 'object'); | ||
|
||
h.dispose(); | ||
|
||
const f = await c.handleRawMessage({ uri: '' }); | ||
assert.ok('code' in f); | ||
assert.deepStrictEqual(f.code, 0); | ||
}); | ||
|
||
test('Not found', async () => { | ||
const c = new HLASMExternalConfigurationProvider({ | ||
onRequest: <R, E>(method: string, handler: vscodelc.GenericRequestHandler<R, E>): vscode.Disposable => { | ||
return { dispose: () => { } }; | ||
}, | ||
sendNotification: async (method: string, params: any): Promise<void> => { } | ||
}); | ||
|
||
let calledWithUri: unknown; | ||
c.addHandler(async (uri) => { | ||
assert.ok(!calledWithUri); | ||
calledWithUri = uri; | ||
return null; | ||
}); | ||
|
||
const f = await c.handleRawMessage({ uri: 'schema:path' }); | ||
assert.ok('code' in f); | ||
assert.deepStrictEqual(f.code, 0); | ||
|
||
assert.ok(calledWithUri instanceof vscode.Uri); | ||
assert.deepStrictEqual(calledWithUri.toString(), 'schema:path'); | ||
}); | ||
|
||
test('Return configuration', async () => { | ||
const c = new HLASMExternalConfigurationProvider({ | ||
onRequest: <R, E>(method: string, handler: vscodelc.GenericRequestHandler<R, E>): vscode.Disposable => { | ||
return { dispose: () => { } }; | ||
}, | ||
sendNotification: async (method: string, params: any): Promise<void> => { } | ||
}); | ||
|
||
let calledWithUri: unknown; | ||
c.addHandler(async (uri) => { | ||
assert.ok(!calledWithUri); | ||
calledWithUri = uri; | ||
return { configuration: 'PROCGRP' }; | ||
}); | ||
|
||
const f = await c.handleRawMessage({ uri: 'schema:path' }); | ||
assert.deepStrictEqual(f, { configuration: 'PROCGRP' }); | ||
|
||
assert.ok(calledWithUri instanceof vscode.Uri); | ||
assert.deepStrictEqual(calledWithUri.toString(), 'schema:path'); | ||
}); | ||
|
||
test('Invalidation', async () => { | ||
let notificationParam: unknown; | ||
const c = new HLASMExternalConfigurationProvider({ | ||
onRequest: <R, E>(method: string, handler: vscodelc.GenericRequestHandler<R, E>): vscode.Disposable => { | ||
return { dispose: () => { } }; | ||
}, | ||
sendNotification: async (method: string, params: any): Promise<void> => { | ||
assert.deepEqual(method, 'invalidate_external_configuration'); | ||
notificationParam = params; | ||
} | ||
}); | ||
|
||
const h = c.addHandler(async (_) => null); | ||
|
||
await h.invalidate(null); | ||
assert.deepStrictEqual(notificationParam, {}); | ||
|
||
await h.invalidate(vscode.Uri.parse('schema:path')); | ||
assert.deepStrictEqual(notificationParam, { uri: 'schema:path' }); | ||
}); | ||
|
||
test('Throwing handler', async () => { | ||
const c = new HLASMExternalConfigurationProvider({ | ||
onRequest: <R, E>(method: string, handler: vscodelc.GenericRequestHandler<R, E>): vscode.Disposable => { | ||
return { dispose: () => { } }; | ||
}, | ||
sendNotification: async (method: string, params: any): Promise<void> => { } | ||
}); | ||
|
||
const h = c.addHandler(async (_) => { throw Error('Error message') }); | ||
|
||
const f = await c.handleRawMessage({ uri: 'schema:path' }); | ||
assert.ok('code' in f && 'message' in f); | ||
assert.deepStrictEqual(f.code, -106); | ||
assert.deepStrictEqual(f.message, 'Error message'); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
MAC 1 | ||
|
||
MACRO | ||
TEST | ||
MNOTE 4,'&SYSPARM' | ||
MEND | ||
TEST | ||
|
||
|
||
|
||
|
||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
MAC 1 | ||
|
||
MNOTE 'DONE' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
MAC 1 |
Oops, something went wrong.