createBlipTesterWithSpec creates a blip tester targeting a specific RestTester. Returns an error to allow for testing connection error conditions. Use NewBlipTesterFromSpec for most tests.
(rt *RestTester, spec BlipTesterSpec)
| 1450 | // createBlipTesterWithSpec creates a blip tester targeting a specific RestTester. Returns an error to allow for |
| 1451 | // testing connection error conditions. Use NewBlipTesterFromSpec for most tests. |
| 1452 | func createBlipTesterWithSpec(rt *RestTester, spec BlipTesterSpec) (*BlipTester, error) { |
| 1453 | bt := &BlipTester{ |
| 1454 | restTester: rt, |
| 1455 | } |
| 1456 | |
| 1457 | if !rt.GetDatabase().OnlyDefaultCollection() { |
| 1458 | bt.useCollections = true |
| 1459 | } |
| 1460 | |
| 1461 | // Since blip requests all go over the public handler, wrap the public handler with the httptest server |
| 1462 | publicHandler := bt.restTester.TestPublicHandler() |
| 1463 | |
| 1464 | // Create a _temporary_ test server bound to an actual port that is used to make the blip connection. |
| 1465 | // This is needed because the mock-based approach fails with a "Connection not hijackable" error when |
| 1466 | // trying to do the websocket upgrade. Since it's only needed to setup the websocket, it can be closed |
| 1467 | // as soon as the websocket is established, hence the defer srv.Close() call. |
| 1468 | srv := httptest.NewServer(publicHandler) |
| 1469 | defer srv.Close() |
| 1470 | |
| 1471 | // Construct URL to connect to blipsync target endpoint |
| 1472 | destUrl := fmt.Sprintf("%s/%s/_blipsync", srv.URL, rt.GetDatabase().Name) |
| 1473 | u, err := url.Parse(destUrl) |
| 1474 | require.NoError(bt.TB(), err) |
| 1475 | u.Scheme = "ws" |
| 1476 | |
| 1477 | // If protocols are not set use V3 as a V3 client would |
| 1478 | protocols := spec.blipProtocols |
| 1479 | if len(protocols) == 0 { |
| 1480 | protocols = []string{db.CBMobileReplicationV3.SubprotocolString()} |
| 1481 | } |
| 1482 | |
| 1483 | origin, err := hostOnlyCORS(bt.restTester.GetDatabase().CORS.Origin) |
| 1484 | if err != nil { |
| 1485 | return nil, err |
| 1486 | } |
| 1487 | // Make BLIP/Websocket connection. Not specifying cancellation context here as this is a |
| 1488 | // client blip context that doesn't require cancellation-based close |
| 1489 | _, bt.blipContext, err = db.NewSGBlipContextWithProtocols(rt.Context(), "", origin, protocols, nil) |
| 1490 | if err != nil { |
| 1491 | return nil, err |
| 1492 | } |
| 1493 | |
| 1494 | // Ensure that errors get correctly surfaced in tests |
| 1495 | bt.blipContext.FatalErrorHandler = func(err error) { |
| 1496 | bt.TB().Fatalf("BLIP fatal error: %v", err) |
| 1497 | } |
| 1498 | bt.blipContext.HandlerPanicHandler = func(request, response *blip.Message, err interface{}) { |
| 1499 | stack := debug.Stack() |
| 1500 | bt.TB().Fatalf("Panic while handling %s: %v\n%s", request.Profile(), err, string(stack)) |
| 1501 | } |
| 1502 | |
| 1503 | config := blip.DialOptions{ |
| 1504 | URL: u.String(), |
| 1505 | } |
| 1506 | |
| 1507 | config.HTTPHeader = make(http.Header) |
| 1508 | if len(spec.connectingUsername) > 0 { |
| 1509 | config.HTTPHeader.Add("Authorization", GetBasicAuthHeader(bt.TB(), spec.connectingUsername, RestTesterDefaultUserPassword)) |