Files
livekit/pkg/service/docker_test.go
Alex FeldgendlerandClaude Opus 5 64a1211517 Skip the docker-backed service tests when there is no docker (#4799)
Let the docker-backed service tests be skipped with a flag.

TestMain called log.Fatalf when it could not reach a docker daemon, so
the whole package refused to run without one, including every test in it
that needs no container at all.

Record why docker is unavailable instead, and gate the tests that want a
container on it. A run asks to go without them with -docker=false;
otherwise a missing daemon still fails the package, so an unreachable
daemon stays a broken build rather than a run that quietly covers less
than the last one did.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 10:32:15 -07:00

110 lines
2.7 KiB
Go

// Copyright 2024 LiveKit, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package service_test
import (
"context"
"flag"
"fmt"
"log"
"net"
"os"
"testing"
"time"
"go.uber.org/atomic"
mobyclient "github.com/moby/moby/client"
"github.com/ory/dockertest/v4"
)
var Docker dockertest.ClosablePool
// go test -docker=false ./pkg/service skips the tests that need a docker
// daemon, for a checkout without one. Running them is the default: a run that
// quietly covers less than the last one is worse than a run that stops, so a
// daemon that should be there and is not still fails the whole package.
var useDocker = flag.Bool("docker", true, "run the tests that need a docker daemon")
func TestMain(m *testing.M) {
// m.Run would parse them, but the flag is read before that
flag.Parse()
if *useDocker {
ctx := context.Background()
pool, err := dockertest.NewPool(ctx, "")
if err != nil {
log.Fatalf("Could not construct pool: %s", err)
}
// uses pool to try to connect to Docker
_, err = pool.Client().Ping(ctx, mobyclient.PingOptions{})
if err != nil {
log.Fatalf("Could not connect to Docker: %s", err)
}
Docker = pool
}
code := m.Run()
os.Exit(code)
}
func requireDocker(t testing.TB) {
t.Helper()
if !*useDocker {
t.Skip("this test needs a docker daemon, and -docker=false says there is none")
}
}
func waitTCPPort(t testing.TB, addr string) {
if err := Docker.Retry(t.Context(), 30*time.Second, func() error {
conn, err := net.Dial("tcp", addr)
if err != nil {
t.Log(err)
return err
}
_ = conn.Close()
return nil
}); err != nil {
t.Fatal(err)
}
}
var redisLast atomic.Uint32
func runRedis(t testing.TB) string {
requireDocker(t)
c, err := Docker.Run(t.Context(),
"redis",
dockertest.WithName(fmt.Sprintf("lktest-redis-%d", redisLast.Inc())),
dockertest.WithTag("latest"),
)
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() {
// t.Context() is canceled before cleanup funcs run, so use a
// non-canceled context to let the container stop/remove complete.
_ = c.Close(context.Background())
})
addr := c.GetHostPort("6379/tcp")
waitTCPPort(t, addr)
t.Log("Redis running on", addr)
return addr
}