Router constructs a chi.Mux wired with a coordinator, DERP server, and the networking routes needed for integration tests.
(t *testing.T, logger slog.Logger)
| 177 | // Router constructs a chi.Mux wired with a coordinator, DERP server, |
| 178 | // and the networking routes needed for integration tests. |
| 179 | func (o SimpleServerOptions) Router(t *testing.T, logger slog.Logger) *chi.Mux { |
| 180 | coord := tailnet.NewCoordinator(logger) |
| 181 | var coordPtr atomic.Pointer[tailnet.Coordinator] |
| 182 | coordPtr.Store(&coord) |
| 183 | t.Cleanup(func() { _ = coord.Close() }) |
| 184 | |
| 185 | cm := connManager{ |
| 186 | conns: make(map[uuid.UUID]net.Conn), |
| 187 | } |
| 188 | |
| 189 | csvc, err := tailnet.NewClientService(tailnet.ClientServiceOptions{ |
| 190 | Logger: logger, |
| 191 | CoordPtr: &coordPtr, |
| 192 | DERPMapUpdateFrequency: 10 * time.Minute, |
| 193 | DERPMapFn: func() *tailcfg.DERPMap { |
| 194 | return &tailcfg.DERPMap{ |
| 195 | // Clients will set their own based on their custom access URL. |
| 196 | Regions: map[int]*tailcfg.DERPRegion{}, |
| 197 | } |
| 198 | }, |
| 199 | NetworkTelemetryHandler: func(_ []*tailnetproto.TelemetryEvent) {}, |
| 200 | ResumeTokenProvider: tailnet.NewInsecureTestResumeTokenProvider(), |
| 201 | }) |
| 202 | require.NoError(t, err) |
| 203 | |
| 204 | derpServer := atomic.Pointer[derpServer]{} |
| 205 | derpServer.Store(newDerpServer(t, logger)) |
| 206 | t.Cleanup(func() { |
| 207 | derpServer.Load().Close() |
| 208 | }) |
| 209 | |
| 210 | r := chi.NewRouter() |
| 211 | r.Use( |
| 212 | func(next http.Handler) http.Handler { |
| 213 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| 214 | logger.Debug(r.Context(), "start "+r.Method, slog.F("path", r.URL.Path), slog.F("remote_ip", r.RemoteAddr)) |
| 215 | next.ServeHTTP(w, r) |
| 216 | }) |
| 217 | }, |
| 218 | tracing.StatusWriterMiddleware, |
| 219 | loggermw.Logger(logger, nil), |
| 220 | ) |
| 221 | |
| 222 | r.Route("/derp", func(r chi.Router) { |
| 223 | r.Get("/", func(w http.ResponseWriter, r *http.Request) { |
| 224 | logger.Info(r.Context(), "start derp request", slog.F("path", r.URL.Path), slog.F("remote_ip", r.RemoteAddr)) |
| 225 | |
| 226 | upgrade := strings.ToLower(r.Header.Get("Upgrade")) |
| 227 | if upgrade != "derp" && upgrade != "websocket" { |
| 228 | http.Error(w, "invalid DERP upgrade header", http.StatusBadRequest) |
| 229 | t.Errorf("invalid DERP upgrade header: %s", upgrade) |
| 230 | return |
| 231 | } |
| 232 | |
| 233 | if o.FailUpgradeDERP && upgrade == "derp" { |
| 234 | // 4xx status codes will cause the client to fallback to |
| 235 | // DERP-over-WebSocket. |
| 236 | http.Error(w, "test derp upgrade failure", http.StatusBadRequest) |