196 lines
6.1 KiB
Go
196 lines
6.1 KiB
Go
package updatepackage
|
|
|
|
import (
|
|
"archive/zip"
|
|
"bytes"
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestOpenAndExtractNativeBackend(t *testing.T) {
|
|
jar := []byte("native backend JAR")
|
|
packagePath := writeBackendPackage(t, jar, nil)
|
|
|
|
updatePackage, err := OpenBackendNative(packagePath)
|
|
if err != nil {
|
|
t.Fatalf("open native backend package: %v", err)
|
|
}
|
|
defer updatePackage.Close()
|
|
if updatePackage.CustomerCode != "customer-01" || updatePackage.VersionID != "V1.1.8" || updatePackage.ArtifactID != 42 {
|
|
t.Fatalf("unexpected package metadata: %+v", updatePackage)
|
|
}
|
|
if updatePackage.Identity.Size != int64(len(jar)) || updatePackage.PackageSHA256 == "" {
|
|
t.Fatalf("unexpected package identity: package=%s artifact=%+v", updatePackage.PackageSHA256, updatePackage.Identity)
|
|
}
|
|
|
|
destination := filepath.Join(t.TempDir(), "incoming", "backend.jar")
|
|
if err := updatePackage.ExtractArtifact(destination); err != nil {
|
|
t.Fatalf("extract native backend artifact: %v", err)
|
|
}
|
|
actual, err := os.ReadFile(destination)
|
|
if err != nil || !bytes.Equal(actual, jar) {
|
|
t.Fatalf("unexpected extracted artifact: content=%q err=%v", actual, err)
|
|
}
|
|
}
|
|
|
|
func TestOpenRejectsUnknownManifestField(t *testing.T) {
|
|
jar := []byte("native backend JAR")
|
|
packagePath := writeBackendPackage(t, jar, func(manifest map[string]any) {
|
|
manifest["VersionID"] = "wrong-case"
|
|
})
|
|
_, err := OpenBackendNative(packagePath)
|
|
if err == nil || !strings.Contains(err.Error(), "VersionID") {
|
|
t.Fatalf("expected unknown manifest field rejection, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestOpenRejectsMissingDeclaredArtifact(t *testing.T) {
|
|
jar := []byte("native backend JAR")
|
|
packagePath := writePackageEntries(t, map[string][]byte{
|
|
manifestName: manifestJSON(t, jar, func(manifest map[string]any) {
|
|
artifacts := manifest["backendArtifacts"].([]any)
|
|
artifacts[0].(map[string]any)["fileName"] = "missing.jar"
|
|
}),
|
|
})
|
|
_, err := OpenBackendNative(packagePath)
|
|
if err == nil || !strings.Contains(err.Error(), "missing.jar") {
|
|
t.Fatalf("expected missing artifact rejection, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestExtractRejectsArtifactDigestMismatch(t *testing.T) {
|
|
jar := []byte("native backend JAR")
|
|
packagePath := writeBackendPackage(t, jar, func(manifest map[string]any) {
|
|
artifacts := manifest["backendArtifacts"].([]any)
|
|
artifacts[0].(map[string]any)["sha256"] = strings.Repeat("0", 64)
|
|
})
|
|
updatePackage, err := OpenBackendNative(packagePath)
|
|
if err != nil {
|
|
t.Fatalf("open package before digest verification: %v", err)
|
|
}
|
|
defer updatePackage.Close()
|
|
destination := filepath.Join(t.TempDir(), "backend.jar")
|
|
if err := updatePackage.ExtractArtifact(destination); err == nil || !strings.Contains(err.Error(), "SHA-256 mismatch") {
|
|
t.Fatalf("expected artifact digest mismatch, got %v", err)
|
|
}
|
|
if _, err := os.Stat(destination); !os.IsNotExist(err) {
|
|
t.Fatalf("digest mismatch published artifact: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestOpenRejectsUnsafeAndDuplicateEntries(t *testing.T) {
|
|
jar := []byte("native backend JAR")
|
|
manifest := manifestJSON(t, jar, nil)
|
|
|
|
t.Run("unsafe", func(t *testing.T) {
|
|
packagePath := writePackageEntries(t, map[string][]byte{
|
|
manifestName: manifest,
|
|
"backend.jar": jar,
|
|
"../escape": []byte("escape"),
|
|
})
|
|
if _, err := OpenBackendNative(packagePath); err == nil {
|
|
t.Fatal("expected unsafe ZIP entry rejection")
|
|
}
|
|
})
|
|
|
|
t.Run("duplicate", func(t *testing.T) {
|
|
path := filepath.Join(t.TempDir(), "package.zip")
|
|
file, err := os.Create(path)
|
|
if err != nil {
|
|
t.Fatalf("create duplicate package: %v", err)
|
|
}
|
|
writer := zip.NewWriter(file)
|
|
for _, content := range [][]byte{manifest, manifest} {
|
|
entry, err := writer.Create(manifestName)
|
|
if err != nil {
|
|
t.Fatalf("create duplicate manifest entry: %v", err)
|
|
}
|
|
if _, err := entry.Write(content); err != nil {
|
|
t.Fatalf("write duplicate manifest entry: %v", err)
|
|
}
|
|
}
|
|
if err := writer.Close(); err != nil {
|
|
t.Fatalf("close duplicate package writer: %v", err)
|
|
}
|
|
if err := file.Close(); err != nil {
|
|
t.Fatalf("close duplicate package: %v", err)
|
|
}
|
|
if _, err := OpenBackendNative(path); err == nil || !strings.Contains(err.Error(), "duplicate") {
|
|
t.Fatalf("expected duplicate ZIP entry rejection, got %v", err)
|
|
}
|
|
})
|
|
}
|
|
|
|
func writeBackendPackage(t *testing.T, jar []byte, modify func(map[string]any)) string {
|
|
t.Helper()
|
|
return writePackageEntries(t, map[string][]byte{
|
|
manifestName: manifestJSON(t, jar, modify),
|
|
"backend.jar": jar,
|
|
})
|
|
}
|
|
|
|
func manifestJSON(t *testing.T, jar []byte, modify func(map[string]any)) []byte {
|
|
t.Helper()
|
|
digest := sha256.Sum256(jar)
|
|
manifest := map[string]any{
|
|
"customerCode": "customer-01",
|
|
"customerDisplayName": "Customer 01",
|
|
"versionId": "V1.1.8",
|
|
"items": []string{"deploy-sync.sh"},
|
|
"backendArtifacts": []any{map[string]any{
|
|
"id": int64(42),
|
|
"versionCode": "V1.1.8",
|
|
"artifactKind": backendArtifactKind,
|
|
"type": nativeArtifactType,
|
|
"selectedType": nativeArtifactType,
|
|
"platform": nil,
|
|
"fileName": "backend.jar",
|
|
"filePath": "/archive/backend.jar",
|
|
"sha256": hex.EncodeToString(digest[:]),
|
|
"imageRef": nil,
|
|
}},
|
|
"frontendArtifacts": []any{},
|
|
"nodeSsrArtifacts": []any{},
|
|
"remark": nil,
|
|
}
|
|
if modify != nil {
|
|
modify(manifest)
|
|
}
|
|
content, err := json.Marshal(manifest)
|
|
if err != nil {
|
|
t.Fatalf("encode manifest: %v", err)
|
|
}
|
|
return content
|
|
}
|
|
|
|
func writePackageEntries(t *testing.T, entries map[string][]byte) string {
|
|
t.Helper()
|
|
packagePath := filepath.Join(t.TempDir(), "package.zip")
|
|
file, err := os.Create(packagePath)
|
|
if err != nil {
|
|
t.Fatalf("create package: %v", err)
|
|
}
|
|
writer := zip.NewWriter(file)
|
|
for name, content := range entries {
|
|
entry, err := writer.Create(name)
|
|
if err != nil {
|
|
t.Fatalf("create package entry %s: %v", name, err)
|
|
}
|
|
if _, err := entry.Write(content); err != nil {
|
|
t.Fatalf("write package entry %s: %v", name, err)
|
|
}
|
|
}
|
|
if err := writer.Close(); err != nil {
|
|
t.Fatalf("close package writer: %v", err)
|
|
}
|
|
if err := file.Close(); err != nil {
|
|
t.Fatalf("close package: %v", err)
|
|
}
|
|
return packagePath
|
|
}
|