From 8a85a32561d48d4e9b57ff37f8f8fd68d4e3a898 Mon Sep 17 00:00:00 2001 From: Alexis Couvreur Date: Thu, 3 Nov 2022 19:04:29 +0000 Subject: [PATCH] feat: update JSON object returned by blocking strategy Closes #68 --- README.md | 31 ++++++----- app/http/routes/strategies.go | 2 +- app/http/routes/strategies_test.go | 82 +++++++++++++++++++++++++++++- app/sessions/sessions_manager.go | 17 +++++-- 4 files changed, 112 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 073857c..1a4d8bd 100644 --- a/README.md +++ b/README.md @@ -41,26 +41,29 @@ docker run -v /var/run/docker.sock:/var/run/docker.sock -p 10000:10000 ghcr.io/a # Start the containers, the request will hang until both containers are up and running curl 'http://localhost:10000/api/strategies/blocking?names=nginx&names=whoami&session_duration=1m' -[ +{ + "session": { + "instances": [ { - "Instance": { - "Name": "whoami", - "CurrentReplicas": 1, - "Status": "ready", - "Message": "" + "instance": { + "name": "nginx", + "currentReplicas": 1, + "status": "ready" }, - "Error": null + "error": null }, { - "Instance": { - "Name": "nginx", - "CurrentReplicas": 1, - "Status": "ready", - "Message": "" + "instance": { + "name": "nginx", + "currentReplicas": 1, + "status": "ready" }, - "Error": null + "error": null } -] + ], + "status":"ready" + } +} ``` ## ⚙️ Configuration diff --git a/app/http/routes/strategies.go b/app/http/routes/strategies.go index 77238a3..e21cc5a 100644 --- a/app/http/routes/strategies.go +++ b/app/http/routes/strategies.go @@ -128,7 +128,7 @@ func (s *ServeStrategy) ServeBlocking(c *gin.Context) { c.Header("X-Sablier-Session-Status", "not-ready") } - c.JSON(http.StatusOK, sessionState) + c.JSON(http.StatusOK, map[string]interface{}{"session": sessionState}) } func sessionStateToRenderOptionsInstanceState(sessionState *sessions.SessionState) (instances []pages.RenderOptionsInstanceState) { diff --git a/app/http/routes/strategies_test.go b/app/http/routes/strategies_test.go index 2934a79..4be35d7 100644 --- a/app/http/routes/strategies_test.go +++ b/app/http/routes/strategies_test.go @@ -53,7 +53,7 @@ func TestServeStrategy_ServeDynamic(t *testing.T) { expectedHeaderValue string }{ { - name: "return HTML Theme", + name: "header has not ready value when not ready", arg: arg{ body: models.DynamicRequest{ Names: []string{"nginx"}, @@ -71,7 +71,7 @@ func TestServeStrategy_ServeDynamic(t *testing.T) { expectedHeaderValue: "not-ready", }, { - name: "temporary redirect when session is ready", + name: "header has ready value when session is ready", arg: arg{ body: models.DynamicRequest{ Names: []string{"nginx"}, @@ -112,6 +112,84 @@ func TestServeStrategy_ServeDynamic(t *testing.T) { } } +func TestServeStrategy_ServeBlocking(t *testing.T) { + type arg struct { + body models.BlockingRequest + session sessions.SessionState + } + tests := []struct { + name string + arg arg + expectedBody string + expectedHeaderKey string + expectedHeaderValue string + }{ + { + name: "not ready returns session status not ready", + arg: arg{ + body: models.BlockingRequest{ + Names: []string{"nginx"}, + Timeout: 10 * time.Second, + SessionDuration: 1 * time.Minute, + }, + session: sessions.SessionState{ + Instances: createMap([]*instance.State{ + {Name: "nginx", Status: instance.NotReady, CurrentReplicas: 0}, + }), + }, + }, + expectedBody: `{"session":{"instances":[{"instance":{"name":"nginx","currentReplicas":0,"status":"not-ready"},"error":null}],"status":"not-ready"}}`, + expectedHeaderKey: "X-Sablier-Session-Status", + expectedHeaderValue: "not-ready", + }, + { + name: "ready returns session status ready", + arg: arg{ + body: models.BlockingRequest{ + Names: []string{"nginx"}, + SessionDuration: 1 * time.Minute, + }, + session: sessions.SessionState{ + Instances: createMap([]*instance.State{ + {Name: "nginx", Status: instance.Ready, CurrentReplicas: 1}, + }), + }, + }, + expectedBody: `{"session":{"instances":[{"instance":{"name":"nginx","currentReplicas":1,"status":"ready"},"error":null}],"status":"ready"}}`, + expectedHeaderKey: "X-Sablier-Session-Status", + expectedHeaderValue: "ready", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + + s := &ServeStrategy{ + SessionsManager: &SessionsManagerMock{ + SessionState: tt.arg.session, + }, + StrategyConfig: config.NewStrategyConfig(), + } + recorder := httptest.NewRecorder() + c := GetTestGinContext(recorder) + MockJsonPost(c, tt.arg.body) + + s.ServeBlocking(c) + + res := recorder.Result() + defer res.Body.Close() + + bytes, err := io.ReadAll(res.Body) + + if err != nil { + panic(err) + } + + assert.Equal(t, c.Writer.Header().Get(tt.expectedHeaderKey), tt.expectedHeaderValue) + assert.Equal(t, string(bytes), tt.expectedBody) + }) + } +} + // mock gin context func GetTestGinContext(w *httptest.ResponseRecorder) *gin.Context { gin.SetMode(gin.TestMode) diff --git a/app/sessions/sessions_manager.go b/app/sessions/sessions_manager.go index be1b1cb..8134d6a 100644 --- a/app/sessions/sessions_manager.go +++ b/app/sessions/sessions_manager.go @@ -49,8 +49,8 @@ func (sm *SessionsManager) SaveSessions(writer io.WriteCloser) error { } type InstanceState struct { - Instance *instance.State - Error error + Instance *instance.State `json:"instance"` + Error error `json:"error"` } type SessionState struct { @@ -72,6 +72,14 @@ func (s *SessionState) IsReady() bool { return ready } +func (s *SessionState) Status() string { + if s.IsReady() { + return "ready" + } + + return "not-ready" +} + func (s *SessionsManager) RequestSession(names []string, duration time.Duration) (sessionState *SessionState) { if len(names) == 0 { @@ -194,5 +202,8 @@ func (s *SessionState) MarshalJSON() ([]byte, error) { return true }) - return json.Marshal(instances) + return json.Marshal(map[string]any{ + "instances": instances, + "status": s.Status(), + }) }