@@ -16,7 +16,8 @@ public sealed class LcgAssignmentTests
1616{
1717 [ ClassDataSource < WebApplicationFactory > ( Shared = SharedType . PerTestSession ) ]
1818 public required WebApplicationFactory WebApplicationFactory { get ; init ; }
19-
19+
20+ private const string ParalellGateway = "gateway_assignment" ;
2021 private Guid _userId ;
2122 private Guid _hubId ;
2223 private string _hubToken = string . Empty ;
@@ -32,7 +33,7 @@ public async Task Setup()
3233 _userId = Guid . CreateVersion7 ( ) ;
3334 _hubId = Guid . CreateVersion7 ( ) ;
3435 _hubToken = CryptoUtils . RandomAlphaNumericString ( 256 ) ;
35-
36+
3637 // Create mock data
3738 db . Users . Add ( new User
3839 {
@@ -60,54 +61,114 @@ public async Task Teardown()
6061 var db = context . ServiceProvider . GetRequiredService < OpenShockContext > ( ) ;
6162 var redisConnectionProvider = context . ServiceProvider . GetRequiredService < IRedisConnectionProvider > ( ) ;
6263 var lcgNodesCollection = redisConnectionProvider . RedisCollection < LcgNode > ( false ) ;
63-
64+
6465 // Data cleanup
6566 await db . Devices . Where ( x => x . Id == _hubId ) . ExecuteDeleteAsync ( ) ;
6667 await db . Users . Where ( x => x . Id == _userId ) . ExecuteDeleteAsync ( ) ;
67-
68+
6869 var allLcg = await lcgNodesCollection . ToArrayAsync ( ) ;
6970 await lcgNodesCollection . DeleteAsync ( allLcg ) ;
7071 }
7172
7273 [ Test ]
73- [ NotInParallel ]
74- [ Arguments ( "US" , "us1.example.com" , new [ ] { "US|us1.example.com" , "DE|de1.example.com" , "AS|as1.example.com" } ) ]
75- [ Arguments ( "DE" , "de1.example.com" , new [ ] { "US|us1.example.com" , "DE|de1.example.com" , "AS|as1.example.com" } ) ]
76- [ Arguments ( "CA" , "us1.example.com" , new [ ] { "US|us1.example.com" , "DE|de1.example.com" , "AS|as1.example.com" } ) ]
77- [ Arguments ( "CA" , "us1.example.com" , new [ ] { "US|us1.example.com" , "DE|de1.example.com" , "AS|as1.example.com" } ) ]
78- [ Arguments ( "AT" , "de1.example.com" , new [ ] { "US|us1.example.com" , "DE|de1.example.com" , "AS|as1.example.com" } ) ]
79- [ Arguments ( "FR" , "de1.example.com" , new [ ] { "US|us1.example.com" , "DE|de1.example.com" , "AS|as1.example.com" } ) ]
80- public async Task GetLcgAssignment ( string requesterCountry , string expectedHost , string [ ] availableGateways )
74+ [ NotInParallel ( ParalellGateway ) ]
75+ [ Arguments ( "US" , "us1.example.com" ) ]
76+ [ Arguments ( "DE" , "de1.example.com" ) ]
77+ [ Arguments ( "CA" , "us1.example.com" ) ]
78+ [ Arguments ( "CA" , "us1.example.com" ) ]
79+ [ Arguments ( "AT" , "de1.example.com" ) ]
80+ [ Arguments ( "FR" , "de1.example.com" ) ]
81+ public async Task CheckBasicAssignments ( string requesterCountry , string expectedHost )
8182 {
82- // Dependency Resolution
83- await using var context = WebApplicationFactory . Services . CreateAsyncScope ( ) ;
84- var redisConnectionProvider = context . ServiceProvider . GetRequiredService < IRedisConnectionProvider > ( ) ;
85- var lcgNodesCollection = redisConnectionProvider . RedisCollection < LcgNode > ( saveState : true ) ;
86- var webHostEnvironment = context . ServiceProvider . GetRequiredService < IWebHostEnvironment > ( ) ;
87-
88- // Create mock data
89- await lcgNodesCollection . InsertAsync ( availableGateways . Select ( x => x . Split ( '|' , 2 ) ) . Select ( x => new LcgNode
90- {
91- Country = x [ 0 ] ,
92- Fqdn = x [ 1 ] ,
93- Load = 0 ,
94- Environment = webHostEnvironment . EnvironmentName
95- } ) ) ;
96-
97- using var client = WebApplicationFactory . CreateClient ( ) ;
83+ await AddGateways ( [ "US|us1.example.com" , "DE|de1.example.com" , "AS|as1.example.com" ] ) ;
84+ var response = await SendAssignRequest ( requesterCountry ) ;
85+ await Assert . That ( response . StatusCode ) . IsEqualTo ( HttpStatusCode . OK ) ;
86+ var mediaType = response . Content . Headers . ContentType ? . MediaType ;
87+ await Assert . That ( mediaType ) . IsEqualTo ( MediaTypeNames . Application . Json ) ;
9888
99- var httpRequest = new HttpRequestMessage ( HttpMethod . Get , "/2/device/assignLCG?version=1" ) ;
100- httpRequest . Headers . Add ( "Device-Token" , _hubToken ) ;
101- httpRequest . Headers . Add ( "CF-IPCountry" , requesterCountry ) ;
102- var response = await client . SendAsync ( httpRequest ) ;
89+ var data = await response . Content . ReadFromJsonAsync < LcgNodeResponseV2 > ( ) ;
90+ await Assert . That ( data ) . IsNotNull ( ) ;
91+ await Assert . That ( data . Host ) . IsEqualTo ( expectedHost ) ;
92+ }
10393
94+ [ Test ]
95+ [ NotInParallel ( ParalellGateway ) ]
96+ [ Arguments ( "US" ) ]
97+ [ Arguments ( "DE" ) ]
98+ [ Arguments ( "XX" ) ]
99+ [ Arguments ( null ) ]
100+ public async Task CheckAnyGateway ( string ? requesterCountry )
101+ {
102+ await AddGateways ( [ "US|us1.example.com" , "DE|de1.example.com" , "AS|as1.example.com" ] ) ;
103+ var response = await SendAssignRequest ( requesterCountry ) ;
104104 await Assert . That ( response . StatusCode ) . IsEqualTo ( HttpStatusCode . OK ) ;
105-
106105 var mediaType = response . Content . Headers . ContentType ? . MediaType ;
107106 await Assert . That ( mediaType ) . IsEqualTo ( MediaTypeNames . Application . Json ) ;
108107
109108 var data = await response . Content . ReadFromJsonAsync < LcgNodeResponseV2 > ( ) ;
110109 await Assert . That ( data ) . IsNotNull ( ) ;
111- await Assert . That ( data . Host ) . IsEqualTo ( expectedHost ) ;
110+ await Assert . That ( data . Host ) . IsNotNullOrWhiteSpace ( ) ;
111+ }
112+
113+ [ Test ]
114+ [ NotInParallel ( ParalellGateway ) ]
115+ [ Arguments ( "US" ) ]
116+ [ Arguments ( "XX" ) ]
117+ [ Arguments ( null ) ]
118+ public async Task CheckUnavailable ( string ? requesterCountry )
119+ {
120+ // We dont add any gateways here
121+ var response = await SendAssignRequest ( requesterCountry ) ;
122+
123+ await Assert . That ( response . StatusCode ) . IsEqualTo ( HttpStatusCode . ServiceUnavailable ) ;
124+ }
125+
126+ [ Test ]
127+ [ NotInParallel ( ParalellGateway ) ]
128+ public async Task CheckEnvironmentFilter ( )
129+ {
130+ await AddGateways ( [
131+ "US|us-dev.example.com" ,
132+ "DE|de-dev.example.com" ,
133+ "AS|as-dev.example.com"
134+ ] , "SomethingThatDoesntExist!" ) ;
135+
136+ // This sends a request with an actual environment like development or production
137+ var response = await SendAssignRequest ( "XX" ) ;
138+ await Assert . That ( response . StatusCode ) . IsEqualTo ( HttpStatusCode . ServiceUnavailable ) ;
139+ }
140+
141+ private async Task AddGateways ( string [ ] availableGateways , string ? environmentOverride = null )
142+ {
143+ await using var context = WebApplicationFactory . Services . CreateAsyncScope ( ) ;
144+ var redisConnectionProvider = context . ServiceProvider . GetRequiredService < IRedisConnectionProvider > ( ) ;
145+ var webHostEnvironment = context . ServiceProvider . GetRequiredService < IWebHostEnvironment > ( ) ;
146+ var lcgNodesCollection = redisConnectionProvider . RedisCollection < LcgNode > ( false ) ;
147+ var testGateways = availableGateways . Select ( x =>
148+ {
149+ var split = x . Split ( '|' ) ;
150+ if ( split . Length != 2 )
151+ throw new ArgumentException ( "Invalid gateway format" ) ;
152+
153+ return new LcgNode
154+ {
155+ Country = split [ 0 ] ,
156+ Fqdn = split [ 1 ] ,
157+ Load = 0 ,
158+ Environment = environmentOverride ?? webHostEnvironment . EnvironmentName
159+ } ;
160+ } ) ;
161+
162+ await lcgNodesCollection . InsertAsync ( testGateways ) ;
163+ }
164+
165+ private async Task < HttpResponseMessage > SendAssignRequest ( string ? requesterCountry )
166+ {
167+ var httpRequest = new HttpRequestMessage ( HttpMethod . Get , "/2/device/assignLCG?version=1" ) ;
168+ httpRequest . Headers . Add ( "Device-Token" , _hubToken ) ;
169+ if ( ! string . IsNullOrEmpty ( requesterCountry ) ) httpRequest . Headers . Add ( "CF-IPCountry" , requesterCountry ) ;
170+
171+ using var client = WebApplicationFactory . CreateClient ( ) ;
172+ return await client . SendAsync ( httpRequest ) ;
112173 }
113174}
0 commit comments