1
0
mirror of https://github.com/IBM/fp-go.git synced 2025-11-25 22:21:49 +02:00
Files
fp-go/v2/context/readerioresult/http/builder/builder_test.go
Dr. Carsten Leue 600521b220 fix: refactor
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2025-11-11 11:01:49 +01:00

288 lines
8.6 KiB
Go

// Copyright (c) 2023 - 2025 IBM Corp.
// All rights reserved.
//
// 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 builder
import (
"context"
"net/http"
"net/url"
"testing"
RIOE "github.com/IBM/fp-go/v2/context/readerioresult"
E "github.com/IBM/fp-go/v2/either"
F "github.com/IBM/fp-go/v2/function"
R "github.com/IBM/fp-go/v2/http/builder"
IO "github.com/IBM/fp-go/v2/io"
"github.com/stretchr/testify/assert"
)
func TestBuilderWithQuery(t *testing.T) {
// add some query
withLimit := R.WithQueryArg("limit")("10")
withURL := R.WithURL("http://www.example.org?a=b")
b := F.Pipe2(
R.Default,
withLimit,
withURL,
)
req := F.Pipe3(
b,
Requester,
RIOE.Map(func(r *http.Request) *url.URL {
return r.URL
}),
RIOE.ChainFirstIOK(func(u *url.URL) IO.IO[any] {
return IO.FromImpure(func() {
q := u.Query()
assert.Equal(t, "10", q.Get("limit"))
assert.Equal(t, "b", q.Get("a"))
})
}),
)
assert.True(t, E.IsRight(req(context.Background())()))
}
// TestBuilderWithoutBody tests creating a request without a body
func TestBuilderWithoutBody(t *testing.T) {
builder := F.Pipe2(
R.Default,
R.WithURL("https://api.example.com/users"),
R.WithMethod("GET"),
)
requester := Requester(builder)
result := requester(context.Background())()
assert.True(t, E.IsRight(result), "Expected Right result")
req := E.GetOrElse(func(error) *http.Request { return nil })(result)
assert.NotNil(t, req, "Expected non-nil request")
assert.Equal(t, "GET", req.Method)
assert.Equal(t, "https://api.example.com/users", req.URL.String())
assert.Nil(t, req.Body, "Expected nil body for GET request")
}
// TestBuilderWithBody tests creating a request with a body
func TestBuilderWithBody(t *testing.T) {
bodyData := []byte(`{"name":"John","age":30}`)
builder := F.Pipe3(
R.Default,
R.WithURL("https://api.example.com/users"),
R.WithMethod("POST"),
R.WithBytes(bodyData),
)
requester := Requester(builder)
result := requester(context.Background())()
assert.True(t, E.IsRight(result), "Expected Right result")
req := E.GetOrElse(func(error) *http.Request { return nil })(result)
assert.NotNil(t, req, "Expected non-nil request")
assert.Equal(t, "POST", req.Method)
assert.Equal(t, "https://api.example.com/users", req.URL.String())
assert.NotNil(t, req.Body, "Expected non-nil body for POST request")
assert.Equal(t, "24", req.Header.Get("Content-Length"))
}
// TestBuilderWithHeaders tests that headers are properly set
func TestBuilderWithHeaders(t *testing.T) {
builder := F.Pipe3(
R.Default,
R.WithURL("https://api.example.com/data"),
R.WithHeader("Authorization")("Bearer token123"),
R.WithHeader("Accept")("application/json"),
)
requester := Requester(builder)
result := requester(context.Background())()
assert.True(t, E.IsRight(result), "Expected Right result")
req := E.GetOrElse(func(error) *http.Request { return nil })(result)
assert.NotNil(t, req, "Expected non-nil request")
assert.Equal(t, "Bearer token123", req.Header.Get("Authorization"))
assert.Equal(t, "application/json", req.Header.Get("Accept"))
}
// TestBuilderWithInvalidURL tests error handling for invalid URLs
func TestBuilderWithInvalidURL(t *testing.T) {
builder := F.Pipe1(
R.Default,
R.WithURL("://invalid-url"),
)
requester := Requester(builder)
result := requester(context.Background())()
assert.True(t, E.IsLeft(result), "Expected Left result for invalid URL")
}
// TestBuilderWithEmptyMethod tests creating a request with empty method
func TestBuilderWithEmptyMethod(t *testing.T) {
builder := F.Pipe2(
R.Default,
R.WithURL("https://api.example.com/users"),
R.WithMethod(""),
)
requester := Requester(builder)
result := requester(context.Background())()
// Empty method should still work (defaults to GET in http.NewRequest)
assert.True(t, E.IsRight(result), "Expected Right result")
}
// TestBuilderWithMultipleHeaders tests setting multiple headers
func TestBuilderWithMultipleHeaders(t *testing.T) {
builder := F.Pipe4(
R.Default,
R.WithURL("https://api.example.com/data"),
R.WithHeader("X-Custom-Header-1")("value1"),
R.WithHeader("X-Custom-Header-2")("value2"),
R.WithHeader("X-Custom-Header-3")("value3"),
)
requester := Requester(builder)
result := requester(context.Background())()
assert.True(t, E.IsRight(result), "Expected Right result")
req := E.GetOrElse(func(error) *http.Request { return nil })(result)
assert.NotNil(t, req, "Expected non-nil request")
assert.Equal(t, "value1", req.Header.Get("X-Custom-Header-1"))
assert.Equal(t, "value2", req.Header.Get("X-Custom-Header-2"))
assert.Equal(t, "value3", req.Header.Get("X-Custom-Header-3"))
}
// TestBuilderWithBodyAndHeaders tests combining body and headers
func TestBuilderWithBodyAndHeaders(t *testing.T) {
bodyData := []byte(`{"test":"data"}`)
builder := F.Pipe4(
R.Default,
R.WithURL("https://api.example.com/submit"),
R.WithMethod("PUT"),
R.WithBytes(bodyData),
R.WithHeader("X-Request-ID")("12345"),
)
requester := Requester(builder)
result := requester(context.Background())()
assert.True(t, E.IsRight(result), "Expected Right result")
req := E.GetOrElse(func(error) *http.Request { return nil })(result)
assert.NotNil(t, req, "Expected non-nil request")
assert.Equal(t, "PUT", req.Method)
assert.NotNil(t, req.Body, "Expected non-nil body")
assert.Equal(t, "12345", req.Header.Get("X-Request-ID"))
assert.Equal(t, "15", req.Header.Get("Content-Length"))
}
// TestBuilderContextCancellation tests that context cancellation is respected
func TestBuilderContextCancellation(t *testing.T) {
builder := F.Pipe1(
R.Default,
R.WithURL("https://api.example.com/users"),
)
requester := Requester(builder)
// Create a cancelled context
ctx, cancel := context.WithCancel(context.Background())
cancel() // Cancel immediately
result := requester(ctx)()
// The request should still be created (cancellation affects execution, not creation)
// But we verify the context is properly passed
req := E.GetOrElse(func(error) *http.Request { return nil })(result)
if req != nil {
assert.Equal(t, ctx, req.Context(), "Expected context to be set in request")
}
}
// TestBuilderWithDifferentMethods tests various HTTP methods
func TestBuilderWithDifferentMethods(t *testing.T) {
methods := []string{"GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"}
for _, method := range methods {
t.Run(method, func(t *testing.T) {
builder := F.Pipe2(
R.Default,
R.WithURL("https://api.example.com/resource"),
R.WithMethod(method),
)
requester := Requester(builder)
result := requester(context.Background())()
assert.True(t, E.IsRight(result), "Expected Right result for method %s", method)
req := E.GetOrElse(func(error) *http.Request { return nil })(result)
assert.NotNil(t, req, "Expected non-nil request for method %s", method)
assert.Equal(t, method, req.Method)
})
}
}
// TestBuilderWithJSON tests creating a request with JSON body
func TestBuilderWithJSON(t *testing.T) {
data := map[string]string{"username": "testuser", "email": "test@example.com"}
builder := F.Pipe3(
R.Default,
R.WithURL("https://api.example.com/v1/users"),
R.WithMethod("POST"),
R.WithJSON(data),
)
requester := Requester(builder)
result := requester(context.Background())()
assert.True(t, E.IsRight(result), "Expected Right result")
req := E.GetOrElse(func(error) *http.Request { return nil })(result)
assert.NotNil(t, req, "Expected non-nil request")
assert.Equal(t, "POST", req.Method)
assert.Equal(t, "https://api.example.com/v1/users", req.URL.String())
assert.Equal(t, "application/json", req.Header.Get("Content-Type"))
assert.NotNil(t, req.Body)
}
// TestBuilderWithBearer tests adding Bearer token
func TestBuilderWithBearer(t *testing.T) {
builder := F.Pipe2(
R.Default,
R.WithURL("https://api.example.com/protected"),
R.WithBearer("my-secret-token"),
)
requester := Requester(builder)
result := requester(context.Background())()
assert.True(t, E.IsRight(result), "Expected Right result")
req := E.GetOrElse(func(error) *http.Request { return nil })(result)
assert.NotNil(t, req, "Expected non-nil request")
assert.Equal(t, "Bearer my-secret-token", req.Header.Get("Authorization"))
}