Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
SHELL = /bin/sh

VERSION=1.1.2
VERSION=1.1.3
BUILD=`git rev-parse HEAD`

LDFLAGS=-ldflags "-w -s \
Expand Down
38 changes: 38 additions & 0 deletions fakeserver/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ type v1Assignment struct {
Unsynced bool `json:"unsynced"`
}

// v2AssignmentOverrideRequestBody is the JSON input for the V2 assignment override endpoint
type v2AssignmentOverrideRequestBody struct {
Assignments []v1Assignment `json:"assignments"`
}

Comment on lines +29 to +33
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ended up introducing this to help with deserialization

// v1VisitorConfig is the JSON output type for V1 visitor_config endpoints
type v1VisitorConfig struct {
Splits map[string]*splits.Weights `json:"splits"`
Expand Down Expand Up @@ -112,6 +117,10 @@ func (s *server) routes() {
"/api/v1/assignment_override",
postV1AssignmentOverride,
)
s.handlePostReturnNoContent(
"/api/v2/visitors/{v}/assignment_overrides",
postV2AssignmentOverride,
)
s.handleGet(
"/api/v1/apps/{a}/versions/{v}/builds/{b}/visitors/{id}/config",
getV1AppVisitorConfig,
Expand Down Expand Up @@ -257,6 +266,35 @@ func postV1AssignmentOverride(r *http.Request) error {
return nil
}

func postV2AssignmentOverride(r *http.Request) error {
var assignments []v1Assignment
contentType := r.Header.Get("content-type")
switch {
case strings.HasPrefix(contentType, "application/json"):
requestBytes, err := ioutil.ReadAll(r.Body)
if err != nil {
return err
}
var assignmentBody v2AssignmentOverrideRequestBody
err = json.Unmarshal(requestBytes, &assignmentBody)
if err != nil {
return err
}
assignments = assignmentBody.Assignments
default:
return fmt.Errorf("got unexpected content type %s", contentType)
}
storedAssignments, err := fakeassignments.Read()
for _, assignment := range assignments {
(*storedAssignments)[assignment.SplitName] = assignment.Variant
}
Comment on lines +288 to +290
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the other new bit compared to the previous singular version. before this was a single assignment, now it's a loop ➰

err = fakeassignments.Write(storedAssignments)
if err != nil {
return err
}
return nil
}

func getV1AppVisitorConfig() (interface{}, error) {
isplitRegistry, err := getV1SplitRegistry()
splitRegistry := isplitRegistry.(map[string]*splits.Weights)
Expand Down
42 changes: 42 additions & 0 deletions fakeserver/server_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package fakeserver

import (
"bytes"
"io/ioutil"
"log"
"net/http"
Expand All @@ -27,6 +28,10 @@ splits:
weights:
control: 60
treatment: 40
- name: test.test2_experiment
weights:
control: 60
treatment: 40
`

func TestMain(m *testing.M) {
Expand Down Expand Up @@ -150,3 +155,40 @@ func TestPersistAssignment(t *testing.T) {
require.Equal(t, "control", (*assignments)["test.test_experiment"])
})
}

func TestPersistAssignmentV2(t *testing.T) {
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@smudge i snuck a test in here too since i noticed that there was one for the old way

os.Remove("testdata/assignments.yml")

t.Run("it persists assignments to yaml", func(t *testing.T) {
w := httptest.NewRecorder()
h := createHandler()

overrides := v2AssignmentOverrideRequestBody{
Assignments: []v1Assignment{
v1Assignment{
SplitName: "test.test_experiment",
Variant: "control",
},
v1Assignment{
SplitName: "test.test2_experiment",
Variant: "treatment",
},
},
}
data, err := json.Marshal(overrides)
require.Nil(t, err)

request := httptest.NewRequest("POST", "/api/v2/visitors/1/assignment_overrides", bytes.NewReader(data))
request.Header.Add("Content-Type", "application/json")
request.Header.Add("Content-Length", strconv.Itoa(len(data)))

h.ServeHTTP(w, request)

require.Equal(t, http.StatusNoContent, w.Code)

assignments, err := fakeassignments.Read()
require.Nil(t, err)
require.Equal(t, "control", (*assignments)["test.test_experiment"])
require.Equal(t, "treatment", (*assignments)["test.test2_experiment"])
})
}