github.com/qiniu/go-sdk/v7@v7.27.0/storagev2/resolver/resolver_test.go (about) 1 //go:build unit 2 // +build unit 3 4 package resolver_test 5 6 import ( 7 "context" 8 "net" 9 "os" 10 "testing" 11 "time" 12 13 "github.com/qiniu/go-sdk/v7/storagev2/resolver" 14 ) 15 16 func TestDefaultResolver(t *testing.T) { 17 ips, err := resolver.NewDefaultResolver().Resolve(context.Background(), "upload.qiniup.com") 18 if err != nil { 19 t.Fatalf("Unexpected error: %v", err) 20 } else if len(ips) == 0 { 21 t.Fatal("Unexpected empty ips") 22 } 23 } 24 25 type mockResolver struct { 26 m map[string][]net.IP 27 c map[string]int 28 } 29 30 func (mr *mockResolver) Resolve(ctx context.Context, host string) ([]net.IP, error) { 31 mr.c[host]++ 32 return mr.m[host], nil 33 } 34 35 func (mr *mockResolver) FeedbackGood(context.Context, string, []net.IP) {} 36 37 func (mr *mockResolver) FeedbackBad(context.Context, string, []net.IP) {} 38 39 func TestCacheResolver(t *testing.T) { 40 tmpFile, err := os.CreateTemp("", "") 41 if err != nil { 42 t.Fatal(err) 43 } 44 defer os.Remove(tmpFile.Name()) 45 defer tmpFile.Close() 46 47 mr := &mockResolver{m: map[string][]net.IP{"upload.qiniup.com": {net.IPv4(1, 1, 1, 1), net.IPv4(1, 1, 2, 2)}}, c: make(map[string]int)} 48 resolver, err := resolver.NewCacheResolver(mr, &resolver.CacheResolverConfig{ 49 PersistentFilePath: tmpFile.Name(), 50 CacheRefreshAfter: 3 * time.Second, 51 CacheLifetime: 2 * time.Second, 52 }) 53 if err != nil { 54 t.Fatal(err) 55 } 56 for i := 0; i < 10; i++ { 57 ips, err := resolver.Resolve(context.Background(), "upload.qiniup.com") 58 if err != nil { 59 t.Fatal(err) 60 } 61 if len(ips) != 2 || !ips[0].Equal(net.IPv4(1, 1, 1, 1)) || !ips[1].Equal(net.IPv4(1, 1, 2, 2)) { 62 t.Fatal("Unexpected ips") 63 } 64 } 65 if mr.c["upload.qiniup.com"] != 1 { 66 t.Fatal("Unexpected cache") 67 } 68 69 time.Sleep(1000 * time.Millisecond) 70 resolver.FeedbackGood(context.Background(), "upload.qiniup.com", []net.IP{net.IPv4(1, 1, 1, 1)}) 71 time.Sleep(1500 * time.Millisecond) 72 ips, err := resolver.Resolve(context.Background(), "upload.qiniup.com") 73 if err != nil { 74 t.Fatal(err) 75 } 76 if len(ips) != 1 || !ips[0].Equal(net.IPv4(1, 1, 1, 1)) { 77 t.Fatal("Unexpected ips") 78 } 79 if mr.c["upload.qiniup.com"] != 1 { 80 t.Fatal("Unexpected cache") 81 } 82 } 83 84 func TestCacheResolverMaxLifetime(t *testing.T) { 85 tmpFile, err := os.CreateTemp("", "") 86 if err != nil { 87 t.Fatal(err) 88 } 89 defer os.Remove(tmpFile.Name()) 90 defer tmpFile.Close() 91 92 mr := &mockResolver{ 93 m: map[string][]net.IP{"upload.qiniup.com": {net.IPv4(1, 1, 1, 1)}}, 94 c: make(map[string]int), 95 } 96 r, err := resolver.NewCacheResolver(mr, &resolver.CacheResolverConfig{ 97 PersistentFilePath: tmpFile.Name(), 98 CacheRefreshAfter: 2 * time.Second, 99 CacheLifetime: 5 * time.Second, 100 CacheMaxLifetime: 3 * time.Second, 101 }) 102 if err != nil { 103 t.Fatal(err) 104 } 105 106 // 首次解析,触发 DNS 查询 107 ips, err := r.Resolve(context.Background(), "upload.qiniup.com") 108 if err != nil { 109 t.Fatal(err) 110 } 111 if len(ips) != 1 || !ips[0].Equal(net.IPv4(1, 1, 1, 1)) { 112 t.Fatal("Unexpected ips") 113 } 114 if mr.c["upload.qiniup.com"] != 1 { 115 t.Fatalf("Expected 1 resolve call, got %d", mr.c["upload.qiniup.com"]) 116 } 117 118 // 每隔 500ms 调用 FeedbackGood 延长缓存,持续 4 秒(超过 CacheMaxLifetime 3s) 119 for i := 0; i < 8; i++ { 120 time.Sleep(500 * time.Millisecond) 121 r.FeedbackGood(context.Background(), "upload.qiniup.com", []net.IP{net.IPv4(1, 1, 1, 1)}) 122 } 123 124 // 此时 CacheMaxLifetime(3s)已过,FeedbackGood 无法继续推迟 RefreshAfter 125 // 下次 Resolve 应触发异步 DNS 重新查询 126 ips, err = r.Resolve(context.Background(), "upload.qiniup.com") 127 if err != nil { 128 t.Fatal(err) 129 } 130 if len(ips) != 1 || !ips[0].Equal(net.IPv4(1, 1, 1, 1)) { 131 t.Fatal("Unexpected ips") 132 } 133 134 // 等待异步刷新完成 135 time.Sleep(1 * time.Second) 136 137 if mr.c["upload.qiniup.com"] != 2 { 138 t.Fatalf("Expected 2 resolve calls after max lifetime, got %d", mr.c["upload.qiniup.com"]) 139 } 140 }