github.com/anthropics/anthropic-sdk-go@v1.70.1/internal/requestconfig/requestconfig_test.go (about)

     1  package requestconfig
     2  
     3  import (
     4  	"context"
     5  	"net/http"
     6  	"net/http/httptest"
     7  	"net/url"
     8  	"testing"
     9  
    10  	"github.com/anthropics/anthropic-sdk-go/internal/apierror"
    11  	"github.com/anthropics/anthropic-sdk-go/shared"
    12  	"github.com/stretchr/testify/assert"
    13  	"github.com/stretchr/testify/require"
    14  )
    15  
    16  // mockBaseURL is a helper function to create a URL for testing
    17  func mockBaseURL(server *httptest.Server) *url.URL {
    18  	u, _ := url.Parse(server.URL)
    19  	return u
    20  }
    21  
    22  // TestErrorWithRequestID tests that RequestID is properly extracted from response headers
    23  // and included in the Error struct when API errors occur
    24  func TestErrorWithRequestID(t *testing.T) {
    25  	// Create a test server that simulates an API returning an error with request-id
    26  	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    27  		// Set the request-id header - using the same header name as in the code
    28  		w.Header().Set("request-id", "req_123456789")
    29  		w.Header().Set("anthropic-workspace-id", "wrkspc_123")
    30  		// Return a 400 error with error JSON
    31  		w.WriteHeader(http.StatusBadRequest)
    32  		w.Write([]byte(`{"error":{"type":"invalid_request_error","message":"Invalid request"}}`))
    33  	}))
    34  	defer server.Close()
    35  
    36  	// Create a request to the test server
    37  	req, err := http.NewRequest("GET", "/test", nil)
    38  	require.NoError(t, err, "Failed to create request")
    39  
    40  	// Create a RequestConfig with proper BaseURL
    41  	cfg := &RequestConfig{
    42  		Context:    context.Background(),
    43  		Request:    req,
    44  		BaseURL:    mockBaseURL(server),
    45  		HTTPClient: http.DefaultClient,
    46  	}
    47  
    48  	// Execute the request, which should return an error
    49  	err = cfg.Execute()
    50  	require.Error(t, err, "Expected an error, but got nil")
    51  
    52  	// The error should be of type *apierror.Error
    53  	apiErr, ok := err.(*apierror.Error)
    54  	require.True(t, ok, "Expected error of type *apierror.Error, got %T", err)
    55  
    56  	// Verify that RequestID field was properly set from the header
    57  	expectedRequestID := "req_123456789"
    58  	assert.Equal(t, expectedRequestID, apiErr.RequestID, "Expected RequestID to be %s, got %s", expectedRequestID, apiErr.RequestID)
    59  	assert.Equal(t, "wrkspc_123", apiErr.WorkspaceID)
    60  
    61  	// Verify that the error message includes the RequestID
    62  	errorMsg := apiErr.Error()
    63  	assert.Contains(t, errorMsg, "Request-ID: req_123456789", "Error message should contain request ID")
    64  	assert.Contains(t, errorMsg, "Workspace-ID: wrkspc_123", "Error message should contain workspace ID")
    65  }
    66  
    67  func TestErrorType(t *testing.T) {
    68  	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    69  		w.Header().Set("request-id", "req_test123")
    70  		w.WriteHeader(http.StatusBadRequest)
    71  		w.Write([]byte(`{"type":"error","error":{"type":"invalid_request_error","message":"Bad request"}}`))
    72  	}))
    73  	defer server.Close()
    74  
    75  	req, err := http.NewRequest("GET", "/test", nil)
    76  	require.NoError(t, err)
    77  
    78  	cfg := &RequestConfig{
    79  		Context:    context.Background(),
    80  		Request:    req,
    81  		BaseURL:    mockBaseURL(server),
    82  		HTTPClient: http.DefaultClient,
    83  	}
    84  	err = cfg.Execute()
    85  	require.Error(t, err)
    86  
    87  	apiErr, ok := err.(*apierror.Error)
    88  	require.True(t, ok, "Expected *apierror.Error, got %T", err)
    89  	assert.Equal(t, shared.ErrorTypeInvalidRequestError, apiErr.Type())
    90  	assert.Equal(t, 400, apiErr.StatusCode)
    91  	assert.Equal(t, "req_test123", apiErr.RequestID)
    92  }
    93  
    94  func TestErrorTypeAbsent(t *testing.T) {
    95  	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    96  		w.WriteHeader(http.StatusInternalServerError)
    97  		w.Write([]byte(`{"message":"Internal error"}`))
    98  	}))
    99  	defer server.Close()
   100  
   101  	req, err := http.NewRequest("GET", "/test", nil)
   102  	require.NoError(t, err)
   103  
   104  	cfg := &RequestConfig{
   105  		Context:    context.Background(),
   106  		Request:    req,
   107  		BaseURL:    mockBaseURL(server),
   108  		HTTPClient: http.DefaultClient,
   109  	}
   110  	err = cfg.Execute()
   111  	require.Error(t, err)
   112  
   113  	apiErr, ok := err.(*apierror.Error)
   114  	require.True(t, ok, "Expected *apierror.Error, got %T", err)
   115  	assert.Equal(t, shared.ErrorType(""), apiErr.Type())
   116  	assert.Equal(t, 500, apiErr.StatusCode)
   117  }