@@ -0,0 +1,119 @@
|
||||
package saas
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ed25519"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"data-terminal-cloud/internal/audit"
|
||||
"data-terminal-cloud/internal/identity"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
func TestOpsFirmwareReleaseLifecycle(t *testing.T) {
|
||||
databaseURL := os.Getenv("TEST_DATABASE_URL")
|
||||
if databaseURL == "" {
|
||||
t.Skip("TEST_DATABASE_URL is not set")
|
||||
}
|
||||
ctx := context.Background()
|
||||
pool, err := pgxpool.New(ctx, databaseURL)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer pool.Close()
|
||||
store := &firmwareIntegrationStore{}
|
||||
service := NewService(pool, audit.NewRepository(), nil, nil)
|
||||
service.ConfigureFirmwareStore(store, 4*time.Minute)
|
||||
var operator identity.Principal
|
||||
if err := pool.QueryRow(ctx, `SELECT oidc_issuer,oidc_subject FROM user_account WHERE public_id='10000000-0000-0000-0000-000000000114'::uuid AND status='active' AND account_kind='operator'`).Scan(&operator.Issuer, &operator.Subject); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
const tenantID = "10000000-0000-0000-0000-000000000010"
|
||||
keyID := "ops-firmware-" + uuid.NewString()
|
||||
version := "ops-" + uuid.NewString()
|
||||
var releaseID, rolloutID string
|
||||
defer func() {
|
||||
_, _ = pool.Exec(ctx, `DELETE FROM audit_event WHERE request_id LIKE 'ops-firmware-integration-%'`)
|
||||
if rolloutID != "" {
|
||||
_, _ = pool.Exec(ctx, `DELETE FROM firmware_rollout WHERE public_id=$1::uuid`, rolloutID)
|
||||
}
|
||||
if releaseID != "" {
|
||||
_, _ = pool.Exec(ctx, `DELETE FROM device_command WHERE payload->>'release_id'=$1`, releaseID)
|
||||
}
|
||||
if releaseID != "" {
|
||||
_, _ = pool.Exec(ctx, `DELETE FROM firmware_release WHERE public_id=$1::uuid`, releaseID)
|
||||
}
|
||||
_, _ = pool.Exec(ctx, `DELETE FROM firmware_signing_key WHERE key_id=$1`, keyID)
|
||||
}()
|
||||
|
||||
publicKey, privateKey, err := ed25519.GenerateKey(rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := service.RegisterOpsFirmwareSigningKey(ctx, operator, tenantID, "ops-firmware-integration-key", keyID, base64.StdEncoding.EncodeToString(publicKey)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
firmware := []byte("synthetic operations firmware")
|
||||
digestBytes := sha256.Sum256(firmware)
|
||||
digest := hex.EncodeToString(digestBytes[:])
|
||||
model, hardware := "simulated-terminal", "sim-rev-a"
|
||||
signature := base64.StdEncoding.EncodeToString(ed25519.Sign(privateKey, []byte(firmwareManifest(model, hardware, version, digest, int64(len(firmware))))))
|
||||
prepared, err := service.PrepareOpsFirmwareRelease(ctx, operator, tenantID, "ops-firmware-integration-prepare", PrepareFirmwareInput{
|
||||
Model: model, HardwareRevision: hardware, Version: version, ExpectedSize: int64(len(firmware)), ExpectedDigest: digest,
|
||||
Signature: signature, SigningKeyID: keyID, ReleaseChannel: "BETA", Mandatory: true, ReleaseNotes: "维护端集成测试",
|
||||
})
|
||||
if err != nil || prepared.Status != "UPLOADING" || prepared.HouseholdID != "" || prepared.CreatedSource != "OPS" || prepared.ReleaseChannel != "BETA" || !prepared.Mandatory || prepared.UploadURL == "" {
|
||||
t.Fatalf("prepared=%+v err=%v", prepared, err)
|
||||
}
|
||||
releaseID = prepared.ID
|
||||
ready, err := service.FinalizeOpsFirmwareRelease(ctx, operator, tenantID, releaseID, "ops-firmware-integration-finalize")
|
||||
if err != nil || ready.Status != "READY" || ready.VerifiedAt == nil || ready.PublishedAt == nil || store.verifiedDigest != digest {
|
||||
t.Fatalf("ready=%+v store=%+v err=%v", ready, store, err)
|
||||
}
|
||||
items, err := service.ListOpsFirmwareReleases(ctx, operator, tenantID, model, "READY")
|
||||
if err != nil || len(items) != 1 || items[0].ID != releaseID {
|
||||
t.Fatalf("items=%+v err=%v", items, err)
|
||||
}
|
||||
download, err := service.OpsFirmwareDownload(ctx, operator, tenantID, releaseID, "ops-firmware-integration-download")
|
||||
if err != nil || download.ReleaseID != releaseID || download.SHA256 != digest || download.DownloadURL == "" {
|
||||
t.Fatalf("download=%+v err=%v", download, err)
|
||||
}
|
||||
rollout, err := service.StartOpsFirmwareRollout(ctx, operator, tenantID, releaseID, "ops-firmware-integration-rollout", "维护端OTA", 100, []string{"10000000-0000-0000-0000-000000000511"})
|
||||
if err != nil || rollout.Targeted != 1 || rollout.HouseholdID != "" || rollout.Status != "RUNNING" {
|
||||
t.Fatalf("rollout=%+v err=%v", rollout, err)
|
||||
}
|
||||
rolloutID = rollout.ID
|
||||
detail, err := service.GetOpsFirmwareRollout(ctx, operator, tenantID, rolloutID)
|
||||
if err != nil || len(detail.Assignments) != 1 || detail.Assignments[0].Status != "ASSIGNED" {
|
||||
t.Fatalf("rollout detail=%+v err=%v", detail, err)
|
||||
}
|
||||
pausedRollout, err := service.PauseOpsFirmwareRollout(ctx, operator, tenantID, rolloutID, "ops-firmware-integration-rollout-pause")
|
||||
if err != nil || pausedRollout.Status != "PAUSED" {
|
||||
t.Fatalf("paused rollout=%+v err=%v", pausedRollout, err)
|
||||
}
|
||||
paused, err := service.PauseOpsFirmwareRelease(ctx, operator, tenantID, releaseID, "ops-firmware-integration-pause")
|
||||
if err != nil || paused.Status != "PAUSED" {
|
||||
t.Fatalf("paused=%+v err=%v", paused, err)
|
||||
}
|
||||
resumed, err := service.ResumeOpsFirmwareRelease(ctx, operator, tenantID, releaseID, "ops-firmware-integration-resume")
|
||||
if err != nil || resumed.Status != "READY" {
|
||||
t.Fatalf("resumed=%+v err=%v", resumed, err)
|
||||
}
|
||||
retired, err := service.RetireOpsFirmwareRelease(ctx, operator, tenantID, releaseID, "ops-firmware-integration-retire")
|
||||
if err != nil || retired.Status != "RETIRED" || len(store.removed) != 0 {
|
||||
t.Fatalf("retired=%+v removed=%v err=%v", retired, store.removed, err)
|
||||
}
|
||||
customer := identity.Principal{Issuer: testIssuer, Subject: testOwnerSubject}
|
||||
if _, err := service.ListOpsFirmwareReleases(ctx, customer, tenantID, "", ""); !errors.Is(err, ErrAccessDenied) {
|
||||
t.Fatalf("customer ops access error=%v", err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user