@@ -56,3 +56,96 @@ test('generateTraceId should generate a 32 character hex string', () => {
56
56
57
57
expect ( / ^ [ 0 - 9 a - f ] { 32 } $ / . test ( id ) ) . toEqual ( true )
58
58
} )
59
+
60
+ describe ( '#826 trace id should be unique' , ( ) => {
61
+ test ( 'should not generate subsequent ids that are the same' , ( ) => {
62
+ expect ( uniqueId . generateTraceId ( ) ) . not . toEqual ( uniqueId . generateTraceId ( ) )
63
+ } )
64
+ } )
65
+
66
+ describe ( 'rough randomness tests' , ( ) => {
67
+ /**
68
+ * This tests the distribution of each hex character. The distribution of each character
69
+ * should approach 1.0 to show that each character is being used as evenly as possible to
70
+ * produce the resulting string.
71
+ */
72
+ test ( 'should have sufficient distribution of 8 bit character usage' , ( ) => {
73
+ const tally = new Map ( )
74
+ const sampleSize = 100000 // A large sample size but not so large that it causes the test to take forever
75
+
76
+ for ( let i = 0 ; i < sampleSize ; i ++ ) {
77
+ const chars = uniqueId . generateTraceId ( ) . split ( '' )
78
+ chars . forEach ( char => {
79
+ if ( ! tally . has ( char ) ) {
80
+ tally . set ( char , 1 )
81
+ } else {
82
+ tally . set ( char , ( tally . get ( char ) ) + 1 )
83
+ }
84
+ } )
85
+ }
86
+
87
+ tally . forEach ( ( distributionCount ) => {
88
+ /*
89
+ Take the square root of the distribution count as a variance stabilization:
90
+ https://en.wikipedia.org/wiki/Variance-stabilizing_transformation
91
+
92
+ Divide by the total number of possible values accounting for placement within the
93
+ resulting string:
94
+ 16 === the number of unique hex characters
95
+ 32 === the length of the string returned by our random function
96
+ sampleSize === the total number of times we are running the function
97
+
98
+ Subtract 1 to make the result into a percentage.
99
+ */
100
+ const distributionDeviation = 1 - Math . sqrt ( distributionCount ) / ( 16 * 32 * sampleSize )
101
+ expect ( distributionDeviation ) . toBeGreaterThanOrEqual ( 0.999 )
102
+ } )
103
+ } )
104
+
105
+ /**
106
+ * This tests the distribution of each hex character. The distribution of each character
107
+ * should approach 1.0 to show that each character is being used as evenly as possible to
108
+ * produce the resulting string.
109
+ */
110
+ test ( 'should have sufficient distribution of sequential characters' , ( ) => {
111
+ const tally = new Map ( )
112
+ const sampleSize = 100000 // A large sample size but not so large that it causes the test to take forever
113
+
114
+ for ( let i = 0 ; i < sampleSize ; i ++ ) {
115
+ const chars = uniqueId . generateTraceId ( ) . split ( '' )
116
+
117
+ chars . forEach ( ( char , index ) => {
118
+ let charSequence
119
+
120
+ if ( index === 0 ) {
121
+ charSequence = `_${ char } `
122
+ } else {
123
+ charSequence = `${ chars [ index - 1 ] } ${ char } `
124
+ }
125
+
126
+ if ( ! tally . has ( charSequence ) ) {
127
+ tally . set ( charSequence , 1 )
128
+ } else {
129
+ tally . set ( charSequence , ( tally . get ( charSequence ) ) + 1 )
130
+ }
131
+ } )
132
+ }
133
+
134
+ tally . forEach ( ( distributionCount ) => {
135
+ /*
136
+ Take the square root of the distribution count as a variance stabilization:
137
+ https://en.wikipedia.org/wiki/Variance-stabilizing_transformation
138
+
139
+ Divide by the total number of possible values accounting for placement within the
140
+ resulting string:
141
+ 16 === the number of unique hex characters
142
+ 32 === the length of the string returned by our random function
143
+ sampleSize === the total number of times we are running the function
144
+
145
+ Subtract 1 to make the result into a percentage.
146
+ */
147
+ const distributionDeviation = 1 - Math . sqrt ( distributionCount ) / ( 16 * 32 * sampleSize )
148
+ expect ( distributionDeviation ) . toBeGreaterThanOrEqual ( 0.999 )
149
+ } )
150
+ } )
151
+ } )
0 commit comments