Skip to content

Commit d1ad818

Browse files
authored
Merge pull request #75 from kmala/health
feat(appsettings): Add Maintanence support
2 parents e768455 + 47c6fd5 commit d1ad818

3 files changed

Lines changed: 327 additions & 0 deletions

File tree

api/appsettings.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package api
2+
3+
// AppSettings is the structure of an app's settings.
4+
type AppSettings struct {
5+
// Owner is the app owner. It cannot be updated with AppSettings.Set(). See app.Transfer().
6+
Owner string `json:"owner,omitempty"`
7+
// App is the app name. It cannot be updated at all right now.
8+
App string `json:"app,omitempty"`
9+
// Created is the time that the application settings was created and cannot be updated.
10+
Created string `json:"created,omitempty"`
11+
// Updated is the last time the application settings was changed and cannot be updated.
12+
Updated string `json:"updated,omitempty"`
13+
// UUID is a unique string reflecting the application settings in its current state.
14+
// It changes every time the application settings is changed and cannot be updated.
15+
UUID string `json:"uuid,omitempty"`
16+
// Maintenance determines if the application is taken down for maintenance or not.
17+
Maintenance *bool `json:"maintenance"`
18+
}

appsettings/appsettings.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// Package appsettings provides methods for managing application settings of apps.
2+
package appsettings
3+
4+
import (
5+
"encoding/json"
6+
"fmt"
7+
"io"
8+
"io/ioutil"
9+
10+
deis "github.com/deis/controller-sdk-go"
11+
"github.com/deis/controller-sdk-go/api"
12+
)
13+
14+
// List lists an app's settings.
15+
func List(c *deis.Client, app string) (api.AppSettings, error) {
16+
u := fmt.Sprintf("/v2/apps/%s/settings/", app)
17+
18+
res, reqErr := c.Request("GET", u, nil)
19+
if reqErr != nil {
20+
return api.AppSettings{}, reqErr
21+
}
22+
// Fix json.Decoder bug in <go1.7
23+
defer func() {
24+
io.Copy(ioutil.Discard, res.Body)
25+
res.Body.Close()
26+
}()
27+
28+
settings := api.AppSettings{}
29+
if err := json.NewDecoder(res.Body).Decode(&settings); err != nil {
30+
return api.AppSettings{}, err
31+
}
32+
33+
return settings, reqErr
34+
}
35+
36+
// Set sets an app's settings variables.
37+
// This is a patching operation, which means when you call Set() with an api.AppSettings:
38+
//
39+
// - If the variable does not exist, it will be set.
40+
// - If the variable exists, it will be overwritten.
41+
// - If the variable is set to nil, it will be unset.
42+
// - If the variable was ignored in the api.AppSettings, it will remain unchanged.
43+
//
44+
// Calling Set() with an empty api.AppSettings will return a deis.ErrConflict.
45+
func Set(c *deis.Client, app string, appSettings api.AppSettings) (api.AppSettings, error) {
46+
body, err := json.Marshal(appSettings)
47+
48+
if err != nil {
49+
return api.AppSettings{}, err
50+
}
51+
52+
u := fmt.Sprintf("/v2/apps/%s/settings/", app)
53+
54+
res, reqErr := c.Request("POST", u, body)
55+
if reqErr != nil {
56+
return api.AppSettings{}, reqErr
57+
}
58+
// Fix json.Decoder bug in <go1.7
59+
defer func() {
60+
io.Copy(ioutil.Discard, res.Body)
61+
res.Body.Close()
62+
}()
63+
64+
newAppSettings := api.AppSettings{}
65+
if err = json.NewDecoder(res.Body).Decode(&newAppSettings); err != nil {
66+
return api.AppSettings{}, err
67+
}
68+
69+
return newAppSettings, reqErr
70+
}

