(t *testing.T)
| 139 | } |
| 140 | |
| 141 | func TestConcurrentRouter_ConcurrentReadWrite(t *testing.T) { |
| 142 | router := NewConcurrentRouter(NewRouter(RouterConfig{})) |
| 143 | |
| 144 | initialPaths := []string{"/read1", "/read2", "/read3"} |
| 145 | for _, path := range initialPaths { |
| 146 | _, err := router.Add(Route{Method: http.MethodGet, Path: path, Handler: handlerFunc}) |
| 147 | if err != nil { |
| 148 | t.Fatal(err) |
| 149 | } |
| 150 | } |
| 151 | |
| 152 | var wg sync.WaitGroup |
| 153 | var routeCallCount atomic.Int64 |
| 154 | var addCallCount atomic.Int64 |
| 155 | var routesCallCount atomic.Int64 |
| 156 | |
| 157 | // Launch 4 reader goroutines: call Route() 100 times each |
| 158 | for range 4 { |
| 159 | wg.Go(func() { |
| 160 | for j := range 100 { |
| 161 | path := initialPaths[j%len(initialPaths)] |
| 162 | |
| 163 | req := httptest.NewRequest(http.MethodGet, path, nil) |
| 164 | rec := httptest.NewRecorder() |
| 165 | c := newContext(req, rec, nil) |
| 166 | |
| 167 | handler := router.Route(c) |
| 168 | if handler != nil { |
| 169 | routeCallCount.Add(1) |
| 170 | } |
| 171 | } |
| 172 | }) |
| 173 | } |
| 174 | |
| 175 | // Launch 2 writer goroutines: call Add() 20 times each |
| 176 | for i := range 2 { |
| 177 | wg.Add(1) |
| 178 | go func(goroutineID int) { |
| 179 | defer wg.Done() |
| 180 | for j := range 20 { |
| 181 | path := fmt.Sprintf("/write-g%d-n%d", goroutineID, j) |
| 182 | _, err := router.Add(Route{ |
| 183 | Method: http.MethodGet, |
| 184 | Path: path, |
| 185 | Handler: handlerFunc, |
| 186 | }) |
| 187 | if err == nil { |
| 188 | addCallCount.Add(1) |
| 189 | } |
| 190 | } |
| 191 | }(i) |
| 192 | } |
| 193 | |
| 194 | // Launch 2 inspector goroutines: call Routes() 50 times each |
| 195 | for range 2 { |
| 196 | wg.Go(func() { |
| 197 | for range 50 { |
| 198 | routes := router.Routes() |
nothing calls this directly
no test coverage detected
searching dependent graphs…