mirror of
https://github.com/sablierapp/sablier.git
synced 2025-12-24 06:28:21 +01:00
31
README.md
31
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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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(),
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user