diff --git a/src/pkg/p2p/preheat/instance/manager.go b/src/pkg/p2p/preheat/instance/manager.go index 3f4418a10..6590d2896 100644 --- a/src/pkg/p2p/preheat/instance/manager.go +++ b/src/pkg/p2p/preheat/instance/manager.go @@ -16,7 +16,6 @@ package instance import ( "context" - "encoding/json" "github.com/goharbor/harbor/src/lib/q" dao "github.com/goharbor/harbor/src/pkg/p2p/preheat/dao/instance" @@ -119,11 +118,9 @@ func (dm *manager) Get(ctx context.Context, id int64) (*provider.Instance, error if err != nil { return nil, err } - // mapping auth data to auth info. - if len(ins.AuthData) > 0 { - if err := json.Unmarshal([]byte(ins.AuthData), &ins.AuthInfo); err != nil { - return nil, err - } + + if err := ins.Decode(); err != nil { + return nil, err } return ins, nil @@ -131,7 +128,16 @@ func (dm *manager) Get(ctx context.Context, id int64) (*provider.Instance, error // Get implements @Manager.GetByName func (dm *manager) GetByName(ctx context.Context, name string) (*provider.Instance, error) { - return dm.dao.GetByName(ctx, name) + ins, err := dm.dao.GetByName(ctx, name) + if err != nil { + return nil, err + } + + if err := ins.Decode(); err != nil { + return nil, err + } + + return ins, nil } // Count implements @Manager.Count @@ -141,5 +147,16 @@ func (dm *manager) Count(ctx context.Context, query *q.Query) (int64, error) { // List implements @Manager.List func (dm *manager) List(ctx context.Context, query *q.Query) ([]*provider.Instance, error) { - return dm.dao.List(ctx, query) + inss, err := dm.dao.List(ctx, query) + if err != nil { + return nil, err + } + + for i := range inss { + if err := inss[i].Decode(); err != nil { + return nil, err + } + } + + return inss, nil } diff --git a/src/pkg/p2p/preheat/models/provider/instance.go b/src/pkg/p2p/preheat/models/provider/instance.go index 407daf0ad..405d20d0b 100644 --- a/src/pkg/p2p/preheat/models/provider/instance.go +++ b/src/pkg/p2p/preheat/models/provider/instance.go @@ -82,6 +82,33 @@ func (ins *Instance) ToJSON() (string, error) { return string(data), nil } +// Decode decodes the instance. +func (ins *Instance) Decode() error { + // decode the auth data. + authInfo, err := decodeAuthData(ins.AuthData) + if err != nil { + return err + } + + if len(authInfo) > 0 { + ins.AuthInfo = authInfo + } + + return nil +} + +// decodeAuthData decodes the auth data. +func decodeAuthData(data string) (map[string]string, error) { + authInfo := make(map[string]string) + if len(data) > 0 { + if err := json.Unmarshal([]byte(data), &authInfo); err != nil { + return nil, errors.Wrap(err, "decode auth data error") + } + } + + return authInfo, nil +} + // TableName ... func (ins *Instance) TableName() string { return "p2p_preheat_instance" diff --git a/src/pkg/p2p/preheat/models/provider/instance_test.go b/src/pkg/p2p/preheat/models/provider/instance_test.go new file mode 100644 index 000000000..329b5e0b2 --- /dev/null +++ b/src/pkg/p2p/preheat/models/provider/instance_test.go @@ -0,0 +1,139 @@ +// 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 provider + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestInstance_FromJSON(t *testing.T) { + tests := []struct { + name string + json string + wantErr bool + }{ + { + name: "Empty JSON", + json: "", + wantErr: true, + }, + { + name: "Invalid JSON", + json: "{invalid}", + wantErr: true, + }, + { + name: "Valid JSON", + json: `{ + "id": 1, + "name": "test-instance", + "description": "test description", + "vendor": "test-vendor", + "endpoint": "http://test-endpoint", + "auth_mode": "basic", + "auth_info": {"username": "test", "password": "test123"}, + "enabled": true, + "default": false, + "insecure": false, + "setup_timestamp": 1234567890 + }`, + wantErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ins := &Instance{} + err := ins.FromJSON(tt.json) + if tt.wantErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + assert.Equal(t, int64(1), ins.ID) + assert.Equal(t, "test-instance", ins.Name) + } + }) + } +} + +func TestInstance_ToJSON(t *testing.T) { + ins := &Instance{ + ID: 1, + Name: "test-instance", + Description: "test description", + Vendor: "test-vendor", + Endpoint: "http://test-endpoint", + AuthMode: "basic", + AuthInfo: map[string]string{"username": "test", "password": "test123"}, + Enabled: true, + Default: false, + Insecure: false, + } + + jsonStr, err := ins.ToJSON() + assert.NoError(t, err) + + // Verify the JSON can be decoded back + var decoded Instance + err = json.Unmarshal([]byte(jsonStr), &decoded) + assert.NoError(t, err) + assert.Equal(t, ins.ID, decoded.ID) + assert.Equal(t, ins.Name, decoded.Name) + assert.Equal(t, ins.AuthInfo, decoded.AuthInfo) +} + +func TestInstance_Decode(t *testing.T) { + tests := []struct { + name string + authData string + wantErr bool + }{ + { + name: "Empty auth data", + authData: "", + wantErr: false, + }, + { + name: "Invalid auth data", + authData: "{invalid}", + wantErr: true, + }, + { + name: "Valid auth data", + authData: `{"username": "test", "password": "test123"}`, + wantErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ins := &Instance{ + AuthData: tt.authData, + } + err := ins.Decode() + if tt.wantErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + if tt.authData != "" { + assert.NotEmpty(t, ins.AuthInfo) + } + } + }) + } +}