mirror of
https://github.com/ultravioletrs/cocos.git
synced 2026-06-23 04:10:25 +00:00
b44780df95
CI / lint (push) Has been cancelled
CI / test (agent) (push) Has been cancelled
CI / test (cli) (push) Has been cancelled
CI / test (cmd) (push) Has been cancelled
CI / test (internal) (push) Has been cancelled
CI / test (manager, true) (push) Has been cancelled
CI / test (pkg) (push) Has been cancelled
CI / upload-coverage (push) Has been cancelled
* feat: Enhance OCI image extraction to return algorithm and requirements paths, and add deferred cleanup for temporary files. Signed-off-by: Sammy Oina <sammyoina@gmail.com> * feat: implement deterministic zipping and enhance checksum verification for resources Signed-off-by: Sammy Oina <sammyoina@gmail.com> * feat: Update component build sources, add gRPC health checks to the CVM server, and refine algorithm argument handling and documentation. Signed-off-by: Sammy Oina <sammyoina@gmail.com> * docs: Update remote resources testing guide with `sudo` for KBS, algorithm result saving, `requirements.txt`, and `algo-args` for RVPS. Signed-off-by: Sammy Oina <sammyoina@gmail.com> * refactor: Explicitly ignore `stderr.Write` return values and add minor whitespace in tests. Signed-off-by: Sammy Oina <sammyoina@gmail.com> * test: add comprehensive error path and edge case tests for file, zip, OCI, and agent components. Signed-off-by: Sammy Oina <sammyoina@gmail.com> * feat: Add mutexes for thread-safe algorithm execution and expand recognized data file extensions to include common archive formats. Signed-off-by: Sammy Oina <sammyoina@gmail.com> * feat: Add OCI extraction tests for Python algorithms and multi-layer datasets, refactor algorithm execution for testability, and enhance algorithm stop and error handling tests. Signed-off-by: Sammy Oina <sammyoina@gmail.com> * test: Add error assertions to OCI extraction test helpers and remove an unused mock exec command. Signed-off-by: Sammy Oina <sammyoina@gmail.com> * test: Improve error handling test coverage for algorithm execution and OCI resource extraction. Signed-off-by: Sammy Oina <sammyoina@gmail.com> * fix: Improve algorithm process termination, enhance computation error handling, and add concurrency safety to agent service. Signed-off-by: Sammy Oina <sammyoina@gmail.com> --------- Signed-off-by: Sammy Oina <sammyoina@gmail.com>
202 lines
5.9 KiB
Go
202 lines
5.9 KiB
Go
// Copyright (c) Ultraviolet
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package oci
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestNewSkopeoClient(t *testing.T) {
|
|
t.Run("valid work directory", func(t *testing.T) {
|
|
workDir := t.TempDir()
|
|
client, err := NewSkopeoClient(workDir)
|
|
if err != nil && err.Error() == "skopeo not found in PATH: exec: \"skopeo\": executable file not found in $PATH" {
|
|
t.Skip("skopeo not installed, skipping test")
|
|
}
|
|
require.NoError(t, err)
|
|
assert.NotNil(t, client)
|
|
})
|
|
|
|
t.Run("new work directory", func(t *testing.T) {
|
|
workDir := filepath.Join(t.TempDir(), "new", "nested", "dir")
|
|
client, err := NewSkopeoClient(workDir)
|
|
if err != nil && err.Error() == "skopeo not found in PATH: exec: \"skopeo\": executable file not found in $PATH" {
|
|
t.Skip("skopeo not installed, skipping test")
|
|
}
|
|
require.NoError(t, err)
|
|
assert.NotNil(t, client)
|
|
})
|
|
}
|
|
|
|
func TestSkopeoClient_GetLocalImagePath(t *testing.T) {
|
|
workDir := t.TempDir()
|
|
client, err := NewSkopeoClient(workDir)
|
|
if err != nil {
|
|
t.Skip("skopeo not installed, skipping test")
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
imgName string
|
|
expected string
|
|
}{
|
|
{"simple image name", "myimage", filepath.Join(workDir, "myimage")},
|
|
{"image with tag", "myimage:latest", filepath.Join(workDir, "myimage:latest")},
|
|
{"nested path", "registry/repo/image", filepath.Join(workDir, "registry/repo/image")},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := client.GetLocalImagePath(tt.imgName)
|
|
assert.Equal(t, tt.expected, got)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestSkopeoClient_PullAndDecrypt(t *testing.T) {
|
|
workDir := t.TempDir()
|
|
client, err := NewSkopeoClient(workDir)
|
|
if err != nil {
|
|
t.Skip("skopeo not installed, skipping test")
|
|
}
|
|
|
|
t.Run("invalid source URI", func(t *testing.T) {
|
|
ctx := context.Background()
|
|
destDir := t.TempDir()
|
|
source := ResourceSource{
|
|
Type: ResourceTypeOCIImage,
|
|
URI: "invalid://not-a-valid-uri",
|
|
Encrypted: false,
|
|
}
|
|
err := client.PullAndDecrypt(ctx, source, destDir)
|
|
assert.Error(t, err)
|
|
})
|
|
|
|
t.Run("destination directory created", func(t *testing.T) {
|
|
ctx := context.Background()
|
|
destDir := filepath.Join(t.TempDir(), "new", "nested", "dest")
|
|
source := ResourceSource{
|
|
Type: ResourceTypeOCIImage,
|
|
URI: "invalid://test",
|
|
Encrypted: false,
|
|
}
|
|
_ = client.PullAndDecrypt(ctx, source, destDir)
|
|
_, err := os.Stat(destDir)
|
|
assert.NoError(t, err)
|
|
})
|
|
}
|
|
|
|
func TestSkopeoClient_Inspect(t *testing.T) {
|
|
workDir := t.TempDir()
|
|
client, err := NewSkopeoClient(workDir)
|
|
if err != nil {
|
|
t.Skip("skopeo not installed, skipping test")
|
|
}
|
|
|
|
t.Run("invalid image reference", func(t *testing.T) {
|
|
ctx := context.Background()
|
|
manifest, err := client.Inspect(ctx, "invalid://not-a-valid-ref")
|
|
assert.Error(t, err)
|
|
assert.Nil(t, manifest)
|
|
})
|
|
}
|
|
|
|
func TestResourceSource(t *testing.T) {
|
|
t.Run("ResourceType constants", func(t *testing.T) {
|
|
assert.Equal(t, ResourceType("oci-image"), ResourceTypeOCIImage)
|
|
})
|
|
|
|
t.Run("ResourceSource structure", func(t *testing.T) {
|
|
source := ResourceSource{
|
|
Type: ResourceTypeOCIImage,
|
|
URI: "docker://registry/repo:tag",
|
|
Encrypted: true,
|
|
KBSResourcePath: "default/key/algo-key",
|
|
}
|
|
assert.Equal(t, ResourceTypeOCIImage, source.Type)
|
|
assert.Equal(t, "docker://registry/repo:tag", source.URI)
|
|
assert.True(t, source.Encrypted)
|
|
assert.Equal(t, "default/key/algo-key", source.KBSResourcePath)
|
|
})
|
|
}
|
|
|
|
func TestImageManifest(t *testing.T) {
|
|
t.Run("ImageManifest structure", func(t *testing.T) {
|
|
manifest := ImageManifest{
|
|
Reference: "docker://registry/repo:tag",
|
|
Digest: "sha256:abc123",
|
|
Layers: []string{"sha256:layer1", "sha256:layer2"},
|
|
}
|
|
assert.Equal(t, "docker://registry/repo:tag", manifest.Reference)
|
|
assert.Equal(t, "sha256:abc123", manifest.Digest)
|
|
assert.Len(t, manifest.Layers, 2)
|
|
})
|
|
}
|
|
|
|
func TestSkopeoConstants(t *testing.T) {
|
|
assert.Equal(t, "OCICRYPT_KEYPROVIDER_CONFIG", OCICryptKeyproviderConfig)
|
|
assert.Equal(t, "/etc/ocicrypt_keyprovider.conf", DefaultOCICryptConfig)
|
|
assert.Equal(t, "provider:attestation-agent:cc_kbc::null", DecryptionKeyProvider)
|
|
}
|
|
|
|
func TestNewSkopeoClientUnwritableDir(t *testing.T) {
|
|
if os.Getuid() == 0 {
|
|
t.Skip("cannot test unwritable dir as root")
|
|
}
|
|
|
|
// Create a file where a directory is expected
|
|
tmpDir := t.TempDir()
|
|
blockingFile := filepath.Join(tmpDir, "blocking")
|
|
require.NoError(t, os.WriteFile(blockingFile, []byte("data"), 0o444))
|
|
|
|
// Try to create a client with workDir inside a file (not a dir)
|
|
_, err := NewSkopeoClient(filepath.Join(blockingFile, "subdir"))
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestSkopeoClientPullAndDecryptEncrypted(t *testing.T) {
|
|
workDir := t.TempDir()
|
|
client, err := NewSkopeoClient(workDir)
|
|
if err != nil {
|
|
t.Skip("skopeo not installed, skipping test")
|
|
}
|
|
|
|
t.Run("encrypted image uses decryption key flag", func(t *testing.T) {
|
|
ctx := context.Background()
|
|
destDir := t.TempDir()
|
|
// Encrypted source - skopeo call will fail but the --decryption-key arg is built
|
|
source := ResourceSource{
|
|
Type: ResourceTypeOCIImage,
|
|
URI: "docker://invalid.registry/nonexistent:latest",
|
|
Encrypted: true,
|
|
}
|
|
err := client.PullAndDecrypt(ctx, source, destDir)
|
|
// We expect an error (no such image) but the encrypted code path was exercised
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "skopeo copy failed")
|
|
})
|
|
}
|
|
|
|
func TestSkopeoClient_ToDockerArchive(t *testing.T) {
|
|
workDir := t.TempDir()
|
|
client, err := NewSkopeoClient(workDir)
|
|
if err != nil {
|
|
t.Skip("skopeo not installed, skipping test")
|
|
}
|
|
|
|
t.Run("invalid oci directory", func(t *testing.T) {
|
|
ctx := context.Background()
|
|
destFile := filepath.Join(t.TempDir(), "archive.tar")
|
|
err := client.ToDockerArchive(ctx, "/non/existent/oci/dir", destFile)
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "skopeo copy to docker-archive failed")
|
|
})
|
|
}
|