Add unittests for http and tcp.
authorBrian Brazil <brian.brazil@robustperception.io>
Thu, 17 Sep 2015 14:06:21 +0000 (15:06 +0100)
committerBrian Brazil <brian.brazil@robustperception.io>
Thu, 17 Sep 2015 14:41:43 +0000 (15:41 +0100)
Fix bug in default status codes accepted by http.
Allow for how redirect errors are handled.

http.go
http_test.go [new file with mode: 0644]
tcp_test.go [new file with mode: 0644]

diff --git a/http.go b/http.go
index 8e1475868034ae7567b01eada2b6c9604272867d..0d1c279aa89322fd99c1b4aab5db0c3b806ee6c0 100644 (file)
--- a/http.go
+++ b/http.go
@@ -41,6 +41,9 @@ func probeHTTP(target string, w http.ResponseWriter, module Module) (success boo
        if !strings.HasPrefix(target, "http://") && !strings.HasPrefix(target, "https://") {
                target = "http://" + target
        }
+       if config.Method == "" {
+               config.Method = "GET"
+       }
 
        request, err := http.NewRequest(config.Method, target, nil)
        if err != nil {
@@ -48,7 +51,8 @@ func probeHTTP(target string, w http.ResponseWriter, module Module) (success boo
        }
 
        resp, err := client.Do(request)
-       if err != nil {
+       // Err won't be nil if redirects were turned off. See https://github.com/golang/go/issues/3795
+       if err != nil && resp == nil {
                log.Warnf("Error for HTTP request to %s: %s", target, err)
        } else {
                defer resp.Body.Close()
@@ -59,7 +63,7 @@ func probeHTTP(target string, w http.ResponseWriter, module Module) (success boo
                                        break
                                }
                        }
-               } else if 200 >= resp.StatusCode && resp.StatusCode < 300 {
+               } else if 200 <= resp.StatusCode && resp.StatusCode < 300 {
                        success = true
                }
        }
diff --git a/http_test.go b/http_test.go
new file mode 100644 (file)
index 0000000..0302e01
--- /dev/null
@@ -0,0 +1,127 @@
+// Copyright 2015 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package main
+
+import (
+       "net/http"
+       "net/http/httptest"
+       "strings"
+       "testing"
+       "time"
+)
+
+func TestHTTPStatusCodes(t *testing.T) {
+       tests := []struct {
+               StatusCode       int
+               ValidStatusCodes []int
+               ShouldSucceed    bool
+       }{
+               {200, []int{}, true},
+               {201, []int{}, true},
+               {299, []int{}, true},
+               {300, []int{}, false},
+               {404, []int{}, false},
+               {404, []int{200, 404}, true},
+               {200, []int{200, 404}, true},
+               {201, []int{200, 404}, false},
+               {404, []int{404}, true},
+               {200, []int{404}, false},
+       }
+
+       for i, test := range tests {
+               ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+                       w.WriteHeader(test.StatusCode)
+               }))
+               defer ts.Close()
+               recorder := httptest.NewRecorder()
+               result := probeHTTP(ts.URL, recorder,
+                       Module{Timeout: time.Second, HTTP: HTTPProbe{ValidStatusCodes: test.ValidStatusCodes}})
+               body := recorder.Body.String()
+               if result != test.ShouldSucceed {
+                       t.Fatalf("Test %d had unexpected result: %s", i, body)
+               }
+       }
+}
+
+func TestRedirectFollowed(t *testing.T) {
+       ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+               if r.URL.Path == "/" {
+                       http.Redirect(w, r, "/noredirect", http.StatusFound)
+               }
+       }))
+       defer ts.Close()
+
+       // Follow redirect, should succeed with 200.
+       recorder := httptest.NewRecorder()
+       result := probeHTTP(ts.URL, recorder, Module{Timeout: time.Second, HTTP: HTTPProbe{}})
+       body := recorder.Body.String()
+       if !result {
+               t.Fatalf("Redirect test failed unexpectedly, got %s", body)
+       }
+       if !strings.Contains(body, "probe_http_redirects 1\n") {
+               t.Fatalf("Expected one redirect, got %s", body)
+       }
+
+}
+
+func TestRedirectNotFollowed(t *testing.T) {
+       ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+               http.Redirect(w, r, "/noredirect", http.StatusFound)
+       }))
+       defer ts.Close()
+
+       // Follow redirect, should succeed with 200.
+       recorder := httptest.NewRecorder()
+       result := probeHTTP(ts.URL, recorder,
+               Module{Timeout: time.Second, HTTP: HTTPProbe{NoFollowRedirects: true, ValidStatusCodes: []int{302}}})
+       body := recorder.Body.String()
+       if !result {
+               t.Fatalf("Redirect test failed unexpectedly, got %s", body)
+       }
+
+}
+
+func TestPost(t *testing.T) {
+       ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+               if r.Method != "POST" {
+                       w.WriteHeader(http.StatusBadRequest)
+               }
+       }))
+       defer ts.Close()
+
+       recorder := httptest.NewRecorder()
+       result := probeHTTP(ts.URL, recorder,
+               Module{Timeout: time.Second, HTTP: HTTPProbe{Method: "POST"}})
+       body := recorder.Body.String()
+       if !result {
+               t.Fatalf("Post test failed unexpectedly, got %s", body)
+       }
+}
+
+func TestFailIfNotSSL(t *testing.T) {
+       ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+       }))
+       defer ts.Close()
+
+       recorder := httptest.NewRecorder()
+       result := probeHTTP(ts.URL, recorder,
+               Module{Timeout: time.Second, HTTP: HTTPProbe{FailIfNotSSL: true}})
+       body := recorder.Body.String()
+       if result {
+               t.Fatalf("Fail if not SSL test suceeded unexpectedly, got %s", body)
+       }
+       if !strings.Contains(body, "probe_http_ssl 0\n") {
+               t.Fatalf("Expected HTTP without SSL, got %s", body)
+       }
+}
diff --git a/tcp_test.go b/tcp_test.go
new file mode 100644 (file)
index 0000000..9d4ddfd
--- /dev/null
@@ -0,0 +1,49 @@
+// Copyright 2015 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package main
+
+import (
+       "net"
+       "testing"
+       "time"
+)
+
+func TestTCPConnection(t *testing.T) {
+       ln, err := net.Listen("tcp", "localhost:")
+       if err != nil {
+               t.Fatalf("Error listening on socket: %s", err)
+       }
+       defer ln.Close()
+
+       ch := make(chan (struct{}))
+       go func() {
+               conn, err := ln.Accept()
+               if err != nil {
+                       t.Fatalf("Error accepting on socket: %s", err)
+               }
+               conn.Close()
+               ch <- struct{}{}
+       }()
+       if !probeTCP(ln.Addr().String(), nil, Module{Timeout: time.Second}) {
+               t.Fatalf("TCP module failed, expected success.")
+       }
+       <-ch
+}
+
+func TestTCPConnectionFails(t *testing.T) {
+       // Invalid port number.
+       if probeTCP(":0", nil, Module{Timeout: time.Second}) {
+               t.Fatalf("TCP module suceeded, expected failure.")
+       }
+}