0
Fork 0
mirror of https://github.com/project-zot/zot.git synced 2024-12-16 21:56:37 -05:00
zot/pkg/test/image-utils/upload_test.go

549 lines
13 KiB
Go
Raw Normal View History

package image_test
import (
"encoding/json"
"os"
"path"
"testing"
godigest "github.com/opencontainers/go-digest"
"github.com/opencontainers/image-spec/specs-go"
ispec "github.com/opencontainers/image-spec/specs-go/v1"
. "github.com/smartystreets/goconvey/convey"
"zotregistry.io/zot/pkg/api"
"zotregistry.io/zot/pkg/api/config"
tcommon "zotregistry.io/zot/pkg/test/common"
. "zotregistry.io/zot/pkg/test/image-utils"
"zotregistry.io/zot/pkg/test/inject"
)
func TestUploadImage(t *testing.T) {
Convey("Manifest without schemaVersion should fail validation", t, func() {
port := tcommon.GetFreePort()
baseURL := tcommon.GetBaseURL(port)
conf := config.New()
conf.HTTP.Port = port
conf.Storage.RootDirectory = t.TempDir()
ctlr := api.NewController(conf)
ctlrManager := tcommon.NewControllerManager(ctlr)
ctlrManager.StartAndWait(port)
defer ctlrManager.StopServer()
layerBlob := []byte("test")
img := Image{
Layers: [][]byte{
layerBlob,
},
Manifest: ispec.Manifest{
Layers: []ispec.Descriptor{
{
Digest: godigest.FromBytes(layerBlob),
Size: int64(len(layerBlob)),
MediaType: ispec.MediaTypeImageLayerGzip,
},
},
Config: ispec.DescriptorEmptyJSON,
},
Config: ispec.Image{},
}
err := UploadImage(img, baseURL, "test", img.DigestStr())
So(err, ShouldNotBeNil)
})
Convey("Post request results in an error", t, func() {
port := tcommon.GetFreePort()
baseURL := tcommon.GetBaseURL(port)
conf := config.New()
conf.HTTP.Port = port
conf.Storage.RootDirectory = t.TempDir()
img := Image{
Layers: make([][]byte, 10),
}
err := UploadImage(img, baseURL, "test", "")
So(err, ShouldNotBeNil)
})
Convey("Post request status differs from accepted", t, func() {
port := tcommon.GetFreePort()
baseURL := tcommon.GetBaseURL(port)
tempDir := t.TempDir()
conf := config.New()
conf.HTTP.Port = port
conf.Storage.RootDirectory = tempDir
err := os.Chmod(tempDir, 0o400)
if err != nil {
t.Fatal(err)
}
ctlr := api.NewController(conf)
ctlrManager := tcommon.NewControllerManager(ctlr)
ctlrManager.StartAndWait(port)
defer ctlrManager.StopServer()
img := Image{
Layers: make([][]byte, 10),
}
err = UploadImage(img, baseURL, "test", "")
So(err, ShouldNotBeNil)
})
Convey("Put request results in an error", t, func() {
port := tcommon.GetFreePort()
baseURL := tcommon.GetBaseURL(port)
conf := config.New()
conf.HTTP.Port = port
conf.Storage.RootDirectory = t.TempDir()
ctlr := api.NewController(conf)
ctlrManager := tcommon.NewControllerManager(ctlr)
ctlrManager.StartAndWait(port)
defer ctlrManager.StopServer()
img := Image{
Layers: make([][]byte, 10), // invalid format that will result in an error
Config: ispec.Image{},
}
err := UploadImage(img, baseURL, "test", "")
So(err, ShouldNotBeNil)
})
Convey("Image uploaded successfully", t, func() {
port := tcommon.GetFreePort()
baseURL := tcommon.GetBaseURL(port)
conf := config.New()
conf.HTTP.Port = port
conf.Storage.RootDirectory = t.TempDir()
ctlr := api.NewController(conf)
ctlrManager := tcommon.NewControllerManager(ctlr)
ctlrManager.StartAndWait(port)
defer ctlrManager.StopServer()
layerBlob := []byte("test")
img := Image{
Layers: [][]byte{
layerBlob,
},
Manifest: ispec.Manifest{
Versioned: specs.Versioned{
SchemaVersion: 2,
},
Layers: []ispec.Descriptor{
{
Digest: godigest.FromBytes(layerBlob),
Size: int64(len(layerBlob)),
MediaType: ispec.MediaTypeImageLayerGzip,
},
},
Config: ispec.DescriptorEmptyJSON,
},
Config: ispec.Image{},
}
err := UploadImage(img, baseURL, "test", img.DigestStr())
So(err, ShouldBeNil)
})
Convey("Upload image with authentification", t, func() {
tempDir := t.TempDir()
conf := config.New()
port := tcommon.GetFreePort()
baseURL := tcommon.GetBaseURL(port)
user1 := "test"
password1 := "test"
testString1 := tcommon.GetCredString(user1, password1)
htpasswdPath := tcommon.MakeHtpasswdFileFromString(testString1)
defer os.Remove(htpasswdPath)
conf.HTTP.Auth = &config.AuthConfig{
HTPasswd: config.AuthHTPasswd{
Path: htpasswdPath,
},
}
conf.HTTP.Port = port
conf.HTTP.AccessControl = &config.AccessControlConfig{
Repositories: config.Repositories{
"repo": config.PolicyGroup{
Policies: []config.Policy{
{
Users: []string{user1},
Actions: []string{"read", "create"},
},
},
DefaultPolicy: []string{},
},
"inaccessibleRepo": config.PolicyGroup{
Policies: []config.Policy{
{
Users: []string{user1},
Actions: []string{"create"},
},
},
DefaultPolicy: []string{},
},
},
AdminPolicy: config.Policy{
Users: []string{},
Actions: []string{},
},
}
ctlr := api.NewController(conf)
ctlr.Config.Storage.RootDirectory = tempDir
ctlrManager := tcommon.NewControllerManager(ctlr)
ctlrManager.StartAndWait(port)
defer ctlrManager.StopServer()
Convey("Request fail while pushing layer", func() {
err := UploadImageWithBasicAuth(Image{Layers: [][]byte{{1, 2, 3}}}, "badURL", "", "", "", "")
So(err, ShouldNotBeNil)
})
Convey("Request status is not StatusOk while pushing layer", func() {
err := UploadImageWithBasicAuth(Image{Layers: [][]byte{{1, 2, 3}}}, baseURL, "", "repo", "", "")
So(err, ShouldNotBeNil)
})
Convey("Request fail while pushing config", func() {
err := UploadImageWithBasicAuth(Image{}, "badURL", "", "", "", "")
So(err, ShouldNotBeNil)
})
Convey("Request status is not StatusOk while pushing config", func() {
err := UploadImageWithBasicAuth(Image{}, baseURL, "", "repo", "", "")
So(err, ShouldNotBeNil)
})
})
Convey("Blob upload wrong response status code", t, func() {
port := tcommon.GetFreePort()
baseURL := tcommon.GetBaseURL(port)
tempDir := t.TempDir()
conf := config.New()
conf.HTTP.Port = port
conf.Storage.RootDirectory = tempDir
ctlr := api.NewController(conf)
ctlrManager := tcommon.NewControllerManager(ctlr)
ctlrManager.StartAndWait(port)
defer ctlrManager.StopServer()
layerBlob := []byte("test")
layerBlobDigest := godigest.FromBytes(layerBlob)
layerPath := path.Join(tempDir, "test", "blobs", "sha256")
if _, err := os.Stat(layerPath); os.IsNotExist(err) {
err = os.MkdirAll(layerPath, 0o700)
if err != nil {
t.Fatal(err)
}
file, err := os.Create(path.Join(layerPath, layerBlobDigest.Encoded()))
if err != nil {
t.Fatal(err)
}
err = os.Chmod(layerPath, 0o000)
if err != nil {
t.Fatal(err)
}
defer func() {
err = os.Chmod(layerPath, 0o700)
if err != nil {
t.Fatal(err)
}
os.RemoveAll(file.Name())
}()
}
img := Image{
Layers: [][]byte{
layerBlob,
}, // invalid format that will result in an error
Config: ispec.Image{},
}
err := UploadImage(img, baseURL, "test", "")
So(err, ShouldNotBeNil)
})
Convey("CreateBlobUpload wrong response status code", t, func() {
port := tcommon.GetFreePort()
baseURL := tcommon.GetBaseURL(port)
tempDir := t.TempDir()
conf := config.New()
conf.HTTP.Port = port
conf.Storage.RootDirectory = tempDir
ctlr := api.NewController(conf)
ctlrManager := tcommon.NewControllerManager(ctlr)
ctlrManager.StartAndWait(port)
defer ctlrManager.StopServer()
layerBlob := []byte("test")
img := Image{
Layers: [][]byte{
layerBlob,
}, // invalid format that will result in an error
Config: ispec.Image{},
}
Convey("CreateBlobUpload", func() {
injected := inject.InjectFailure(2)
if injected {
err := UploadImage(img, baseURL, "test", img.DigestStr())
So(err, ShouldNotBeNil)
}
})
Convey("UpdateBlobUpload", func() {
injected := inject.InjectFailure(4)
if injected {
err := UploadImage(img, baseURL, "test", img.DigestStr())
So(err, ShouldNotBeNil)
}
})
})
}
func TestInjectUploadImage(t *testing.T) {
Convey("Inject failures for unreachable lines", t, func() {
port := tcommon.GetFreePort()
baseURL := tcommon.GetBaseURL(port)
tempDir := t.TempDir()
conf := config.New()
conf.HTTP.Port = port
conf.Storage.RootDirectory = tempDir
ctlr := api.NewController(conf)
ctlrManager := tcommon.NewControllerManager(ctlr)
ctlrManager.StartAndWait(port)
defer ctlrManager.StopServer()
layerBlob := []byte("test")
layerPath := path.Join(tempDir, "test", ".uploads")
if _, err := os.Stat(layerPath); os.IsNotExist(err) {
err = os.MkdirAll(layerPath, 0o700)
if err != nil {
t.Fatal(err)
}
}
img := Image{
Layers: [][]byte{
layerBlob,
}, // invalid format that will result in an error
Config: ispec.Image{},
}
Convey("first marshal", func() {
injected := inject.InjectFailure(0)
if injected {
err := UploadImage(img, baseURL, "test", img.DigestStr())
So(err, ShouldNotBeNil)
}
})
Convey("CreateBlobUpload POST call", func() {
injected := inject.InjectFailure(1)
if injected {
err := UploadImage(img, baseURL, "test", img.DigestStr())
So(err, ShouldNotBeNil)
}
})
Convey("UpdateBlobUpload PUT call", func() {
injected := inject.InjectFailure(3)
if injected {
err := UploadImage(img, baseURL, "test", img.DigestStr())
So(err, ShouldNotBeNil)
}
})
Convey("second marshal", func() {
injected := inject.InjectFailure(5)
if injected {
err := UploadImage(img, baseURL, "test", img.DigestStr())
So(err, ShouldNotBeNil)
}
})
})
}
func TestUploadMultiarchImage(t *testing.T) {
Convey("make controller", t, func() {
port := tcommon.GetFreePort()
baseURL := tcommon.GetBaseURL(port)
conf := config.New()
conf.HTTP.Port = port
conf.Storage.RootDirectory = t.TempDir()
ctlr := api.NewController(conf)
ctlrManager := tcommon.NewControllerManager(ctlr)
ctlrManager.StartAndWait(port)
defer ctlrManager.StopServer()
layerBlob := []byte("test")
img := Image{
Layers: [][]byte{
layerBlob,
},
Manifest: ispec.Manifest{
Versioned: specs.Versioned{
SchemaVersion: 2,
},
Layers: []ispec.Descriptor{
{
Digest: godigest.FromBytes(layerBlob),
Size: int64(len(layerBlob)),
MediaType: ispec.MediaTypeImageLayerGzip,
},
},
Config: ispec.DescriptorEmptyJSON,
},
Config: ispec.Image{},
}
manifestBuf, err := json.Marshal(img.Manifest)
So(err, ShouldBeNil)
Convey("Multiarch image uploaded successfully", func() {
err = UploadMultiarchImage(MultiarchImage{
Index: ispec.Index{
Versioned: specs.Versioned{
SchemaVersion: 2,
},
MediaType: ispec.MediaTypeImageIndex,
Manifests: []ispec.Descriptor{
{
MediaType: ispec.MediaTypeImageManifest,
Digest: godigest.FromBytes(manifestBuf),
Size: int64(len(manifestBuf)),
},
},
},
Images: []Image{img},
}, baseURL, "test", "index")
So(err, ShouldBeNil)
})
Convey("Multiarch image without schemaVersion should fail validation", func() {
err = UploadMultiarchImage(MultiarchImage{
Index: ispec.Index{
MediaType: ispec.MediaTypeImageIndex,
Manifests: []ispec.Descriptor{
{
MediaType: ispec.MediaTypeImageManifest,
Digest: godigest.FromBytes(manifestBuf),
Size: int64(len(manifestBuf)),
},
},
},
Images: []Image{img},
}, baseURL, "test", "index")
So(err, ShouldNotBeNil)
})
})
}
func TestInjectUploadImageWithBasicAuth(t *testing.T) {
Convey("Inject failures for unreachable lines", t, func() {
port := tcommon.GetFreePort()
baseURL := tcommon.GetBaseURL(port)
tempDir := t.TempDir()
conf := config.New()
conf.HTTP.Port = port
conf.Storage.RootDirectory = tempDir
user := "user"
password := "password"
testString := tcommon.GetCredString(user, password)
htpasswdPath := tcommon.MakeHtpasswdFileFromString(testString)
defer os.Remove(htpasswdPath)
conf.HTTP.Auth = &config.AuthConfig{
HTPasswd: config.AuthHTPasswd{
Path: htpasswdPath,
},
}
ctlr := api.NewController(conf)
ctlrManager := tcommon.NewControllerManager(ctlr)
ctlrManager.StartAndWait(port)
defer ctlrManager.StopServer()
layerBlob := []byte("test")
layerPath := path.Join(tempDir, "test", ".uploads")
if _, err := os.Stat(layerPath); os.IsNotExist(err) {
err = os.MkdirAll(layerPath, 0o700)
if err != nil {
t.Fatal(err)
}
}
img := Image{
Layers: [][]byte{
layerBlob,
}, // invalid format that will result in an error
Config: ispec.Image{},
}
Convey("first marshal", func() {
injected := inject.InjectFailure(0)
if injected {
err := UploadImageWithBasicAuth(img, baseURL, "test", img.DigestStr(), "user", "password")
So(err, ShouldNotBeNil)
}
})
Convey("CreateBlobUpload POST call", func() {
injected := inject.InjectFailure(1)
if injected {
err := UploadImageWithBasicAuth(img, baseURL, "test", img.DigestStr(), "user", "password")
So(err, ShouldNotBeNil)
}
})
Convey("UpdateBlobUpload PUT call", func() {
injected := inject.InjectFailure(3)
if injected {
err := UploadImageWithBasicAuth(img, baseURL, "test", img.DigestStr(), "user", "password")
So(err, ShouldNotBeNil)
}
})
Convey("second marshal", func() {
injected := inject.InjectFailure(5)
if injected {
err := UploadImageWithBasicAuth(img, baseURL, "test", img.DigestStr(), "user", "password")
So(err, ShouldNotBeNil)
}
})
})
}