-
Notifications
You must be signed in to change notification settings - Fork 1
chore: Update data sources to send FDv2-compatible payloads #229
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
d51a650
24ff176
62b0692
e8a199b
17c4ad0
2df808a
16cd235
0a06635
f98543a
730cc95
b239411
5809c1b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| package framework | ||
|
|
||
| import ( | ||
| "encoding/json" | ||
|
|
||
| "github.com/launchdarkly/eventsource" | ||
| ) | ||
|
|
||
| type PollingPayload struct { | ||
| Events []PayloadEvent `json:"events"` | ||
| } | ||
|
|
||
| type PayloadEvent struct { | ||
| Name string `json:"name"` | ||
| EventData interface{} `json:"data"` | ||
| } | ||
|
|
||
| type ChangeSet struct { | ||
| intent *ServerIntent | ||
| events []eventsource.Event | ||
| } | ||
|
|
||
| type ServerIntent struct { | ||
| Payloads []Payload `json:"payloads"` | ||
| } | ||
|
|
||
| type Payload struct { | ||
| // The id here doesn't seem to match the state that is included in the | ||
| // payload transferred object. | ||
|
|
||
| // It would be nice if we had the same value available in both so we could | ||
| // use that as the key consistently throughout the process. | ||
| ID string `json:"id"` | ||
| Target int `json:"target"` | ||
| Code string `json:"code"` | ||
| Reason string `json:"reason"` | ||
| } | ||
|
|
||
| // This is the general shape of a put-object event. The delete-object is the same, with the object field being nil. | ||
| type BaseObject struct { | ||
| Version int `json:"version"` | ||
| Kind string `json:"kind"` | ||
| Key string `json:"key"` | ||
| Object json.RawMessage `json:"object,omitempty"` | ||
| } | ||
|
|
||
| type PayloadTransferred struct { | ||
| State string `json:"state"` | ||
| Version int `json:"version"` | ||
| } | ||
|
|
||
| // TODO: Todd doesn't have this in his spec. What are we going to do here? | ||
| // | ||
| //nolint:godox | ||
| type ErrorEvent struct { | ||
| PayloadID string `json:"payloadId"` | ||
| Reason string `json:"reason"` | ||
| } | ||
|
|
||
| // type heartBeat struct{} | ||
|
|
||
| type Goodbye struct { | ||
| Reason string `json:"reason"` | ||
| Silent bool `json:"silent"` | ||
| Catastrophe bool `json:"catastrophe"` | ||
| //nolint:godox | ||
| // TODO: Might later include some advice or backoff information | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -152,29 +152,84 @@ func (p *PollingService) pollingHandler(getDataFn func(*PollingService, *http.Re | |
|
|
||
| func (p *PollingService) standardPollingHandler() http.Handler { | ||
| return p.pollingHandler(func(p *PollingService, r *http.Request) []byte { | ||
| return p.currentData.Serialize() | ||
| fdv2SdkData, ok := p.currentData.(FDv2SDKData) | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This translation bit is a mess and is going to require the most rework. I wanted to see how the changes emerged as we developed additional FDv2 tests (like the xfer-changes stuff) before I tried to fix this hack too much. |
||
| if !ok { | ||
| p.debugLogger.Println("poller cannot handle non-fdv2 sdk data at this time") | ||
| return nil | ||
| } | ||
|
|
||
| // QUESTION: How dynamic do we need to make this? | ||
| serverIntent := framework.ServerIntent{ | ||
| Payloads: []framework.Payload{ | ||
| { | ||
| ID: "payloadID", | ||
| Target: 1, | ||
| Code: "xfer-full", | ||
| Reason: "payload-missing", | ||
| }, | ||
| }, | ||
| } | ||
|
|
||
| payloadTransferred := framework.PayloadTransferred{ | ||
| State: "state", // TODO: Need to replace this with a valid state value | ||
| Version: 1, | ||
| } | ||
|
|
||
| events := make([]framework.PayloadEvent, 0, len(fdv2SdkData)+2) | ||
| events = append(events, framework.PayloadEvent{ | ||
| Name: "server-intent", | ||
| EventData: serverIntent, | ||
| }) | ||
| for _, obj := range fdv2SdkData { | ||
| events = append(events, framework.PayloadEvent{ | ||
| Name: "put-object", | ||
| EventData: obj, | ||
| }) | ||
| } | ||
| events = append(events, framework.PayloadEvent{ | ||
| Name: "payload-transferred", | ||
| EventData: payloadTransferred, | ||
| }) | ||
|
|
||
| payload := framework.PollingPayload{ | ||
| Events: events, | ||
| } | ||
|
|
||
| data, err := json.Marshal(payload) | ||
| if err != nil { | ||
| p.debugLogger.Printf("failed to marshal polling data: %v", err) | ||
| return nil | ||
| } | ||
|
|
||
| return data | ||
| }) | ||
| } | ||
|
|
||
| func (p *PollingService) phpFlagHandler() http.Handler { | ||
| return p.pollingHandler(func(p *PollingService, r *http.Request) []byte { | ||
| data, _ := p.currentData.(ServerSDKData) | ||
| return data["flags"][mux.Vars(r)["key"]] | ||
| // TODO: Update this logic | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. PHP stuff will come later. |
||
| return []byte("UNSUPPORTED") | ||
| // data, _ := p.currentData.(ServerSDKData) | ||
| // return data["flags"][mux.Vars(r)["key"]] | ||
| }) | ||
| } | ||
|
|
||
| func (p *PollingService) phpSegmentHandler() http.Handler { | ||
| return p.pollingHandler(func(p *PollingService, r *http.Request) []byte { | ||
| data, _ := p.currentData.(ServerSDKData) | ||
| return data["segments"][mux.Vars(r)["key"]] | ||
| // TODO: Update this logic | ||
| return []byte("UNSUPPORTED") | ||
| // data, _ := p.currentData.(ServerSDKData) | ||
| // return data["segments"][mux.Vars(r)["key"]] | ||
| }) | ||
| } | ||
|
|
||
| func (p *PollingService) phpAllFlagsHandler() http.Handler { | ||
| return p.pollingHandler(func(p *PollingService, r *http.Request) []byte { | ||
| data, _ := p.currentData.(ServerSDKData) | ||
| flagsJSON, _ := json.Marshal(data["flags"]) | ||
| return flagsJSON | ||
| // TODO: Update this logic | ||
| return []byte("UNSUPPORTED") | ||
| // data, _ := p.currentData.(ServerSDKData) | ||
| // flagsJSON, _ := json.Marshal(data["flags"]) | ||
| // return flagsJSON | ||
| }) | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,86 +1,84 @@ | ||
| package mockld | ||
|
|
||
| import ( | ||
| "encoding/json" | ||
| "fmt" | ||
| "io" | ||
| "net/http" | ||
| "net/http/httptest" | ||
| "testing" | ||
|
|
||
| "github.com/launchdarkly/go-test-helpers/v2/httphelpers" | ||
| m "github.com/launchdarkly/go-test-helpers/v2/matchers" | ||
| h "github.com/launchdarkly/sdk-test-harness/v2/framework/helpers" | ||
|
|
||
| "github.com/launchdarkly/go-sdk-common/v3/ldlog" | ||
| "github.com/launchdarkly/go-sdk-common/v3/ldlogtest" | ||
| "github.com/launchdarkly/go-sdk-common/v3/ldvalue" | ||
|
|
||
| "github.com/stretchr/testify/require" | ||
| ) | ||
|
|
||
| func TestPollingServiceServerSide(t *testing.T) { | ||
| doPollingServiceTests( | ||
| t, | ||
| ServerSideSDK, | ||
| EmptyServerSDKData(), | ||
| NewServerSDKDataBuilder().RawFlag("flag1", json.RawMessage(`{"key": "flag1"}`)).Build(), | ||
| "GET", | ||
| "/sdk/latest-all", | ||
| ) | ||
| } | ||
| // TODO: Re-enable these tests | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will fix the unit tests later. Again, just getting something working out in front of you. |
||
|
|
||
| func TestPollingServiceMobile(t *testing.T) { | ||
| for _, oldUserPaths := range []bool{false, true} { | ||
| userOrContext := h.IfElse(oldUserPaths, "user", "context") | ||
| t.Run(userOrContext, func(t *testing.T) { | ||
| for _, useReport := range []bool{true, false} { | ||
| method := h.IfElse(useReport, "REPORT", "GET") | ||
| endpoint := h.IfElse( | ||
| useReport, | ||
| fmt.Sprintf("/msdk/evalx/%s", userOrContext), | ||
| fmt.Sprintf("/msdk/evalx/%ss/fakeuserdata", userOrContext), | ||
| ) | ||
| t.Run(method, func(t *testing.T) { | ||
| doPollingServiceTests( | ||
| t, | ||
| MobileSDK, | ||
| EmptyClientSDKData(), | ||
| NewClientSDKDataBuilder().FlagWithValue("flag1", 1, ldvalue.String("yes"), 0).Build(), | ||
| method, | ||
| endpoint, | ||
| ) | ||
| }) | ||
| } | ||
| }) | ||
| } | ||
| } | ||
| // func TestPollingServiceServerSide(t *testing.T) { | ||
| // doPollingServiceTests( | ||
| // t, | ||
| // ServerSideSDK, | ||
| // EmptyServerSDKData(), | ||
| // NewServerSDKDataBuilder().RawFlag("flag1", json.RawMessage(`{"key": "flag1"}`)).Build(), | ||
| // "GET", | ||
| // "/sdk/latest-all", | ||
| // ) | ||
| // } | ||
|
|
||
| func TestPollingServiceJSClient(t *testing.T) { | ||
| for _, oldUserPaths := range []bool{false, true} { | ||
| userOrContext := h.IfElse(oldUserPaths, "user", "context") | ||
| t.Run(userOrContext, func(t *testing.T) { | ||
| for _, useReport := range []bool{true, false} { | ||
| method := h.IfElse(useReport, "REPORT", "GET") | ||
| endpoint := h.IfElse( | ||
| useReport, | ||
| fmt.Sprintf("/sdk/evalx/fakeid/%s", userOrContext), | ||
| fmt.Sprintf("/sdk/evalx/fakeid/%ss/fakeuserdata", userOrContext), | ||
| ) | ||
| t.Run(method, func(t *testing.T) { | ||
| doPollingServiceTests( | ||
| t, | ||
| JSClientSDK, | ||
| EmptyClientSDKData(), | ||
| NewClientSDKDataBuilder().FlagWithValue("flag1", 1, ldvalue.String("yes"), 0).Build(), | ||
| method, | ||
| endpoint, | ||
| ) | ||
| }) | ||
| } | ||
| }) | ||
| } | ||
| } | ||
| // func TestPollingServiceMobile(t *testing.T) { | ||
| // for _, oldUserPaths := range []bool{false, true} { | ||
| // userOrContext := h.IfElse(oldUserPaths, "user", "context") | ||
| // t.Run(userOrContext, func(t *testing.T) { | ||
| // for _, useReport := range []bool{true, false} { | ||
| // method := h.IfElse(useReport, "REPORT", "GET") | ||
| // endpoint := h.IfElse( | ||
| // useReport, | ||
| // fmt.Sprintf("/msdk/evalx/%s", userOrContext), | ||
| // fmt.Sprintf("/msdk/evalx/%ss/fakeuserdata", userOrContext), | ||
| // ) | ||
| // t.Run(method, func(t *testing.T) { | ||
| // doPollingServiceTests( | ||
| // t, | ||
| // MobileSDK, | ||
| // EmptyClientSDKData(), | ||
| // NewClientSDKDataBuilder().FlagWithValue("flag1", 1, ldvalue.String("yes"), 0).Build(), | ||
| // method, | ||
| // endpoint, | ||
| // ) | ||
| // }) | ||
| // } | ||
| // }) | ||
| // } | ||
| // } | ||
|
|
||
| // func TestPollingServiceJSClient(t *testing.T) { | ||
| // for _, oldUserPaths := range []bool{false, true} { | ||
| // userOrContext := h.IfElse(oldUserPaths, "user", "context") | ||
| // t.Run(userOrContext, func(t *testing.T) { | ||
| // for _, useReport := range []bool{true, false} { | ||
| // method := h.IfElse(useReport, "REPORT", "GET") | ||
| // endpoint := h.IfElse( | ||
| // useReport, | ||
| // fmt.Sprintf("/sdk/evalx/fakeid/%s", userOrContext), | ||
| // fmt.Sprintf("/sdk/evalx/fakeid/%ss/fakeuserdata", userOrContext), | ||
| // ) | ||
| // t.Run(method, func(t *testing.T) { | ||
| // doPollingServiceTests( | ||
| // t, | ||
| // JSClientSDK, | ||
| // EmptyClientSDKData(), | ||
| // NewClientSDKDataBuilder().FlagWithValue("flag1", 1, ldvalue.String("yes"), 0).Build(), | ||
| // method, | ||
| // endpoint, | ||
| // ) | ||
| // }) | ||
| // } | ||
| // }) | ||
| // } | ||
| // } | ||
|
|
||
| func doPollingServiceTests( | ||
| t *testing.T, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same basic types I'm carrying around everywhere right now. Need to get these into the events package or somewhere core.