@@ -2,10 +2,8 @@ import {
22 SubaccountUsernamesTable ,
33 SubaccountTable ,
44 QueryableField ,
5-
65 testMocks ,
76 dbHelpers ,
8- SubaccountUsernamesFromDatabase ,
97 SubaccountFromDatabase ,
108 testConstants ,
119} from '@dydxprotocol-indexer/postgres' ;
@@ -21,8 +19,12 @@ describe('subaccount-username-generator', () => {
2119 await testMocks . seedData ( ) ;
2220 await testMocks . seedAdditionalSubaccounts ( ) ;
2321 // delete all usernames that were seeded
24- await SubaccountUsernamesTable . deleteBySubaccountId ( testConstants . defaultSubaccountId ) ;
25- await SubaccountUsernamesTable . deleteBySubaccountId ( testConstants . defaultSubaccountId2 ) ;
22+ await SubaccountUsernamesTable . deleteBySubaccountId (
23+ testConstants . defaultSubaccountId ,
24+ ) ;
25+ await SubaccountUsernamesTable . deleteBySubaccountId (
26+ testConstants . defaultSubaccountId2 ,
27+ ) ;
2628 } ) ;
2729
2830 afterAll ( async ( ) => {
@@ -36,30 +38,154 @@ describe('subaccount-username-generator', () => {
3638 } ) ;
3739
3840 it ( 'Successfully creates a username for all subaccount' , async ( ) => {
39- const subaccounts : SubaccountFromDatabase [ ] = await
40- SubaccountTable . findAll ( {
41- subaccountNumber : 0 ,
42- } , [ QueryableField . SUBACCOUNT_NUMBER ] , { } ) ;
41+ const subaccounts : SubaccountFromDatabase [ ] = await SubaccountTable . findAll (
42+ {
43+ subaccountNumber : 0 ,
44+ } ,
45+ [ QueryableField . SUBACCOUNT_NUMBER ] ,
46+ { } ,
47+ ) ;
4348
4449 const subaccountsLength : number = subaccounts . length ;
45- const subaccountsWithUsernames : SubaccountUsernamesFromDatabase [ ] = await
46- SubaccountUsernamesTable . findAll (
47- { } , [ ] , { } ) ;
48- expect ( subaccountsWithUsernames . length ) . toEqual ( 0 ) ;
50+ const before = await SubaccountUsernamesTable . findAll (
51+ { } ,
52+ [ ] ,
53+ { readReplica : true } ,
54+ ) ;
55+ expect ( before . length ) . toEqual ( 0 ) ;
4956
5057 await subaccountUsernameGenerator ( ) ;
51- const subaccountsWithUsernamesAfter : SubaccountUsernamesFromDatabase [ ] = await
52- SubaccountUsernamesTable . findAll (
53- { } , [ ] , { } ) ;
58+ const after = await SubaccountUsernamesTable . findAll (
59+ { } ,
60+ [ ] ,
61+ { readReplica : true } ,
62+ ) ;
5463
5564 const expectedUsernames = [
5665 'BubblyEarH5Y' , // dydx1n88uc38xhjgxzw9nwre4ep2c8ga4fjxc575lnf
5766 'GreenSnowWTT' , // dydx1n88uc38xhjgxzw9nwre4ep2c8ga4fjxc565lnf
5867 'LunarMatFK5' , // dydx199tqg4wdlnu4qjlxchpd7seg454937hjrknju4
5968 ] ;
60- expect ( subaccountsWithUsernamesAfter . length ) . toEqual ( subaccountsLength ) ;
69+ expect ( after . length ) . toEqual ( subaccountsLength ) ;
6170 for ( let i = 0 ; i < expectedUsernames . length ; i ++ ) {
62- expect ( subaccountsWithUsernamesAfter [ i ] . username ) . toEqual ( expectedUsernames [ i ] ) ;
71+ expect ( after [ i ] . username ) . toEqual ( expectedUsernames [ i ] ) ;
72+ }
73+ } ) ;
74+
75+ it ( 'Falls back to a second username when there is a conflict on the first attempt' , async ( ) => {
76+ const subaccounts : SubaccountFromDatabase [ ] = await SubaccountTable . findAll (
77+ {
78+ subaccountNumber : 0 ,
79+ } ,
80+ [ QueryableField . SUBACCOUNT_NUMBER ] ,
81+ { } ,
82+ ) ;
83+ const targetSubaccount = subaccounts [ 0 ] ;
84+ const otherSubaccount = subaccounts [ 1 ] ;
85+
86+ const { generateUsernameForSubaccount } = require ( '../../src/helpers/usernames-helper' ) ;
87+
88+ const usernameAttempt0 = generateUsernameForSubaccount (
89+ targetSubaccount . address ,
90+ 0 ,
91+ 0 ,
92+ ) ;
93+ await SubaccountUsernamesTable . create ( {
94+ username : usernameAttempt0 ,
95+ subaccountId : otherSubaccount . id ,
96+ } ) ;
97+
98+ const afterPreInsert = await SubaccountUsernamesTable . findAll (
99+ { subaccountId : [ targetSubaccount . id ] } , [ QueryableField . SUBACCOUNT_ID ] , { } ,
100+ ) ;
101+ expect ( afterPreInsert . length ) . toBe ( 0 ) ;
102+
103+ await subaccountUsernameGenerator ( ) ;
104+
105+ const created = await SubaccountUsernamesTable . findAll (
106+ { subaccountId : [ targetSubaccount . id ] } , [ QueryableField . SUBACCOUNT_ID ] , { } ,
107+ ) ;
108+ expect ( created . length ) . toBe ( 1 ) ;
109+
110+ const fallbackUsername = generateUsernameForSubaccount (
111+ targetSubaccount . address ,
112+ 0 ,
113+ 1 ,
114+ ) ;
115+ expect ( created [ 0 ] . username ) . toEqual ( fallbackUsername ) ;
116+
117+ const conflict = await SubaccountUsernamesTable . findAll (
118+ { username : [ usernameAttempt0 ] } , [ QueryableField . USERNAME ] , { } ,
119+ ) ;
120+ expect ( conflict . length ) . toBe ( 1 ) ;
121+ expect ( conflict [ 0 ] . subaccountId ) . not . toEqual ( targetSubaccount . id ) ;
122+ } ) ;
123+
124+ it ( 'Handles batch where one username succeeds and the other needs a fallback' , async ( ) => {
125+ const subaccounts : SubaccountFromDatabase [ ] = await SubaccountTable . findAll (
126+ {
127+ subaccountNumber : 0 ,
128+ } ,
129+ [ QueryableField . SUBACCOUNT_NUMBER ] ,
130+ { } ,
131+ ) ;
132+ expect ( subaccounts . length ) . toBeGreaterThanOrEqual ( 2 ) ;
133+
134+ const sub0 = subaccounts [ 0 ] ;
135+ const sub1 = subaccounts [ 1 ] ;
136+
137+ const { generateUsernameForSubaccount } = require ( '../../src/helpers/usernames-helper' ) ;
138+
139+ const sub0Attempt0 = generateUsernameForSubaccount ( sub0 . address , 0 , 0 ) ;
140+ await SubaccountUsernamesTable . create ( {
141+ username : sub0Attempt0 ,
142+ subaccountId : sub1 . id ,
143+ } ) ;
144+
145+ // pre-run checks
146+ const preUsernames = await SubaccountUsernamesTable . findAll (
147+ { } ,
148+ [ ] ,
149+ { readReplica : true } ,
150+ ) ;
151+ expect (
152+ preUsernames . find ( ( u : any ) => u . username === sub0Attempt0 ) ,
153+ ) . toBeDefined ( ) ;
154+ expect ( preUsernames . filter ( ( u : any ) => u . subaccountId === sub0 . id ) . length ) . toBe ( 0 ) ;
155+ expect ( preUsernames . filter (
156+ ( u : any ) => u . subaccountId === sub1 . id && u . username !== sub0Attempt0 ,
157+ ) . length ) . toBe ( 0 ) ;
158+
159+ // run generator
160+ await subaccountUsernameGenerator ( ) ;
161+
162+ // fetch results
163+ const after = await SubaccountUsernamesTable . findAll (
164+ { } ,
165+ [ ] ,
166+ { readReplica : true } ,
167+ ) ;
168+
169+ // sub0 should have fallback username
170+ const sub0UsernameRow = after . find ( ( u : any ) => u . subaccountId === sub0 . id ) ;
171+ const sub0ExpectedFallback = generateUsernameForSubaccount ( sub0 . address , 0 , 1 ) ;
172+ expect ( sub0UsernameRow ) . toBeDefined ( ) ;
173+ if ( sub0UsernameRow ) {
174+ expect ( sub0UsernameRow . username ) . toEqual ( sub0ExpectedFallback ) ;
175+ }
176+ const sub1UsernameRow = after . find (
177+ ( u : any ) => u . subaccountId === sub1 . id && u . username !== sub0Attempt0 ) ;
178+ if ( sub1UsernameRow ) {
179+ expect ( sub1UsernameRow ) . toBeDefined ( ) ;
180+ }
181+
182+ // There should not be two usernames with the same value
183+ const usernameCounts = after . reduce ( ( acc : Record < string , number > , u : any ) => {
184+ acc [ u . username ] = ( acc [ u . username ] || 0 ) + 1 ;
185+ return acc ;
186+ } , { } ) ;
187+ for ( const count of Object . values ( usernameCounts ) ) {
188+ expect ( count ) . toBe ( 1 ) ;
63189 }
64190 } ) ;
65191} ) ;
0 commit comments