Skip to content

Commit

Permalink
feat: fetch v2 for remote eval client (#26)
Browse files Browse the repository at this point in the history
* feat: fetch v2 for remote eval client

* simplify

* use v2 fetch in cmd
  • Loading branch information
bgiori authored Apr 19, 2024
1 parent f678656 commit 7f7b073
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 29 deletions.
2 changes: 1 addition & 1 deletion cmd/xpmt/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func fetch() {

client := remote.Initialize(*apiKey, config)
start := time.Now()
variants, err := client.Fetch(user)
variants, err := client.FetchV2(user)
if err != nil {
fmt.Printf("error: %v\n", err)
os.Exit(1)
Expand Down
55 changes: 36 additions & 19 deletions pkg/experiment/remote/client.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package remote

import (
"bytes"
"context"
"encoding/base64"
"encoding/json"
"fmt"
"math"
Expand Down Expand Up @@ -47,7 +47,19 @@ func Initialize(apiKey string, config *Config) *Client {
return client
}

// Deprecated: Use FetchV2
func (c *Client) Fetch(user *experiment.User) (map[string]experiment.Variant, error) {
variants, err := c.FetchV2(user)
if err != nil {
return nil, err
}
results := filterDefaultVariants(variants)
return results, nil
}

// FetchV2 fetches variants for a user from the remote evaluation service.
// Unlike Fetch, this method returns all variants, including default variants.
func (c *Client) FetchV2(user *experiment.User) (map[string]experiment.Variant, error) {
variants, err := c.doFetch(user, c.config.FetchTimeout)
if err != nil {
c.log.Error("fetch error: %v", err)
Expand All @@ -66,7 +78,7 @@ func (c *Client) doFetch(user *experiment.User, timeout time.Duration) (map[stri
if err != nil {
return nil, err
}
endpoint.Path = "sdk/vardata"
endpoint.Path = "sdk/v2/vardata"
if c.config.Debug {
endpoint.RawQuery = fmt.Sprintf("d=%s", randStringRunes(5))
}
Expand All @@ -77,13 +89,13 @@ func (c *Client) doFetch(user *experiment.User, timeout time.Duration) (map[stri
c.log.Debug("fetch variants for user %s", string(jsonBytes))
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
req, err := http.NewRequest("POST", endpoint.String(), bytes.NewBuffer(jsonBytes))
req, err := http.NewRequestWithContext(ctx, "GET", endpoint.String(), nil)
if err != nil {
return nil, err
}
req = req.WithContext(ctx)
req.Header.Set("Authorization", fmt.Sprintf("Api-Key %s", c.apiKey))
req.Header.Set("Content-Type", "application/json; charset=UTF-8")
req.Header.Set("X-Amp-Exp-User", base64.StdEncoding.EncodeToString(jsonBytes))
c.log.Debug("fetch request: %v", req)
resp, err := c.client.Do(req)
if err != nil {
Expand Down Expand Up @@ -122,24 +134,11 @@ func (c *Client) retryFetch(user *experiment.User) (map[string]experiment.Varian
}

func (c *Client) parseResponse(resp *http.Response) (map[string]experiment.Variant, error) {
interop := make(interopVariants)
err := json.NewDecoder(resp.Body).Decode(&interop)
variants := make(map[string]experiment.Variant)
err := json.NewDecoder(resp.Body).Decode(&variants)
if err != nil {
return nil, err
}
variants := make(map[string]experiment.Variant)
for k, iv := range interop {
var value string
if iv.Value != "" {
value = iv.Value
} else if iv.Key != "" {
value = iv.Key
}
variants[k] = experiment.Variant{
Value: value,
Payload: iv.Payload,
}
}
c.log.Debug("parsed variants from response: %v", variants)
return variants, nil
}
Expand Down Expand Up @@ -172,3 +171,21 @@ func shouldRetryFetch(err error) bool {
}
return true
}

func filterDefaultVariants(variants map[string]experiment.Variant) map[string]experiment.Variant {
results := make(map[string]experiment.Variant)
for key, variant := range variants {
isDefault, ok := variant.Metadata["default"].(bool)
if !ok {
isDefault = false
}
isDeployed, ok := variant.Metadata["deployed"].(bool)
if !ok {
isDeployed = true
}
if !isDefault && isDeployed {
results[key] = variant
}
}
return results
}
22 changes: 22 additions & 0 deletions pkg/experiment/remote/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,28 @@ import (
"github.com/stretchr/testify/require"
)

func TestClient_Fetch_DoesNotReturnDefaultVariants(t *testing.T) {
client := Initialize("server-qz35UwzJ5akieoAdIgzM4m9MIiOLXLoz", nil)
user := &experiment.User{}
result, err := client.Fetch(user)
require.NoError(t, err)
require.NotNil(t, result)
variant := result["sdk-ci-test"]
require.Empty(t, variant)
}


func TestClient_FetchV2_ReturnsDefaultVariants(t *testing.T) {
client := Initialize("server-qz35UwzJ5akieoAdIgzM4m9MIiOLXLoz", nil)
user := &experiment.User{}
result, err := client.FetchV2(user)
require.NoError(t, err)
require.NotNil(t, result)
variant := result["sdk-ci-test"]
require.NotNil(t, variant)
require.Equal(t, "off", variant.Key)
}

func TestClient_FetchRetryWithDifferentResponseCodes(t *testing.T) {
// Test data: Response code, error message, and expected number of fetch calls
testData := []struct {
Expand Down
9 changes: 0 additions & 9 deletions pkg/experiment/remote/types.go

This file was deleted.

0 comments on commit 7f7b073

Please sign in to comment.