appsettings/appsettings_test.go

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
package appsettings
2+
3+
import (
4+
"fmt"
5+
"io/ioutil"
6+
"net/http"
7+
"net/http/httptest"
8+
"reflect"
9+
"testing"
10+
11+
deis "github.com/deis/controller-sdk-go"
12+
"github.com/deis/controller-sdk-go/api"
13+
)
14+
15+
const appSettingsFixture string = `
16+
{
17+
"owner": "test",
18+
"app": "example-go",
19+
"maintenance": true,
20+
"created": "2014-01-01T00:00:00UTC",
21+
"updated": "2014-01-01T00:00:00UTC",
22+
"uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
23+
}
24+
`
25+
26+
const appSettingsUnsetFixture string = `
27+
{
28+
"owner": "test",
29+
"app": "unset-test",
30+
"maintenance": true,
31+
"created": "2014-01-01T00:00:00UTC",
32+
"updated": "2014-01-01T00:00:00UTC",
33+
"uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
34+
}
35+
`
36+
37+
const appSettingsSetExpected string = `{"maintenance":true}`
38+
const appSettingsUnsetExpected string = `{"maintenance":true}`
39+
40+
var trueVar = true
41+
42+
type fakeHTTPServer struct{}
43+
44+
func (f *fakeHTTPServer) ServeHTTP(res http.ResponseWriter, req *http.Request) {
45+
res.Header().Add("DEIS_API_VERSION", deis.APIVersion)
46+
47+
if req.URL.Path == "/v2/apps/example-go/settings/" && req.Method == "POST" {
48+
body, err := ioutil.ReadAll(req.Body)
49+
50+
if err != nil {
51+
fmt.Println(err)
52+
res.WriteHeader(http.StatusInternalServerError)
53+
res.Write(nil)
54+
}
55+
56+
if string(body) != appSettingsSetExpected {
57+
fmt.Printf("Expected '%s', Got '%s'\n", appSettingsSetExpected, body)
58+
res.WriteHeader(http.StatusInternalServerError)
59+
res.Write(nil)
60+
return
61+
}
62+
63+
res.WriteHeader(http.StatusCreated)
64+
res.Write([]byte(appSettingsFixture))
65+
return
66+
}
67+
68+
if req.URL.Path == "/v2/apps/unset-test/settings/" && req.Method == "POST" {
69+
body, err := ioutil.ReadAll(req.Body)
70+
71+
if err != nil {
72+
fmt.Println(err)
73+
res.WriteHeader(http.StatusInternalServerError)
74+
res.Write(nil)
75+
}
76+
77+
if string(body) != appSettingsUnsetExpected {
78+
fmt.Printf("Expected '%s', Got '%s'\n", appSettingsUnsetExpected, body)
79+
res.WriteHeader(http.StatusInternalServerError)
80+
res.Write(nil)
81+
return
82+
}
83+
84+
res.WriteHeader(http.StatusCreated)
85+
res.Write([]byte(appSettingsUnsetFixture))
86+
return
87+
}
88+
89+
if req.URL.Path == "/v2/apps/invalidjson-test/settings/" && req.Method == "POST" {
90+
res.WriteHeader(http.StatusCreated)
91+
res.Write([]byte(`"maintenance": "test"`))
92+
return
93+
}
94+
95+
if req.URL.Path == "/v2/apps/example-go/settings/" && req.Method == "GET" {
96+
res.Write([]byte(appSettingsFixture))
97+
return
98+
}
99+
100+
if req.URL.Path == "/v2/apps/invalidjson-test/settings/" && req.Method == "GET" {
101+
res.Write([]byte(`"maintenance": "test"`))
102+
return
103+
}
104+
105+
fmt.Printf("Unrecognized URL %s\n", req.URL)
106+
res.WriteHeader(http.StatusNotFound)
107+
res.Write(nil)
108+
}
109+
110+
func TestAppSettingsSet(t *testing.T) {
111+
t.Parallel()
112+
113+
handler := fakeHTTPServer{}
114+
server := httptest.NewServer(&handler)
115+
defer server.Close()
116+
117+
deis, err := deis.New(false, server.URL, "abc")
118+
if err != nil {
119+
t.Fatal(err)
120+
}
121+
122+
expected := api.AppSettings{
123+
Owner: "test",
124+
App: "example-go",
125+
Maintenance: &trueVar,
126+
Created: "2014-01-01T00:00:00UTC",
127+
Updated: "2014-01-01T00:00:00UTC",
128+
UUID: "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75",
129+
}
130+
131+
appSettingsVars := api.AppSettings{
132+
Maintenance: &trueVar,
133+
}
134+
135+
actual, err := Set(deis, "example-go", appSettingsVars)
136+
137+
if err != nil {
138+
t.Error(err)
139+
}
140+
141+
if !reflect.DeepEqual(expected, actual) {
142+
t.Errorf("Expected %v, Got %v", expected, actual)
143+
}
144+
}
145+
146+
func TestAppSettingsUnset(t *testing.T) {
147+
t.Parallel()
148+
149+
handler := fakeHTTPServer{}
150+
server := httptest.NewServer(&handler)
151+
defer server.Close()
152+
153+
deis, err := deis.New(false, server.URL, "abc")
154+
if err != nil {
155+
t.Fatal(err)
156+
}
157+
158+
expected := api.AppSettings{
159+
Owner: "test",
160+
App: "unset-test",
161+
Maintenance: &trueVar,
162+
Created: "2014-01-01T00:00:00UTC",
163+
Updated: "2014-01-01T00:00:00UTC",
164+
UUID: "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75",
165+
}
166+
167+
appSettingsVars := api.AppSettings{
168+
Maintenance: &trueVar,
169+
}
170+
171+
actual, err := Set(deis, "unset-test", appSettingsVars)
172+
173+
if err != nil {
174+
t.Error(err)
175+
}
176+
177+
if !reflect.DeepEqual(expected, actual) {
178+
t.Errorf("Expected %v, Got %v", expected, actual)
179+
}
180+
}
181+
182+
func TestAppSettingsList(t *testing.T) {
183+
t.Parallel()
184+
185+
handler := fakeHTTPServer{}
186+
server := httptest.NewServer(&handler)
187+
defer server.Close()
188+
189+
deis, err := deis.New(false, server.URL, "abc")
190+
if err != nil {
191+
t.Fatal(err)
192+
}
193+
194+
expected := api.AppSettings{
195+
Owner: "test",
196+
App: "example-go",
197+
Maintenance: &trueVar,
198+
Created: "2014-01-01T00:00:00UTC",
199+
Updated: "2014-01-01T00:00:00UTC",
200+
UUID: "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75",
201+
}
202+
203+
actual, err := List(deis, "example-go")
204+
205+
if err != nil {
206+
t.Error(err)
207+
}
208+
209+
if !reflect.DeepEqual(expected, actual) {
210+
t.Errorf("Expected %v, Got %v", expected, actual)
211+
}
212+
}
213+
214+
func TestAppSettingsInvalidJson(t *testing.T) {
215+
t.Parallel()
216+
217+
handler := fakeHTTPServer{}
218+
server := httptest.NewServer(&handler)
219+
defer server.Close()
220+
221+
deis, err := deis.New(false, server.URL, "abc")
222+
if err != nil {
223+
t.Fatal(err)
224+
}
225+
226+
_, err = List(deis, "invalidjson-test")
227+
expected := "json: cannot unmarshal string into Go value of type api.AppSettings"
228+
if err == nil || !reflect.DeepEqual(expected, err.Error()) {
229+
t.Errorf("Expected %v, Got %v", expected, err)
230+
}
231+
232+
appSettingsVars := api.AppSettings{
233+
Maintenance: &trueVar,
234+
}
235+
_, err = Set(deis, "invalidjson-test", appSettingsVars)
236+
if err == nil || !reflect.DeepEqual(expected, err.Error()) {
237+
t.Errorf("Expected %v, Got %v", expected, err)
238+
}
239+
}

0 commit comments

Comments
 (0)