Skip to content

Commit 36166e7

Browse files
committed
test: 💍 add MNL and MOUNT protocol tests
1 parent ee28006 commit 36166e7

File tree

2 files changed

+653
-0
lines changed

2 files changed

+653
-0
lines changed
Lines changed: 398 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,398 @@
1+
import {Reader} from '@jsonjoy.com/buffers/lib/Reader';
2+
import {NlmEncoder} from '../NlmEncoder';
3+
import {NlmDecoder} from '../NlmDecoder';
4+
import {NlmProc, Nlm4Stat} from '../constants';
5+
import * as msg from '../messages';
6+
import * as structs from '../structs';
7+
8+
describe('NlmEncoder', () => {
9+
let encoder: NlmEncoder;
10+
let decoder: NlmDecoder;
11+
12+
beforeEach(() => {
13+
encoder = new NlmEncoder();
14+
decoder = new NlmDecoder();
15+
});
16+
17+
const createTestCookie = (): Reader => {
18+
return new Reader(new Uint8Array([1, 2, 3, 4]));
19+
};
20+
21+
const createTestFileHandle = (): Reader => {
22+
return new Reader(new Uint8Array([10, 20, 30, 40, 50, 60, 70, 80]));
23+
};
24+
25+
const createTestOwnerHandle = (): Reader => {
26+
return new Reader(new Uint8Array([11, 22, 33, 44]));
27+
};
28+
29+
const createTestLock = (): structs.Nlm4Lock => {
30+
return new structs.Nlm4Lock(
31+
'client.example.com',
32+
createTestFileHandle(),
33+
createTestOwnerHandle(),
34+
12345,
35+
BigInt(0),
36+
BigInt(1000),
37+
);
38+
};
39+
40+
describe('TEST', () => {
41+
it('encodes and decodes TEST request', () => {
42+
const args = new msg.Nlm4TestArgs(createTestCookie(), true, createTestLock());
43+
const request = new msg.Nlm4TestRequest(args);
44+
const encoded = encoder.encodeMessage(request, NlmProc.TEST, true);
45+
const decoded = decoder.decodeMessage(new Reader(encoded), NlmProc.TEST, true) as msg.Nlm4TestRequest;
46+
expect(decoded).toBeInstanceOf(msg.Nlm4TestRequest);
47+
expect(decoded.args.cookie.uint8).toEqual(createTestCookie().uint8);
48+
expect(decoded.args.exclusive).toBe(true);
49+
expect(decoded.args.lock.callerName).toBe('client.example.com');
50+
expect(decoded.args.lock.svid).toBe(12345);
51+
});
52+
53+
it('encodes and decodes TEST response (granted)', () => {
54+
const response = new msg.Nlm4TestResponse(createTestCookie(), Nlm4Stat.NLM4_GRANTED, undefined);
55+
const encoded = encoder.encodeMessage(response, NlmProc.TEST, false);
56+
const decoded = decoder.decodeMessage(new Reader(encoded), NlmProc.TEST, false) as msg.Nlm4TestResponse;
57+
expect(decoded).toBeInstanceOf(msg.Nlm4TestResponse);
58+
expect(decoded.stat).toBe(Nlm4Stat.NLM4_GRANTED);
59+
expect(decoded.holder).toBeUndefined();
60+
});
61+
62+
it('encodes and decodes TEST response (denied with holder)', () => {
63+
const holder = new structs.Nlm4Holder(true, 54321, createTestOwnerHandle(), BigInt(500), BigInt(1500));
64+
const response = new msg.Nlm4TestResponse(createTestCookie(), Nlm4Stat.NLM4_DENIED, holder);
65+
const encoded = encoder.encodeMessage(response, NlmProc.TEST, false);
66+
const decoded = decoder.decodeMessage(new Reader(encoded), NlmProc.TEST, false) as msg.Nlm4TestResponse;
67+
expect(decoded.stat).toBe(Nlm4Stat.NLM4_DENIED);
68+
expect(decoded.holder).toBeDefined();
69+
expect(decoded.holder!.exclusive).toBe(true);
70+
expect(decoded.holder!.svid).toBe(54321);
71+
expect(decoded.holder!.offset).toBe(BigInt(500));
72+
expect(decoded.holder!.length).toBe(BigInt(1500));
73+
});
74+
75+
it('handles exclusive and non-exclusive locks', () => {
76+
const exclusiveArgs = new msg.Nlm4TestArgs(createTestCookie(), true, createTestLock());
77+
const sharedArgs = new msg.Nlm4TestArgs(createTestCookie(), false, createTestLock());
78+
const exclusiveReq = new msg.Nlm4TestRequest(exclusiveArgs);
79+
const sharedReq = new msg.Nlm4TestRequest(sharedArgs);
80+
const encoded1 = encoder.encodeMessage(exclusiveReq, NlmProc.TEST, true);
81+
const encoded2 = encoder.encodeMessage(sharedReq, NlmProc.TEST, true);
82+
const decoded1 = decoder.decodeMessage(new Reader(encoded1), NlmProc.TEST, true) as msg.Nlm4TestRequest;
83+
const decoded2 = decoder.decodeMessage(new Reader(encoded2), NlmProc.TEST, true) as msg.Nlm4TestRequest;
84+
expect(decoded1.args.exclusive).toBe(true);
85+
expect(decoded2.args.exclusive).toBe(false);
86+
});
87+
});
88+
89+
describe('LOCK', () => {
90+
it('encodes and decodes LOCK request', () => {
91+
const args = new msg.Nlm4LockArgs(createTestCookie(), true, true, createTestLock(), false, 100);
92+
const request = new msg.Nlm4LockRequest(args);
93+
const encoded = encoder.encodeMessage(request, NlmProc.LOCK, true);
94+
const decoded = decoder.decodeMessage(new Reader(encoded), NlmProc.LOCK, true) as msg.Nlm4LockRequest;
95+
expect(decoded).toBeInstanceOf(msg.Nlm4LockRequest);
96+
expect(decoded.args.block).toBe(true);
97+
expect(decoded.args.exclusive).toBe(true);
98+
expect(decoded.args.reclaim).toBe(false);
99+
expect(decoded.args.state).toBe(100);
100+
});
101+
102+
it('encodes and decodes LOCK response', () => {
103+
const response = new msg.Nlm4Response(createTestCookie(), Nlm4Stat.NLM4_GRANTED);
104+
const encoded = encoder.encodeMessage(response, NlmProc.LOCK, false);
105+
const decoded = decoder.decodeMessage(new Reader(encoded), NlmProc.LOCK, false) as msg.Nlm4Response;
106+
expect(decoded).toBeInstanceOf(msg.Nlm4Response);
107+
expect(decoded.stat).toBe(Nlm4Stat.NLM4_GRANTED);
108+
});
109+
110+
it('handles blocking and non-blocking requests', () => {
111+
const blockingArgs = new msg.Nlm4LockArgs(createTestCookie(), true, true, createTestLock(), false, 100);
112+
const nonBlockingArgs = new msg.Nlm4LockArgs(createTestCookie(), false, true, createTestLock(), false, 100);
113+
const blockingReq = new msg.Nlm4LockRequest(blockingArgs);
114+
const nonBlockingReq = new msg.Nlm4LockRequest(nonBlockingArgs);
115+
const encoded1 = encoder.encodeMessage(blockingReq, NlmProc.LOCK, true);
116+
const encoded2 = encoder.encodeMessage(nonBlockingReq, NlmProc.LOCK, true);
117+
const decoded1 = decoder.decodeMessage(new Reader(encoded1), NlmProc.LOCK, true) as msg.Nlm4LockRequest;
118+
const decoded2 = decoder.decodeMessage(new Reader(encoded2), NlmProc.LOCK, true) as msg.Nlm4LockRequest;
119+
expect(decoded1.args.block).toBe(true);
120+
expect(decoded2.args.block).toBe(false);
121+
});
122+
123+
it('handles reclaim flag', () => {
124+
const args = new msg.Nlm4LockArgs(createTestCookie(), false, true, createTestLock(), true, 200);
125+
const request = new msg.Nlm4LockRequest(args);
126+
const encoded = encoder.encodeMessage(request, NlmProc.LOCK, true);
127+
const decoded = decoder.decodeMessage(new Reader(encoded), NlmProc.LOCK, true) as msg.Nlm4LockRequest;
128+
expect(decoded.args.reclaim).toBe(true);
129+
});
130+
});
131+
132+
describe('CANCEL', () => {
133+
it('encodes and decodes CANCEL request', () => {
134+
const args = new msg.Nlm4CancelArgs(createTestCookie(), true, true, createTestLock());
135+
const request = new msg.Nlm4CancelRequest(args);
136+
const encoded = encoder.encodeMessage(request, NlmProc.CANCEL, true);
137+
const decoded = decoder.decodeMessage(new Reader(encoded), NlmProc.CANCEL, true) as msg.Nlm4CancelRequest;
138+
expect(decoded).toBeInstanceOf(msg.Nlm4CancelRequest);
139+
expect(decoded.args.block).toBe(true);
140+
expect(decoded.args.exclusive).toBe(true);
141+
});
142+
143+
it('encodes and decodes CANCEL response', () => {
144+
const response = new msg.Nlm4Response(createTestCookie(), Nlm4Stat.NLM4_GRANTED);
145+
const encoded = encoder.encodeMessage(response, NlmProc.CANCEL, false);
146+
const decoded = decoder.decodeMessage(new Reader(encoded), NlmProc.CANCEL, false) as msg.Nlm4Response;
147+
expect(decoded.stat).toBe(Nlm4Stat.NLM4_GRANTED);
148+
});
149+
});
150+
151+
describe('UNLOCK', () => {
152+
it('encodes and decodes UNLOCK request', () => {
153+
const args = new msg.Nlm4UnlockArgs(createTestCookie(), createTestLock());
154+
const request = new msg.Nlm4UnlockRequest(args);
155+
const encoded = encoder.encodeMessage(request, NlmProc.UNLOCK, true);
156+
const decoded = decoder.decodeMessage(new Reader(encoded), NlmProc.UNLOCK, true) as msg.Nlm4UnlockRequest;
157+
expect(decoded).toBeInstanceOf(msg.Nlm4UnlockRequest);
158+
expect(decoded.args.lock.callerName).toBe('client.example.com');
159+
});
160+
161+
it('encodes and decodes UNLOCK response', () => {
162+
const response = new msg.Nlm4Response(createTestCookie(), Nlm4Stat.NLM4_GRANTED);
163+
const encoded = encoder.encodeMessage(response, NlmProc.UNLOCK, false);
164+
const decoded = decoder.decodeMessage(new Reader(encoded), NlmProc.UNLOCK, false) as msg.Nlm4Response;
165+
expect(decoded.stat).toBe(Nlm4Stat.NLM4_GRANTED);
166+
});
167+
});
168+
169+
describe('GRANTED', () => {
170+
it('encodes and decodes GRANTED request', () => {
171+
const args = new msg.Nlm4TestArgs(createTestCookie(), true, createTestLock());
172+
const request = new msg.Nlm4GrantedRequest(args);
173+
const encoded = encoder.encodeMessage(request, NlmProc.GRANTED, true);
174+
const decoded = decoder.decodeMessage(new Reader(encoded), NlmProc.GRANTED, true) as msg.Nlm4GrantedRequest;
175+
expect(decoded).toBeInstanceOf(msg.Nlm4GrantedRequest);
176+
expect(decoded.args.exclusive).toBe(true);
177+
});
178+
179+
it('encodes and decodes GRANTED response', () => {
180+
const response = new msg.Nlm4Response(createTestCookie(), Nlm4Stat.NLM4_GRANTED);
181+
const encoded = encoder.encodeMessage(response, NlmProc.GRANTED, false);
182+
const decoded = decoder.decodeMessage(new Reader(encoded), NlmProc.GRANTED, false) as msg.Nlm4Response;
183+
expect(decoded.stat).toBe(Nlm4Stat.NLM4_GRANTED);
184+
});
185+
});
186+
187+
describe('SHARE', () => {
188+
it('encodes and decodes SHARE request', () => {
189+
const share = new structs.Nlm4Share('client.example.com', createTestFileHandle(), createTestOwnerHandle(), 1, 2);
190+
const args = new msg.Nlm4ShareArgs(createTestCookie(), share, false);
191+
const request = new msg.Nlm4ShareRequest(args);
192+
const encoded = encoder.encodeMessage(request, NlmProc.SHARE, true);
193+
const decoded = decoder.decodeMessage(new Reader(encoded), NlmProc.SHARE, true) as msg.Nlm4ShareRequest;
194+
expect(decoded).toBeInstanceOf(msg.Nlm4ShareRequest);
195+
expect(decoded.args.share.callerName).toBe('client.example.com');
196+
expect(decoded.args.share.mode).toBe(1);
197+
expect(decoded.args.share.access).toBe(2);
198+
expect(decoded.args.reclaim).toBe(false);
199+
});
200+
201+
it('encodes and decodes SHARE response', () => {
202+
const response = new msg.Nlm4ShareResponse(createTestCookie(), Nlm4Stat.NLM4_GRANTED, 5);
203+
const encoded = encoder.encodeMessage(response, NlmProc.SHARE, false);
204+
const decoded = decoder.decodeMessage(new Reader(encoded), NlmProc.SHARE, false) as msg.Nlm4ShareResponse;
205+
expect(decoded).toBeInstanceOf(msg.Nlm4ShareResponse);
206+
expect(decoded.stat).toBe(Nlm4Stat.NLM4_GRANTED);
207+
expect(decoded.sequence).toBe(5);
208+
});
209+
210+
it('handles different mode and access values', () => {
211+
const share = new structs.Nlm4Share('client.example.com', createTestFileHandle(), createTestOwnerHandle(), 7, 15);
212+
const args = new msg.Nlm4ShareArgs(createTestCookie(), share, false);
213+
const request = new msg.Nlm4ShareRequest(args);
214+
const encoded = encoder.encodeMessage(request, NlmProc.SHARE, true);
215+
const decoded = decoder.decodeMessage(new Reader(encoded), NlmProc.SHARE, true) as msg.Nlm4ShareRequest;
216+
expect(decoded.args.share.mode).toBe(7);
217+
expect(decoded.args.share.access).toBe(15);
218+
});
219+
});
220+
221+
describe('UNSHARE', () => {
222+
it('encodes and decodes UNSHARE request', () => {
223+
const share = new structs.Nlm4Share('client.example.com', createTestFileHandle(), createTestOwnerHandle(), 1, 2);
224+
const args = new msg.Nlm4ShareArgs(createTestCookie(), share, false);
225+
const request = new msg.Nlm4UnshareRequest(args);
226+
const encoded = encoder.encodeMessage(request, NlmProc.UNSHARE, true);
227+
const decoded = decoder.decodeMessage(new Reader(encoded), NlmProc.UNSHARE, true) as msg.Nlm4UnshareRequest;
228+
expect(decoded).toBeInstanceOf(msg.Nlm4UnshareRequest);
229+
expect(decoded.args.share.callerName).toBe('client.example.com');
230+
});
231+
232+
it('encodes and decodes UNSHARE response', () => {
233+
const response = new msg.Nlm4ShareResponse(createTestCookie(), Nlm4Stat.NLM4_GRANTED, 3);
234+
const encoded = encoder.encodeMessage(response, NlmProc.UNSHARE, false);
235+
const decoded = decoder.decodeMessage(new Reader(encoded), NlmProc.UNSHARE, false) as msg.Nlm4ShareResponse;
236+
expect(decoded.stat).toBe(Nlm4Stat.NLM4_GRANTED);
237+
expect(decoded.sequence).toBe(3);
238+
});
239+
});
240+
241+
describe('NM_LOCK', () => {
242+
it('encodes and decodes NM_LOCK request', () => {
243+
const args = new msg.Nlm4LockArgs(createTestCookie(), false, true, createTestLock(), false, 100);
244+
const request = new msg.Nlm4NmLockRequest(args);
245+
const encoded = encoder.encodeMessage(request, NlmProc.NM_LOCK, true);
246+
const decoded = decoder.decodeMessage(new Reader(encoded), NlmProc.NM_LOCK, true) as msg.Nlm4NmLockRequest;
247+
expect(decoded).toBeInstanceOf(msg.Nlm4NmLockRequest);
248+
expect(decoded.args.state).toBe(100);
249+
});
250+
251+
it('encodes and decodes NM_LOCK response', () => {
252+
const response = new msg.Nlm4Response(createTestCookie(), Nlm4Stat.NLM4_GRANTED);
253+
const encoded = encoder.encodeMessage(response, NlmProc.NM_LOCK, false);
254+
const decoded = decoder.decodeMessage(new Reader(encoded), NlmProc.NM_LOCK, false) as msg.Nlm4Response;
255+
expect(decoded.stat).toBe(Nlm4Stat.NLM4_GRANTED);
256+
});
257+
});
258+
259+
describe('FREE_ALL', () => {
260+
it('encodes and decodes FREE_ALL request', () => {
261+
const notify = new structs.Nlm4Notify('client.example.com', 42);
262+
const request = new msg.Nlm4FreeAllRequest(notify);
263+
const encoded = encoder.encodeMessage(request, NlmProc.FREE_ALL, true);
264+
const decoded = decoder.decodeMessage(new Reader(encoded), NlmProc.FREE_ALL, true) as msg.Nlm4FreeAllRequest;
265+
expect(decoded).toBeInstanceOf(msg.Nlm4FreeAllRequest);
266+
expect(decoded.notify.name).toBe('client.example.com');
267+
expect(decoded.notify.state).toBe(42);
268+
});
269+
});
270+
271+
describe('lock regions', () => {
272+
it('handles zero offset locks', () => {
273+
const lock = new structs.Nlm4Lock(
274+
'client.example.com',
275+
createTestFileHandle(),
276+
createTestOwnerHandle(),
277+
12345,
278+
BigInt(0),
279+
BigInt(100),
280+
);
281+
const args = new msg.Nlm4TestArgs(createTestCookie(), true, lock);
282+
const request = new msg.Nlm4TestRequest(args);
283+
const encoded = encoder.encodeMessage(request, NlmProc.TEST, true);
284+
const decoded = decoder.decodeMessage(new Reader(encoded), NlmProc.TEST, true) as msg.Nlm4TestRequest;
285+
expect(decoded.args.lock.offset).toBe(BigInt(0));
286+
expect(decoded.args.lock.length).toBe(BigInt(100));
287+
});
288+
289+
it('handles large offset locks', () => {
290+
const lock = new structs.Nlm4Lock(
291+
'client.example.com',
292+
createTestFileHandle(),
293+
createTestOwnerHandle(),
294+
12345,
295+
BigInt('9223372036854775807'),
296+
BigInt(1000),
297+
);
298+
const args = new msg.Nlm4TestArgs(createTestCookie(), true, lock);
299+
const request = new msg.Nlm4TestRequest(args);
300+
const encoded = encoder.encodeMessage(request, NlmProc.TEST, true);
301+
const decoded = decoder.decodeMessage(new Reader(encoded), NlmProc.TEST, true) as msg.Nlm4TestRequest;
302+
expect(decoded.args.lock.offset).toBe(BigInt('9223372036854775807'));
303+
});
304+
305+
it('handles zero-length locks (lock to EOF)', () => {
306+
const lock = new structs.Nlm4Lock(
307+
'client.example.com',
308+
createTestFileHandle(),
309+
createTestOwnerHandle(),
310+
12345,
311+
BigInt(500),
312+
BigInt(0),
313+
);
314+
const args = new msg.Nlm4TestArgs(createTestCookie(), true, lock);
315+
const request = new msg.Nlm4TestRequest(args);
316+
const encoded = encoder.encodeMessage(request, NlmProc.TEST, true);
317+
const decoded = decoder.decodeMessage(new Reader(encoded), NlmProc.TEST, true) as msg.Nlm4TestRequest;
318+
expect(decoded.args.lock.length).toBe(BigInt(0));
319+
});
320+
});
321+
322+
describe('error status codes', () => {
323+
it('handles all NLM4 status codes', () => {
324+
const statusCodes = [
325+
Nlm4Stat.NLM4_GRANTED,
326+
Nlm4Stat.NLM4_DENIED,
327+
Nlm4Stat.NLM4_DENIED_NOLOCKS,
328+
Nlm4Stat.NLM4_BLOCKED,
329+
Nlm4Stat.NLM4_DENIED_GRACE_PERIOD,
330+
Nlm4Stat.NLM4_DEADLCK,
331+
Nlm4Stat.NLM4_ROFS,
332+
Nlm4Stat.NLM4_STALE_FH,
333+
Nlm4Stat.NLM4_FBIG,
334+
Nlm4Stat.NLM4_FAILED,
335+
];
336+
for (const status of statusCodes) {
337+
const response = new msg.Nlm4Response(createTestCookie(), status);
338+
const encoded = encoder.encodeMessage(response, NlmProc.LOCK, false);
339+
const decoded = decoder.decodeMessage(new Reader(encoded), NlmProc.LOCK, false) as msg.Nlm4Response;
340+
expect(decoded.stat).toBe(status);
341+
}
342+
});
343+
});
344+
345+
describe('edge cases', () => {
346+
it('handles empty cookie', () => {
347+
const emptyCookie = new Reader(new Uint8Array([]));
348+
const args = new msg.Nlm4TestArgs(emptyCookie, true, createTestLock());
349+
const request = new msg.Nlm4TestRequest(args);
350+
const encoded = encoder.encodeMessage(request, NlmProc.TEST, true);
351+
const decoded = decoder.decodeMessage(new Reader(encoded), NlmProc.TEST, true) as msg.Nlm4TestRequest;
352+
expect(decoded.args.cookie.uint8.length).toBe(0);
353+
});
354+
355+
it('handles large cookie', () => {
356+
const largeCookie = new Reader(new Uint8Array(64).fill(123));
357+
const args = new msg.Nlm4TestArgs(largeCookie, true, createTestLock());
358+
const request = new msg.Nlm4TestRequest(args);
359+
const encoded = encoder.encodeMessage(request, NlmProc.TEST, true);
360+
const decoded = decoder.decodeMessage(new Reader(encoded), NlmProc.TEST, true) as msg.Nlm4TestRequest;
361+
expect(decoded.args.cookie.uint8.length).toBe(64);
362+
expect(decoded.args.cookie.uint8[0]).toBe(123);
363+
});
364+
365+
it('handles empty caller name', () => {
366+
const lock = new structs.Nlm4Lock(
367+
'',
368+
createTestFileHandle(),
369+
createTestOwnerHandle(),
370+
12345,
371+
BigInt(0),
372+
BigInt(100),
373+
);
374+
const args = new msg.Nlm4TestArgs(createTestCookie(), true, lock);
375+
const request = new msg.Nlm4TestRequest(args);
376+
const encoded = encoder.encodeMessage(request, NlmProc.TEST, true);
377+
const decoded = decoder.decodeMessage(new Reader(encoded), NlmProc.TEST, true) as msg.Nlm4TestRequest;
378+
expect(decoded.args.lock.callerName).toBe('');
379+
});
380+
381+
it('handles long caller name', () => {
382+
const longName = 'a'.repeat(500);
383+
const lock = new structs.Nlm4Lock(
384+
longName,
385+
createTestFileHandle(),
386+
createTestOwnerHandle(),
387+
12345,
388+
BigInt(0),
389+
BigInt(100),
390+
);
391+
const args = new msg.Nlm4TestArgs(createTestCookie(), true, lock);
392+
const request = new msg.Nlm4TestRequest(args);
393+
const encoded = encoder.encodeMessage(request, NlmProc.TEST, true);
394+
const decoded = decoder.decodeMessage(new Reader(encoded), NlmProc.TEST, true) as msg.Nlm4TestRequest;
395+
expect(decoded.args.lock.callerName).toBe(longName);
396+
});
397+
});
398+
});

0 commit comments

Comments
 (0)