Merge pull request #7391 from kofj/ut_for_native_adapter

Ut for native adapter
This commit is contained in:
Wenkai Yin 2019-04-16 08:24:31 +08:00 committed by GitHub
commit d6f08dead6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 440 additions and 8 deletions

View File

@ -26,14 +26,7 @@ const registryTypeNative model.RegistryType = "native"
func init() {
if err := adp.RegisterFactory(registryTypeNative, func(registry *model.Registry) (adp.Adapter, error) {
reg, err := adp.NewDefaultImageRegistry(registry)
if err != nil {
return nil, err
}
return &native{
registry: registry,
DefaultImageRegistry: reg,
}, nil
return newAdapter(registry)
}); err != nil {
log.Errorf("failed to register factory for %s: %v", registryTypeNative, err)
return
@ -41,6 +34,17 @@ func init() {
log.Infof("the factory for adapter %s registered", registryTypeNative)
}
func newAdapter(registry *model.Registry) (*native, error) {
reg, err := adp.NewDefaultImageRegistry(registry)
if err != nil {
return nil, err
}
return &native{
registry: registry,
DefaultImageRegistry: reg,
}, nil
}
type native struct {
*adp.DefaultImageRegistry
registry *model.Registry

View File

@ -0,0 +1,153 @@
package native
import (
"testing"
adp "github.com/goharbor/harbor/src/replication/adapter"
"github.com/goharbor/harbor/src/replication/model"
"github.com/stretchr/testify/assert"
)
func Test_newAdapter(t *testing.T) {
tests := []struct {
name string
registry *model.Registry
wantErr bool
}{
{name: "Nil Registry URL", registry: &model.Registry{}, wantErr: true},
{name: "Right", registry: &model.Registry{URL: "abc"}, wantErr: false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := newAdapter(tt.registry)
if tt.wantErr {
assert.NotNil(t, err)
assert.Nil(t, got)
} else {
assert.Nil(t, err)
assert.NotNil(t, got)
}
})
}
}
func Test_native_Info(t *testing.T) {
var registry = &model.Registry{URL: "abc"}
var reg, _ = adp.NewDefaultImageRegistry(registry)
var adapter = native{
DefaultImageRegistry: reg,
registry: registry,
}
assert.NotNil(t, adapter)
var info, err = adapter.Info()
assert.Nil(t, err)
assert.NotNil(t, info)
assert.Equal(t, registryTypeNative, info.Type)
assert.Equal(t, 1, len(info.SupportedResourceTypes))
assert.Equal(t, 2, len(info.SupportedResourceFilters))
assert.Equal(t, 2, len(info.SupportedTriggers))
assert.Equal(t, model.ResourceTypeRepository, info.SupportedResourceTypes[0])
}
func Test_native_ConvertResourceMetadata(t *testing.T) {
var registry = &model.Registry{URL: "abc"}
var reg, _ = adp.NewDefaultImageRegistry(registry)
var adapter = native{
DefaultImageRegistry: reg,
registry: registry,
}
assert.NotNil(t, adapter)
tests := []struct {
name string
metadata *model.ResourceMetadata
namespace *model.Namespace
want string
wantErr bool
}{
{name: "nil metadata", metadata: nil, wantErr: true},
{
name: "2 level",
metadata: &model.ResourceMetadata{
Namespace: &model.Namespace{Name: "a"},
Repository: &model.Repository{Name: "b"},
},
namespace: nil,
want: "a/b",
wantErr: false,
},
{
name: "2 level rename reomte repository",
metadata: &model.ResourceMetadata{
Namespace: &model.Namespace{Name: "a"},
Repository: &model.Repository{Name: "b"},
},
namespace: &model.Namespace{Name: "c"},
want: "c/b",
wantErr: false,
},
{
name: "3 level",
metadata: &model.ResourceMetadata{
Namespace: &model.Namespace{Name: "a"},
Repository: &model.Repository{Name: "b/c"},
},
namespace: nil,
want: "a/b/c",
wantErr: false,
},
{
name: "3 level rename reomte repository",
metadata: &model.ResourceMetadata{
Namespace: &model.Namespace{Name: "a"},
Repository: &model.Repository{Name: "b/c"},
},
namespace: &model.Namespace{Name: "d"},
want: "d/b/c",
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var convert, err = adapter.ConvertResourceMetadata(tt.metadata, tt.namespace)
if tt.wantErr {
assert.NotNil(t, err)
} else {
assert.Nil(t, err)
assert.NotNil(t, convert)
assert.Nil(t, convert.Namespace)
assert.Equal(t, tt.want, convert.Repository.Name)
assert.Equal(t, tt.want, convert.GetResourceName())
}
})
}
}
func Test_native_PrepareForPush(t *testing.T) {
var registry = &model.Registry{URL: "abc"}
var reg, _ = adp.NewDefaultImageRegistry(registry)
var adapter = native{
DefaultImageRegistry: reg,
registry: registry,
}
assert.NotNil(t, adapter)
var err = adapter.PrepareForPush(nil)
assert.Nil(t, err)
}
func Test_native_ListNamespaces(t *testing.T) {
var registry = &model.Registry{URL: "abc"}
var reg, _ = adp.NewDefaultImageRegistry(registry)
var adapter = native{
DefaultImageRegistry: reg,
registry: registry,
}
assert.NotNil(t, adapter)
var ns, err = adapter.ListNamespaces(nil)
assert.Nil(t, err)
assert.NotNil(t, ns)
}

View File

@ -0,0 +1,275 @@
package native
import (
"fmt"
"net/http"
"net/http/httptest"
"testing"
"github.com/goharbor/harbor/src/common/utils/test"
adp "github.com/goharbor/harbor/src/replication/adapter"
"github.com/goharbor/harbor/src/replication/model"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func mockNativeRegistry() (mock *httptest.Server) {
return test.NewServer(
&test.RequestHandlerMapping{
Method: http.MethodGet,
Pattern: "/v2/_catalog",
Handler: func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(`{"repositories":["test/a1","test/b2","test/c3/3level"]}`))
},
},
&test.RequestHandlerMapping{
Method: http.MethodGet,
Pattern: "/v2/test/a1/tags/list",
Handler: func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(`{"name":"test/a1","tags":["tag11"]}`))
},
},
&test.RequestHandlerMapping{
Method: http.MethodGet,
Pattern: "/v2/test/b2/tags/list",
Handler: func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(`{"name":"test/b2","tags":["tag11","tag2","tag13"]}`))
},
},
&test.RequestHandlerMapping{
Method: http.MethodGet,
Pattern: "/v2/test/c3/3level/tags/list",
Handler: func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(`{"name":"test/c3/3level","tags":["tag4"]}`))
},
},
)
}
func Test_native_FetchImages(t *testing.T) {
var mock = mockNativeRegistry()
defer mock.Close()
fmt.Println("mockNativeRegistry URL: ", mock.URL)
var registry = &model.Registry{
Type: registryTypeNative,
URL: mock.URL,
Insecure: true,
}
var reg, err = adp.NewDefaultImageRegistry(registry)
assert.NotNil(t, reg)
assert.Nil(t, err)
var adapter = native{
DefaultImageRegistry: reg,
registry: registry,
}
assert.NotNil(t, adapter)
tests := []struct {
name string
namespaces []string
filters []*model.Filter
want []*model.Resource
wantErr bool
}{
{name: "namespace not empty", namespaces: []string{"ns"}, wantErr: true},
// TODO: discuss: should we report error if not found in the source native registry.
// {
// name: "repository not exist",
// filters: []*model.Filter{
// {
// Type: model.FilterTypeName,
// Value: "b1",
// },
// },
// wantErr: true,
// },
// {
// name: "tag not exist",
// filters: []*model.Filter{
// {
// Type: model.FilterTypeTag,
// Value: "c",
// },
// },
// wantErr: true,
// },
{
name: "no filters",
filters: []*model.Filter{},
want: []*model.Resource{
{
Metadata: &model.ResourceMetadata{
Repository: &model.Repository{Name: "test/a1"},
Vtags: []string{"tag11"},
},
},
{
Metadata: &model.ResourceMetadata{
Repository: &model.Repository{Name: "test/b2"},
Vtags: []string{"tag11", "tag2", "tag13"},
},
},
{
Metadata: &model.ResourceMetadata{
Repository: &model.Repository{Name: "test/c3/3level"},
Vtags: []string{"tag4"},
},
},
},
wantErr: false,
},
{
name: "only special repository",
namespaces: []string{},
filters: []*model.Filter{
{
Type: model.FilterTypeName,
Value: "test/a1",
},
},
want: []*model.Resource{
{
Metadata: &model.ResourceMetadata{
Repository: &model.Repository{Name: "test/a1"},
Vtags: []string{"tag11"},
},
},
},
wantErr: false,
},
{
name: "only special tag",
namespaces: []string{},
filters: []*model.Filter{
{
Type: model.FilterTypeTag,
Value: "tag11",
},
},
want: []*model.Resource{
{
Metadata: &model.ResourceMetadata{
Repository: &model.Repository{Name: "test/a1"},
Vtags: []string{"tag11"},
},
},
{
Metadata: &model.ResourceMetadata{
Repository: &model.Repository{Name: "test/b2"},
Vtags: []string{"tag11"},
},
},
},
wantErr: false,
},
{
name: "special repository and special tag",
namespaces: []string{},
filters: []*model.Filter{
{
Type: model.FilterTypeName,
Value: "test/b2",
},
{
Type: model.FilterTypeTag,
Value: "tag2",
},
},
want: []*model.Resource{
{
Metadata: &model.ResourceMetadata{
Repository: &model.Repository{Name: "test/b2"},
Vtags: []string{"tag2"},
},
},
},
wantErr: false,
},
{
name: "only wildcard repository",
namespaces: []string{},
filters: []*model.Filter{
{
Type: model.FilterTypeName,
Value: "test/b*",
},
},
want: []*model.Resource{
{
Metadata: &model.ResourceMetadata{
Repository: &model.Repository{Name: "test/b2"},
Vtags: []string{"tag11", "tag2", "tag13"},
},
},
},
wantErr: false,
},
{
name: "only wildcard tag",
namespaces: []string{},
filters: []*model.Filter{
{
Type: model.FilterTypeTag,
Value: "tag1*",
},
},
want: []*model.Resource{
{
Metadata: &model.ResourceMetadata{
Repository: &model.Repository{Name: "test/a1"},
Vtags: []string{"tag11"},
},
},
{
Metadata: &model.ResourceMetadata{
Repository: &model.Repository{Name: "test/b2"},
Vtags: []string{"tag11", "tag13"},
},
},
},
wantErr: false,
},
{
name: "wildcard repository and wildcard tag",
namespaces: []string{},
filters: []*model.Filter{
{
Type: model.FilterTypeName,
Value: "test/b*",
},
{
Type: model.FilterTypeTag,
Value: "tag1*",
},
},
want: []*model.Resource{
{
Metadata: &model.ResourceMetadata{
Repository: &model.Repository{Name: "test/b2"},
Vtags: []string{"tag11", "tag13"},
},
},
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var resources, err = adapter.FetchImages(tt.namespaces, tt.filters)
if tt.wantErr {
require.Len(t, resources, 0)
require.NotNil(t, err)
} else {
require.Equal(t, len(tt.want), len(resources))
for i, resource := range resources {
require.NotNil(t, resource.Metadata)
assert.Equal(t, tt.want[i].Metadata.Namespace, resource.Metadata.Namespace)
assert.Equal(t, tt.want[i].Metadata.Repository, resource.Metadata.Repository)
assert.Equal(t, tt.want[i].Metadata.Vtags, resource.Metadata.Vtags)
}
}
})
}
}