Files
upaas/internal/service/deploy/export_test.go
T
sneak 4c6d3f464d
Check / check (pull_request) Skipped
Remove old images by tag, and test the step after a deploy (closes #216)
Old images are now removed by their upaas-<app>:<N> tag, without force,
so Docker deletes an image only when no other tag (such as another app's
build of the same source) and no container still uses it. Removing by ID
with force could delete another app's rollback image.

The step after a deploy (record the new image, keep the replaced one for
rollback, remove the rest) is its own function, tested against a fake
Docker API, so the test fails if the removal is dropped or runs before
the images are updated.

Model: opus-5-5
2026-09-23 10:09:47 +00:00

111 lines
2.7 KiB
Go

package deploy
import (
"context"
"fmt"
"log/slog"
"os"
"path/filepath"
"strings"
"sneak.berlin/go/upaas/internal/config"
"sneak.berlin/go/upaas/internal/docker"
"sneak.berlin/go/upaas/internal/models"
)
// NewTestService creates a Service with minimal dependencies for testing.
func NewTestService(log *slog.Logger) *Service {
return &Service{
log: log,
}
}
// CancelActiveDeploy exposes cancelActiveDeploy for testing.
func (svc *Service) CancelActiveDeploy(appID string) {
svc.cancelActiveDeploy(appID)
}
// RegisterActiveDeploy registers an active deploy for testing.
func (svc *Service) RegisterActiveDeploy(
appID string,
cancel context.CancelFunc,
done chan struct{},
) {
svc.activeDeploys.Store(appID, &activeDeploy{cancel: cancel, done: done})
}
// TryLockApp exposes tryLockApp for testing.
func (svc *Service) TryLockApp(appID string) bool {
return svc.tryLockApp(appID)
}
// UnlockApp exposes unlockApp for testing.
func (svc *Service) UnlockApp(appID string) {
svc.unlockApp(appID)
}
// NewTestServiceWithConfig creates a Service with config and docker client for testing.
func NewTestServiceWithConfig(
log *slog.Logger,
cfg *config.Config,
dockerClient *docker.Client,
) *Service {
return &Service{
log: log,
config: cfg,
docker: dockerClient,
}
}
// CleanupCancelledDeploy exposes the build directory cleanup portion of
// cleanupCancelledDeploy for testing. It removes build directories matching
// the deployment ID prefix.
func (svc *Service) CleanupCancelledDeploy(
_ context.Context,
appName string,
deploymentID int64,
_ string,
) {
// We can't create real models.App/Deployment in tests easily,
// so we test the build dir cleanup portion directly.
buildDir := svc.GetBuildDir(appName)
entries, err := os.ReadDir(buildDir)
if err != nil {
return
}
prefix := fmt.Sprintf("%d-", deploymentID)
for _, entry := range entries {
if entry.IsDir() && strings.HasPrefix(entry.Name(), prefix) {
dirPath := filepath.Join(buildDir, entry.Name())
_ = os.RemoveAll(dirPath)
}
}
}
// GetBuildDirExported exposes GetBuildDir for testing.
func (svc *Service) GetBuildDirExported(appName string) string {
return svc.GetBuildDir(appName)
}
// RecordDeployedImage exposes recordDeployedImage for testing.
func (svc *Service) RecordDeployedImage(
ctx context.Context,
app *models.App,
deployment *models.Deployment,
imageID docker.ImageID,
) error {
return svc.recordDeployedImage(ctx, app, deployment, imageID)
}
// BuildContainerOptionsExported exposes buildContainerOptions for testing.
func (svc *Service) BuildContainerOptionsExported(
ctx context.Context,
app *models.App,
imageID docker.ImageID,
) (docker.CreateContainerOptions, error) {
return svc.buildContainerOptions(ctx, app, imageID)
}