mirror of
https://github.com/zitadel/zitadel.git
synced 2024-12-15 04:18:01 +00:00
348 lines
7.6 KiB
Go
348 lines
7.6 KiB
Go
|
package execution
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"encoding/json"
|
||
|
"io"
|
||
|
"net/http"
|
||
|
"net/http/httptest"
|
||
|
"testing"
|
||
|
"time"
|
||
|
|
||
|
"github.com/stretchr/testify/assert"
|
||
|
"github.com/stretchr/testify/require"
|
||
|
|
||
|
"github.com/zitadel/zitadel/internal/domain"
|
||
|
)
|
||
|
|
||
|
var _ Target = &mockTarget{}
|
||
|
|
||
|
type mockTarget struct {
|
||
|
InstanceID string
|
||
|
ExecutionID string
|
||
|
TargetID string
|
||
|
TargetType domain.TargetType
|
||
|
Endpoint string
|
||
|
Timeout time.Duration
|
||
|
InterruptOnError bool
|
||
|
}
|
||
|
|
||
|
func (e *mockTarget) GetTargetID() string {
|
||
|
return e.TargetID
|
||
|
}
|
||
|
func (e *mockTarget) IsInterruptOnError() bool {
|
||
|
return e.InterruptOnError
|
||
|
}
|
||
|
func (e *mockTarget) GetEndpoint() string {
|
||
|
return e.Endpoint
|
||
|
}
|
||
|
func (e *mockTarget) GetTargetType() domain.TargetType {
|
||
|
return e.TargetType
|
||
|
}
|
||
|
func (e *mockTarget) GetTimeout() time.Duration {
|
||
|
return e.Timeout
|
||
|
}
|
||
|
|
||
|
func Test_Call(t *testing.T) {
|
||
|
type args struct {
|
||
|
ctx context.Context
|
||
|
timeout time.Duration
|
||
|
sleep time.Duration
|
||
|
method string
|
||
|
body []byte
|
||
|
respBody []byte
|
||
|
statusCode int
|
||
|
}
|
||
|
type res struct {
|
||
|
body []byte
|
||
|
wantErr bool
|
||
|
}
|
||
|
tests := []struct {
|
||
|
name string
|
||
|
args args
|
||
|
res res
|
||
|
}{
|
||
|
{
|
||
|
"not ok status",
|
||
|
args{
|
||
|
ctx: context.Background(),
|
||
|
timeout: time.Minute,
|
||
|
sleep: time.Second,
|
||
|
method: http.MethodPost,
|
||
|
body: []byte("{\"request\": \"values\"}"),
|
||
|
respBody: []byte("{\"response\": \"values\"}"),
|
||
|
statusCode: http.StatusBadRequest,
|
||
|
},
|
||
|
res{
|
||
|
wantErr: true,
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"timeout",
|
||
|
args{
|
||
|
ctx: context.Background(),
|
||
|
timeout: time.Second,
|
||
|
sleep: time.Second,
|
||
|
method: http.MethodPost,
|
||
|
body: []byte("{\"request\": \"values\"}"),
|
||
|
respBody: []byte("{\"response\": \"values\"}"),
|
||
|
statusCode: http.StatusOK,
|
||
|
},
|
||
|
res{
|
||
|
wantErr: true,
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"ok",
|
||
|
args{
|
||
|
ctx: context.Background(),
|
||
|
timeout: time.Minute,
|
||
|
sleep: time.Second,
|
||
|
method: http.MethodPost,
|
||
|
body: []byte("{\"request\": \"values\"}"),
|
||
|
respBody: []byte("{\"response\": \"values\"}"),
|
||
|
statusCode: http.StatusOK,
|
||
|
},
|
||
|
res{
|
||
|
body: []byte("{\"response\": \"values\"}"),
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
for _, tt := range tests {
|
||
|
t.Run(tt.name, func(t *testing.T) {
|
||
|
respBody, err := testServerCall(t,
|
||
|
tt.args.method,
|
||
|
tt.args.body,
|
||
|
tt.args.sleep,
|
||
|
tt.args.statusCode,
|
||
|
tt.args.respBody,
|
||
|
testCall(tt.args.ctx, tt.args.timeout, tt.args.body),
|
||
|
)
|
||
|
if tt.res.wantErr {
|
||
|
assert.Error(t, err)
|
||
|
assert.Nil(t, respBody)
|
||
|
} else {
|
||
|
assert.NoError(t, err)
|
||
|
assert.Equal(t, tt.res.body, respBody)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func testCall(ctx context.Context, timeout time.Duration, body []byte) func(string) ([]byte, error) {
|
||
|
return func(url string) ([]byte, error) {
|
||
|
return call(ctx, url, timeout, body)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func testCallTarget(ctx context.Context,
|
||
|
target *mockTarget,
|
||
|
info ContextInfoRequest,
|
||
|
) func(string) ([]byte, error) {
|
||
|
return func(url string) (r []byte, err error) {
|
||
|
target.Endpoint = url
|
||
|
return CallTarget(ctx, target, info)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func testServerCall(
|
||
|
t *testing.T,
|
||
|
method string,
|
||
|
body []byte,
|
||
|
timeout time.Duration,
|
||
|
statusCode int,
|
||
|
respBody []byte,
|
||
|
call func(string) ([]byte, error),
|
||
|
) ([]byte, error) {
|
||
|
handler := func(w http.ResponseWriter, r *http.Request) {
|
||
|
checkRequest(t, r, method, body)
|
||
|
|
||
|
if statusCode != http.StatusOK {
|
||
|
http.Error(w, "error", statusCode)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
time.Sleep(timeout)
|
||
|
|
||
|
w.Header().Set("Content-Type", "application/json")
|
||
|
if _, err := io.WriteString(w, string(respBody)); err != nil {
|
||
|
http.Error(w, "error", http.StatusInternalServerError)
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
|
||
|
server := httptest.NewServer(http.HandlerFunc(handler))
|
||
|
defer server.Close()
|
||
|
|
||
|
return call(server.URL)
|
||
|
}
|
||
|
|
||
|
func checkRequest(t *testing.T, sent *http.Request, method string, expectedBody []byte) {
|
||
|
sentBody, err := io.ReadAll(sent.Body)
|
||
|
require.NoError(t, err)
|
||
|
require.Equal(t, expectedBody, sentBody)
|
||
|
require.Equal(t, method, sent.Method)
|
||
|
}
|
||
|
|
||
|
var _ ContextInfoRequest = &mockContextInfoRequest{}
|
||
|
|
||
|
type request struct {
|
||
|
Request string `json:"request"`
|
||
|
}
|
||
|
|
||
|
type mockContextInfoRequest struct {
|
||
|
Request *request `json:"request"`
|
||
|
}
|
||
|
|
||
|
func newMockContextInfoRequest(s string) *mockContextInfoRequest {
|
||
|
return &mockContextInfoRequest{&request{s}}
|
||
|
}
|
||
|
|
||
|
func (c *mockContextInfoRequest) GetHTTPRequestBody() []byte {
|
||
|
data, _ := json.Marshal(c)
|
||
|
return data
|
||
|
}
|
||
|
|
||
|
func (c *mockContextInfoRequest) GetContent() []byte {
|
||
|
data, _ := json.Marshal(c.Request)
|
||
|
return data
|
||
|
}
|
||
|
|
||
|
func Test_CallTarget(t *testing.T) {
|
||
|
type args struct {
|
||
|
ctx context.Context
|
||
|
target *mockTarget
|
||
|
sleep time.Duration
|
||
|
|
||
|
info ContextInfoRequest
|
||
|
|
||
|
method string
|
||
|
body []byte
|
||
|
|
||
|
respBody []byte
|
||
|
statusCode int
|
||
|
}
|
||
|
type res struct {
|
||
|
body []byte
|
||
|
wantErr bool
|
||
|
}
|
||
|
tests := []struct {
|
||
|
name string
|
||
|
args args
|
||
|
res res
|
||
|
}{
|
||
|
{
|
||
|
"unknown targettype, error",
|
||
|
args{
|
||
|
ctx: context.Background(),
|
||
|
sleep: time.Second,
|
||
|
method: http.MethodPost,
|
||
|
info: newMockContextInfoRequest("content1"),
|
||
|
target: &mockTarget{
|
||
|
TargetType: 4,
|
||
|
},
|
||
|
body: []byte("{\"request\":{\"request\":\"content1\"}}"),
|
||
|
respBody: []byte("{\"request\":\"content2\"}"),
|
||
|
statusCode: http.StatusInternalServerError,
|
||
|
},
|
||
|
res{
|
||
|
wantErr: true,
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"webhook, error",
|
||
|
args{
|
||
|
ctx: context.Background(),
|
||
|
sleep: time.Second,
|
||
|
method: http.MethodPost,
|
||
|
info: newMockContextInfoRequest("content1"),
|
||
|
target: &mockTarget{
|
||
|
TargetType: domain.TargetTypeWebhook,
|
||
|
Timeout: time.Minute,
|
||
|
},
|
||
|
body: []byte("{\"request\":{\"request\":\"content1\"}}"),
|
||
|
respBody: []byte("{\"request\":\"content2\"}"),
|
||
|
statusCode: http.StatusInternalServerError,
|
||
|
},
|
||
|
res{
|
||
|
wantErr: true,
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"webhook, ok",
|
||
|
args{
|
||
|
ctx: context.Background(),
|
||
|
sleep: time.Second,
|
||
|
method: http.MethodPost,
|
||
|
info: newMockContextInfoRequest("content1"),
|
||
|
target: &mockTarget{
|
||
|
TargetType: domain.TargetTypeWebhook,
|
||
|
Timeout: time.Minute,
|
||
|
},
|
||
|
body: []byte("{\"request\":{\"request\":\"content1\"}}"),
|
||
|
respBody: []byte("{\"request\":\"content2\"}"),
|
||
|
statusCode: http.StatusOK,
|
||
|
},
|
||
|
res{
|
||
|
body: nil,
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"request response, error",
|
||
|
args{
|
||
|
ctx: context.Background(),
|
||
|
sleep: time.Second,
|
||
|
method: http.MethodPost,
|
||
|
info: newMockContextInfoRequest("content1"),
|
||
|
target: &mockTarget{
|
||
|
TargetType: domain.TargetTypeCall,
|
||
|
Timeout: time.Minute,
|
||
|
},
|
||
|
body: []byte("{\"request\":{\"request\":\"content1\"}}"),
|
||
|
respBody: []byte("{\"request\":\"content2\"}"),
|
||
|
statusCode: http.StatusInternalServerError,
|
||
|
},
|
||
|
res{
|
||
|
wantErr: true,
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"request response, ok",
|
||
|
args{
|
||
|
ctx: context.Background(),
|
||
|
sleep: time.Second,
|
||
|
method: http.MethodPost,
|
||
|
info: newMockContextInfoRequest("content1"),
|
||
|
target: &mockTarget{
|
||
|
TargetType: domain.TargetTypeCall,
|
||
|
Timeout: time.Minute,
|
||
|
},
|
||
|
body: []byte("{\"request\":{\"request\":\"content1\"}}"),
|
||
|
respBody: []byte("{\"request\":\"content2\"}"),
|
||
|
statusCode: http.StatusOK,
|
||
|
},
|
||
|
res{
|
||
|
body: []byte("{\"request\":\"content2\"}"),
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
for _, tt := range tests {
|
||
|
t.Run(tt.name, func(t *testing.T) {
|
||
|
respBody, err := testServerCall(t,
|
||
|
tt.args.method,
|
||
|
tt.args.body,
|
||
|
tt.args.sleep,
|
||
|
tt.args.statusCode,
|
||
|
tt.args.respBody,
|
||
|
testCallTarget(tt.args.ctx, tt.args.target, tt.args.info),
|
||
|
)
|
||
|
if tt.res.wantErr {
|
||
|
assert.Error(t, err)
|
||
|
} else {
|
||
|
assert.NoError(t, err)
|
||
|
}
|
||
|
assert.Equal(t, tt.res.body, respBody)
|
||
|
})
|
||
|
}
|
||
|
}
|