@@ -1202,3 +1202,117 @@ func TestNeverPickSTUNOnlyRegionAsPreferredDERP(t *testing.T) {
1202
1202
t .Errorf ("got PreferredDERP=%d; want 1" , r .PreferredDERP )
1203
1203
}
1204
1204
}
1205
+
1206
+ func Test_makeProbePlan_incremental (t * testing.T ) {
1207
+ type testcase struct {
1208
+ name string
1209
+ haveV4 bool
1210
+ haveV6 bool
1211
+ stunPorts []int
1212
+ expected []string
1213
+ }
1214
+ testcases := []testcase {
1215
+ {
1216
+ name : "slowSTUN" ,
1217
+ haveV4 : true ,
1218
+ stunPorts : []int {- 1 , - 1 , - 1 , 4 , 5 , 6 },
1219
+ expected : []string {"region-4-v4" , "region-5-v4" , "region-6-v4" },
1220
+ },
1221
+ {
1222
+ name : "fastSTUN" ,
1223
+ haveV4 : true ,
1224
+ stunPorts : []int {1 , 2 , 3 , - 1 , - 1 , - 1 },
1225
+ expected : []string {"region-1-v4" , "region-2-v4" , "region-2-v4" },
1226
+ },
1227
+ {
1228
+ name : "dualStackFast" ,
1229
+ haveV4 : true ,
1230
+ haveV6 : true ,
1231
+ stunPorts : []int {1 , 2 , 3 , - 1 , - 1 , - 1 },
1232
+ expected : []string {
1233
+ "region-1-v4" , "region-2-v4" , "region-2-v4" ,
1234
+ "region-1-v6" , "region-2-v6" , // only fastest 2 have v6
1235
+ },
1236
+ },
1237
+ {
1238
+ name : "dualStackSlow" ,
1239
+ haveV4 : true ,
1240
+ haveV6 : true ,
1241
+ stunPorts : []int {- 1 , - 1 , - 1 , 4 , 5 , 6 },
1242
+ expected : []string {
1243
+ "region-4-v4" , "region-5-v4" , "region-6-v4" ,
1244
+ "region-4-v6" , "region-5-v6" , // only fastest 2 have v6
1245
+ },
1246
+ },
1247
+ {
1248
+ // pathological case: STUN regions are not in top 3 and even
1249
+ // indexes re: latency
1250
+ name : "dualStackInterspersed" ,
1251
+ haveV4 : true ,
1252
+ haveV6 : true ,
1253
+ stunPorts : []int {- 1 , - 1 , - 1 , 4 , - 1 , 6 , - 1 , 8 },
1254
+ expected : []string {
1255
+ "region-4-v4" , "region-6-v4" , "region-8-v4" ,
1256
+ "region-4-v6" , "region-6-v6" , // only fastest 2 have v6
1257
+ },
1258
+ },
1259
+ }
1260
+ for _ , tc := range testcases {
1261
+ tc := tc
1262
+ t .Run (tc .name , func (t * testing.T ) {
1263
+ state := & interfaces.State {
1264
+ HaveV4 : tc .haveV4 ,
1265
+ HaveV6 : tc .haveV6 ,
1266
+ }
1267
+ plan := makeProbePlan (
1268
+ derpMapBySTUNPort (tc .stunPorts ),
1269
+ state ,
1270
+ reportLatencyAscending (len (tc .stunPorts ), tc .haveV4 , tc .haveV6 ),
1271
+ )
1272
+ for _ , e := range tc .expected {
1273
+ if _ , ok := plan [e ]; ! ok {
1274
+ t .Errorf ("expected %s in the plan" , e )
1275
+ }
1276
+ }
1277
+ })
1278
+ }
1279
+
1280
+ }
1281
+
1282
+ func derpMapBySTUNPort (ports []int ) * tailcfg.DERPMap {
1283
+ derpMap := & tailcfg.DERPMap {Regions : make (map [int ]* tailcfg.DERPRegion )}
1284
+ for i , p := range ports {
1285
+ j := i + 1
1286
+ var name string
1287
+ if p < 0 {
1288
+ name = fmt .Sprintf ("noSTUN%d" , j )
1289
+ } else {
1290
+ name = fmt .Sprintf ("STUN%d" , j )
1291
+ }
1292
+ derpMap .Regions [j ] = & tailcfg.DERPRegion {
1293
+ RegionID : j ,
1294
+ RegionCode : name ,
1295
+ Nodes : []* tailcfg.DERPNode {
1296
+ {Name : name , STUNPort : p },
1297
+ }}
1298
+ }
1299
+ return derpMap
1300
+ }
1301
+
1302
+ func reportLatencyAscending (n int , haveV4 , haveV6 bool ) * Report {
1303
+ r := & Report {
1304
+ RegionLatency : make (map [int ]time.Duration ),
1305
+ RegionV4Latency : make (map [int ]time.Duration ),
1306
+ RegionV6Latency : make (map [int ]time.Duration ),
1307
+ }
1308
+ for i := 1 ; i <= n ; i ++ {
1309
+ r .RegionLatency [i ] = time .Duration (i ) * time .Millisecond
1310
+ if haveV4 {
1311
+ r .RegionV4Latency [i ] = time .Duration (i ) * time .Millisecond
1312
+ }
1313
+ if haveV6 {
1314
+ r .RegionV6Latency [i ] = time .Duration (i ) * time .Millisecond
1315
+ }
1316
+ }
1317
+ return r
1318
+ }
0 commit comments