web server running in container

This commit is contained in:
Divyansh Manchanda 2019-06-10 11:53:02 +05:30
Родитель 0ab71c9f71
Коммит 20438986c8
3 изменённых файлов: 13 добавлений и 170 удалений

Просмотреть файл

@ -2,5 +2,15 @@ FROM golang:alpine
MAINTAINER Divyansh Manchanda <divyanshm@gmail.com>
RUN apk add --no-cache git mercurial \
&& go get github.com/garyburd/redigo/redis \
&& go get github.com/gorilla/handlers \
&& apk del git mercurial
RUN mkdir /app
ADD . /app/
WORKDIR /app
RUN go build -o main .
EXPOSE 8082
ENTRYPOINT ["app"]
CMD ["/app/main"]

30
main.go
Просмотреть файл

@ -13,9 +13,9 @@ import (
const (
// Name of the application
Name = "simple webserver"
Name = "divman's GoServer"
// Version of the application
Version = "1.1.1"
Version = "1.0.0"
)
func main() {
@ -32,7 +32,6 @@ func main() {
s := http.NewServeMux()
s.HandleFunc("/", RootHandler)
s.HandleFunc("/ping", PingHandler(r))
s.HandleFunc("/kill", KillHandler)
s.HandleFunc("/version", VersionHandler)
s.HandleFunc("/payload", PayloadHandler)
@ -68,31 +67,6 @@ func PingHandler(s Storage) http.HandlerFunc {
}
}
// KillHandler handles request to the "/kill" endpoint.
// Will shut down the webserver immediately (via exit code 1).
// Only DELETE requests are accepted.
// Other request methods will throw a HTTP Status Code 405 (Method Not Allowed)
func KillHandler(resp http.ResponseWriter, req *http.Request) {
if req.Method != "DELETE" {
resp.WriteHeader(http.StatusMethodNotAllowed)
return
}
// We need to send a HTTP Status Code 200 (OK)
// to respond that we have accepted the request.
// Here we send a chunked response to the requester.
flusher, ok := resp.(http.Flusher)
if !ok {
resp.WriteHeader(http.StatusInternalServerError)
return
}
resp.WriteHeader(http.StatusOK)
flusher.Flush()
// And we kill the server (like requested)
os.Exit(1)
}
// VersionHandler handles request to the "/version" endpoint.
// It prints the Name and Version of this app.
func VersionHandler(resp http.ResponseWriter, req *http.Request) {

Просмотреть файл

@ -1,141 +0,0 @@
package main
import (
"fmt"
"net/http"
"net/http/httptest"
"os"
"os/exec"
"testing"
)
type dummyStorage struct{}
func (s *dummyStorage) Ping() (string, error) {
return "PONG", nil
}
func TestPingHandler(t *testing.T) {
req, err := http.NewRequest("GET", "/ping", nil)
if err != nil {
t.Fatal(err)
}
backend := &dummyStorage{}
rr := httptest.NewRecorder()
handler := http.HandlerFunc(PingHandler(backend))
handler.ServeHTTP(rr, req)
if status := rr.Code; status != http.StatusOK {
t.Errorf("Wrong status code: got %v, expected %v", status, http.StatusOK)
}
expected := "PONG\n"
if rr.Body.String() != expected {
t.Errorf("Unexpected body: got %q, want %q", rr.Body.String(), expected)
}
}
type dummyErrorStorage struct{}
func (s *dummyErrorStorage) Ping() (string, error) {
return "", fmt.Errorf("Connection timeout to storage backend")
}
func TestPingHandler_Error(t *testing.T) {
req, err := http.NewRequest("GET", "/ping", nil)
if err != nil {
t.Fatal(err)
}
backend := &dummyErrorStorage{}
rr := httptest.NewRecorder()
handler := http.HandlerFunc(PingHandler(backend))
handler.ServeHTTP(rr, req)
if status := rr.Code; status != http.StatusInternalServerError {
t.Errorf("Wrong status code: got %v, expected %v", status, http.StatusInternalServerError)
}
expected := "Connection timeout to storage backend"
if rr.Body.String() != expected {
t.Errorf("Unexpected body: got %q, want %q", rr.Body.String(), expected)
}
}
func TestVersionHandler(t *testing.T) {
req, err := http.NewRequest("GET", "/version", nil)
if err != nil {
t.Fatal(err)
}
rr := httptest.NewRecorder()
handler := http.HandlerFunc(VersionHandler)
handler.ServeHTTP(rr, req)
if status := rr.Code; status != http.StatusOK {
t.Errorf("Wrong status code: got %v, expected %v", status, http.StatusOK)
}
expected := fmt.Sprintf("%s v%s\n", Name, Version)
if rr.Body.String() != expected {
t.Errorf("Unexpected body: got %q, want %q", rr.Body.String(), expected)
}
}
func TestKillHandler(t *testing.T) {
// Here we only test if the end point kills itself.
if os.Getenv("KILL_ENDPOINT") == "1" {
req, err := http.NewRequest("DELETE", "/kill", nil)
if err != nil {
t.Fatal(err)
}
rr := httptest.NewRecorder()
handler := http.HandlerFunc(KillHandler)
handler.ServeHTTP(rr, req)
return
}
cmd := exec.Command(os.Args[0], "-test.run=TestKillHandler")
cmd.Env = append(os.Environ(), "KILL_ENDPOINT=1")
err := cmd.Run()
if e, ok := err.(*exec.ExitError); ok && !e.Success() {
return
}
t.Errorf("Process ran with err %v, want exit status 1", err)
}
func TestKillHandler_WrongMethod(t *testing.T) {
req, err := http.NewRequest("POST", "/kill", nil)
if err != nil {
t.Fatal(err)
}
rr := httptest.NewRecorder()
handler := http.HandlerFunc(KillHandler)
handler.ServeHTTP(rr, req)
if status := rr.Code; status != http.StatusMethodNotAllowed {
t.Errorf("Wrong status code: got %v, expected %v", status, http.StatusMethodNotAllowed)
}
}
func TestEnvOrDefault_Fallback(t *testing.T) {
expected := "dummy"
got := EnvOrDefault("TEST_DEFAULT_ENV", expected)
if expected != got {
t.Errorf("Wrong fallback value: got %v, expected %v", got, expected)
}
}
func TestEnvOrDefault_WithEnv(t *testing.T) {
expected := "dummy-from-env"
os.Setenv("TEST_SET_ENV", expected)
got := EnvOrDefault("TEST_SET_ENV", "dummy-fallback")
if expected != got {
t.Errorf("Wrong env value: got %v, expected %v", got, expected)
}
}