1. Fix TCR Adapter namespcae check.
2. Add Chart UT.

Signed-off-by: 疯魔慕薇 <kfanjian@gmail.com>
This commit is contained in:
疯魔慕薇 2022-03-04 14:09:25 +08:00 committed by GitHub
parent 3c9fc9fa5a
commit 1c4495361b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 234 additions and 8 deletions

View File

@ -90,7 +90,7 @@ func newAdapter(registry *model.Registry) (a *adapter, err error) {
// only validate registryURL.Host in non-UT scenario // only validate registryURL.Host in non-UT scenario
if os.Getenv("UTTEST") != "true" { if os.Getenv("UTTEST") != "true" {
if strings.Index(registryURL.Host, ".tencentcloudcr.com") < 0 { if !strings.Contains(registryURL.Host, ".tencentcloudcr.com") {
log.Errorf("[tencent-tcr.newAdapter] errInvalidTcrEndpoint=%v", err) log.Errorf("[tencent-tcr.newAdapter] errInvalidTcrEndpoint=%v", err)
return nil, errInvalidTcrEndpoint return nil, errInvalidTcrEndpoint
} }

View File

@ -42,7 +42,7 @@ var _ adp.ChartRegistry = &adapter{}
func (a *adapter) FetchCharts(filters []*model.Filter) (resources []*model.Resource, err error) { func (a *adapter) FetchCharts(filters []*model.Filter) (resources []*model.Resource, err error) {
log.Debugf("[tencent-tcr.FetchCharts]filters: %#v", filters) log.Debugf("[tencent-tcr.FetchCharts]filters: %#v", filters)
// 1. list namespaces // 1. list namespaces via TCR Special API
var nsPattern, _, _ = filterToPatterns(filters) var nsPattern, _, _ = filterToPatterns(filters)
var nms []string var nms []string
nms, err = a.listCandidateNamespaces(nsPattern) nms, err = a.listCandidateNamespaces(nsPattern)
@ -50,8 +50,12 @@ func (a *adapter) FetchCharts(filters []*model.Filter) (resources []*model.Resou
return return
} }
// 2. list repositories return a.fetchCharts(nms, filters)
for _, ns := range nms { }
func (a *adapter) fetchCharts(namespaces []string, filters []*model.Filter) (resources []*model.Resource, err error) {
// 1. list repositories
for _, ns := range namespaces {
var url = fmt.Sprintf(chartListURL, a.registry.URL, ns) var url = fmt.Sprintf(chartListURL, a.registry.URL, ns)
var repositories = []*model.Repository{} var repositories = []*model.Repository{}
err = a.client.Get(url, &repositories) err = a.client.Get(url, &repositories)
@ -70,7 +74,7 @@ func (a *adapter) FetchCharts(filters []*model.Filter) (resources []*model.Resou
return return
} }
// 3. list versions // 2. list versions
for _, repository := range repositories { for _, repository := range repositories {
var name = strings.SplitN(repository.Name, "/", 2)[1] var name = strings.SplitN(repository.Name, "/", 2)[1]
var url = fmt.Sprintf(chartVersionURL, a.registry.URL, ns, name) var url = fmt.Sprintf(chartVersionURL, a.registry.URL, ns, name)

View File

@ -0,0 +1,172 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package tencentcr
import (
"bytes"
"net/http"
"testing"
commonhttp "github.com/goharbor/harbor/src/common/http"
"github.com/goharbor/harbor/src/common/utils/test"
"github.com/goharbor/harbor/src/pkg/reg/model"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func mockChartClient(registry *model.Registry) *adapter {
return &adapter{
registry: registry,
client: commonhttp.NewClient(
&http.Client{
Transport: commonhttp.GetHTTPTransport(commonhttp.WithInsecure(registry.Insecure)),
},
),
}
}
func TestFetchCharts(t *testing.T) {
server := test.NewServer([]*test.RequestHandlerMapping{
{
Method: http.MethodGet,
Pattern: "/api/chartrepo/library/charts/harbor",
Handler: func(w http.ResponseWriter, r *http.Request) {
data := `[{
"name": "harbor",
"version":"1.0"
},{
"name": "harbor",
"version":"2.0"
}]`
w.Write([]byte(data))
},
},
{
Method: http.MethodGet,
Pattern: "/api/chartrepo/library/charts",
Handler: func(w http.ResponseWriter, r *http.Request) {
data := `[{
"name": "harbor"
}]`
w.Write([]byte(data))
},
},
}...)
defer server.Close()
var adapter = mockChartClient(&model.Registry{URL: server.URL})
// nil filter
resources, err := adapter.fetchCharts([]string{"library"}, nil)
require.Nil(t, err)
assert.Equal(t, 2, len(resources))
assert.Equal(t, model.ResourceTypeChart, resources[0].Type)
assert.Equal(t, "library/harbor", resources[0].Metadata.Repository.Name)
assert.Equal(t, 1, len(resources[0].Metadata.Artifacts))
assert.Equal(t, "1.0", resources[0].Metadata.Artifacts[0].Tags[0])
// not nil filter
filters := []*model.Filter{
{
Type: model.FilterTypeName,
Value: "library/*",
},
{
Type: model.FilterTypeTag,
Value: "1.0",
},
}
resources, err = adapter.fetchCharts([]string{"library"}, filters)
require.Nil(t, err)
require.Equal(t, 1, len(resources))
assert.Equal(t, model.ResourceTypeChart, resources[0].Type)
assert.Equal(t, "library/harbor", resources[0].Metadata.Repository.Name)
assert.Equal(t, 1, len(resources[0].Metadata.Artifacts))
assert.Equal(t, "1.0", resources[0].Metadata.Artifacts[0].Tags[0])
}
func TestChartExist(t *testing.T) {
server := test.NewServer(&test.RequestHandlerMapping{
Method: http.MethodGet,
Pattern: "/api/chartrepo/library/charts/harbor/1.0",
Handler: func(w http.ResponseWriter, r *http.Request) {
data := `{
"metadata": {
"urls":["http://127.0.0.1/charts"]
}
}`
w.Write([]byte(data))
},
})
defer server.Close()
var adapter = mockChartClient(&model.Registry{URL: server.URL})
var exist, err = adapter.ChartExist("library/harbor", "1.0")
require.Nil(t, err)
require.True(t, exist)
}
func TestDownloadChart(t *testing.T) {
server := test.NewServer([]*test.RequestHandlerMapping{
{
Method: http.MethodGet,
Pattern: "/api/chartrepo/library/charts/harbor/1.0",
Handler: func(w http.ResponseWriter, r *http.Request) {
data := `{
"metadata": {
"urls":["charts/harbor-1.0.tgz"]
}
}`
w.Write([]byte(data))
},
},
{
Method: http.MethodGet,
Pattern: "/chartrepo/library/charts/harbor-1.0.tgz",
Handler: func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
},
},
}...)
defer server.Close()
var adapter = mockChartClient(&model.Registry{URL: server.URL})
var _, err = adapter.DownloadChart("library/harbor", "1.0", "")
require.Nil(t, err)
}
func TestUploadChart(t *testing.T) {
server := test.NewServer(&test.RequestHandlerMapping{
Method: http.MethodPost,
Pattern: "/api/chartrepo/library/charts",
Handler: func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
},
})
defer server.Close()
var adapter = mockChartClient(&model.Registry{URL: server.URL})
var err = adapter.UploadChart("library/harbor", "1.0", bytes.NewBuffer(nil))
require.Nil(t, err)
}
func TestDeleteChart(t *testing.T) {
server := test.NewServer(&test.RequestHandlerMapping{
Method: http.MethodDelete,
Pattern: "/api/chartrepo/library/charts/harbor/1.0",
Handler: func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
},
})
defer server.Close()
var adapter = mockChartClient(&model.Registry{URL: server.URL})
var err = adapter.DeleteChart("library/harbor", "1.0")
require.Nil(t, err)
}

View File

@ -131,10 +131,18 @@ func (a *adapter) isNamespaceExist(namespace string) (exist bool, err error) {
} }
log.Warningf("[tencent-tcr.PrepareForPush.isNamespaceExist] namespace=%s, total=%d", namespace, *resp.Response.TotalCount) log.Warningf("[tencent-tcr.PrepareForPush.isNamespaceExist] namespace=%s, total=%d", namespace, *resp.Response.TotalCount)
if int(*resp.Response.TotalCount) != 1 { exist = isTcrNsExist(namespace, resp.Response.NamespaceList)
return
return
}
func isTcrNsExist(name string, list []*tcr.TcrNamespaceInfo) (exist bool) {
for _, ns := range list {
if *ns.Name == name {
exist = true
return
}
} }
exist = true
return return
} }

View File

@ -3,6 +3,9 @@ package tencentcr
import ( import (
"reflect" "reflect"
"testing" "testing"
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
tcr "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tcr/v20190924"
) )
func Test_adapter_createPrivateNamespace(t *testing.T) { func Test_adapter_createPrivateNamespace(t *testing.T) {
@ -131,3 +134,42 @@ func Test_adapter_getImages(t *testing.T) {
}) })
} }
} }
func Test_isTcrNsExist(t *testing.T) {
tests := []struct {
name string
list []*tcr.TcrNamespaceInfo
wantExist bool
}{
{
name: "not_found_any_ns", list: []*tcr.TcrNamespaceInfo{}, wantExist: false,
},
{
name: "found_one_ns", list: []*tcr.TcrNamespaceInfo{
{Name: common.StringPtr("found_one_ns")},
},
wantExist: true,
},
{
name: "found_multi_ns", list: []*tcr.TcrNamespaceInfo{
{Name: common.StringPtr("found_multi_ns")},
{Name: common.StringPtr("found_multi_ns_2")},
},
wantExist: true,
},
{
name: "found_but_not_exist", list: []*tcr.TcrNamespaceInfo{
{Name: common.StringPtr("found_multi_ns_2")},
{Name: common.StringPtr("found_multi_ns_3")},
},
wantExist: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if gotExist := isTcrNsExist(tt.name, tt.list); gotExist != tt.wantExist {
t.Errorf("isTcrNsExist() = %v, want %v", gotExist, tt.wantExist)
}
})
}
}