(t *testing.T, handler http.Handler, requests []streamableRequest)
| 1289 | } |
| 1290 | |
| 1291 | func testStreamableHandler(t *testing.T, handler http.Handler, requests []streamableRequest) { |
| 1292 | httpServer := httptest.NewServer(mustNotPanic(t, handler)) |
| 1293 | defer httpServer.Close() |
| 1294 | |
| 1295 | // blocks records request blocks by jsonrpc. ID. |
| 1296 | // |
| 1297 | // When an OnRequest step is encountered, it waits on the corresponding |
| 1298 | // block. When a request with that ID is received, the block is closed. |
| 1299 | var mu sync.Mutex |
| 1300 | blocks := make(map[int64]chan struct{}) |
| 1301 | for _, req := range requests { |
| 1302 | if req.onRequest > 0 { |
| 1303 | blocks[req.onRequest] = make(chan struct{}) |
| 1304 | } |
| 1305 | } |
| 1306 | |
| 1307 | // signal when all synchronous requests have executed, so we can fail |
| 1308 | // async requests that are blocked. |
| 1309 | syncRequestsDone := make(chan struct{}) |
| 1310 | |
| 1311 | // To avoid complicated accounting for session ID, just set the first |
| 1312 | // non-empty session ID from a response. |
| 1313 | var sessionID atomic.Value |
| 1314 | sessionID.Store("") |
| 1315 | |
| 1316 | // doStep executes a single step. |
| 1317 | doStep := func(t *testing.T, i int, request streamableRequest) { |
| 1318 | if request.onRequest > 0 { |
| 1319 | // Block the step until we've received the server->client request. |
| 1320 | mu.Lock() |
| 1321 | block := blocks[request.onRequest] |
| 1322 | mu.Unlock() |
| 1323 | select { |
| 1324 | case <-block: |
| 1325 | case <-syncRequestsDone: |
| 1326 | t.Errorf("after all sync requests are complete, request still blocked on %d", request.onRequest) |
| 1327 | return |
| 1328 | } |
| 1329 | } |
| 1330 | |
| 1331 | // Collect messages received during this request, unblock other steps |
| 1332 | // when requests are received. |
| 1333 | var got []jsonrpc.Message |
| 1334 | out := make(chan jsonrpc.Message) |
| 1335 | // Cancel the step if we encounter a request that isn't going to be |
| 1336 | // handled. |
| 1337 | // |
| 1338 | // Also, add a timeout (hopefully generous). |
| 1339 | ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) |
| 1340 | |
| 1341 | var wg sync.WaitGroup |
| 1342 | wg.Go(func() { |
| 1343 | |
| 1344 | for m := range out { |
| 1345 | if req, ok := m.(*jsonrpc.Request); ok && req.IsCall() { |
| 1346 | // Encountered a server->client request. We should have a |
| 1347 | // response queued. Otherwise, we may deadlock. |
| 1348 | mu.Lock() |
no test coverage detected
searching dependent graphs…