From cfb31cf6a5a44f8a03e6c6ee677abd36c11ce192 Mon Sep 17 00:00:00 2001 From: Bel LaPointe Date: Sun, 7 Oct 2018 23:06:07 -0600 Subject: [PATCH] Initial server without functionality --- server/server.go | 83 +++++++++++++++++++++++++++++++++++++++++++ server/server_test.go | 57 +++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+) create mode 100644 server/server.go create mode 100644 server/server_test.go diff --git a/server/server.go b/server/server.go new file mode 100644 index 0000000..a2471ab --- /dev/null +++ b/server/server.go @@ -0,0 +1,83 @@ +package server + +import ( + "net/http" + "os" + "os/signal" + "path" + "strings" + "syscall" +) + +type Server struct { + addr string +} + +func New(addr string) (*Server, error) { + return &Server{ + addr: addr, + }, nil +} + +func (s *Server) Serve() error { + var err error + go func() { + port := s.addr + if !strings.HasPrefix(port, ":") { + port = ":" + port + } + err = http.ListenAndServe(port, s) + }() + sigc := make(chan os.Signal) + signal.Notify(sigc, + syscall.SIGHUP, + syscall.SIGINT, + syscall.SIGTERM, + syscall.SIGQUIT, + ) + <-sigc + return err +} + +func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { + switch advance(r) { + case "api": + s.api(w, r) + default: + s.bad(w, r) + } +} + +func (s *Server) bad(w http.ResponseWriter, r *http.Request) { + http.NotFound(w, r) +} + +func (s *Server) api(w http.ResponseWriter, r *http.Request) { + switch advance(r) { + case "feed": + s.feed(w, r) + default: + s.bad(w, r) + } +} + +func (s *Server) feed(w http.ResponseWriter, r *http.Request) { + switch r.Method { + case "GET": + case "POST": + case "PUT": + default: + s.bad(w, r) + } +} + +func advance(r *http.Request) string { + p := path.Clean("/" + r.URL.Path) + i := strings.Index(p[1:], "/") + 1 + if i <= 0 { + r.URL.Path = "/" + return p[1:] + } + r.URL.Path = p[i:] + return p[1:i] +} diff --git a/server/server_test.go b/server/server_test.go new file mode 100644 index 0000000..aaa505b --- /dev/null +++ b/server/server_test.go @@ -0,0 +1,57 @@ +package server + +import ( + "fmt" + "net/http" + "syscall" + "testing" + "time" +) + +const testPort = "39231" + +func Test_Server(t *testing.T) { + cases := []struct { + }{ + {}, + } + + for _, _ = range cases { + var err error + s, err := New(testPort) + if err != nil { + t.Errorf("failed to create server: %v", err) + } + go s.Serve() + time.Sleep(time.Second * 1) + if err := checkStatus("GET", "", http.StatusNotFound); err != nil { + t.Errorf(err.Error()) + } + if err := checkStatus("GET", "api", http.StatusNotFound); err != nil { + t.Errorf(err.Error()) + } + if err := checkStatus("GET", "api/feed", http.StatusOK); err != nil { + t.Errorf(err.Error()) + } + if err := checkStatus("POST", "api/feed", http.StatusOK); err != nil { + t.Errorf(err.Error()) + } + if err := checkStatus("PUT", "api/feed", http.StatusOK); err != nil { + t.Errorf(err.Error()) + } + syscall.Kill(syscall.Getpid(), syscall.SIGINT) + } +} + +func checkStatus(method, path string, code int) error { + client := &http.Client{} + r, _ := http.NewRequest(method, "http://localhost:"+testPort+"/"+path, nil) + resp, err := client.Do(r) + if err != nil { + return fmt.Errorf("failed to %v server: %v", method, err) + } + if resp.StatusCode != code { + return fmt.Errorf("%s %q did not return %v: %v", method, path, code, resp.StatusCode) + } + return nil +}