-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathcache_additional_test.go
More file actions
116 lines (100 loc) · 3.04 KB
/
Copy pathcache_additional_test.go
File metadata and controls
116 lines (100 loc) · 3.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package cloudflared
import (
"crypto/x509"
"net/http"
"net/url"
"sync/atomic"
"testing"
"github.com/sagernet/sing-cloudflared/internal/config"
N "github.com/sagernet/sing/common/network"
)
func TestAccessValidatorCacheReturnsExistingValueWhenConcurrentStoreWins(t *testing.T) {
originalFactory := newAccessValidator
defer func() {
newAccessValidator = originalFactory
}()
var buildCount atomic.Int32
firstBuildStarted := make(chan struct{})
releaseFirstBuild := make(chan struct{})
cachedValidator := &fakeAccessValidator{}
firstBuiltValidator := &fakeAccessValidator{}
newAccessValidator = func(access config.AccessConfig, dialer N.Dialer) (accessValidator, error) {
if buildCount.Add(1) == 1 {
close(firstBuildStarted)
<-releaseFirstBuild
return firstBuiltValidator, nil
}
return cachedValidator, nil
}
cache := &accessValidatorCache{values: make(map[string]accessValidator)}
config := config.AccessConfig{Required: true, TeamName: "team", AudTag: []string{"aud"}}
firstResultCh := make(chan accessValidator, 1)
firstErrCh := make(chan error, 1)
go func() {
validator, err := cache.Get(config)
firstResultCh <- validator
firstErrCh <- err
}()
<-firstBuildStarted
second, err := cache.Get(config)
if err != nil {
t.Fatal(err)
}
close(releaseFirstBuild)
first := <-firstResultCh
if err := <-firstErrCh; err != nil {
t.Fatal(err)
}
if first != cachedValidator || second != cachedValidator {
t.Fatalf("expected both callers to receive cached validator, got %p and %p", first, second)
}
}
func TestNewDirectOriginTransportReturnsExistingValueWhenConcurrentStoreWins(t *testing.T) {
originalBaseLoader := loadOriginCABasePool
originalProxy := proxyFromEnvironment
defer func() {
loadOriginCABasePool = originalBaseLoader
proxyFromEnvironment = originalProxy
}()
var buildCount atomic.Int32
firstBuildStarted := make(chan struct{})
releaseFirstBuild := make(chan struct{})
loadOriginCABasePool = func() (*x509.CertPool, error) {
if buildCount.Add(1) == 1 {
close(firstBuildStarted)
<-releaseFirstBuild
}
return x509.NewCertPool(), nil
}
proxyFromEnvironment = func(request *http.Request) (*url.URL, error) {
return nil, nil
}
serviceInstance := &Service{
directTransports: make(map[string]*http.Transport),
}
service := config.ResolvedService{
Kind: config.ResolvedServiceUnix,
UnixPath: "/tmp/test.sock",
BaseURL: &url.URL{Scheme: "http", Host: "localhost"},
}
firstTransportCh := make(chan *http.Transport, 1)
firstErrCh := make(chan error, 1)
go func() {
transport, _, err := serviceInstance.newDirectOriginTransport(service, "example.com")
firstTransportCh <- transport
firstErrCh <- err
}()
<-firstBuildStarted
secondTransport, _, err := serviceInstance.newDirectOriginTransport(service, "example.com")
if err != nil {
t.Fatal(err)
}
close(releaseFirstBuild)
firstTransport := <-firstTransportCh
if err := <-firstErrCh; err != nil {
t.Fatal(err)
}
if firstTransport != secondTransport {
t.Fatalf("expected concurrent builders to converge on cached transport")
}
}