Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/services/extensions/test/common/rpcProtocol.test.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import assert from 'assert';
7
import { VSBuffer } from '../../../../../base/common/buffer.js';
8
import { CancellationToken, CancellationTokenSource } from '../../../../../base/common/cancellation.js';
9
import { Emitter, Event } from '../../../../../base/common/event.js';
10
import { DisposableStore } from '../../../../../base/common/lifecycle.js';
11
import { IMessagePassingProtocol } from '../../../../../base/parts/ipc/common/ipc.js';
12
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';
13
import { ProxyIdentifier, SerializableObjectWithBuffers } from '../../common/proxyIdentifier.js';
14
import { RPCProtocol } from '../../common/rpcProtocol.js';
15
16
suite('RPCProtocol', () => {
17
18
let disposables: DisposableStore;
19
20
class MessagePassingProtocol implements IMessagePassingProtocol {
21
private _pair?: MessagePassingProtocol;
22
23
private readonly _onMessage = new Emitter<VSBuffer>();
24
public readonly onMessage: Event<VSBuffer> = this._onMessage.event;
25
26
public setPair(other: MessagePassingProtocol) {
27
this._pair = other;
28
}
29
30
public send(buffer: VSBuffer): void {
31
Promise.resolve().then(() => {
32
this._pair!._onMessage.fire(buffer);
33
});
34
}
35
}
36
37
let delegate: (a1: any, a2: any) => any;
38
let bProxy: BClass;
39
class BClass {
40
$m(a1: any, a2: any): Promise<any> {
41
return Promise.resolve(delegate.call(null, a1, a2));
42
}
43
}
44
45
setup(() => {
46
disposables = new DisposableStore();
47
48
const a_protocol = new MessagePassingProtocol();
49
const b_protocol = new MessagePassingProtocol();
50
a_protocol.setPair(b_protocol);
51
b_protocol.setPair(a_protocol);
52
53
const A = disposables.add(new RPCProtocol(a_protocol));
54
const B = disposables.add(new RPCProtocol(b_protocol));
55
56
const bIdentifier = new ProxyIdentifier<BClass>('bb');
57
const bInstance = new BClass();
58
B.set(bIdentifier, bInstance);
59
bProxy = A.getProxy(bIdentifier);
60
});
61
62
teardown(() => {
63
disposables.dispose();
64
});
65
66
ensureNoDisposablesAreLeakedInTestSuite();
67
68
test('simple call', function (done) {
69
delegate = (a1: number, a2: number) => a1 + a2;
70
bProxy.$m(4, 1).then((res: number) => {
71
assert.strictEqual(res, 5);
72
done(null);
73
}, done);
74
});
75
76
test('simple call without result', function (done) {
77
delegate = (a1: number, a2: number) => { };
78
bProxy.$m(4, 1).then((res: number) => {
79
assert.strictEqual(res, undefined);
80
done(null);
81
}, done);
82
});
83
84
test('passing buffer as argument', function (done) {
85
delegate = (a1: VSBuffer, a2: number) => {
86
assert.ok(a1 instanceof VSBuffer);
87
return a1.buffer[a2];
88
};
89
const b = VSBuffer.alloc(4);
90
b.buffer[0] = 1;
91
b.buffer[1] = 2;
92
b.buffer[2] = 3;
93
b.buffer[3] = 4;
94
bProxy.$m(b, 2).then((res: number) => {
95
assert.strictEqual(res, 3);
96
done(null);
97
}, done);
98
});
99
100
test('returning a buffer', function (done) {
101
delegate = (a1: number, a2: number) => {
102
const b = VSBuffer.alloc(4);
103
b.buffer[0] = 1;
104
b.buffer[1] = 2;
105
b.buffer[2] = 3;
106
b.buffer[3] = 4;
107
return b;
108
};
109
bProxy.$m(4, 1).then((res: VSBuffer) => {
110
assert.ok(res instanceof VSBuffer);
111
assert.strictEqual(res.buffer[0], 1);
112
assert.strictEqual(res.buffer[1], 2);
113
assert.strictEqual(res.buffer[2], 3);
114
assert.strictEqual(res.buffer[3], 4);
115
done(null);
116
}, done);
117
});
118
119
test('cancelling a call via CancellationToken before', function (done) {
120
delegate = (a1: number, a2: number) => a1 + a2;
121
const p = bProxy.$m(4, CancellationToken.Cancelled);
122
p.then((res: number) => {
123
assert.fail('should not receive result');
124
}, (err) => {
125
assert.ok(true);
126
done(null);
127
});
128
});
129
130
test('passing CancellationToken.None', function (done) {
131
delegate = (a1: number, token: CancellationToken) => {
132
assert.ok(!!token);
133
return a1 + 1;
134
};
135
bProxy.$m(4, CancellationToken.None).then((res: number) => {
136
assert.strictEqual(res, 5);
137
done(null);
138
}, done);
139
});
140
141
test('cancelling a call via CancellationToken quickly', function (done) {
142
// this is an implementation which, when cancellation is triggered, will return 7
143
delegate = (a1: number, token: CancellationToken) => {
144
return new Promise((resolve, reject) => {
145
const disposable = token.onCancellationRequested((e) => {
146
disposable.dispose();
147
resolve(7);
148
});
149
});
150
};
151
const tokenSource = new CancellationTokenSource();
152
const p = bProxy.$m(4, tokenSource.token);
153
p.then((res: number) => {
154
assert.strictEqual(res, 7);
155
}, (err) => {
156
assert.fail('should not receive error');
157
}).finally(done);
158
tokenSource.cancel();
159
});
160
161
test('throwing an error', function (done) {
162
delegate = (a1: number, a2: number) => {
163
throw new Error(`nope`);
164
};
165
bProxy.$m(4, 1).then((res) => {
166
assert.fail('unexpected');
167
}, (err) => {
168
assert.strictEqual(err.message, 'nope');
169
}).finally(done);
170
});
171
172
test('error promise', function (done) {
173
delegate = (a1: number, a2: number) => {
174
return Promise.reject(undefined);
175
};
176
bProxy.$m(4, 1).then((res) => {
177
assert.fail('unexpected');
178
}, (err) => {
179
assert.strictEqual(err, undefined);
180
}).finally(done);
181
});
182
183
test('issue #60450: Converting circular structure to JSON', function (done) {
184
delegate = (a1: number, a2: number) => {
185
const circular = <any>{};
186
circular.self = circular;
187
return circular;
188
};
189
bProxy.$m(4, 1).then((res) => {
190
assert.strictEqual(res, null);
191
}, (err) => {
192
assert.fail('unexpected');
193
}).finally(done);
194
});
195
196
test('issue #72798: null errors are hard to digest', function (done) {
197
delegate = (a1: number, a2: number) => {
198
// eslint-disable-next-line no-throw-literal
199
throw { 'what': 'what' };
200
};
201
bProxy.$m(4, 1).then((res) => {
202
assert.fail('unexpected');
203
}, (err) => {
204
assert.strictEqual(err.what, 'what');
205
}).finally(done);
206
});
207
208
test('undefined arguments arrive as null', function () {
209
delegate = (a1: any, a2: any) => {
210
assert.strictEqual(typeof a1, 'undefined');
211
assert.strictEqual(a2, null);
212
return 7;
213
};
214
return bProxy.$m(undefined, null).then((res) => {
215
assert.strictEqual(res, 7);
216
});
217
});
218
219
test('issue #81424: SerializeRequest should throw if an argument can not be serialized', () => {
220
const badObject = {};
221
(<any>badObject).loop = badObject;
222
223
assert.throws(() => {
224
bProxy.$m(badObject, '2');
225
});
226
});
227
228
test('SerializableObjectWithBuffers is correctly transfered', function (done) {
229
delegate = (a1: SerializableObjectWithBuffers<{ string: string; buff: VSBuffer }>, a2: number) => {
230
return new SerializableObjectWithBuffers({ string: a1.value.string + ' world', buff: a1.value.buff });
231
};
232
233
const b = VSBuffer.alloc(4);
234
b.buffer[0] = 1;
235
b.buffer[1] = 2;
236
b.buffer[2] = 3;
237
b.buffer[3] = 4;
238
239
bProxy.$m(new SerializableObjectWithBuffers({ string: 'hello', buff: b }), undefined).then((res: SerializableObjectWithBuffers<any>) => {
240
assert.ok(res instanceof SerializableObjectWithBuffers);
241
assert.strictEqual(res.value.string, 'hello world');
242
243
assert.ok(res.value.buff instanceof VSBuffer);
244
245
const bufferValues = Array.from(res.value.buff.buffer);
246
247
assert.strictEqual(bufferValues[0], 1);
248
assert.strictEqual(bufferValues[1], 2);
249
assert.strictEqual(bufferValues[2], 3);
250
assert.strictEqual(bufferValues[3], 4);
251
done(null);
252
}, done);
253
});
254
});
255
256