1+ import test from 'node:test' ;
2+ import assert from 'node:assert/strict' ;
3+ import * as core from '../mutex_core.js' ;
4+ import { stepN , stepUntil , lastTrace , assertSafety , inCS } from './helpers.mjs' ;
5+
6+ test ( 'TokenRing basic request / entry / release / pass' , ( ) => {
7+ const model = core . makeModel ( 4 , 'TokenRing' ) ;
8+
9+ assert . equal ( core . requestCS ( model , 'P1' ) . ok , true ) ;
10+ stepUntil ( core , model , ( ) => inCS ( core , model , 'P1' ) , 50 , 'P1 enters' ) ;
11+ assertSafety ( core , model ) ;
12+
13+ assert . equal ( core . requestCS ( model , 'P2' ) . ok , true ) ;
14+ stepN ( core , model , 3 ) ;
15+ assert . equal ( inCS ( core , model , 'P1' ) , true ) ;
16+ assert . equal ( inCS ( core , model , 'P2' ) , false ) ;
17+ assert . match ( lastTrace ( model ) , / r e l e a s e r e q u i r e d / ) ;
18+
19+ assert . equal ( core . releaseCS ( model , 'P1' ) . ok , true ) ;
20+ stepUntil ( core , model , ( ) => inCS ( core , model , 'P2' ) , 100 , 'P2 enters' ) ;
21+ assertSafety ( core , model ) ;
22+ } ) ;
23+
24+ test ( 'TokenRing invalid request / release cases' , ( ) => {
25+ const model = core . makeModel ( 3 , 'TokenRing' ) ;
26+ assert . equal ( core . requestCS ( model , 'P9' ) . reason , 'unknown_process' ) ;
27+ assert . equal ( core . releaseCS ( model , 'P1' ) . reason , 'not_in_cs' ) ;
28+
29+ assert . equal ( core . requestCS ( model , 'P1' ) . ok , true ) ;
30+ assert . equal ( core . requestCS ( model , 'P1' ) . reason , 'already_requesting' ) ;
31+
32+ stepUntil ( core , model , ( ) => inCS ( core , model , 'P1' ) , 20 , 'P1 enters' ) ;
33+ assert . equal ( core . requestCS ( model , 'P1' ) . reason , 'already_in_cs' ) ;
34+
35+ core . crashProcess ( model , 'P2' ) ;
36+ assert . equal ( core . requestCS ( model , 'P2' ) . reason , 'crashed' ) ;
37+ } ) ;
38+
39+ test ( 'TokenRing token loss and regeneration' , ( ) => {
40+ const model = core . makeModel ( 4 , 'TokenRing' ) ;
41+
42+ assert . equal ( core . dropToken ( model ) . ok , true ) ;
43+ assert . equal ( model . token . lost , true ) ;
44+
45+ assert . equal ( core . requestCS ( model , 'P1' ) . ok , true ) ;
46+ stepN ( core , model , 2 ) ;
47+ assert . equal ( inCS ( core , model , 'P1' ) , false ) ;
48+ assert . match ( lastTrace ( model ) , / t o k e n i s l o s t / ) ;
49+
50+ assert . equal ( core . regenerateToken ( model ) . ok , true ) ;
51+ stepUntil ( core , model , ( ) => inCS ( core , model , 'P1' ) , 20 , 'P1 enters after regen' ) ;
52+ } ) ;
53+
54+ test ( 'TokenRing crash / recover edge cases' , ( ) => {
55+ const model = core . makeModel ( 3 , 'TokenRing' ) ;
56+
57+ assert . equal ( model . token . holder , 'P1' ) ;
58+ assert . equal ( core . crashProcess ( model , 'P1' ) . ok , true ) ;
59+ assert . equal ( model . token . lost , true ) ;
60+ assert . equal ( core . crashProcess ( model , 'P1' ) . reason , 'already_crashed' ) ;
61+
62+ assert . equal ( core . recoverProcess ( model , 'P1' ) . ok , true ) ;
63+ assert . equal ( core . recoverProcess ( model , 'P1' ) . reason , 'not_crashed' ) ;
64+
65+ assert . equal ( core . regenerateToken ( model ) . ok , true ) ;
66+
67+ core . requestCS ( model , 'P1' ) ;
68+ stepUntil ( core , model , ( ) => inCS ( core , model , 'P1' ) , 20 , 'P1 enters' ) ;
69+
70+ core . crashProcess ( model , 'P1' ) ;
71+ const r = core . stepOnce ( model ) ;
72+ assert . equal ( r . reason , 'token_lost' ) ;
73+ assert . match ( model . trace . map ( e => e . text ) . join ( '\n' ) , / c r a s h e d i n t h e c r i t i c a l s e c t i o n | t o k e n i s l o s t / ) ;
74+ } ) ;
75+
76+ test ( 'TokenRing script-mode events cover normal and invalid paths' , ( ) => {
77+ const demo = {
78+ type : 'MutexDemo' ,
79+ algorithm : 'TokenRing' ,
80+ processes : [ 'P1' , 'P2' ] ,
81+ events : [
82+ { } ,
83+ { t : 1 , op : 'holdToken' , on : 'P2' } ,
84+ { t : 2 , op : 'passToken' , to : 'P1' } ,
85+ { t : 3 , op : 'requestCS' , on : 'P1' } ,
86+ { t : 4 , op : 'releaseCS' , on : 'P1' } ,
87+ { t : 5 , op : 'releaseCS' , on : 'P2' } ,
88+ { t : 6 , op : 'dropToken' } ,
89+ { t : 7 , op : 'regenerateToken' , on : 'P2' } ,
90+ { t : 8 , op : 'crash' , on : 'P2' } ,
91+ { t : 9 , op : 'recover' , on : 'P2' } ,
92+ { t : 10 , op : 'unknownOp' }
93+ ]
94+ } ;
95+
96+ const model = core . loadFromJsonObject ( demo ) ;
97+ assert . equal ( model . mode , 'script' ) ;
98+
99+ stepN ( core , model , demo . events . length + 2 ) ;
100+ const trace = model . trace . map ( e => e . text ) . join ( '\n' ) ;
101+ assert . match ( trace , / L o a d e d s c r i p t e d s c e n a r i o / ) ;
102+ assert . match ( trace , / S c r i p t f i n i s h e d / ) ;
103+ } ) ;
0 commit comments