Repository: flipt-io/flipt-client-sdks (language: python)

Issue:
fix(engine-ffi): handle errors from http response
closes #346




Discussion / hints:
## [Codecov](https://app.codecov.io/gh/flipt-io/flipt-client-sdks/pull/347?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=flipt-io) Report
Attention: Patch coverage is `78.37838%` with `8 lines` in your changes missing coverage. Please review.
> Project coverage is 88.31%. Comparing base [(`7e318f3`)](https://app.codecov.io/gh/flipt-io/flipt-client-sdks/commit/7e318f3f2f27eefeea5ac85b671e4b3900b7b59b?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=flipt-io) to head [(`a91966d`)](https://app.codecov.io/gh/flipt-io/flipt-client-sdks/commit/a91966d4d2f89652915dff83316ddff22c1b0dd0?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=flipt-io).

| [Files with missing lines](https://app.codecov.io/gh/flipt-io/flipt-client-sdks/pull/347?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=flipt-io) | Patch % | Lines |
|---|---|---|
| [flipt-engine-ffi/src/http.rs](https://app.codecov.io/gh/flipt-io/flipt-client-sdks/pull/347?src=pr&el=tree&filepath=flipt-engine-ffi%2Fsrc%2Fhttp.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=flipt-io#diff-ZmxpcHQtZW5naW5lLWZmaS9zcmMvaHR0cC5ycw==) | 78.37% | [8 Missing :warning: ](https://app.codecov.io/gh/flipt-io/flipt-client-sdks/pull/347?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=flipt-io) |

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main     #347      +/-   ##
==========================================
- Coverage   88.40%   88.31%   -0.09%     
==========================================
  Files          10       10              
  Lines        3682     3706      +24     
==========================================
+ Hits         3255     3273      +18     
- Misses        427      433       +6     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/flipt-io/flipt-client-sdks/pull/347?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=flipt-io).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=flipt-io).


Fix patch:
diff --git a/flipt-client-go/evaluation.go b/flipt-client-go/evaluation.go
index 8c6a89a0..697fa42d 100644
--- a/flipt-client-go/evaluation.go
+++ b/flipt-client-go/evaluation.go
@@ -14,9 +14,12 @@ import "C"
 import (
 	"context"
 	"encoding/json"
+	"errors"
 	"unsafe"
 )
 
+const statusSuccess = "success"
+
 // Client wraps the functionality of making variant and boolean evaluation of Flipt feature flags.
 type Client struct {
 	engine         unsafe.Pointer
@@ -128,7 +131,11 @@ func (e *Client) EvaluateVariant(_ context.Context, flagKey, entityID string, ev
 		return nil, err
 	}
 
-	return vr, nil
+	if vr.Status == statusSuccess {
+		return vr, nil
+	}
+
+	return nil, errors.New(vr.ErrorMessage)
 }
 
 // EvaluateBoolean performs evaluation for a boolean flag.
@@ -157,7 +164,11 @@ func (e *Client) EvaluateBoolean(_ context.Context, flagKey, entityID string, ev
 		return nil, err
 	}
 
-	return br, nil
+	if br.Status == statusSuccess {
+		return br, nil
+	}
+
+	return nil, errors.New(br.ErrorMessage)
 }
 
 // EvaluateBatch performs evaluation for a batch of flags.
@@ -192,7 +203,11 @@ func (e *Client) EvaluateBatch(_ context.Context, requests []*EvaluationRequest)
 		return nil, err
 	}
 
-	return br, nil
+	if br.Status == statusSuccess {
+		return br, nil
+	}
+
+	return nil, errors.New(br.ErrorMessage)
 }
 
 func (e *Client) ListFlags(_ context.Context) (*ListFlagsResult, error) {
@@ -207,7 +222,11 @@ func (e *Client) ListFlags(_ context.Context) (*ListFlagsResult, error) {
 		return nil, err
 	}
 
-	return fl, nil
+	if fl.Status == statusSuccess {
+		return fl, nil
+	}
+
+	return nil, errors.New(fl.ErrorMessage)
 }
 
 // Close cleans up the allocated engine as it was initialized in the constructor.


Test patch:
diff --git a/flipt-client-go/evaluation_test.go b/flipt-client-go/evaluation_test.go
index 50e8a6a1..8780fe55 100644
--- a/flipt-client-go/evaluation_test.go
+++ b/flipt-client-go/evaluation_test.go
@@ -10,15 +10,19 @@ import (
 	flipt "go.flipt.io/flipt-client"
 )
 
-var evaluationClient *flipt.Client
+var (
+	evaluationClient *flipt.Client
+	fliptUrl         string
+	authToken        string
+)
 
 func init() {
-	fliptUrl := os.Getenv("FLIPT_URL")
+	fliptUrl = os.Getenv("FLIPT_URL")
 	if fliptUrl == "" {
 		panic("set FLIPT_URL")
 	}
 
-	authToken := os.Getenv("FLIPT_AUTH_TOKEN")
+	authToken = os.Getenv("FLIPT_AUTH_TOKEN")
 	if authToken == "" {
 		panic("set FLIPT_AUTH_TOKEN")
 	}
@@ -30,14 +34,21 @@ func init() {
 	}
 }
 
