diff --git a/src/segment_nightscout.go b/src/segment_nightscout.go index 6e63fa9d..00cd148a 100644 --- a/src/segment_nightscout.go +++ b/src/segment_nightscout.go @@ -2,6 +2,7 @@ package main import ( "encoding/json" + "errors" ) // segment struct, makes templating easier @@ -82,46 +83,59 @@ func (ns *nightscout) string() string { } func (ns *nightscout) getResult() (*NightscoutData, error) { - url := ns.props.getString(URL, "") - // natural and understood NS timeout is 5, anything else is unusual - cacheTimeout := ns.props.getInt(NSCacheTimeout, 5) - response := &NightscoutData{} - if cacheTimeout > 0 { - // check if data stored in cache - val, found := ns.env.cache().get(url) + parseSingleElement := func(data []byte) (*NightscoutData, error) { + var result []*NightscoutData + err := json.Unmarshal(data, &result) + if err != nil { + return nil, err + } + if len(result) == 0 { + return nil, errors.New("no elements in the array") + } + return result[0], nil + } + getCacheValue := func(key string) (*NightscoutData, error) { + val, found := ns.env.cache().get(key) // we got something from the cache if found { - err := json.Unmarshal([]byte(val), response) - if err != nil { - return nil, err + if data, err := parseSingleElement([]byte(val)); err == nil { + return data, nil } - return response, nil + } + return nil, errors.New("no data in cache") + } + + url := ns.props.getString(URL, "") + httpTimeout := ns.props.getInt(HTTPTimeout, DefaultHTTPTimeout) + // natural and understood NS timeout is 5, anything else is unusual + cacheTimeout := ns.props.getInt(NSCacheTimeout, 5) + + if cacheTimeout > 0 { + if data, err := getCacheValue(url); err == nil { + return data, nil } } - httpTimeout := ns.props.getInt(HTTPTimeout, DefaultHTTPTimeout) - body, err := ns.env.doGet(url, httpTimeout) if err != nil { - return &NightscoutData{}, err + return nil, err } var arr []*NightscoutData err = json.Unmarshal(body, &arr) if err != nil { - return &NightscoutData{}, err + return nil, err } - firstelement := arr[0] - firstData, err := json.Marshal(firstelement) + data, err := parseSingleElement(body) if err != nil { - return &NightscoutData{}, err + return nil, err } if cacheTimeout > 0 { // persist new sugars in cache - ns.env.cache().set(url, string(firstData), cacheTimeout) + ns.env.cache().set(url, string(body), cacheTimeout) } - return firstelement, nil + return data, nil } func (ns *nightscout) init(props *properties, env environmentInfo) { diff --git a/src/segment_nightscout_test.go b/src/segment_nightscout_test.go index b3286904..3e5cb370 100644 --- a/src/segment_nightscout_test.go +++ b/src/segment_nightscout_test.go @@ -17,6 +17,8 @@ func TestNSSegment(t *testing.T) { JSONResponse string ExpectedString string ExpectedEnabled bool + CacheTimeout int + CacheFoundFail bool Template string Error error }{ @@ -82,18 +84,65 @@ func TestNSSegment(t *testing.T) { Error: errors.New("Something went wrong"), ExpectedEnabled: false, }, + { + Case: "Empty array", + JSONResponse: "[]", + ExpectedEnabled: false, + }, + { + Case: "DoubleDown 50 from cache", + JSONResponse: ` + [{"_id":"619d6fa819696e8ded5b2206","sgv":50,"date":1637707537000,"dateString":"2021-11-23T22:45:37.000Z","trend":4,"direction":"DoubleDown","device":"share2","type":"sgv","utcOffset":0,"sysTime":"2021-11-23T22:45:37.000Z","mills":1637707537000}]`, // nolint:lll + Template: " {{.Sgv}}{{.TrendIcon}}", + ExpectedString: " 50↓↓", + ExpectedEnabled: true, + CacheTimeout: 10, + }, + { + Case: "DoubleDown 50 from cache not found", + JSONResponse: ` + [{"_id":"619d6fa819696e8ded5b2206","sgv":50,"date":1637707537000,"dateString":"2021-11-23T22:45:37.000Z","trend":4,"direction":"DoubleDown","device":"share2","type":"sgv","utcOffset":0,"sysTime":"2021-11-23T22:45:37.000Z","mills":1637707537000}]`, // nolint:lll + Template: " {{.Sgv}}{{.TrendIcon}}", + ExpectedString: " 50↓↓", + ExpectedEnabled: true, + CacheTimeout: 10, + CacheFoundFail: true, + }, + { + Case: "Error parsing response", + JSONResponse: ` + 4tffgt4e4567`, + Template: " {{.Sgv}}{{.TrendIcon}}", + ExpectedString: " 50↓↓", + ExpectedEnabled: false, + CacheTimeout: 10, + }, + { + Case: "Faulty template", + JSONResponse: ` + [{"sgv":50,"direction":"DoubleDown"}]`, + Template: " {{.Sgv}}{{.Burp}}", + ExpectedString: incorrectTemplate, + ExpectedEnabled: true, + CacheTimeout: 10, + }, } for _, tc := range cases { env := &MockedEnvironment{} props := &properties{ values: map[Property]interface{}{ - CacheTimeout: 0, + CacheTimeout: tc.CacheTimeout, URL: "FAKE", }, } + cache := &MockedCache{} + cache.On("get", NSAPIURL).Return(tc.JSONResponse, !tc.CacheFoundFail) + cache.On("set", NSAPIURL, tc.JSONResponse, tc.CacheTimeout).Return() + env.On("doGet", NSAPIURL).Return([]byte(tc.JSONResponse), tc.Error) + env.On("cache", nil).Return(cache) if tc.Template != "" { props.values[SegmentTemplate] = tc.Template