revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73"
version = "v1.1.1"
+[[projects]]
+ digest = "1:a63cff6b5d8b95638bfe300385d93b2a6d9d687734b863da8e09dc834510a690"
+ name = "github.com/google/go-querystring"
+ packages = ["query"]
+ pruneopts = "UT"
+ revision = "44c6ddd0a2342c386950e880b658017258da92fc"
+ version = "v1.0.0"
+
[[projects]]
digest = "1:0028cb19b2e4c3112225cd871870f2d9cf49b9b4276531f03438a88e94be86fe"
name = "github.com/pmezard/go-difflib"
name = "github.com/stretchr/testify"
packages = [
"assert",
- "require",
+ "require"
]
pruneopts = "UT"
revision = "f35b8ab0b5a2cef36673838d662e249dd9c94686"
analyzer-version = 1
input-imports = [
"github.com/DreamItGetIT/statuscake",
+ "github.com/google/go-querystring/query",
"github.com/stretchr/testify/assert",
- "github.com/stretchr/testify/require",
+ "github.com/stretchr/testify/require"
]
solver-name = "gps-cdcl"
solver-version = 1
[prune]
go-tests = true
unused-packages = true
+
+[[constraint]]
+ name = "github.com/google/go-querystring"
+ version = "1.0.0"
--- /dev/null
+package statuscake
+
+import (
+ "bytes"
+ "io"
+ "io/ioutil"
+ "log"
+ "net/http"
+ "net/url"
+ "os"
+ "path/filepath"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestAuth_validate(t *testing.T) {
+ assert := assert.New(t)
+ require := require.New(t)
+
+ auth := &Auth{}
+ err := auth.validate()
+
+ require.NotNil(err)
+ assert.Contains(err.Error(), "Username is required")
+ assert.Contains(err.Error(), "Apikey is required")
+
+ auth.Username = "foo"
+ err = auth.validate()
+
+ require.NotNil(err)
+ assert.Equal("Apikey is required", err.Error())
+
+ auth.Apikey = "bar"
+ err = auth.validate()
+ assert.Nil(err)
+}
+
+func TestClient(t *testing.T) {
+ require := require.New(t)
+ assert := assert.New(t)
+
+ c, err := New(Auth{Username: "random-user", Apikey: "my-pass"})
+ require.Nil(err)
+
+ assert.Equal("random-user", c.username)
+ assert.Equal("my-pass", c.apiKey)
+}
+
+func TestClient_newRequest(t *testing.T) {
+ assert := assert.New(t)
+ require := require.New(t)
+
+ c, err := New(Auth{Username: "random-user", Apikey: "my-pass"})
+ require.Nil(err)
+
+ r, err := c.newRequest("GET", "/hello", nil, nil)
+
+ require.Nil(err)
+ assert.Equal("GET", r.Method)
+ assert.Equal("https://app.statuscake.com/API/hello", r.URL.String())
+ assert.Equal("random-user", r.Header.Get("Username"))
+ assert.Equal("my-pass", r.Header.Get("API"))
+}
+
+func TestClient_doRequest(t *testing.T) {
+ assert := assert.New(t)
+ require := require.New(t)
+
+ c, err := New(Auth{Username: "random-user", Apikey: "my-pass"})
+ require.Nil(err)
+
+ hc := &fakeHTTPClient{StatusCode: 200}
+ c.c = hc
+
+ req, err := http.NewRequest("GET", "http://example.com/test", nil)
+ require.Nil(err)
+
+ _, err = c.doRequest(req)
+ require.Nil(err)
+
+ assert.Len(hc.requests, 1)
+ assert.Equal("http://example.com/test", hc.requests[0].URL.String())
+}
+
+func TestClient_doRequest_WithHTTPErrors(t *testing.T) {
+ assert := assert.New(t)
+ require := require.New(t)
+
+ c, err := New(Auth{Username: "random-user", Apikey: "my-pass"})
+ require.Nil(err)
+
+ hc := &fakeHTTPClient{
+ StatusCode: 500,
+ }
+ c.c = hc
+
+ req, err := http.NewRequest("GET", "http://example.com/test", nil)
+ require.Nil(err)
+
+ _, err = c.doRequest(req)
+ require.NotNil(err)
+ assert.IsType(&httpError{}, err)
+}
+
+func TestClient_doRequest_HttpAuthenticationErrors(t *testing.T) {
+ assert := assert.New(t)
+ require := require.New(t)
+
+ c, err := New(Auth{Username: "random-user", Apikey: "my-pass"})
+ require.Nil(err)
+
+ hc := &fakeHTTPClient{
+ StatusCode: 200,
+ Fixture: "auth_error.json",
+ }
+ c.c = hc
+
+ req, err := http.NewRequest("GET", "http://example.com/test", nil)
+ require.Nil(err)
+
+ _, err = c.doRequest(req)
+ require.NotNil(err)
+ assert.IsType(&AuthenticationError{}, err)
+}
+
+func TestClient_get(t *testing.T) {
+ require := require.New(t)
+ assert := assert.New(t)
+
+ c, err := New(Auth{Username: "random-user", Apikey: "my-pass"})
+ require.Nil(err)
+
+ hc := &fakeHTTPClient{}
+ c.c = hc
+
+ c.get("/hello", nil)
+ assert.Len(hc.requests, 1)
+ assert.Equal("GET", hc.requests[0].Method)
+ assert.Equal("https://app.statuscake.com/API/hello", hc.requests[0].URL.String())
+}
+
+func TestClient_put(t *testing.T) {
+ require := require.New(t)
+ assert := assert.New(t)
+
+ c, err := New(Auth{Username: "random-user", Apikey: "my-pass"})
+ require.Nil(err)
+
+ hc := &fakeHTTPClient{}
+ c.c = hc
+
+ v := url.Values{"foo": {"bar"}}
+ c.put("/hello", v)
+ assert.Len(hc.requests, 1)
+ assert.Equal("PUT", hc.requests[0].Method)
+ assert.Equal("https://app.statuscake.com/API/hello", hc.requests[0].URL.String())
+
+ b, err := ioutil.ReadAll(hc.requests[0].Body)
+ require.Nil(err)
+ assert.Equal("foo=bar", string(b))
+}
+
+func TestClient_delete(t *testing.T) {
+ require := require.New(t)
+ assert := assert.New(t)
+
+ c, err := New(Auth{Username: "random-user", Apikey: "my-pass"})
+ require.Nil(err)
+
+ hc := &fakeHTTPClient{}
+ c.c = hc
+
+ v := url.Values{"foo": {"bar"}}
+ c.delete("/hello", v)
+ assert.Len(hc.requests, 1)
+ assert.Equal("DELETE", hc.requests[0].Method)
+ assert.Equal("https://app.statuscake.com/API/hello?foo=bar", hc.requests[0].URL.String())
+}
+
+func TestClient_Tests(t *testing.T) {
+ require := require.New(t)
+ assert := assert.New(t)
+
+ c, err := New(Auth{Username: "random-user", Apikey: "my-pass"})
+ require.Nil(err)
+
+ expected := &tests{
+ client: c,
+ }
+
+ assert.Equal(expected, c.Tests())
+}
+
+type fakeBody struct {
+ io.Reader
+}
+
+func (f *fakeBody) Close() error {
+ return nil
+}
+
+type fakeHTTPClient struct {
+ StatusCode int
+ Fixture string
+ requests []*http.Request
+}
+
+func (c *fakeHTTPClient) Do(r *http.Request) (*http.Response, error) {
+ c.requests = append(c.requests, r)
+ var body []byte
+
+ if c.Fixture != "" {
+ p := filepath.Join("fixtures", c.Fixture)
+ f, err := os.Open(p)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer f.Close()
+
+ b, err := ioutil.ReadAll(f)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ body = b
+ }
+
+ resp := &http.Response{
+ StatusCode: c.StatusCode,
+ Body: &fakeBody{Reader: bytes.NewReader(body)},
+ }
+
+ return resp, nil
+}
--- /dev/null
+package main
+
+import (
+ "fmt"
+ logpkg "log"
+ "os"
+ "strconv"
+
+ "github.com/DreamItGetIT/statuscake"
+ "strings"
+)
+
+var log *logpkg.Logger
+
+type command func(*statuscake.Client, ...string) error
+
+var commands map[string]command
+
+func init() {
+ log = logpkg.New(os.Stderr, "", 0)
+ commands = map[string]command{
+ "list": cmdList,
+ "detail": cmdDetail,
+ "delete": cmdDelete,
+ "create": cmdCreate,
+ "update": cmdUpdate,
+ }
+}
+
+func colouredStatus(s string) string {
+ switch s {
+ case "Up":
+ return fmt.Sprintf("\033[0;32m%s\033[0m", s)
+ case "Down":
+ return fmt.Sprintf("\033[0;31m%s\033[0m", s)
+ default:
+ return s
+ }
+}
+
+func getEnv(name string) string {
+ v := os.Getenv(name)
+ if v == "" {
+ log.Fatalf("`%s` env variable is required", name)
+ }
+
+ return v
+}
+
+func cmdList(c *statuscake.Client, args ...string) error {
+ tt := c.Tests()
+ tests, err := tt.All()
+ if err != nil {
+ return err
+ }
+
+ for _, t := range tests {
+ var paused string
+ if t.Paused {
+ paused = "yes"
+ } else {
+ paused = "no"
+ }
+
+ fmt.Printf("* %d: %s\n", t.TestID, colouredStatus(t.Status))
+ fmt.Printf(" WebsiteName: %s\n", t.WebsiteName)
+ fmt.Printf(" TestType: %s\n", t.TestType)
+ fmt.Printf(" Paused: %s\n", paused)
+ fmt.Printf(" ContactGroup: %s\n", fmt.Sprint(t.ContactGroup))
+ fmt.Printf(" Uptime: %f\n", t.Uptime)
+ }
+
+ return nil
+}
+
+func cmdDetail(c *statuscake.Client, args ...string) error {
+ if len(args) != 1 {
+ return fmt.Errorf("command `detail` requires a single argument `TestID`")
+ }
+
+ id, err := strconv.Atoi(args[0])
+ if err != nil {
+ return err
+ }
+
+ tt := c.Tests()
+ t, err := tt.Detail(id)
+ if err != nil {
+ return err
+ }
+
+ var paused string
+ if t.Paused {
+ paused = "yes"
+ } else {
+ paused = "no"
+ }
+
+ fmt.Printf("* %d: %s\n", t.TestID, colouredStatus(t.Status))
+ fmt.Printf(" WebsiteName: %s\n", t.WebsiteName)
+ fmt.Printf(" WebsiteURL: %s\n", t.WebsiteURL)
+ fmt.Printf(" PingURL: %s\n", t.PingURL)
+ fmt.Printf(" TestType: %s\n", t.TestType)
+ fmt.Printf(" Paused: %s\n", paused)
+ fmt.Printf(" ContactGroup: %s\n", fmt.Sprint(t.ContactGroup))
+ fmt.Printf(" Uptime: %f\n", t.Uptime)
+ fmt.Printf(" NodeLocations: %s\n", fmt.Sprint(t.NodeLocations))
+
+ return nil
+}
+
+func cmdDelete(c *statuscake.Client, args ...string) error {
+ if len(args) != 1 {
+ return fmt.Errorf("command `delete` requires a single argument `TestID`")
+ }
+
+ id, err := strconv.Atoi(args[0])
+ if err != nil {
+ return err
+ }
+
+ return c.Tests().Delete(id)
+}
+
+func askString(name string) string {
+ var v string
+
+ fmt.Printf("%s: ", name)
+ _, err := fmt.Scanln(&v)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ return v
+}
+
+func askInt(name string) int {
+ v := askString(name)
+ i, err := strconv.Atoi(v)
+ if err != nil {
+ log.Fatalf("Invalid number `%s`", v)
+ }
+
+ return i
+}
+
+func cmdCreate(c *statuscake.Client, args ...string) error {
+ websiteName := askString("WebsiteName")
+ websiteURL := askString("WebsiteURL")
+ testType := askString("TestType")
+ checkRate := askInt("CheckRate")
+ contactGroupString := askString("ContactGroup (comma separated list)")
+ contactGroup := strings.Split(contactGroupString, ",")
+ nodeLocationsString := askString("NodeLocations (comma separated list)")
+ nodeLocations := strings.Split(nodeLocationsString, ",")
+
+ t := &statuscake.Test{
+ WebsiteName: websiteName,
+ WebsiteURL: websiteURL,
+ TestType: testType,
+ CheckRate: checkRate,
+ NodeLocations: nodeLocations,
+ ContactGroup: contactGroup,
+ }
+
+ t2, err := c.Tests().Update(t)
+ if err != nil {
+ return err
+ }
+
+ fmt.Printf("CREATED: \n%+v\n", t2)
+
+ return nil
+}
+
+func cmdUpdate(c *statuscake.Client, args ...string) error {
+ if len(args) != 1 {
+ return fmt.Errorf("command `update` requires a single argument `TestID`")
+ }
+
+ id, err := strconv.Atoi(args[0])
+ if err != nil {
+ return err
+ }
+
+ tt := c.Tests()
+ t, err := tt.Detail(id)
+ if err != nil {
+ return err
+ }
+
+ t.TestID = id
+ t.WebsiteName = askString(fmt.Sprintf("WebsiteName [%s]", t.WebsiteName))
+ t.WebsiteURL = askString(fmt.Sprintf("WebsiteURL [%s]", t.WebsiteURL))
+ t.TestType = askString(fmt.Sprintf("TestType [%s]", t.TestType))
+ t.CheckRate = askInt(fmt.Sprintf("CheckRate [%d]", t.CheckRate))
+ contactGroupString := askString("ContactGroup (comma separated list)")
+ t.ContactGroup = strings.Split(contactGroupString, ",")
+ nodeLocationsString := askString("NodeLocations (comma separated list)")
+ t.NodeLocations = strings.Split(nodeLocationsString, ",")
+
+ t2, err := c.Tests().Update(t)
+ if err != nil {
+ return err
+ }
+
+ fmt.Printf("UPDATED: \n%+v\n", t2)
+
+ return nil
+}
+
+func usage() {
+ fmt.Printf("Usage:\n")
+ fmt.Printf(" %s COMMAND\n", os.Args[0])
+ fmt.Printf("Available commands:\n")
+ for k := range commands {
+ fmt.Printf(" %+v\n", k)
+ }
+}
+
+func main() {
+ username := getEnv("STATUSCAKE_USERNAME")
+ apikey := getEnv("STATUSCAKE_APIKEY")
+
+ if len(os.Args) < 2 {
+ usage()
+ os.Exit(1)
+ }
+
+ var err error
+
+ c, err := statuscake.New(statuscake.Auth{Username: username, Apikey: apikey})
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ if cmd, ok := commands[os.Args[1]]; ok {
+ err = cmd(c, os.Args[2:]...)
+ } else {
+ err = fmt.Errorf("Unknown command `%s`", os.Args[1])
+ }
+
+ if err != nil {
+ log.Fatalf("Error running command `%s`: %s", os.Args[1], err.Error())
+ }
+}
--- /dev/null
+{
+ "ErrNo": 0,
+ "Error": "Can not access account. Was both Username and API Key provided?"
+}
--- /dev/null
+{
+ "Success": true,
+ "Message": 143616,
+ "Input": {
+ "domain": "https://www.exemple.com",
+ "checkrate": "2073600",
+ "contact_groups": "",
+ "alert_reminder": true,
+ "alert_expiry": true,
+ "alert_broken": true,
+ "alert_mixed": true,
+ "alert_at": "7,18,2019"
+ }
+}
--- /dev/null
+{
+ "Success": true,
+ "Message": "Deletion successful"
+}
--- /dev/null
+[
+ {
+ "id": "143615",
+ "checkrate": 2073600,
+ "paused": false,
+ "domain": "https://www.exemple.com",
+ "issuer_cn": "Let's Encrypt Authority X3",
+ "cert_score": "95",
+ "cipher_score": "100",
+ "cert_status": "CERT_OK",
+ "cipher": "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
+ "valid_from_utc": "2019-05-28 01:22:00",
+ "valid_until_utc": "2019-08-26 01:22:00",
+ "mixed_content": [],
+ "flags": {
+ "is_extended": false,
+ "has_pfs": true,
+ "is_broken": false,
+ "is_expired": false,
+ "is_missing": false,
+ "is_revoked": false,
+ "has_mixed": false
+ },
+ "contact_groups": [],
+ "alert_at": "7,18,2019",
+ "last_reminder": 2019,
+ "alert_reminder": true,
+ "alert_expiry": true,
+ "alert_broken": true,
+ "alert_mixed": true,
+ "last_updated_utc": "2019-06-20 10:11:03"
+ },
+ {
+ "id": "143616",
+ "checkrate": 2073600,
+ "paused": false,
+ "domain": "https://www.exemple.com",
+ "issuer_cn": "Let's Encrypt Authority X3",
+ "cert_score": "95",
+ "cipher_score": "100",
+ "cert_status": "CERT_OK",
+ "cipher": "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
+ "valid_from_utc": "2019-05-28 01:22:00",
+ "valid_until_utc": "2019-08-26 01:22:00",
+ "mixed_content": [
+ {
+ "type": "img",
+ "src": "http://example.com/image.gif"
+ }
+ ],
+ "flags": {
+ "is_extended": false,
+ "has_pfs": true,
+ "is_broken": false,
+ "is_expired": false,
+ "is_missing": false,
+ "is_revoked": false,
+ "has_mixed": false
+ },
+ "contact_groups": ["12","13","34"],
+ "alert_at": "7,18,2019",
+ "last_reminder": 2019,
+ "alert_reminder": true,
+ "alert_expiry": true,
+ "alert_broken": true,
+ "alert_mixed": true,
+ "last_updated_utc": "2019-06-20 10:23:14"
+ },
+ {
+ "id": "143617",
+ "checkrate": 2073600,
+ "paused": false,
+ "domain": "https://www.exemple.com",
+ "issuer_cn": "Let's Encrypt Authority X3",
+ "cert_score": "95",
+ "cipher_score": "100",
+ "cert_status": "CERT_OK",
+ "cipher": "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
+ "valid_from_utc": "2019-05-28 01:22:00",
+ "valid_until_utc": "2019-08-26 01:22:00",
+ "mixed_content": [],
+ "flags": {
+ "is_extended": false,
+ "has_pfs": true,
+ "is_broken": false,
+ "is_expired": false,
+ "is_missing": false,
+ "is_revoked": false,
+ "has_mixed": false
+ },
+ "contact_groups": [],
+ "alert_at": "7,18,2019",
+ "last_reminder": 2019,
+ "alert_reminder": true,
+ "alert_expiry": true,
+ "alert_broken": true,
+ "alert_mixed": true,
+ "last_updated_utc": "2019-06-20 10:23:20"
+ }
+]
--- /dev/null
+{
+ "Success": true,
+ "Message": "SSL test has been updated successfully"
+}
--- /dev/null
+[
+ {
+ "id": "12345",
+ "paused": false,
+ "domain": "https://google.com",
+ "cert_score": "95",
+ "cipher_score": "100",
+ "cert_status": "CERT_OK",
+ "cipher": "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
+ "valid_from_utc": "2017-10-10 14:06:00",
+ "valid_until_utc": "2017-12-29 00:00:00",
+ "mixed_content": [
+ {
+ "type": "img",
+ "src": "http://example.com/image.gif"
+ }
+ ],
+ "flags": {
+ "is_extended": false,
+ "has_pfs": true,
+ "is_broken": false,
+ "is_expired": false,
+ "is_missing": false,
+ "is_revoked": false,
+ "is_mixed": false
+ },
+ "contact_groups": [12, 13, 14],
+ "alert_at": "1,7,30",
+ "last_reminder": 0,
+ "alert_reminder": false,
+ "alert_expiry": false,
+ "alert_broken": false,
+ "alert_mixed": false,
+ "last_updated_utc": "2017-10-24 09:02:25"
+ },
+ {
+ "id": "12346",
+ "paused": false,
+ "domain": "https://google2.com",
+ "cert_score": "95",
+ "cipher_score": "100",
+ "cert_status": "CERT_OK",
+ "cipher": "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
+ "valid_from_utc": "2017-10-10 14:06:00",
+ "valid_until_utc": "2017-12-29 00:00:00",
+ "mixed_content": [
+ {
+ "type": "img",
+ "src": "http://example.com/image.gif"
+ }
+ ],
+ "flags": {
+ "is_extended": false,
+ "has_pfs": true,
+ "is_broken": false,
+ "is_expired": false,
+ "is_missing": false,
+ "is_revoked": false,
+ "is_mixed": false
+ },
+ "contact_groups": [12, 13, 14],
+ "alert_at": "1,7,30",
+ "last_reminder": 0,
+ "alert_reminder": false,
+ "alert_expiry": false,
+ "alert_broken": false,
+ "alert_mixed": false,
+ "last_updated_utc": "2017-10-24 09:02:25"
+ }
+]
--- /dev/null
+{
+ "Success": true,
+ "Message": 12345,
+ "Input": {
+ "domain": "https://example.com",
+ "checkrate": 86400,
+ "contact_groups": "1000,2000",
+ "alert_reminder": false,
+ "alert_expiry": false,
+ "alert_broken": false,
+ "alert_at": "59,60,61"
+ }
+}
--- /dev/null
+{
+ "Success": false,
+ "Message": "Error creating test",
+ "Input": {
+ "domain": "https://example.com",
+ "checkrate": 86400,
+ "contact_groups": "1000,2000",
+ "alert_reminder": false,
+ "alert_expiry": false,
+ "alert_broken": false,
+ "alert_at": "59,60,61"
+ }
+}
--- /dev/null
+{
+ "Success": true,
+ "Message": "SSL test has been updated successfully"
+}
--- /dev/null
+[
+ {
+ "TestID": 100,
+ "Paused": false,
+ "TestType": "HTTP",
+ "WebsiteName": "www 1",
+ "ContactGroup": ["1"],
+ "Status": "Up",
+ "Uptime": 100,
+ "NodeLocations": ["foo", "bar"]
+ },
+ {
+ "TestID": 101,
+ "Paused": true,
+ "TestType": "HTTP",
+ "WebsiteName": "www 2",
+ "ContactGroup": ["2"],
+ "Status": "Down",
+ "Uptime": 0,
+ "NodeLocations": ["foo"],
+ "TestTags": ["test1", "test2"]
+ }
+]
--- /dev/null
+{
+ "Success": false,
+ "Error": "this is an error"
+}
+
--- /dev/null
+{
+ "TestID": 6735,
+ "Affected": 1,
+ "Success": true,
+ "Message": "This Check Has Been Deleted. It can not be recovered."
+}
--- /dev/null
+{
+ "TestID": 6735,
+ "TestType": "HTTP",
+ "Paused": false,
+ "WebsiteName": "NL",
+ "CustomHeader": "{\"some\":{\"json\": [\"value\"]}}",
+ "UserAgent": "product/version (comment)",
+ "ContactGroups": [
+ {
+ "ID": 536,
+ "Name": "Dummy ContactGroup",
+ "Email": "github-dreamitgetit-statuscake@maildrop.cc"
+ }
+ ],
+ "ContactID": 536,
+ "Status": "Up",
+ "Uptime": 0,
+ "CheckRate": 60,
+ "Timeout": 40,
+ "LogoImage": "",
+ "WebsiteHost": "Various",
+ "NodeLocations": [
+ "foo",
+ "bar"
+ ],
+ "FindString": "",
+ "DoNotFind": false,
+ "LastTested": "2013-01-20 14:38:18",
+ "NextLocation": "USNY",
+ "Processing": false,
+ "ProcessingState": "Pretest",
+ "ProcessingOn": "dalas.localdomain",
+ "DownTimes": "0",
+ "UseJar": 0,
+ "PostRaw": "",
+ "FinalEndpoint": "",
+ "EnableSSLWarning": false,
+ "FollowRedirect": false
+}
--- /dev/null
+{
+ "Issues": {
+ "WebsiteName": "issue a",
+ "WebsiteURL": "issue b",
+ "CheckRate": "issue c"
+ },
+ "Success": false,
+ "Message": "Required Data is Missing."
+}
--- /dev/null
+{
+ "Issues": ["hello", "world"],
+ "Success": false,
+ "Message": "Required Data is Missing."
+}
--- /dev/null
+{
+ "Issues": {},
+ "Success": true,
+ "Message": "",
+ "InsertID": 1234
+}
--- /dev/null
+package statuscake
+
+import (
+ "encoding/json"
+ "fmt"
+ "net/url"
+ "strings"
+ "strconv"
+
+ "github.com/google/go-querystring/query"
+)
+
+//Ssl represent the data received by the API with GET
+type Ssl struct {
+ ID string `json:"id" url:"id,omitempty"`
+ Domain string `json:"domain" url:"domain,omitempty"`
+ Checkrate int `json:"checkrate" url:"checkrate,omitempty"`
+ ContactGroupsC string ` url:"contact_groups,omitempty"`
+ AlertAt string `json:"alert_at" url:"alert_at,omitempty"`
+ AlertReminder bool `json:"alert_reminder" url:"alert_expiry,omitempty"`
+ AlertExpiry bool `json:"alert_expiry" url:"alert_reminder,omitempty"`
+ AlertBroken bool `json:"alert_broken" url:"alert_broken,omitempty"`
+ AlertMixed bool `json:"alert_mixed" url:"alert_mixed,omitempty"`
+ Paused bool `json:"paused"`
+ IssuerCn string `json:"issuer_cn"`
+ CertScore string `json:"cert_score"`
+ CipherScore string `json:"cipher_score"`
+ CertStatus string `json:"cert_status"`
+ Cipher string `json:"cipher"`
+ ValidFromUtc string `json:"valid_from_utc"`
+ ValidUntilUtc string `json:"valid_until_utc"`
+ MixedContent []map[string]string `json:"mixed_content"`
+ Flags map[string]bool `json:"flags"`
+ ContactGroups []string `json:"contact_groups"`
+ LastReminder int `json:"last_reminder"`
+ LastUpdatedUtc string `json:"last_updated_utc"`
+}
+
+//PartialSsl represent a ssl test creation or modification
+type PartialSsl struct {
+ ID int
+ Domain string
+ Checkrate string
+ ContactGroupsC string
+ AlertAt string
+ AlertExpiry bool
+ AlertReminder bool
+ AlertBroken bool
+ AlertMixed bool
+}
+
+type createSsl struct {
+ ID int `url:"id,omitempty"`
+ Domain string `url:"domain" json:"domain"`
+ Checkrate string `url:"checkrate" json:"checkrate"`
+ ContactGroupsC string `url:"contact_groups" json:"contact_groups"`
+ AlertAt string `url:"alert_at" json:"alert_at"`
+ AlertExpiry bool `url:"alert_expiry" json:"alert_expiry"`
+ AlertReminder bool `url:"alert_reminder" json:"alert_reminder"`
+ AlertBroken bool `url:"alert_broken" json:"alert_broken"`
+ AlertMixed bool `url:"alert_mixed" json:"alert_mixed"`
+}
+
+type updateSsl struct {
+ ID int `url:"id"`
+ Domain string `url:"domain" json:"domain"`
+ Checkrate string `url:"checkrate" json:"checkrate"`
+ ContactGroupsC string `url:"contact_groups" json:"contact_groups"`
+ AlertAt string `url:"alert_at" json:"alert_at"`
+ AlertExpiry bool `url:"alert_expiry" json:"alert_expiry"`
+ AlertReminder bool `url:"alert_reminder" json:"alert_reminder"`
+ AlertBroken bool `url:"alert_broken" json:"alert_broken"`
+ AlertMixed bool `url:"alert_mixed" json:"alert_mixed"`
+}
+
+
+type sslUpdateResponse struct {
+ Success bool `json:"Success"`
+ Message interface{} `json:"Message"`
+}
+
+type sslCreateResponse struct {
+ Success bool `json:"Success"`
+ Message interface{} `json:"Message"`
+ Input createSsl `json:"Input"`
+}
+
+//Ssls represent the actions done wit the API
+type Ssls interface {
+ All() ([]*Ssl, error)
+ completeSsl(*PartialSsl) (*Ssl, error)
+ Detail(string) (*Ssl, error)
+ Update(*PartialSsl) (*Ssl, error)
+ UpdatePartial(*PartialSsl) (*PartialSsl, error)
+ Delete(ID string) error
+ CreatePartial(*PartialSsl) (*PartialSsl, error)
+ Create(*PartialSsl) (*Ssl, error)
+}
+
+func consolidateSsl(s *Ssl) {
+ (*s).ContactGroupsC = strings.Trim(strings.Join(strings.Fields(fmt.Sprint((*s).ContactGroups)), ","), "[]")
+}
+
+func findSsl(responses []*Ssl, id string) (*Ssl, error) {
+ var response *Ssl
+ for _, elem := range responses {
+ if (*elem).ID == id {
+ return elem, nil
+ }
+ }
+ return response, fmt.Errorf("%s Not found", id)
+}
+
+func (tt *ssls) completeSsl(s *PartialSsl) (*Ssl, error) {
+ full, err := tt.Detail(strconv.Itoa((*s).ID))
+ if err != nil {
+ return nil, err
+ }
+ (*full).ContactGroups = strings.Split((*s).ContactGroupsC,",")
+ return full, nil
+}
+
+//Partial return a PartialSsl corresponding to the Ssl
+func Partial(s *Ssl) (*PartialSsl,error) {
+ if s==nil {
+ return nil,fmt.Errorf("s is nil")
+ }
+ id,err:=strconv.Atoi(s.ID)
+ if(err!=nil){
+ return nil,err
+ }
+ return &PartialSsl{
+ ID: id,
+ Domain: s.Domain,
+ Checkrate: strconv.Itoa(s.Checkrate),
+ ContactGroupsC: s.ContactGroupsC,
+ AlertReminder: s.AlertReminder,
+ AlertExpiry: s.AlertExpiry,
+ AlertBroken: s.AlertBroken,
+ AlertMixed: s.AlertMixed,
+ AlertAt: s.AlertAt,
+ },nil
+
+}
+
+type ssls struct {
+ client apiClient
+}
+
+//NewSsls return a new ssls
+func NewSsls(c apiClient) Ssls {
+ return &ssls{
+ client: c,
+ }
+}
+
+//All return a list of all the ssl from the API
+func (tt *ssls) All() ([]*Ssl, error) {
+ rawResponse, err := tt.client.get("/SSL", nil)
+ if err != nil {
+ return nil, fmt.Errorf("Error getting StatusCake Ssl: %s", err.Error())
+ }
+ var getResponse []*Ssl
+ err = json.NewDecoder(rawResponse.Body).Decode(&getResponse)
+ if err != nil {
+ return nil, err
+ }
+
+ for ssl := range getResponse {
+ consolidateSsl(getResponse[ssl])
+ }
+
+ return getResponse, err
+}
+
+//Detail return the ssl corresponding to the id
+func (tt *ssls) Detail(id string) (*Ssl, error) {
+ responses, err := tt.All()
+ if err != nil {
+ return nil, err
+ }
+ mySsl, errF := findSsl(responses, id)
+ if errF != nil {
+ return nil, errF
+ }
+ return mySsl, nil
+}
+
+//Update update the API with s and create one if s.ID=0 then return the corresponding Ssl
+func (tt *ssls) Update(s *PartialSsl) (*Ssl, error) {
+ var err error
+ s, err = tt.UpdatePartial(s)
+ if err!= nil {
+ return nil, err
+ }
+ return tt.completeSsl(s)
+}
+
+//UpdatePartial update the API with s and create one if s.ID=0 then return the corresponding PartialSsl
+func (tt *ssls) UpdatePartial(s *PartialSsl) (*PartialSsl, error) {
+
+ if((*s).ID == 0){
+ return tt.CreatePartial(s)
+ }
+ var v url.Values
+
+ v, _ = query.Values(updateSsl(*s))
+
+ rawResponse, err := tt.client.put("/SSL/Update", v)
+ if err != nil {
+ return nil, fmt.Errorf("Error creating StatusCake Ssl: %s", err.Error())
+ }
+
+ var updateResponse sslUpdateResponse
+ err = json.NewDecoder(rawResponse.Body).Decode(&updateResponse)
+ if err != nil {
+ return nil, err
+ }
+
+ if !updateResponse.Success {
+ return nil, fmt.Errorf("%s", updateResponse.Message.(string))
+ }
+
+
+ return s, nil
+}
+
+//Delete delete the ssl which ID is id
+func (tt *ssls) Delete(id string) error {
+ _, err := tt.client.delete("/SSL/Update", url.Values{"id": {fmt.Sprint(id)}})
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+//Create create the ssl whith the data in s and return the Ssl created
+func (tt *ssls) Create(s *PartialSsl) (*Ssl, error) {
+ var err error
+ s, err = tt.CreatePartial(s)
+ if err!= nil {
+ return nil, err
+ }
+ return tt.completeSsl(s)
+}
+
+//CreatePartial create the ssl whith the data in s and return the PartialSsl created
+func (tt *ssls) CreatePartial(s *PartialSsl) (*PartialSsl, error) {
+ (*s).ID=0
+ var v url.Values
+ v, _ = query.Values(createSsl(*s))
+
+ rawResponse, err := tt.client.put("/SSL/Update", v)
+ if err != nil {
+ return nil, fmt.Errorf("Error creating StatusCake Ssl: %s", err.Error())
+ }
+
+ var createResponse sslCreateResponse
+ err = json.NewDecoder(rawResponse.Body).Decode(&createResponse)
+ if err != nil {
+ return nil, err
+ }
+
+ if !createResponse.Success {
+ return nil, fmt.Errorf("%s", createResponse.Message.(string))
+ }
+ *s = PartialSsl(createResponse.Input)
+ (*s).ID = int(createResponse.Message.(float64))
+
+ return s,nil
+}
+
--- /dev/null
+package statuscake
+
+import (
+ "testing"
+ //"fmt"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+ "net/url"
+)
+
+func TestSsl_All(t *testing.T) {
+ assert := assert.New(t)
+ require := require.New(t)
+
+ c := &fakeAPIClient{
+ fixture: "sslListAllOk.json",
+ }
+ tt := NewSsls(c)
+ ssls, err := tt.All()
+ require.Nil(err)
+
+ assert.Equal("/SSL", c.sentRequestPath)
+ assert.Equal("GET", c.sentRequestMethod)
+ assert.Nil(c.sentRequestValues)
+ assert.Len(ssls, 3)
+ mixed := make(map[string]string)
+ flags := make(map[string]bool)
+ flags["is_extended"] = false
+ flags["has_pfs"] = true
+ flags["is_broken"] = false
+ flags["is_expired"] = false
+ flags["is_missing"] = false
+ flags["is_revoked"] = false
+ flags["has_mixed"] = false
+ expectedTest := &Ssl{
+ ID: "143615",
+ Checkrate: 2073600,
+ Paused: false,
+ Domain: "https://www.exemple.com",
+ IssuerCn: "Let's Encrypt Authority X3",
+ CertScore: "95",
+ CipherScore: "100",
+ CertStatus: "CERT_OK",
+ Cipher: "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
+ ValidFromUtc: "2019-05-28 01:22:00",
+ ValidUntilUtc: "2019-08-26 01:22:00",
+ MixedContent: []map[string]string{},
+ Flags: flags,
+ ContactGroups: []string{},
+ ContactGroupsC: "",
+ AlertAt: "7,18,2019",
+ LastReminder: 2019,
+ AlertReminder: true,
+ AlertExpiry: true,
+ AlertBroken: true,
+ AlertMixed: true,
+ LastUpdatedUtc: "2019-06-20 10:11:03",
+ }
+ assert.Equal(expectedTest, ssls[0])
+
+ expectedTest.ID="143617"
+ expectedTest.LastUpdatedUtc="2019-06-20 10:23:20"
+ assert.Equal(expectedTest, ssls[2])
+
+ expectedTest.ID="143616"
+ expectedTest.LastUpdatedUtc="2019-06-20 10:23:14"
+ mixed["type"]="img"
+ mixed["src"]="http://example.com/image.gif"
+ expectedTest.MixedContent=[]map[string]string{mixed}
+ expectedTest.ContactGroupsC="12,13,34"
+ expectedTest.ContactGroups=[]string{"12","13","34"}
+ assert.Equal(expectedTest, ssls[1])
+}
+
+func TestSsls_Detail_OK(t *testing.T) {
+ assert := assert.New(t)
+ require := require.New(t)
+
+ c := &fakeAPIClient{
+ fixture: "sslListAllOk.json",
+ }
+ tt := NewSsls(c)
+
+ ssl, err := tt.Detail("143616")
+ require.Nil(err)
+ assert.Equal("/SSL", c.sentRequestPath)
+ assert.Equal("GET", c.sentRequestMethod)
+ assert.Nil(c.sentRequestValues)
+
+ mixed := make(map[string]string)
+ flags := make(map[string]bool)
+
+ mixed["type"]="img"
+ mixed["src"]="http://example.com/image.gif"
+
+ flags["is_extended"] = false
+ flags["has_pfs"] = true
+ flags["is_broken"] = false
+ flags["is_expired"] = false
+ flags["is_missing"] = false
+ flags["is_revoked"] = false
+ flags["has_mixed"] = false
+ expectedTest := &Ssl{
+ ID: "143616",
+ Checkrate: 2073600,
+ Paused: false,
+ Domain: "https://www.exemple.com",
+ IssuerCn: "Let's Encrypt Authority X3",
+ CertScore: "95",
+ CipherScore: "100",
+ CertStatus: "CERT_OK",
+ Cipher: "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
+ ValidFromUtc: "2019-05-28 01:22:00",
+ ValidUntilUtc: "2019-08-26 01:22:00",
+ MixedContent: []map[string]string{mixed},
+ Flags: flags,
+ ContactGroups: []string{"12","13","34"},
+ ContactGroupsC: "12,13,34",
+ AlertAt: "7,18,2019",
+ LastReminder: 2019,
+ AlertReminder: true,
+ AlertExpiry: true,
+ AlertBroken: true,
+ AlertMixed: true,
+ LastUpdatedUtc: "2019-06-20 10:23:14",
+ }
+
+ assert.Equal(expectedTest, ssl)
+}
+
+func TestSsls_CreatePartial_OK(t *testing.T) {
+ assert := assert.New(t)
+ require := require.New(t)
+
+ c := &fakeAPIClient{
+ fixture: "sslCreateOk.json",
+ }
+ tt := NewSsls(c)
+ partial := &PartialSsl{
+ Domain: "https://www.exemple.com",
+ Checkrate: "2073600",
+ ContactGroupsC: "",
+ AlertReminder: true,
+ AlertExpiry: true,
+ AlertBroken: true,
+ AlertMixed: true,
+ AlertAt: "7,18,2019",
+ }
+ expectedRes := &PartialSsl {
+ ID: 143616,
+ Domain: "https://www.exemple.com",
+ Checkrate: "2073600",
+ ContactGroupsC: "",
+ AlertReminder: true,
+ AlertExpiry: true,
+ AlertBroken: true,
+ AlertMixed: true,
+ AlertAt: "7,18,2019",
+ }
+ res, err := tt.CreatePartial(partial)
+ require.Nil(err)
+ assert.Equal("/SSL/Update", c.sentRequestPath)
+ assert.Equal("PUT", c.sentRequestMethod)
+ assert.Equal(c.sentRequestValues,url.Values(url.Values{"domain":[]string{"https://www.exemple.com"}, "checkrate":[]string{"2073600"}, "contact_groups":[]string{""}, "alert_at":[]string{"7,18,2019"}, "alert_expiry":[]string{"true"}, "alert_reminder":[]string{"true"}, "alert_broken":[]string{"true"}, "alert_mixed":[]string{"true"}}))
+
+ assert.Equal(expectedRes, res)
+}
+
+func TestSsls_UpdatePartial_OK(t *testing.T) {
+ assert := assert.New(t)
+ require := require.New(t)
+
+ c := &fakeAPIClient{
+ fixture: "sslUpdateOk.json",
+ }
+ tt := NewSsls(c)
+ partial := &PartialSsl{
+ ID: 143616,
+ Domain: "https://www.exemple.com",
+ Checkrate: "2073600",
+ ContactGroupsC: "",
+ AlertReminder: false,
+ AlertExpiry: true,
+ AlertBroken: true,
+ AlertMixed: true,
+ AlertAt: "7,18,2019",
+ }
+ expectedRes := &PartialSsl {
+ ID: 143616,
+ Domain: "https://www.exemple.com",
+ Checkrate: "2073600",
+ ContactGroupsC: "",
+ AlertReminder: false,
+ AlertExpiry: true,
+ AlertBroken: true,
+ AlertMixed: true,
+ AlertAt: "7,18,2019",
+ }
+ res, err := tt.UpdatePartial(partial)
+ require.Nil(err)
+ assert.Equal(expectedRes, res)
+ assert.Equal("/SSL/Update", c.sentRequestPath)
+ assert.Equal("PUT", c.sentRequestMethod)
+ assert.Equal(c.sentRequestValues,url.Values(url.Values{"id":[]string{"143616"},"domain":[]string{"https://www.exemple.com"}, "checkrate":[]string{"2073600"}, "contact_groups":[]string{""}, "alert_at":[]string{"7,18,2019"}, "alert_expiry":[]string{"true"}, "alert_reminder":[]string{"false"}, "alert_broken":[]string{"true"}, "alert_mixed":[]string{"true"}}))
+}
+
+func TestSsl_complete_OK(t *testing.T) {
+ assert := assert.New(t)
+ require := require.New(t)
+
+ c := &fakeAPIClient{
+ fixture: "sslListAllOk.json",
+ }
+ tt := NewSsls(c)
+
+ partial := &PartialSsl {
+ ID: 143616,
+ Domain: "https://www.exemple.com",
+ Checkrate: "2073600",
+ ContactGroupsC: "12,13,34",
+ AlertReminder: true,
+ AlertExpiry: true,
+ AlertBroken: true,
+ AlertMixed: true,
+ AlertAt: "7,18,2019",
+ }
+ full, err := tt.completeSsl(partial)
+ require.Nil(err)
+ mixed := make(map[string]string)
+ flags := make(map[string]bool)
+
+ mixed["type"]="img"
+ mixed["src"]="http://example.com/image.gif"
+
+ flags["is_extended"] = false
+ flags["has_pfs"] = true
+ flags["is_broken"] = false
+ flags["is_expired"] = false
+ flags["is_missing"] = false
+ flags["is_revoked"] = false
+ flags["has_mixed"] = false
+ expectedTest := &Ssl{
+ ID: "143616",
+ Checkrate: 2073600,
+ Paused: false,
+ Domain: "https://www.exemple.com",
+ IssuerCn: "Let's Encrypt Authority X3",
+ CertScore: "95",
+ CipherScore: "100",
+ CertStatus: "CERT_OK",
+ Cipher: "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
+ ValidFromUtc: "2019-05-28 01:22:00",
+ ValidUntilUtc: "2019-08-26 01:22:00",
+ MixedContent: []map[string]string{mixed},
+ Flags: flags,
+ ContactGroups: []string{"12","13","34"},
+ ContactGroupsC: "12,13,34",
+ AlertAt: "7,18,2019",
+ LastReminder: 2019,
+ AlertReminder: true,
+ AlertExpiry: true,
+ AlertBroken: true,
+ AlertMixed: true,
+ LastUpdatedUtc: "2019-06-20 10:23:14",
+ }
+
+ assert.Equal(expectedTest, full)
+
+}
+
+func TestSsl_partial_OK(t *testing.T) {
+ assert := assert.New(t)
+ require := require.New(t)
+
+ mixed := make(map[string]string)
+ flags := make(map[string]bool)
+
+ mixed["type"]="img"
+ mixed["src"]="http://example.com/image.gif"
+
+ flags["is_extended"] = false
+ flags["has_pfs"] = true
+ flags["is_broken"] = false
+ flags["is_expired"] = false
+ flags["is_missing"] = false
+ flags["is_revoked"] = false
+ flags["has_mixed"] = false
+ full := &Ssl{
+ ID: "143616",
+ Checkrate: 2073600,
+ Paused: false,
+ Domain: "https://www.exemple.com",
+ IssuerCn: "Let's Encrypt Authority X3",
+ CertScore: "95",
+ CipherScore: "100",
+ CertStatus: "CERT_OK",
+ Cipher: "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
+ ValidFromUtc: "2019-05-28 01:22:00",
+ ValidUntilUtc: "2019-08-26 01:22:00",
+ MixedContent: []map[string]string{mixed},
+ Flags: flags,
+ ContactGroups: []string{"12","13","34"},
+ ContactGroupsC: "12,13,34",
+ AlertAt: "7,18,2019",
+ LastReminder: 2019,
+ AlertReminder: true,
+ AlertExpiry: true,
+ AlertBroken: true,
+ AlertMixed: true,
+ LastUpdatedUtc: "2019-06-20 10:23:14",
+ }
+ expectedTest:=&PartialSsl {
+ ID: 143616,
+ Domain: "https://www.exemple.com",
+ Checkrate: "2073600",
+ ContactGroupsC: "12,13,34",
+ AlertReminder: true,
+ AlertExpiry: true,
+ AlertBroken: true,
+ AlertMixed: true,
+ AlertAt: "7,18,2019",
+ }
+ partial,err:=Partial(full)
+ require.Nil(err)
+ assert.Equal(expectedTest, partial)
+
+}
+
+func TestSsls_Delete_OK(t *testing.T) {
+ assert := assert.New(t)
+ require := require.New(t)
+
+ c := &fakeAPIClient{
+ fixture: "sslDeleteOk.json",
+ }
+ tt := NewSsls(c)
+
+ err := tt.Delete("143616")
+ require.Nil(err)
+ assert.Equal("/SSL/Update", c.sentRequestPath)
+ assert.Equal("DELETE", c.sentRequestMethod)
+ assert.Equal(c.sentRequestValues,url.Values(url.Values{"id":[]string{"143616"},},))
+}
--- /dev/null
+package statuscake
+
+import (
+ "bytes"
+ "encoding/json"
+ "io/ioutil"
+ "log"
+ "net/http"
+ "net/url"
+ "os"
+ "path/filepath"
+ "strings"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestTest_Validate(t *testing.T) {
+ assert := assert.New(t)
+ require := require.New(t)
+
+ test := &Test{
+ Timeout: 200,
+ Confirmation: 100,
+ Public: 200,
+ Virus: 200,
+ TestType: "FTP",
+ RealBrowser: 100,
+ TriggerRate: 100,
+ CheckRate: 100000,
+ CustomHeader: "here be dragons",
+ WebsiteName: "",
+ WebsiteURL: "",
+ }
+
+ err := test.Validate()
+ require.NotNil(err)
+
+ message := err.Error()
+ assert.Contains(message, "WebsiteName is required")
+ assert.Contains(message, "WebsiteURL is required")
+ assert.Contains(message, "Timeout must be 0 or between 6 and 99")
+ assert.Contains(message, "Confirmation must be between 0 and 9")
+ assert.Contains(message, "CheckRate must be between 0 and 23999")
+ assert.Contains(message, "Public must be 0 or 1")
+ assert.Contains(message, "Virus must be 0 or 1")
+ assert.Contains(message, "TestType must be HTTP, TCP, or PING")
+ assert.Contains(message, "RealBrowser must be 0 or 1")
+ assert.Contains(message, "TriggerRate must be between 0 and 59")
+ assert.Contains(message, "CustomHeader must be provided as json string")
+
+ test.Timeout = 10
+ test.Confirmation = 2
+ test.Public = 1
+ test.Virus = 1
+ test.TestType = "HTTP"
+ test.RealBrowser = 1
+ test.TriggerRate = 50
+ test.CheckRate = 10
+ test.WebsiteName = "Foo"
+ test.WebsiteURL = "http://example.com"
+ test.CustomHeader = `{"test": 15}`
+ test.NodeLocations = []string{"foo", "bar"}
+
+ err = test.Validate()
+ assert.Nil(err)
+}
+
+func TestTest_ToURLValues(t *testing.T) {
+ assert := assert.New(t)
+
+ test := &Test{
+ TestID: 123,
+ Paused: true,
+ WebsiteName: "Foo Bar",
+ CustomHeader: `{"some":{"json": ["value"]}}`,
+ WebsiteURL: "http://example.com",
+ Port: 3000,
+ NodeLocations: []string{"foo", "bar"},
+ Timeout: 11,
+ PingURL: "http://example.com/ping",
+ Confirmation: 1,
+ CheckRate: 500,
+ BasicUser: "myuser",
+ BasicPass: "mypass",
+ Public: 1,
+ LogoImage: "http://example.com/logo.jpg",
+ Branding: 1,
+ WebsiteHost: "hoster",
+ Virus: 1,
+ FindString: "hello",
+ DoNotFind: true,
+ TestType: "HTTP",
+ RealBrowser: 1,
+ TriggerRate: 50,
+ TestTags: []string{"tag1", "tag2"},
+ StatusCodes: "500",
+ EnableSSLAlert: false,
+ FollowRedirect: false,
+ }
+
+ expected := url.Values{
+ "TestID": {"123"},
+ "Paused": {"1"},
+ "WebsiteName": {"Foo Bar"},
+ "WebsiteURL": {"http://example.com"},
+ "CustomHeader": {`{"some":{"json": ["value"]}}`},
+ "Port": {"3000"},
+ "NodeLocations": {"foo,bar"},
+ "Timeout": {"11"},
+ "PingURL": {"http://example.com/ping"},
+ "ContactGroup": {""},
+ "Confirmation": {"1"},
+ "CheckRate": {"500"},
+ "BasicUser": {"myuser"},
+ "BasicPass": {"mypass"},
+ "Public": {"1"},
+ "LogoImage": {"http://example.com/logo.jpg"},
+ "Branding": {"1"},
+ "WebsiteHost": {"hoster"},
+ "Virus": {"1"},
+ "FindString": {"hello"},
+ "DoNotFind": {"1"},
+ "TestType": {"HTTP"},
+ "RealBrowser": {"1"},
+ "TriggerRate": {"50"},
+ "TestTags": {"tag1,tag2"},
+ "StatusCodes": {"500"},
+ "UseJar": {"0"},
+ "PostRaw": {""},
+ "FinalEndpoint": {""},
+ "EnableSSLAlert": {"0"},
+ "FollowRedirect": {"0"},
+ }
+
+ assert.Equal(expected, test.ToURLValues())
+
+ test.TestID = 0
+ delete(expected, "TestID")
+
+ assert.Equal(expected.Encode(), test.ToURLValues().Encode())
+}
+
+func TestTests_All(t *testing.T) {
+ assert := assert.New(t)
+ require := require.New(t)
+
+ c := &fakeAPIClient{
+ fixture: "tests_all_ok.json",
+ }
+ tt := newTests(c)
+ tests, err := tt.All()
+ require.Nil(err)
+
+ assert.Equal("/Tests", c.sentRequestPath)
+ assert.Equal("GET", c.sentRequestMethod)
+ assert.Nil(c.sentRequestValues)
+ assert.Len(tests, 2)
+
+ expectedTest := &Test{
+ TestID: 100,
+ Paused: false,
+ TestType: "HTTP",
+ WebsiteName: "www 1",
+ ContactGroup: []string{"1"},
+ Status: "Up",
+ Uptime: 100,
+ NodeLocations: []string{"foo", "bar"},
+ }
+ assert.Equal(expectedTest, tests[0])
+
+ expectedTest = &Test{
+ TestID: 101,
+ Paused: true,
+ TestType: "HTTP",
+ WebsiteName: "www 2",
+ ContactGroup: []string{"2"},
+ Status: "Down",
+ Uptime: 0,
+ NodeLocations: []string{"foo"},
+ TestTags: []string{"test1", "test2"},
+ }
+ assert.Equal(expectedTest, tests[1])
+}
+
+func TestTests_AllWithFilter(t *testing.T) {
+ assert := assert.New(t)
+ require := require.New(t)
+
+ c := &fakeAPIClient{
+ fixture: "tests_all_ok.json",
+ }
+
+ v := url.Values{}
+ v.Set("tags", "test1,test2")
+ tt := newTests(c)
+ tests, err := tt.AllWithFilter(v)
+ require.Nil(err)
+
+ assert.Equal("/Tests", c.sentRequestPath)
+ assert.Equal("GET", c.sentRequestMethod)
+ assert.NotNil(c.sentRequestValues)
+ assert.Len(tests, 1)
+
+ expectedTest := &Test{
+ TestID: 101,
+ Paused: true,
+ TestType: "HTTP",
+ WebsiteName: "www 2",
+ ContactGroup: []string{"2"},
+ Status: "Down",
+ Uptime: 0,
+ NodeLocations: []string{"foo"},
+ TestTags: []string{"test1", "test2"},
+ }
+ assert.Equal(expectedTest, tests[0])
+}
+
+func TestTests_Update_OK(t *testing.T) {
+ assert := assert.New(t)
+ require := require.New(t)
+
+ c := &fakeAPIClient{
+ fixture: "tests_update_ok.json",
+ }
+ tt := newTests(c)
+
+ test1 := &Test{
+ WebsiteName: "foo",
+ }
+
+ test2, err := tt.Update(test1)
+ require.Nil(err)
+
+ assert.Equal("/Tests/Update", c.sentRequestPath)
+ assert.Equal("PUT", c.sentRequestMethod)
+ assert.NotNil(c.sentRequestValues)
+ assert.NotNil(test2)
+
+ assert.Equal(1234, test2.TestID)
+}
+
+func TestTests_Update_Error(t *testing.T) {
+ assert := assert.New(t)
+ require := require.New(t)
+
+ c := &fakeAPIClient{
+ fixture: "tests_update_error.json",
+ }
+ tt := newTests(c)
+
+ test1 := &Test{
+ WebsiteName: "foo",
+ }
+
+ test2, err := tt.Update(test1)
+ assert.Nil(test2)
+
+ require.NotNil(err)
+ assert.IsType(&updateError{}, err)
+ assert.Contains(err.Error(), "issue a")
+}
+
+func TestTests_Update_ErrorWithSliceOfIssues(t *testing.T) {
+ assert := assert.New(t)
+ require := require.New(t)
+
+ c := &fakeAPIClient{
+ fixture: "tests_update_error_slice_of_issues.json",
+ }
+ tt := newTests(c)
+
+ test1 := &Test{
+ WebsiteName: "foo",
+ }
+
+ test2, err := tt.Update(test1)
+ assert.Nil(test2)
+
+ require.NotNil(err)
+ assert.IsType(&updateError{}, err)
+ assert.Equal("Required Data is Missing., hello, world", err.Error())
+}
+
+func TestTests_Delete_OK(t *testing.T) {
+ assert := assert.New(t)
+ require := require.New(t)
+
+ c := &fakeAPIClient{
+ fixture: "tests_delete_ok.json",
+ }
+ tt := newTests(c)
+
+ err := tt.Delete(1234)
+ require.Nil(err)
+
+ assert.Equal("/Tests/Details", c.sentRequestPath)
+ assert.Equal("DELETE", c.sentRequestMethod)
+ assert.Equal(url.Values{"TestID": {"1234"}}, c.sentRequestValues)
+}
+
+func TestTests_Delete_Error(t *testing.T) {
+ assert := assert.New(t)
+ require := require.New(t)
+
+ c := &fakeAPIClient{
+ fixture: "tests_delete_error.json",
+ }
+ tt := newTests(c)
+
+ err := tt.Delete(1234)
+ require.NotNil(err)
+ assert.Equal("this is an error", err.Error())
+}
+
+func TestTests_Detail_OK(t *testing.T) {
+ assert := assert.New(t)
+ require := require.New(t)
+
+ c := &fakeAPIClient{
+ fixture: "tests_detail_ok.json",
+ }
+ tt := newTests(c)
+
+ test, err := tt.Detail(1234)
+ require.Nil(err)
+
+ assert.Equal("/Tests/Details", c.sentRequestPath)
+ assert.Equal("GET", c.sentRequestMethod)
+ assert.Equal(url.Values{"TestID": {"1234"}}, c.sentRequestValues)
+
+ assert.Equal(test.TestID, 6735)
+ assert.Equal(test.TestType, "HTTP")
+ assert.Equal(test.Paused, false)
+ assert.Equal(test.WebsiteName, "NL")
+ assert.Equal(test.CustomHeader, `{"some":{"json": ["value"]}}`)
+ assert.Equal(test.UserAgent, "product/version (comment)")
+ assert.Equal(test.ContactGroup, []string{"536"})
+ assert.Equal(test.Status, "Up")
+ assert.Equal(test.Uptime, 0.0)
+ assert.Equal(test.CheckRate, 60)
+ assert.Equal(test.Timeout, 40)
+ assert.Equal(test.LogoImage, "")
+ assert.Equal(test.WebsiteHost, "Various")
+ assert.Equal(test.FindString, "")
+ assert.Equal(test.DoNotFind, false)
+ assert.Equal(test.NodeLocations, []string{"foo", "bar"})
+}
+
+type fakeAPIClient struct {
+ sentRequestPath string
+ sentRequestMethod string
+ sentRequestValues url.Values
+ fixture string
+}
+
+func (c *fakeAPIClient) put(path string, v url.Values) (*http.Response, error) {
+ return c.all("PUT", path, v)
+}
+
+func (c *fakeAPIClient) delete(path string, v url.Values) (*http.Response, error) {
+ return c.all("DELETE", path, v)
+}
+
+func (c *fakeAPIClient) get(path string, v url.Values) (*http.Response, error) {
+ return c.all("GET", path, v)
+}
+
+func (c *fakeAPIClient) all(method string, path string, v url.Values) (*http.Response, error) {
+ c.sentRequestMethod = method
+ c.sentRequestPath = path
+ c.sentRequestValues = v
+
+ p := filepath.Join("fixtures", c.fixture)
+ f, err := os.Open(p)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ var resp *http.Response
+ if len(c.sentRequestValues.Get("tags")) > 0 {
+ var storedResponses []Test
+ var returnResponses []Test
+ byteValue, _ := ioutil.ReadAll(f)
+ json.Unmarshal(byteValue, &storedResponses)
+ requestedTags := strings.Split(c.sentRequestValues.Get("tags"), ",")
+
+ for _, storedResponse := range storedResponses {
+ if len(requestedTags) > len(storedResponse.TestTags) { // if we are requesting more tags than whats stored then there are no matches
+ continue
+ }
+
+ match := true
+ for i, tag := range requestedTags {
+ if tag != storedResponse.TestTags[i] {
+ match = false
+ }
+ }
+
+ if match { // we can add it to the response now
+ returnResponses = append(returnResponses, storedResponse)
+ }
+ }
+
+ if len(returnResponses) == 0 {
+ return nil, nil
+ }
+
+ newByteValue, _ := json.Marshal(&returnResponses)
+ resp = &http.Response{
+ Body: ioutil.NopCloser(bytes.NewBuffer(newByteValue)),
+ }
+
+ } else {
+ resp = &http.Response{
+ Body: f,
+ }
+ }
+
+ return resp, nil
+}