master
go 654 lines 21.6 KB
Raw
1 package autoconf
2
3 import (
4 "context"
5 "encoding/json"
6 "fmt"
7 "net/http"
8 "net/http/httptest"
9 "strings"
10 "testing"
11 "time"
12
13 "github.com/ipfs/boxo/autoconf"
14 "github.com/stretchr/testify/assert"
15 "github.com/stretchr/testify/require"
16 )
17
18 // testAutoConfWithFallback is a helper function that tests autoconf parsing with fallback detection
19 func testAutoConfWithFallback(t *testing.T, serverURL string, expectError bool, expectErrorMsg string) (*autoconf.Config, bool) {
20 return testAutoConfWithFallbackAndTimeout(t, serverURL, expectError, expectErrorMsg, 10*time.Second)
21 }
22
23 // testAutoConfWithFallbackAndTimeout is a helper function that tests autoconf parsing with fallback detection and custom timeout
24 func testAutoConfWithFallbackAndTimeout(t *testing.T, serverURL string, expectError bool, expectErrorMsg string, timeout time.Duration) (*autoconf.Config, bool) {
25 // Use fallback detection to test error conditions with MustGetConfigWithRefresh
26 fallbackUsed := false
27 fallbackConfig := &autoconf.Config{
28 AutoConfVersion: -999, // Special marker to detect fallback usage
29 AutoConfSchema: -999,
30 }
31
32 client, err := autoconf.NewClient(
33 autoconf.WithUserAgent("test-agent"),
34 autoconf.WithURL(serverURL),
35 autoconf.WithRefreshInterval(autoconf.DefaultRefreshInterval),
36 autoconf.WithFallback(func() *autoconf.Config {
37 fallbackUsed = true
38 return fallbackConfig
39 }),
40 )
41 require.NoError(t, err)
42
43 ctx, cancel := context.WithTimeout(context.Background(), timeout)
44 defer cancel()
45 result := client.GetCachedOrRefresh(ctx)
46
47 if expectError {
48 require.True(t, fallbackUsed, expectErrorMsg)
49 require.Equal(t, int64(-999), result.AutoConfVersion, "Should return fallback config for error case")
50 } else {
51 require.False(t, fallbackUsed, "Expected no fallback to be used")
52 require.NotEqual(t, int64(-999), result.AutoConfVersion, "Should return fetched config for success case")
53 }
54
55 return result, fallbackUsed
56 }
57
58 func TestAutoConfFuzz(t *testing.T) {
59 t.Parallel()
60
61 t.Run("fuzz autoconf version", testFuzzAutoConfVersion)
62 t.Run("fuzz bootstrap arrays", testFuzzBootstrapArrays)
63 t.Run("fuzz dns resolvers", testFuzzDNSResolvers)
64 t.Run("fuzz delegated routers", testFuzzDelegatedRouters)
65 t.Run("fuzz delegated publishers", testFuzzDelegatedPublishers)
66 t.Run("fuzz malformed json", testFuzzMalformedJSON)
67 t.Run("fuzz large payloads", testFuzzLargePayloads)
68 }
69
70 func testFuzzAutoConfVersion(t *testing.T) {
71 testCases := []struct {
72 name string
73 version any
74 expectError bool
75 }{
76 {"valid version", 2025071801, false},
77 {"zero version", 0, true}, // Should be invalid
78 {"negative version", -1, false}, // Parser accepts negative versions
79 {"string version", "2025071801", true}, // Should be number
80 {"float version", 2025071801.5, true},
81 {"very large version", 9999999999999999, false}, // Large but valid int64
82 {"null version", nil, true},
83 }
84
85 for _, tc := range testCases {
86 t.Run(tc.name, func(t *testing.T) {
87 config := map[string]any{
88 "AutoConfVersion": tc.version,
89 "AutoConfSchema": 1,
90 "AutoConfTTL": 86400,
91 "SystemRegistry": map[string]any{
92 "AminoDHT": map[string]any{
93 "Description": "Test AminoDHT system",
94 "NativeConfig": map[string]any{
95 "Bootstrap": []string{
96 "/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN",
97 },
98 },
99 },
100 },
101 "DNSResolvers": map[string]any{},
102 "DelegatedEndpoints": map[string]any{},
103 }
104
105 jsonData, err := json.Marshal(config)
106 require.NoError(t, err)
107
108 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
109 w.Header().Set("Content-Type", "application/json")
110 _, _ = w.Write(jsonData)
111 }))
112 defer server.Close()
113
114 // Test that our autoconf parser handles this gracefully
115 _, _ = testAutoConfWithFallback(t, server.URL, tc.expectError, fmt.Sprintf("Expected fallback to be used for %s", tc.name))
116 })
117 }
118 }
119
120 func testFuzzBootstrapArrays(t *testing.T) {
121 type testCase struct {
122 name string
123 bootstrap any
124 expectError bool
125 validate func(*testing.T, *autoconf.Response)
126 }
127
128 testCases := []testCase{
129 {
130 name: "valid bootstrap",
131 bootstrap: []string{"/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN"},
132 validate: func(t *testing.T, resp *autoconf.Response) {
133 expected := []string{"/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN"}
134 bootstrapPeers := resp.Config.GetBootstrapPeers("AminoDHT")
135 assert.Equal(t, expected, bootstrapPeers, "Bootstrap peers should match configured values")
136 },
137 },
138 {
139 name: "empty bootstrap",
140 bootstrap: []string{},
141 validate: func(t *testing.T, resp *autoconf.Response) {
142 bootstrapPeers := resp.Config.GetBootstrapPeers("AminoDHT")
143 assert.Empty(t, bootstrapPeers, "Empty bootstrap should result in empty peers")
144 },
145 },
146 {
147 name: "null bootstrap",
148 bootstrap: nil,
149 validate: func(t *testing.T, resp *autoconf.Response) {
150 bootstrapPeers := resp.Config.GetBootstrapPeers("AminoDHT")
151 assert.Empty(t, bootstrapPeers, "Null bootstrap should result in empty peers")
152 },
153 },
154 {
155 name: "invalid multiaddr",
156 bootstrap: []string{"invalid-multiaddr"},
157 expectError: true,
158 },
159 {
160 name: "very long multiaddr",
161 bootstrap: []string{"/dnsaddr/" + strings.Repeat("a", 100) + ".com/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN"},
162 validate: func(t *testing.T, resp *autoconf.Response) {
163 expected := []string{"/dnsaddr/" + strings.Repeat("a", 100) + ".com/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN"}
164 bootstrapPeers := resp.Config.GetBootstrapPeers("AminoDHT")
165 assert.Equal(t, expected, bootstrapPeers, "Very long multiaddr should be preserved")
166 },
167 },
168 {
169 name: "bootstrap as string",
170 bootstrap: "/dnsaddr/test",
171 expectError: true,
172 },
173 {
174 name: "bootstrap as number",
175 bootstrap: 123,
176 expectError: true,
177 },
178 {
179 name: "mixed types in array",
180 bootstrap: []any{"/dnsaddr/test", 123, nil},
181 expectError: true,
182 },
183 {
184 name: "extremely large array",
185 bootstrap: make([]string, 1000),
186 validate: func(t *testing.T, resp *autoconf.Response) {
187 // Array will be filled in the loop below
188 bootstrapPeers := resp.Config.GetBootstrapPeers("AminoDHT")
189 assert.Len(t, bootstrapPeers, 1000, "Large bootstrap array should be preserved")
190 },
191 },
192 }
193
194 // Fill the large array with valid multiaddrs
195 largeArray := testCases[len(testCases)-1].bootstrap.([]string)
196 for i := range largeArray {
197 largeArray[i] = fmt.Sprintf("/dnsaddr/bootstrap%d.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN", i)
198 }
199
200 for _, tc := range testCases {
201 t.Run(tc.name, func(t *testing.T) {
202 config := map[string]any{
203 "AutoConfVersion": 2025072301,
204 "AutoConfSchema": 1,
205 "AutoConfTTL": 86400,
206 "SystemRegistry": map[string]any{
207 "AminoDHT": map[string]any{
208 "Description": "Test AminoDHT system",
209 "NativeConfig": map[string]any{
210 "Bootstrap": tc.bootstrap,
211 },
212 },
213 },
214 "DNSResolvers": map[string]any{},
215 "DelegatedEndpoints": map[string]any{},
216 }
217
218 jsonData, err := json.Marshal(config)
219 require.NoError(t, err)
220
221 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
222 w.Header().Set("Content-Type", "application/json")
223 _, _ = w.Write(jsonData)
224 }))
225 defer server.Close()
226
227 autoConf, fallbackUsed := testAutoConfWithFallback(t, server.URL, tc.expectError, fmt.Sprintf("Expected fallback to be used for %s", tc.name))
228
229 if !tc.expectError {
230 require.NotNil(t, autoConf, "AutoConf should not be nil for successful parsing")
231
232 // Verify structure is reasonable
233 bootstrapPeers := autoConf.GetBootstrapPeers("AminoDHT")
234 require.IsType(t, []string{}, bootstrapPeers, "Bootstrap should be []string")
235
236 // Run test-specific validation if provided (only for non-fallback cases)
237 if tc.validate != nil && !fallbackUsed {
238 // Create a mock Response for compatibility with validation functions
239 mockResponse := &autoconf.Response{Config: autoConf}
240 tc.validate(t, mockResponse)
241 }
242 }
243 })
244 }
245 }
246
247 func testFuzzDNSResolvers(t *testing.T) {
248 type testCase struct {
249 name string
250 resolvers any
251 expectError bool
252 validate func(*testing.T, *autoconf.Response)
253 }
254
255 testCases := []testCase{
256 {
257 name: "valid resolvers",
258 resolvers: map[string][]string{".": {"https://dns.google/dns-query"}},
259 validate: func(t *testing.T, resp *autoconf.Response) {
260 expected := map[string][]string{".": {"https://dns.google/dns-query"}}
261 assert.Equal(t, expected, resp.Config.DNSResolvers, "DNS resolvers should match configured values")
262 },
263 },
264 {
265 name: "empty resolvers",
266 resolvers: map[string][]string{},
267 validate: func(t *testing.T, resp *autoconf.Response) {
268 assert.Empty(t, resp.Config.DNSResolvers, "Empty resolvers should result in empty map")
269 },
270 },
271 {
272 name: "null resolvers",
273 resolvers: nil,
274 validate: func(t *testing.T, resp *autoconf.Response) {
275 assert.Empty(t, resp.Config.DNSResolvers, "Null resolvers should result in empty map")
276 },
277 },
278 {
279 name: "relative URL (missing scheme)",
280 resolvers: map[string][]string{".": {"not-a-url"}},
281 expectError: true, // Should error due to strict HTTP/HTTPS validation
282 },
283 {
284 name: "invalid URL format",
285 resolvers: map[string][]string{".": {"://invalid-missing-scheme"}},
286 expectError: true, // Should error because url.Parse() fails
287 },
288 {
289 name: "non-HTTP scheme",
290 resolvers: map[string][]string{".": {"ftp://example.com/dns-query"}},
291 expectError: true, // Should error due to non-HTTP/HTTPS scheme
292 },
293 {
294 name: "very long domain",
295 resolvers: map[string][]string{strings.Repeat("a", 1000) + ".com": {"https://dns.google/dns-query"}},
296 validate: func(t *testing.T, resp *autoconf.Response) {
297 expected := map[string][]string{strings.Repeat("a", 1000) + ".com": {"https://dns.google/dns-query"}}
298 assert.Equal(t, expected, resp.Config.DNSResolvers, "Very long domain should be preserved")
299 },
300 },
301 {
302 name: "many resolvers",
303 resolvers: generateManyResolvers(100),
304 validate: func(t *testing.T, resp *autoconf.Response) {
305 expected := generateManyResolvers(100)
306 assert.Equal(t, expected, resp.Config.DNSResolvers, "Many resolvers should be preserved")
307 assert.Equal(t, 100, len(resp.Config.DNSResolvers), "Should have 100 resolvers")
308 },
309 },
310 {
311 name: "resolvers as array",
312 resolvers: []string{"https://dns.google/dns-query"},
313 expectError: true,
314 },
315 {
316 name: "nested invalid structure",
317 resolvers: map[string]any{".": map[string]string{"invalid": "structure"}},
318 expectError: true,
319 },
320 }
321
322 for _, tc := range testCases {
323 t.Run(tc.name, func(t *testing.T) {
324 config := map[string]any{
325 "AutoConfVersion": 2025072301,
326 "AutoConfSchema": 1,
327 "AutoConfTTL": 86400,
328 "SystemRegistry": map[string]any{
329 "AminoDHT": map[string]any{
330 "Description": "Test AminoDHT system",
331 "NativeConfig": map[string]any{
332 "Bootstrap": []string{"/dnsaddr/test"},
333 },
334 },
335 },
336 "DNSResolvers": tc.resolvers,
337 "DelegatedEndpoints": map[string]any{},
338 }
339
340 jsonData, err := json.Marshal(config)
341 require.NoError(t, err)
342
343 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
344 w.Header().Set("Content-Type", "application/json")
345 _, _ = w.Write(jsonData)
346 }))
347 defer server.Close()
348
349 autoConf, fallbackUsed := testAutoConfWithFallback(t, server.URL, tc.expectError, fmt.Sprintf("Expected fallback to be used for %s", tc.name))
350
351 if !tc.expectError {
352 require.NotNil(t, autoConf, "AutoConf should not be nil for successful parsing")
353
354 // Run test-specific validation if provided (only for non-fallback cases)
355 if tc.validate != nil && !fallbackUsed {
356 // Create a mock Response for compatibility with validation functions
357 mockResponse := &autoconf.Response{Config: autoConf}
358 tc.validate(t, mockResponse)
359 }
360 }
361 })
362 }
363 }
364
365 func testFuzzDelegatedRouters(t *testing.T) {
366 // Test various malformed delegated router configurations
367 type testCase struct {
368 name string
369 routers any
370 expectError bool
371 validate func(*testing.T, *autoconf.Response)
372 }
373
374 testCases := []testCase{
375 {
376 name: "valid endpoints",
377 routers: map[string]any{
378 "https://ipni.example.com": map[string]any{
379 "Systems": []string{"IPNI"},
380 "Read": []string{"/routing/v1/providers"},
381 "Write": []string{},
382 },
383 },
384 validate: func(t *testing.T, resp *autoconf.Response) {
385 assert.Len(t, resp.Config.DelegatedEndpoints, 1, "Should have 1 delegated endpoint")
386 for url, config := range resp.Config.DelegatedEndpoints {
387 assert.Contains(t, url, "ipni.example.com", "Endpoint URL should contain expected domain")
388 assert.Contains(t, config.Systems, "IPNI", "Endpoint should have IPNI system")
389 assert.Contains(t, config.Read, "/routing/v1/providers", "Endpoint should have providers read path")
390 }
391 },
392 },
393 {
394 name: "empty routers",
395 routers: map[string]any{},
396 validate: func(t *testing.T, resp *autoconf.Response) {
397 assert.Empty(t, resp.Config.DelegatedEndpoints, "Empty routers should result in empty endpoints")
398 },
399 },
400 {
401 name: "null routers",
402 routers: nil,
403 validate: func(t *testing.T, resp *autoconf.Response) {
404 assert.Empty(t, resp.Config.DelegatedEndpoints, "Null routers should result in empty endpoints")
405 },
406 },
407 {
408 name: "invalid nested structure",
409 routers: map[string]string{"invalid": "structure"},
410 expectError: true,
411 },
412 {
413 name: "invalid endpoint URLs",
414 routers: map[string]any{
415 "not-a-url": map[string]any{
416 "Systems": []string{"IPNI"},
417 "Read": []string{"/routing/v1/providers"},
418 "Write": []string{},
419 },
420 },
421 expectError: true, // Should error due to URL validation
422 },
423 }
424
425 for _, tc := range testCases {
426 t.Run(tc.name, func(t *testing.T) {
427 config := map[string]any{
428 "AutoConfVersion": 2025072301,
429 "AutoConfSchema": 1,
430 "AutoConfTTL": 86400,
431 "SystemRegistry": map[string]any{
432 "AminoDHT": map[string]any{
433 "Description": "Test AminoDHT system",
434 "NativeConfig": map[string]any{
435 "Bootstrap": []string{"/dnsaddr/test"},
436 },
437 },
438 },
439 "DNSResolvers": map[string]any{},
440 "DelegatedEndpoints": tc.routers,
441 }
442
443 jsonData, err := json.Marshal(config)
444 require.NoError(t, err)
445
446 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
447 w.Header().Set("Content-Type", "application/json")
448 _, _ = w.Write(jsonData)
449 }))
450 defer server.Close()
451
452 autoConf, fallbackUsed := testAutoConfWithFallback(t, server.URL, tc.expectError, fmt.Sprintf("Expected fallback to be used for %s", tc.name))
453
454 if !tc.expectError {
455 require.NotNil(t, autoConf, "AutoConf should not be nil for successful parsing")
456
457 // Run test-specific validation if provided (only for non-fallback cases)
458 if tc.validate != nil && !fallbackUsed {
459 // Create a mock Response for compatibility with validation functions
460 mockResponse := &autoconf.Response{Config: autoConf}
461 tc.validate(t, mockResponse)
462 }
463 }
464 })
465 }
466 }
467
468 func testFuzzDelegatedPublishers(t *testing.T) {
469 // DelegatedPublishers use the same autoclient library validation as DelegatedRouters
470 // Test that URL validation works for delegated publishers
471 type testCase struct {
472 name string
473 urls []string
474 expectErr bool
475 validate func(*testing.T, *autoconf.Response)
476 }
477
478 testCases := []testCase{
479 {
480 name: "valid HTTPS URLs",
481 urls: []string{"https://delegated-ipfs.dev", "https://another-publisher.com"},
482 validate: func(t *testing.T, resp *autoconf.Response) {
483 assert.Len(t, resp.Config.DelegatedEndpoints, 2, "Should have 2 delegated endpoints")
484 foundURLs := make([]string, 0, len(resp.Config.DelegatedEndpoints))
485 for url := range resp.Config.DelegatedEndpoints {
486 foundURLs = append(foundURLs, url)
487 }
488 expectedURLs := []string{"https://delegated-ipfs.dev", "https://another-publisher.com"}
489 for _, expectedURL := range expectedURLs {
490 assert.Contains(t, foundURLs, expectedURL, "Should contain configured URL: %s", expectedURL)
491 }
492 },
493 },
494 {
495 name: "invalid URL",
496 urls: []string{"not-a-url"},
497 expectErr: true,
498 },
499 {
500 name: "HTTP URL (accepted during parsing)",
501 urls: []string{"http://insecure-publisher.com"},
502 validate: func(t *testing.T, resp *autoconf.Response) {
503 assert.Len(t, resp.Config.DelegatedEndpoints, 1, "Should have 1 delegated endpoint")
504 for url := range resp.Config.DelegatedEndpoints {
505 assert.Equal(t, "http://insecure-publisher.com", url, "HTTP URL should be preserved during parsing")
506 }
507 },
508 },
509 }
510
511 for _, tc := range testCases {
512 t.Run(tc.name, func(t *testing.T) {
513 autoConfData := map[string]any{
514 "AutoConfVersion": 2025072301,
515 "AutoConfSchema": 1,
516 "AutoConfTTL": 86400,
517 "SystemRegistry": map[string]any{
518 "TestSystem": map[string]any{
519 "Description": "Test system for fuzz testing",
520 "DelegatedConfig": map[string]any{
521 "Read": []string{"/routing/v1/ipns"},
522 "Write": []string{"/routing/v1/ipns"},
523 },
524 },
525 },
526 "DNSResolvers": map[string]any{},
527 "DelegatedEndpoints": map[string]any{},
528 }
529
530 // Add test URLs as delegated endpoints
531 for _, url := range tc.urls {
532 autoConfData["DelegatedEndpoints"].(map[string]any)[url] = map[string]any{
533 "Systems": []string{"TestSystem"},
534 "Read": []string{"/routing/v1/ipns"},
535 "Write": []string{"/routing/v1/ipns"},
536 }
537 }
538
539 jsonData, err := json.Marshal(autoConfData)
540 require.NoError(t, err)
541
542 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
543 w.Header().Set("Content-Type", "application/json")
544 _, _ = w.Write(jsonData)
545 }))
546 defer server.Close()
547
548 // Test that our autoconf parser handles this gracefully
549 autoConf, fallbackUsed := testAutoConfWithFallback(t, server.URL, tc.expectErr, fmt.Sprintf("Expected fallback to be used for %s", tc.name))
550
551 if !tc.expectErr {
552 require.NotNil(t, autoConf, "AutoConf should not be nil for successful parsing")
553
554 // Run test-specific validation if provided (only for non-fallback cases)
555 if tc.validate != nil && !fallbackUsed {
556 // Create a mock Response for compatibility with validation functions
557 mockResponse := &autoconf.Response{Config: autoConf}
558 tc.validate(t, mockResponse)
559 }
560 }
561 })
562 }
563 }
564
565 func testFuzzMalformedJSON(t *testing.T) {
566 malformedJSONs := []string{
567 `{`, // Incomplete JSON
568 `{"AutoConfVersion": }`, // Missing value
569 `{"AutoConfVersion": 123,}`, // Trailing comma
570 `{AutoConfVersion: 123}`, // Unquoted key
571 `{"Bootstrap": [}`, // Incomplete array
572 `{"Bootstrap": ["/test",]}`, // Trailing comma in array
573 `invalid json`, // Not JSON at all
574 `null`, // Just null
575 `[]`, // Array instead of object
576 `""`, // String instead of object
577 }
578
579 for i, malformedJSON := range malformedJSONs {
580 t.Run(fmt.Sprintf("malformed_%d", i), func(t *testing.T) {
581 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
582 w.Header().Set("Content-Type", "application/json")
583 _, _ = w.Write([]byte(malformedJSON))
584 }))
585 defer server.Close()
586
587 // All malformed JSON should result in fallback usage
588 _, _ = testAutoConfWithFallback(t, server.URL, true, fmt.Sprintf("Expected fallback to be used for malformed JSON: %s", malformedJSON))
589 })
590 }
591 }
592
593 func testFuzzLargePayloads(t *testing.T) {
594 // Test with very large but valid JSON payloads
595 largeBootstrap := make([]string, 10000)
596 for i := range largeBootstrap {
597 largeBootstrap[i] = fmt.Sprintf("/dnsaddr/bootstrap%d.example.com/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN", i)
598 }
599
600 largeDNSResolvers := make(map[string][]string)
601 for i := range 1000 {
602 domain := fmt.Sprintf("domain%d.example.com", i)
603 largeDNSResolvers[domain] = []string{
604 fmt.Sprintf("https://resolver%d.example.com/dns-query", i),
605 }
606 }
607
608 config := map[string]any{
609 "AutoConfVersion": 2025072301,
610 "AutoConfSchema": 1,
611 "AutoConfTTL": 86400,
612 "SystemRegistry": map[string]any{
613 "AminoDHT": map[string]any{
614 "Description": "Test AminoDHT system",
615 "NativeConfig": map[string]any{
616 "Bootstrap": largeBootstrap,
617 },
618 },
619 },
620 "DNSResolvers": largeDNSResolvers,
621 "DelegatedEndpoints": map[string]any{},
622 }
623
624 jsonData, err := json.Marshal(config)
625 require.NoError(t, err)
626
627 t.Logf("Large payload size: %d bytes", len(jsonData))
628
629 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
630 w.Header().Set("Content-Type", "application/json")
631 _, _ = w.Write(jsonData)
632 }))
633 defer server.Close()
634
635 // Should handle large payloads gracefully (up to reasonable limits)
636 autoConf, _ := testAutoConfWithFallbackAndTimeout(t, server.URL, false, "Large payload should not trigger fallback", 30*time.Second)
637 require.NotNil(t, autoConf, "Should return valid config")
638
639 // Verify bootstrap entries were preserved
640 bootstrapPeers := autoConf.GetBootstrapPeers("AminoDHT")
641 require.Len(t, bootstrapPeers, 10000, "Should preserve all bootstrap entries")
642 }
643
644 // Helper function to generate many DNS resolvers for testing
645 func generateManyResolvers(count int) map[string][]string {
646 resolvers := make(map[string][]string)
647 for i := range count {
648 domain := fmt.Sprintf("domain%d.example.com", i)
649 resolvers[domain] = []string{
650 fmt.Sprintf("https://resolver%d.example.com/dns-query", i),
651 }
652 }
653 return resolvers
654 }