diff --git a/pkg/extension/action_url.go b/pkg/extension/action_url.go new file mode 100644 index 0000000000000000000000000000000000000000..72d35371e5d14603cba09b3c8f06629c3e3b1a55 --- /dev/null +++ b/pkg/extension/action_url.go @@ -0,0 +1,70 @@ +package extension + +import ( + "net/url" + "strings" + + "git.perx.ru/perxis/perxis-go/pkg/errors" +) + +// ActionURL структура для хранения данных о переданном действии +type ActionURL struct { + actionURL string + actionID string + extensionID string + scheme string + url *url.URL +} + +// NewActionURL возвращает пустую структуру ActionURL, если передано пустое действие +// при передаче в функцию действия - заполняет структуру +func NewActionURL(action string) (*ActionURL, error) { + if action != "" { + parsedURL, err := parseActionURL(action) + if err != nil { + return nil, err + } + return parsedURL, nil + } + return &ActionURL{}, nil +} + +// ID возвращает сохраненный в ActionURL id действия +func (p *ActionURL) ID() string { + return p.actionID +} + +// ExtensionID возвращает сохраненный в ActionURL id расширения +func (p *ActionURL) ExtensionID() string { + return p.extensionID +} + +// Scheme возвращает сохраненную в ActionURL схему +func (p *ActionURL) Scheme() string { + return p.scheme +} + +// parseActionURL функция для заполнения структуры ActionURL из переданного действия +func parseActionURL(action string) (*ActionURL, error) { + u, err := url.Parse(action) + if err != nil { + return nil, err + } + parsed := &ActionURL{} + parsed.actionURL = action + parsed.url = u + parsed.scheme = u.Scheme + if parsed.Scheme() == "grpc" { + path := u.Path + if strings.HasPrefix(u.Path, "/") { + path = u.Path[1:] + } + splitPath := strings.Split(path, "/") + if len(splitPath) < 2 { + return nil, errors.Errorf("incorrect action URL, no action id: '%s'", action) + } + parsed.extensionID = splitPath[0] + parsed.actionID = splitPath[1] + } + return parsed, nil +} diff --git a/pkg/extension/action_url_test.go b/pkg/extension/action_url_test.go new file mode 100644 index 0000000000000000000000000000000000000000..7c5ef5e43559efb9158e698e9adfccfbf21c5d5a --- /dev/null +++ b/pkg/extension/action_url_test.go @@ -0,0 +1,87 @@ +package extension + +import ( + "fmt" + "net/url" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestNewActionURL(t *testing.T) { + u1, _ := url.Parse("build-site") + u2, _ := url.Parse("grpc:///perxisweb/build-site") + u3, _ := url.Parse("ui:///space/env/coll") + u4, _ := url.Parse("https://perx.ru") + tests := []struct { + name string + action string + want *ActionURL + wantErr assert.ErrorAssertionFunc + }{ + { + "Without action", + "", + &ActionURL{}, + assert.NoError, + }, + { + "Without deprecated action call", + "build-site", + &ActionURL{ + actionURL: "build-site", + url: u1, + }, + assert.NoError, + }, + { + name: "With grpc action", + action: "grpc:///perxisweb/build-site", + want: &ActionURL{ + actionURL: "grpc:///perxisweb/build-site", + actionID: "build-site", + extensionID: "perxisweb", + scheme: "grpc", + url: u2, + }, + wantErr: assert.NoError, + }, + { + name: "With ui action", + action: "ui:///space/env/coll", + want: &ActionURL{ + actionURL: "ui:///space/env/coll", + actionID: "", + extensionID: "", + scheme: "ui", + url: u3, + }, + wantErr: assert.NoError, + }, + { + name: "With http action", + action: "https://perx.ru", + want: &ActionURL{ + actionURL: "https://perx.ru", + scheme: "https", + url: u4, + }, + wantErr: assert.NoError, + }, + { + name: "With error in parse", + action: "grpc://user:abc{DEf1=ghi@example.com:5432/db?sslmode=require", + want: nil, + wantErr: assert.Error, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := NewActionURL(tt.action) + if !tt.wantErr(t, err, fmt.Sprintf("NewActionURL(%v)", tt.action)) { + return + } + assert.Equalf(t, tt.want, got, "NewActionURL(%v)", tt.action) + }) + } +} diff --git a/pkg/extension/extension.go b/pkg/extension/extension.go index 174ac51c6d2d8af1bf56d87071e7bbee3dc80f34..fb8044c7a2f4c76b775840c5628319196a0493ae 100644 --- a/pkg/extension/extension.go +++ b/pkg/extension/extension.go @@ -3,8 +3,6 @@ package extension import ( "context" "fmt" - "net/url" - "strings" "git.perx.ru/perxis/perxis-go/pkg/content" "git.perx.ru/perxis/perxis-go/pkg/errors" @@ -107,48 +105,3 @@ func ExtensionFromError(err error) string { ext, _ := v.(string) return ext } - -type ParsedActionURL struct { - actionID string - extensionID string - scheme string -} - -func (p *ParsedActionURL) New() *ParsedActionURL { - return &ParsedActionURL{} -} - -func (p *ParsedActionURL) GetActionID() string { - return p.actionID -} - -func (p *ParsedActionURL) GetExtensionID() string { - return p.extensionID -} - -func (p *ParsedActionURL) GetScheme() string { - return p.scheme -} - -func ParseActionURL(action string) (*ParsedActionURL, error) { - - u, err := url.Parse(action) - if err != nil { - return nil, err - } - parsed := &ParsedActionURL{} - parsed.scheme = u.Scheme - if parsed.GetScheme() == "grpc" { - path := u.Path - if strings.HasPrefix(u.Path, "/") { - path = u.Path[1:] - } - splitPath := strings.Split(path, "/") - if len(splitPath) < 2 { - return nil, errors.Errorf("incorrect action URL, no action id: '%s'", action) - } - parsed.extensionID = splitPath[0] - parsed.actionID = splitPath[1] - } - return parsed, nil -} diff --git a/pkg/extension/server.go b/pkg/extension/server.go index be4b6f0a4a26b30692d1a0c72f212ce0789e570c..bdeac58c14bf37b20104e23ecff96c70cf900930 100644 --- a/pkg/extension/server.go +++ b/pkg/extension/server.go @@ -80,13 +80,16 @@ func (srv *Server) Update(ctx context.Context, request *UpdateRequest) (*UpdateR } func (srv *Server) Action(ctx context.Context, in *pb.ActionRequest) (*pb.ActionResponse, error) { - - parsed, err := ParseActionURL(in.Action) - if err != nil { - return nil, err + extensionID := in.Extension + if extensionID == "" { + actionURL, err := NewActionURL(in.Action) + if err != nil { + return nil, err + } + extensionID = actionURL.extensionID } - svc, ok := srv.services[parsed.GetExtensionID()] + svc, ok := srv.services[extensionID] if !ok { return nil, ErrUnknownExtension } diff --git a/pkg/extension/server_test.go b/pkg/extension/server_test.go index 5400c8c4786cbe09bf2c56fdfb0611d65048d31d..9e8b8f4c71bbdcfc8fa46bcf5651c9e4e0fe81a5 100644 --- a/pkg/extension/server_test.go +++ b/pkg/extension/server_test.go @@ -2,11 +2,13 @@ package extension import ( "context" + "fmt" "reflect" "strings" "testing" "git.perx.ru/perxis/perxis-go/pkg/errors" + "github.com/stretchr/testify/assert" ) func TestGetResults(t *testing.T) { @@ -102,3 +104,82 @@ func (t testServerExtension) Uninstall(ctx context.Context, in *UninstallRequest func (t testServerExtension) Action(ctx context.Context, in *ActionRequest) (*ActionResponse, error) { return &ActionResponse{}, t.err } + +func TestServer_Action(t *testing.T) { + getDummyExtension := func(name string, wantErr ...bool) Extension { + ext := &testServerExtension{name: name} + + if len(wantErr) > 0 { + ext.err = errors.WithDetail(errors.New("some err"), "Ошибка") + } + + return ext + } + + var tests = []struct { + name string + services map[string]Extension + in *ActionRequest + want *ActionResponse + wantErr assert.ErrorAssertionFunc + }{ + { + name: "OK (grpc)", + services: map[string]Extension{"test-extension": getDummyExtension("test-extension")}, + in: &ActionRequest{ + Action: "grpc:///test-extension/test-action", + SpaceId: "sp", + EnvId: "env", + }, + want: &ActionResponse{State: ResponseDone}, + wantErr: assert.NoError, + }, + { + name: "OK (deprecated call)", + services: map[string]Extension{"test-extension": getDummyExtension("test-extension")}, + in: &ActionRequest{ + Action: "test-action", + SpaceId: "sp", + EnvId: "env", + Extension: "test-extension", + }, + want: &ActionResponse{State: ResponseDone}, + wantErr: assert.NoError, + }, + { + name: "Error (unknown extension)", + services: map[string]Extension{"test-extension": getDummyExtension("test-extension")}, + in: &ActionRequest{ + Action: "grpc:///test-extension-2/test-action", + SpaceId: "sp", + EnvId: "env", + }, + want: nil, + wantErr: assert.Error, + }, + { + name: "Error (deprecated call, no extension)", + services: map[string]Extension{"test-extension": getDummyExtension("test-extension")}, + in: &ActionRequest{ + Action: "test-action", + SpaceId: "sp", + EnvId: "env", + }, + want: nil, + wantErr: assert.Error, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + + srv := &Server{ + services: tt.services, + } + got, err := srv.Action(context.Background(), tt.in) + if !tt.wantErr(t, err, fmt.Sprintf("Action(%v)", tt.in)) { + return + } + assert.Equalf(t, tt.want, got, "Action(%v)", tt.in) + }) + } +} diff --git a/pkg/extension/service/extension.go b/pkg/extension/service/extension.go index e0b4e2abcfc82c8d9b3769fff58d53d49f2d7c40..f57f8253965bf45225532a71a67c95fc38f3a735 100644 --- a/pkg/extension/service/extension.go +++ b/pkg/extension/service/extension.go @@ -155,11 +155,15 @@ func (s *Extension) Uninstall(ctx context.Context, in *extension.UninstallReques } func (s *Extension) Action(ctx context.Context, in *extension.ActionRequest) (*extension.ActionResponse, error) { - parsed, err := extension.ParseActionURL(in.Action) - if err != nil { - return nil, err + extensionID := in.Extension + if extensionID == "" { + actionURL, err := extension.NewActionURL(in.Action) + if err != nil { + return nil, err + } + extensionID = actionURL.ExtensionID() } - ok, err := extension.CheckInstalled(ctx, s.Content, in.SpaceId, in.EnvId, parsed.GetExtensionID()) + ok, err := extension.CheckInstalled(ctx, s.Content, in.SpaceId, in.EnvId, extensionID) if err != nil { return nil, errors.Wrap(err, "check extension installed") }