@@ -95,6 +95,15 @@ type PartitionRow = {
9595 _children : PartitionRow [ ] | null ;
9696} ;
9797
98+ function walkRows ( rows : PartitionRow [ ] , visit : ( row : PartitionRow ) => void ) : void {
99+ for ( const row of rows ) {
100+ visit ( row ) ;
101+ if ( row . _children && row . _children . length > 0 ) {
102+ walkRows ( row . _children , visit ) ;
103+ }
104+ }
105+ }
106+
98107function assertPartitionInvariant ( rows : PartitionRow [ ] ) : void {
99108 for ( const row of rows ) {
100109 if ( ! row . _children || row . _children . length === 0 ) {
@@ -140,6 +149,16 @@ function assertPartitionInvariant(rows: PartitionRow[]): void {
140149 }
141150}
142151
152+ function assertRowsDoNotExceedGlobalTotals ( rows : PartitionRow [ ] , global : PartitionRow ) : void {
153+ walkRows ( rows , ( row ) => {
154+ expect ( row . totalTime ) . toBeLessThanOrEqual ( global . totalTime ) ;
155+ expect ( row . dmlCount . total ) . toBeLessThanOrEqual ( global . dmlCount . total ) ;
156+ expect ( row . soqlCount . total ) . toBeLessThanOrEqual ( global . soqlCount . total ) ;
157+ expect ( row . dmlRowCount . total ) . toBeLessThanOrEqual ( global . dmlRowCount . total ) ;
158+ expect ( row . soqlRowCount . total ) . toBeLessThanOrEqual ( global . soqlRowCount . total ) ;
159+ } ) ;
160+ }
161+
143162function sumTraceSelfTime ( events : LogEvent [ ] ) : number {
144163 let total = 0 ;
145164 for ( const event of events ) {
@@ -658,7 +677,7 @@ describe('toBottomUpTree', () => {
658677 expect ( rootSelfBudget ) . toBe ( traceSelfBudget ) ;
659678 } ) ;
660679
661- it ( 'matches worked example A (pure recursion) from BOTTOM_UP_CALL_TREE_SPEC.md ' , ( ) => {
680+ it ( 'matches worked example A (pure recursion)' , ( ) => {
662681 const root = createEvent ( { text : 'LOG_ROOT' , self : 0 , total : 0 , type : 'EXECUTION_STARTED' } ) ;
663682 const outer = createEvent ( { text : 'Outer' , self : 100 , total : 1000 , parent : root } ) ;
664683 const r1 = createEvent ( { text : 'recursive' , self : 10 , total : 35 , parent : outer } ) ;
@@ -689,7 +708,7 @@ describe('toBottomUpTree', () => {
689708 expect ( level3Outer . _children ) . toBeNull ( ) ;
690709 } ) ;
691710
692- it ( 'matches worked example B (other / sub other) from BOTTOM_UP_CALL_TREE_SPEC.md ' , ( ) => {
711+ it ( 'matches worked example B (other / sub other)' , ( ) => {
693712 const root = createEvent ( { text : 'LOG_ROOT' , self : 0 , total : 0 , type : 'EXECUTION_STARTED' } ) ;
694713 const outer = createEvent ( { text : 'Outer' , self : 0 , total : 25 , parent : root } ) ;
695714 const other = createEvent ( { text : 'other' , self : 10 , total : 25 , parent : outer } ) ;
@@ -713,7 +732,7 @@ describe('toBottomUpTree', () => {
713732 expect ( otherOuter ) . toMatchObject ( { totalSelfTime : 10 , totalTime : 25 } ) ;
714733 } ) ;
715734
716- it ( 'matches worked example C (nested Search) from top-down-to-bottom-up-example.md ' , ( ) => {
735+ it ( 'matches worked example C (nested Search)' , ( ) => {
717736 const root = createEvent ( { text : 'LOG_ROOT' , self : 0 , total : 0 , type : 'EXECUTION_STARTED' } ) ;
718737 const outer = createEvent ( { text : 'Outer' , self : 100 , total : 1000 , parent : root } ) ;
719738
@@ -875,6 +894,97 @@ describe('toBottomUpTree', () => {
875894 expect ( limitOnly . dmlCount . self ) . toBe ( 1 ) ;
876895 expect ( limitOnly . totalThrownCount ) . toBe ( 1 ) ;
877896 } ) ;
897+
898+ it ( 'orders roots deterministically by totalSelfTime desc, then name asc for ties' , ( ) => {
899+ const root = createEvent ( { text : 'LOG_ROOT' , self : 0 , total : 0 , type : 'EXECUTION_STARTED' } ) ;
900+ createEvent ( { text : 'Zulu' , self : 30 , total : 30 , parent : root } ) ;
901+ createEvent ( { text : 'Alpha' , self : 20 , total : 20 , parent : root } ) ;
902+ createEvent ( { text : 'Beta' , self : 20 , total : 20 , parent : root } ) ;
903+
904+ const rows = toBottomUpTree ( root . children ) ;
905+ expect ( rows . map ( ( row ) => row . text ) ) . toEqual ( [ 'Zulu' , 'Alpha' , 'Beta' ] ) ;
906+ } ) ;
907+
908+ it ( 'keeps every bottom-up total metric within the top-down global root totals' , ( ) => {
909+ const root = createEvent ( { text : 'LOG_ROOT' , self : 0 , total : 0 , type : 'EXECUTION_STARTED' } ) ;
910+ const outer = createEvent ( {
911+ text : 'Outer' ,
912+ self : 50 ,
913+ total : 500 ,
914+ parent : root ,
915+ dmlSelf : 4 ,
916+ dmlTotal : 40 ,
917+ soqlSelf : 3 ,
918+ soqlTotal : 30 ,
919+ dmlRowSelf : 20 ,
920+ dmlRowTotal : 200 ,
921+ soqlRowSelf : 10 ,
922+ soqlRowTotal : 100 ,
923+ thrown : 7 ,
924+ } ) ;
925+
926+ const search = createEvent ( {
927+ text : 'Search' ,
928+ self : 25 ,
929+ total : 300 ,
930+ parent : outer ,
931+ dmlSelf : 2 ,
932+ dmlTotal : 20 ,
933+ soqlSelf : 1 ,
934+ soqlTotal : 15 ,
935+ dmlRowSelf : 10 ,
936+ dmlRowTotal : 120 ,
937+ soqlRowSelf : 4 ,
938+ soqlRowTotal : 60 ,
939+ thrown : 3 ,
940+ } ) ;
941+
942+ createEvent ( {
943+ text : 'Search' ,
944+ self : 10 ,
945+ total : 150 ,
946+ parent : search ,
947+ dmlSelf : 1 ,
948+ dmlTotal : 8 ,
949+ soqlSelf : 1 ,
950+ soqlTotal : 6 ,
951+ dmlRowSelf : 5 ,
952+ dmlRowTotal : 40 ,
953+ soqlRowSelf : 2 ,
954+ soqlRowTotal : 20 ,
955+ thrown : 1 ,
956+ } ) ;
957+
958+ createEvent ( {
959+ text : 'Worker' ,
960+ self : 60 ,
961+ total : 100 ,
962+ parent : outer ,
963+ dmlSelf : 2 ,
964+ dmlTotal : 12 ,
965+ soqlSelf : 1 ,
966+ soqlTotal : 7 ,
967+ dmlRowSelf : 8 ,
968+ dmlRowTotal : 35 ,
969+ soqlRowSelf : 3 ,
970+ soqlRowTotal : 15 ,
971+ thrown : 1 ,
972+ } ) ;
973+
974+ const rows = toBottomUpTree ( root . children ) as PartitionRow [ ] ;
975+ const globalRoot : PartitionRow = {
976+ text : outer . text ,
977+ totalTime : outer . duration . total ,
978+ totalSelfTime : outer . duration . self ,
979+ dmlCount : { self : outer . dmlCount . self , total : outer . dmlCount . total } ,
980+ soqlCount : { self : outer . soqlCount . self , total : outer . soqlCount . total } ,
981+ dmlRowCount : { self : outer . dmlRowCount . self , total : outer . dmlRowCount . total } ,
982+ soqlRowCount : { self : outer . soqlRowCount . self , total : outer . soqlRowCount . total } ,
983+ _children : null ,
984+ } ;
985+
986+ assertRowsDoNotExceedGlobalTotals ( rows , globalRoot ) ;
987+ } ) ;
878988} ) ;
879989
880990describe ( 'toAggregatedCallTree' , ( ) => {
0 commit comments