+func TestInvalidAuthentication(t *testing.T) {
+	client, err := flipt.NewClient(flipt.WithURL(fliptUrl), flipt.WithClientTokenAuthentication("invalid"))
+	require.NoError(t, err)
+	_, err = client.EvaluateVariant(context.TODO(), "flag1", "someentity", map[string]string{
+		"fizz": "buzz",
+	})
+	assert.EqualError(t, err, "server error: response: HTTP status client error (401 Unauthorized) for url (http://flipt:8080/internal/v1/evaluation/snapshot/namespace/default)")
+}
+
 func TestVariant(t *testing.T) {
 	variant, err := evaluationClient.EvaluateVariant(context.TODO(), "flag1", "someentity", map[string]string{
 		"fizz": "buzz",
 	})
 	require.NoError(t, err)
 
-	assert.Equal(t, "success", variant.Status)
-	assert.Empty(t, variant.ErrorMessage)
 	assert.True(t, variant.Result.Match)
 	assert.Equal(t, "flag1", variant.Result.FlagKey)
 	assert.Equal(t, "MATCH_EVALUATION_REASON", variant.Result.Reason)
@@ -50,8 +61,6 @@ func TestBoolean(t *testing.T) {
 	})
 	require.NoError(t, err)
 
-	assert.Equal(t, "success", boolean.Status)
-	assert.Empty(t, boolean.ErrorMessage)
 	assert.Equal(t, "flag_boolean", boolean.Result.FlagKey)
 	assert.True(t, boolean.Result.Enabled)
 	assert.Equal(t, "MATCH_EVALUATION_REASON", boolean.Result.Reason)
@@ -83,9 +92,6 @@ func TestBatch(t *testing.T) {
 	})
 	require.NoError(t, err)
 
-	assert.Equal(t, "success", batch.Status)
-	assert.Empty(t, batch.ErrorMessage)
-
 	assert.Len(t, batch.Result.Responses, 3)
 
 	variant := batch.Result.Responses[0]
@@ -113,28 +119,19 @@ func TestListFlags(t *testing.T) {
 	require.NoError(t, err)
 
 	assert.NotEmpty(t, response)
-	assert.Equal(t, "success", response.Status)
 	assert.Equal(t, 2, len(*response.Result))
 }
 
 func TestVariantFailure(t *testing.T) {
-	variant, err := evaluationClient.EvaluateVariant(context.TODO(), "nonexistent", "someentity", map[string]string{
+	_, err := evaluationClient.EvaluateVariant(context.TODO(), "nonexistent", "someentity", map[string]string{
 		"fizz": "buzz",
 	})
-	require.NoError(t, err)
-
-	assert.Nil(t, variant.Result)
-	assert.Equal(t, "failure", variant.Status)
-	assert.Equal(t, "invalid request: failed to get flag information default/nonexistent", variant.ErrorMessage)
+	assert.EqualError(t, err, "invalid request: failed to get flag information default/nonexistent")
 }
 
 func TestBooleanFailure(t *testing.T) {
-	boolean, err := evaluationClient.EvaluateBoolean(context.TODO(), "nonexistent", "someentity", map[string]string{
+	_, err := evaluationClient.EvaluateBoolean(context.TODO(), "nonexistent", "someentity", map[string]string{
 		"fizz": "buzz",
 	})
-	require.NoError(t, err)
-
-	assert.Nil(t, boolean.Result)
-	assert.Equal(t, "failure", boolean.Status)
-	assert.Equal(t, "invalid request: failed to get flag information default/nonexistent", boolean.ErrorMessage)
+	assert.EqualError(t, err, "invalid request: failed to get flag information default/nonexistent")
 }
diff --git a/test/main.go b/test/main.go
index 2417e6fb..1e9c48fd 100644
--- a/test/main.go
+++ b/test/main.go
@@ -144,9 +144,9 @@ func getTestDependencies(_ context.Context, client *dagger.Client, hostDirectory
 		WithUser("flipt").
 		WithEnvVariable("FLIPT_STORAGE_TYPE", "local").
 		WithEnvVariable("FLIPT_STORAGE_LOCAL_PATH", "/var/data/flipt").
-		WithEnvVariable("FLIPT_AUTHENTICATION_METHODS_TOKEN_ENABLED", "1").
+		WithEnvVariable("FLIPT_AUTHENTICATION_METHODS_TOKEN_ENABLED", "true").
 		WithEnvVariable("FLIPT_AUTHENTICATION_METHODS_TOKEN_BOOTSTRAP_TOKEN", "secret").
-		WithEnvVariable("FLIPT_AUTHENTICATION_REQUIRED", "1").
+		WithEnvVariable("FLIPT_AUTHENTICATION_REQUIRED", "true").
 		WithExposedPort(8080)
 
 	return flipt, testArgs{