Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 06992b8949 |
35
README.md
35
README.md
@@ -72,6 +72,10 @@ Dynamix SDK - это библиотека, написанная на языке
|
||||
- [Создание универсального клиента](#создание-универсального-клиента)
|
||||
- [Пример создания универсального клиента](#пример-создания-универсального-клиента)
|
||||
- [Пример выполнения запроса](#пример-выполнения-запроса-4)
|
||||
- [Проверка соответствия версии платформы и версии dynamix](#проверка-соответствия-версии-платформы-и-версии-dynamix)
|
||||
- [Пример выполнения запроса](#пример-выполнения-запроса-5)
|
||||
- [Создание mock клиента](#создание-mock-клиента)
|
||||
- [Пример создания mock клиента](#пример-создания-mock-клиента)
|
||||
|
||||
## Установка
|
||||
|
||||
@@ -1698,4 +1702,35 @@ func main(){
|
||||
// Проверка соответствия версии
|
||||
checkInfo, err := client.Check()
|
||||
}
|
||||
```
|
||||
|
||||
# Создание mock клиента
|
||||
|
||||
Создание клиента происходит с помощью функции-строителя `NewMockDecortClient` из основного пакета `decort-sdk`. Функция принимает mock реализацию интерфейса interfaces.Calller, возвращает структуру `MockDecortClient`, с помощью которой можно производить unit тестирование API Decort SDK без подключения к серверу
|
||||
|
||||
#### Пример создания mock клиента
|
||||
```go
|
||||
package unit_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"go.uber.org/mock/gomock"
|
||||
decortsdk "repository.basistech.ru/BASIS/dynamix-golang-sdk/v12"
|
||||
)
|
||||
|
||||
// Пример юнит тестирования на моках
|
||||
func TestClient(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
// Создаем mock интерфейса Caller
|
||||
mockCaller := decortsdk.NewMockCaller(ctrl)
|
||||
// Создаем mock интерфейса DecortClient
|
||||
mockClient := decortsdk.NewMockDecortClient(mockCaller)
|
||||
// ....
|
||||
}
|
||||
```
|
||||
Пример юнит теста можно посмотреть в файле [samples/client/client_test.go](samples/client/client_test.go)
|
||||
|
||||
При редактировании интерфеса interface.Caller необходимо перегенерировать Mock :
|
||||
``` shell
|
||||
make gen-mock
|
||||
```
|
||||
32
client_mock.go
Normal file
32
client_mock.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package decortsdk
|
||||
|
||||
import (
|
||||
"repository.basistech.ru/BASIS/dynamix-golang-sdk/v12/pkg/cloudapi"
|
||||
"repository.basistech.ru/BASIS/dynamix-golang-sdk/v12/pkg/cloudbroker"
|
||||
"repository.basistech.ru/BASIS/dynamix-golang-sdk/v12/pkg/sdn"
|
||||
)
|
||||
|
||||
type MockDecortClient struct {
|
||||
apiCaller *MockCaller
|
||||
}
|
||||
|
||||
func NewMockDecortClient(apiCaller *MockCaller) ClientInterface {
|
||||
return &MockDecortClient{
|
||||
apiCaller: apiCaller,
|
||||
}
|
||||
}
|
||||
|
||||
// CloudAPI builder
|
||||
func (mdc *MockDecortClient) CloudAPI() *cloudapi.CloudAPI {
|
||||
return cloudapi.New(mdc.apiCaller)
|
||||
}
|
||||
|
||||
// CloudBroker builder
|
||||
func (mdc *MockDecortClient) CloudBroker() *cloudbroker.CloudBroker {
|
||||
return cloudbroker.New(mdc.apiCaller)
|
||||
}
|
||||
|
||||
// SDN builder
|
||||
func (mdc *MockDecortClient) SDN() *sdn.SDN {
|
||||
return sdn.New(mdc.apiCaller)
|
||||
}
|
||||
86
client_mock_gen.go
Normal file
86
client_mock_gen.go
Normal file
@@ -0,0 +1,86 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: interfaces/caller.go
|
||||
//
|
||||
// Generated by this command:
|
||||
//
|
||||
// mockgen -package decortsdk -source interfaces/caller.go
|
||||
//
|
||||
|
||||
// Package decortsdk is a generated GoMock package.
|
||||
package decortsdk
|
||||
|
||||
import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
// MockCaller is a mock of Caller interface.
|
||||
type MockCaller struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockCallerMockRecorder
|
||||
isgomock struct{}
|
||||
}
|
||||
|
||||
// MockCallerMockRecorder is the mock recorder for MockCaller.
|
||||
type MockCallerMockRecorder struct {
|
||||
mock *MockCaller
|
||||
}
|
||||
|
||||
// NewMockCaller creates a new mock instance.
|
||||
func NewMockCaller(ctrl *gomock.Controller) *MockCaller {
|
||||
mock := &MockCaller{ctrl: ctrl}
|
||||
mock.recorder = &MockCallerMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockCaller) EXPECT() *MockCallerMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// DecortApiCall mocks base method.
|
||||
func (m *MockCaller) DecortApiCall(ctx context.Context, method, url string, params any) ([]byte, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "DecortApiCall", ctx, method, url, params)
|
||||
ret0, _ := ret[0].([]byte)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// DecortApiCall indicates an expected call of DecortApiCall.
|
||||
func (mr *MockCallerMockRecorder) DecortApiCall(ctx, method, url, params any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DecortApiCall", reflect.TypeOf((*MockCaller)(nil).DecortApiCall), ctx, method, url, params)
|
||||
}
|
||||
|
||||
// DecortApiCallCtype mocks base method.
|
||||
func (m *MockCaller) DecortApiCallCtype(ctx context.Context, method, url, ctype string, params any) ([]byte, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "DecortApiCallCtype", ctx, method, url, ctype, params)
|
||||
ret0, _ := ret[0].([]byte)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// DecortApiCallCtype indicates an expected call of DecortApiCallCtype.
|
||||
func (mr *MockCallerMockRecorder) DecortApiCallCtype(ctx, method, url, ctype, params any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DecortApiCallCtype", reflect.TypeOf((*MockCaller)(nil).DecortApiCallCtype), ctx, method, url, ctype, params)
|
||||
}
|
||||
|
||||
// DecortApiCallMP mocks base method.
|
||||
func (m *MockCaller) DecortApiCallMP(ctx context.Context, method, url string, params any) ([]byte, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "DecortApiCallMP", ctx, method, url, params)
|
||||
ret0, _ := ret[0].([]byte)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// DecortApiCallMP indicates an expected call of DecortApiCallMP.
|
||||
func (mr *MockCallerMockRecorder) DecortApiCallMP(ctx, method, url, params any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DecortApiCallMP", reflect.TypeOf((*MockCaller)(nil).DecortApiCallMP), ctx, method, url, params)
|
||||
}
|
||||
5
go.mod
5
go.mod
@@ -5,15 +5,20 @@ go 1.24.0
|
||||
require (
|
||||
github.com/go-playground/validator/v10 v10.28.0
|
||||
github.com/google/go-querystring v1.1.0
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/stretchr/testify v1.9.0
|
||||
go.uber.org/mock v0.6.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.10 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/google/go-cmp v0.5.9 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
golang.org/x/crypto v0.42.0 // indirect
|
||||
golang.org/x/sys v0.36.0 // indirect
|
||||
golang.org/x/text v0.29.0 // indirect
|
||||
|
||||
8
go.sum
8
go.sum
@@ -15,12 +15,16 @@ github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
|
||||
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
|
||||
golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
|
||||
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
|
||||
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
|
||||
|
||||
@@ -11,14 +11,6 @@ import (
|
||||
|
||||
// CreateRequest struct to create logical port
|
||||
type CreateRequest struct {
|
||||
// ID of the logical port
|
||||
// Required: true
|
||||
LogicalPortID string `url:"logical_port_id" json:"logical_port_id" validate:"required"`
|
||||
|
||||
// ID of the version
|
||||
// Required: true
|
||||
VersionID uint64 `url:"version_id" json:"version_id" validate:"required"`
|
||||
|
||||
// ID of the access group
|
||||
// Required: true
|
||||
AccessGroupID string `url:"access_group_id" json:"access_group_id" validate:"required"`
|
||||
|
||||
42
samples/client/client.go
Normal file
42
samples/client/client.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"errors"
|
||||
|
||||
decortsdk "repository.basistech.ru/BASIS/dynamix-golang-sdk/v12"
|
||||
"repository.basistech.ru/BASIS/dynamix-golang-sdk/v12/pkg/cloudbroker/compute"
|
||||
)
|
||||
|
||||
type Migrator interface {
|
||||
Migrate(ctxOrigin context.Context, vmUUID, to uint64) (bool, error)
|
||||
}
|
||||
|
||||
type migrator struct {
|
||||
cfg *Config
|
||||
client decortsdk.ClientInterface
|
||||
}
|
||||
|
||||
func NewMigrator(cfg *Config, c decortsdk.ClientInterface) Migrator {
|
||||
return &migrator{
|
||||
cfg: cfg,
|
||||
client: c,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *migrator) Migrate(ctxOrigin context.Context, dxVMID, stackID uint64) (bool, error) {
|
||||
req := compute.MigrateRequest{
|
||||
ComputeID: dxVMID,
|
||||
TargetStackID: stackID,
|
||||
Force: false,
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(ctxOrigin, m.cfg.QueryTimeout)
|
||||
ok, err := m.client.CloudBroker().Compute().Migrate(ctx, req)
|
||||
cancel()
|
||||
if err != nil {
|
||||
return false, errors.Join(err, fmt.Errorf("Migrate VM %d to Node %d", dxVMID, stackID))
|
||||
}
|
||||
return ok, nil
|
||||
}
|
||||
76
samples/client/client_test.go
Normal file
76
samples/client/client_test.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package client_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"go.uber.org/mock/gomock"
|
||||
decortsdk "repository.basistech.ru/BASIS/dynamix-golang-sdk/v12"
|
||||
"repository.basistech.ru/BASIS/dynamix-golang-sdk/v12/pkg/cloudbroker/compute"
|
||||
"repository.basistech.ru/BASIS/dynamix-golang-sdk/v12/samples/client"
|
||||
)
|
||||
|
||||
// Пример юнит тестирования на моках
|
||||
func TestClient(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
// Создаем мок инстанс интерфейса Caller
|
||||
mockCaller := decortsdk.NewMockCaller(ctrl)
|
||||
// Создаем мок инстанс интерфейса DecortClient
|
||||
mockClient := decortsdk.NewMockDecortClient(mockCaller)
|
||||
|
||||
dxVMID := uint64(100500)
|
||||
VMID := "vm-100500"
|
||||
|
||||
listComputes := &compute.ListComputes{
|
||||
Data: []compute.ItemCompute{
|
||||
{
|
||||
InfoCompute: compute.InfoCompute{
|
||||
ID: dxVMID,
|
||||
ReferenceID: VMID,
|
||||
},
|
||||
},
|
||||
}}
|
||||
|
||||
b, err := json.Marshal(listComputes)
|
||||
assert.NoError(t, err)
|
||||
// Подготавливаем мок для вызова метода CloudBroker().Compute().List()
|
||||
mockCaller.EXPECT().DecortApiCall(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Eq(compute.ListRequest{})).Return(b, nil).AnyTimes()
|
||||
listComputesRet, err := mockClient.CloudBroker().Compute().List(context.Background(), compute.ListRequest{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, listComputes, listComputesRet)
|
||||
|
||||
}
|
||||
|
||||
// Пример юнит тестирования на моках
|
||||
func TestMigrator(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
// Создаем мок инстанс интерфейса Caller
|
||||
mockCaller := decortsdk.NewMockCaller(ctrl)
|
||||
// Создаем мок инстанс интерфейса interfaces.ClientInterface
|
||||
mockClient := decortsdk.NewMockDecortClient(mockCaller)
|
||||
|
||||
// Передаем мок инстанс интерфейса interfaces.ClientInterface в конструктор Migrator
|
||||
migrator := client.NewMigrator(&client.Config{QueryTimeout: time.Second}, mockClient)
|
||||
|
||||
b, err := json.Marshal(true)
|
||||
assert.NoError(t, err)
|
||||
|
||||
dxVMID := uint64(100500)
|
||||
stackID := uint64(100501)
|
||||
|
||||
// Записываем поведение клиента
|
||||
mockCaller.EXPECT().DecortApiCall(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Eq(compute.AsyncWrapperMigrateRequest{
|
||||
MigrateRequest: compute.MigrateRequest{
|
||||
ComputeID: dxVMID,
|
||||
TargetStackID: stackID,
|
||||
},
|
||||
SyncMode: true})).Return(b, nil).AnyTimes()
|
||||
|
||||
ok, err := migrator.Migrate(context.Background(), dxVMID, stackID)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, ok)
|
||||
}
|
||||
7
samples/client/config.go
Normal file
7
samples/client/config.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package client
|
||||
|
||||
import "time"
|
||||
|
||||
type Config struct {
|
||||
QueryTimeout time.Duration
|
||||
}
|
||||
@@ -7,11 +7,13 @@ import (
|
||||
"repository.basistech.ru/BASIS/dynamix-golang-sdk/v12/config"
|
||||
"repository.basistech.ru/BASIS/dynamix-golang-sdk/v12/pkg/cloudapi"
|
||||
"repository.basistech.ru/BASIS/dynamix-golang-sdk/v12/pkg/cloudbroker"
|
||||
"repository.basistech.ru/BASIS/dynamix-golang-sdk/v12/pkg/sdn"
|
||||
)
|
||||
|
||||
type ClientInterface interface {
|
||||
CloudAPI() *cloudapi.CloudAPI
|
||||
CloudBroker() *cloudbroker.CloudBroker
|
||||
SDN() *sdn.SDN
|
||||
}
|
||||
|
||||
func NewUniversal(cfg config.UniversalConfig) (ClientInterface, error) {
|
||||
|
||||
Reference in New Issue
Block a user