Skip to content

Commit

Permalink
head responses content length
Browse files Browse the repository at this point in the history
  • Loading branch information
lesomnus committed Jul 17, 2023
1 parent 5ff7630 commit 89bc0da
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 71 deletions.
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ ENTRYPOINT ["/vcpkg-cache-http"]

EXPOSE 15151/tcp
VOLUME ["/vcpkg-cache"]
STOPSIGNAL SIGINT
2 changes: 1 addition & 1 deletion config.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ type AppConfig struct {
NoColor bool `json:"no_color"`
LogJson bool `json:"log_json"`

ReadOnly bool `json:"read_only`
ReadOnly bool `json:"read_only"`
WriteOnly bool `json:"write_only"`
}

Expand Down
14 changes: 11 additions & 3 deletions fs_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,13 +110,21 @@ func (s *fsStore) Get(ctx context.Context, desc Description, w io.Writer) error
return err
}

func (s *fsStore) Head(ctx context.Context, desc Description) error {
func (s *fsStore) Head(ctx context.Context, desc Description) (int, error) {
tgt := s.Resolve(desc)
_, err := os.Stat(tgt)
return err
info, err := os.Stat(tgt)
if err != nil {
return 0, err
}

return int(info.Size()), nil
}

func (s *fsStore) Put(ctx context.Context, desc Description, r io.Reader) error {
if err := os.MkdirAll(s.work, 0744); err != nil {
return fmt.Errorf("create work directory: %w", err)
}

f, err := os.CreateTemp(s.work, "")
if err != nil {
return fmt.Errorf("create temp file: %w", err)
Expand Down
48 changes: 38 additions & 10 deletions fs_store_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main_test

import (
"bytes"
"context"
"io"
"os"
Expand All @@ -24,15 +25,11 @@ func (s *FsStoreSetup) New(t *testing.T) (main.Store, error) {
}

func TestFsStoreSuite(t *testing.T) {
t.Parallel()
suite.Run(t, &StoreTestSuite{Store: &FsStoreSetup{}})
}

func TestFsStoreNew(t *testing.T) {
t.Parallel()

t.Run("create store directory if it does not exist", func(t *testing.T) {
t.Parallel()
require := require.New(t)

root := filepath.Join(t.TempDir(), "foo", "bar")
Expand All @@ -42,11 +39,45 @@ func TestFsStoreNew(t *testing.T) {
})
}

func TestFsStoreFail(t *testing.T) {
t.Parallel()
func TestFsStore(t *testing.T) {
t.Run("work directory is created if not exist", func(t *testing.T) {
require := require.New(t)

root := t.TempDir()
work := filepath.Join(root, "foo")

_, err := os.Stat(work)
require.ErrorIs(err, os.ErrNotExist)

_, err = main.NewFsStore(root, main.WithWorkDir(work))
require.NoError(err)

_, err = os.Stat(work)
require.NoError(err)
})

t.Run("work directory is created if it is removed", func(t *testing.T) {
require := require.New(t)

root := t.TempDir()
work := filepath.Join(root, "foo")

store, err := main.NewFsStore(root, main.WithWorkDir(work))
require.NoError(err)

err = os.RemoveAll(work)
require.NoError(err)

err = store.Put(context.Background(), DescriptionFoo, bytes.NewReader([]byte{}))
require.NoError(err)

_, err = os.Stat(work)
require.NoError(err)
})
}

func TestFsStoreFail(t *testing.T) {
t.Run("it cannot create store directory", func(t *testing.T) {
t.Parallel()
require := require.New(t)

root := filepath.Join(t.TempDir(), "foo")
Expand All @@ -58,7 +89,6 @@ func TestFsStoreFail(t *testing.T) {
})

t.Run("file cannot be created in work directory", func(t *testing.T) {
t.Parallel()
require := require.New(t)

work := filepath.Join(t.TempDir(), "foo")
Expand All @@ -70,7 +100,6 @@ func TestFsStoreFail(t *testing.T) {
})

t.Run("file cannot be renamed from work to store directory", func(t *testing.T) {
t.Parallel()
require := require.New(t)

root := filepath.Join(t.TempDir(), "foo")
Expand All @@ -82,7 +111,6 @@ func TestFsStoreFail(t *testing.T) {
})

t.Run("store cannot be closed if the work left", func(t *testing.T) {
t.Parallel()
require := require.New(t)

store, err := main.NewFsStore(t.TempDir())
Expand Down
10 changes: 9 additions & 1 deletion server.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"errors"
"net/http"
"strconv"
"strings"
"time"

Expand Down Expand Up @@ -36,8 +37,9 @@ func (s *Handler) handleGet(res http.ResponseWriter, req *http.Request, desc Des
}

func (s *Handler) handleHead(res http.ResponseWriter, req *http.Request, desc Description) error {
err := s.Store.Head(req.Context(), desc)
size, err := s.Store.Head(req.Context(), desc)
if err == nil {
res.Header().Add("Content-Length", strconv.FormatInt(int64(size), 10))
res.WriteHeader(http.StatusOK)
return nil
}
Expand Down Expand Up @@ -101,6 +103,12 @@ func (s *Handler) parseDescription(res http.ResponseWriter, req *http.Request) (
}

func (s *Handler) ServeHTTP(r http.ResponseWriter, req *http.Request) {
if (req.URL.Path == "/") && (req.Method == http.MethodGet) {
s.Log.Info().Msg("probe")
r.WriteHeader(http.StatusOK)
return
}

t0 := time.Now()
res := &responseWriter{r, http.StatusOK}

Expand Down
89 changes: 36 additions & 53 deletions server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"io"
"net/http"
"net/http/httptest"
"strconv"
"testing"

main "github.com/lesomnus/vcpkg-cache-http"
Expand All @@ -33,16 +34,6 @@ func WithHandler(f func(t *testing.T, store main.Store, handler *main.Handler))
}
}

func WithServer(f func(t *testing.T, store main.Store, client *http.Client, url string)) func(*testing.T) {
return WithHandler(func(t *testing.T, store main.Store, handler *main.Handler) {
server := httptest.NewServer(handler)
defer server.Close()

f(t, store, server.Client(), server.URL)
})

}

func randomData(t *testing.T) []byte {
require := require.New(t)

Expand All @@ -53,29 +44,34 @@ func randomData(t *testing.T) []byte {
return data
}

func TestServerGet(t *testing.T) {
t.Parallel()
func TestServerProbe(t *testing.T) {
WithHandler(func(t *testing.T, store main.Store, handler *main.Handler) {
require := require.New(t)
require.HTTPStatusCode(handler.ServeHTTP, http.MethodGet, "/", nil, http.StatusOK)
})(t)
}

t.Run("200 if cache hit", WithServer(func(t *testing.T, store main.Store, client *http.Client, url string) {
t.Parallel()
func TestServerGet(t *testing.T) {
t.Run("200 if cache hit", WithHandler(func(t *testing.T, store main.Store, handler *main.Handler) {
require := require.New(t)

data := randomData(t)
ctx := context.Background()
err := store.Put(ctx, DescriptionFoo, bytes.NewReader(data))
err := store.Put(context.Background(), DescriptionFoo, bytes.NewReader(data))
require.NoError(err)

res, err := client.Get(url + DescriptionFoo.String())
require.NoError(err)
defer res.Body.Close()
req := httptest.NewRequest(http.MethodGet, DescriptionFoo.String(), nil)
w := httptest.NewRecorder()
handler.ServeHTTP(w, req)

res := w.Result()
require.Equal(http.StatusOK, res.StatusCode)

received, err := io.ReadAll(res.Body)
require.NoError(err)
require.Equal(data, received)
}))

t.Run("404 if cache not exists", WithHandler(func(t *testing.T, store main.Store, handler *main.Handler) {
t.Parallel()
require := require.New(t)

ctx := context.Background()
Expand All @@ -86,7 +82,6 @@ func TestServerGet(t *testing.T) {
}))

t.Run("404 if path invalid", WithHandler(func(t *testing.T, store main.Store, handler *main.Handler) {
t.Parallel()
require := require.New(t)

paths := []string{
Expand All @@ -101,7 +96,6 @@ func TestServerGet(t *testing.T) {
}))

t.Run("405 if not readable", WithHandler(func(t *testing.T, store main.Store, handler *main.Handler) {
t.Parallel()
require := require.New(t)

data := randomData(t)
Expand All @@ -116,82 +110,71 @@ func TestServerGet(t *testing.T) {
}

func TestServerHead(t *testing.T) {
t.Parallel()

t.Run("200 if cache exists", WithHandler(func(t *testing.T, store main.Store, handler *main.Handler) {
t.Parallel()
require := require.New(t)

data := randomData(t)
ctx := context.Background()
err := store.Put(ctx, DescriptionFoo, bytes.NewReader(data))
require.NoError(err)

require.HTTPStatusCode(handler.ServeHTTP, http.MethodGet, DescriptionFoo.String(), nil, http.StatusOK)
req := httptest.NewRequest(http.MethodHead, DescriptionFoo.String(), nil)
w := httptest.NewRecorder()
handler.ServeHTTP(w, req)

res := w.Result()
require.Equal(http.StatusOK, res.StatusCode)
require.Equal(strconv.FormatInt(int64(len(data)), 10), res.Header.Get("Content-Length"))
}))

t.Run("404 if cache not exists", WithHandler(func(t *testing.T, store main.Store, handler *main.Handler) {
t.Parallel()
require := require.New(t)

ctx := context.Background()
err := store.Head(ctx, DescriptionFoo)
_, err := store.Head(ctx, DescriptionFoo)
require.ErrorIs(err, main.ErrNotExist)

require.HTTPStatusCode(handler.ServeHTTP, http.MethodGet, DescriptionFoo.String(), nil, http.StatusNotFound)
require.HTTPStatusCode(handler.ServeHTTP, http.MethodHead, DescriptionFoo.String(), nil, http.StatusNotFound)
}))
}

func TestServerPut(t *testing.T) {
t.Parallel()

t.Run("cache will hit after PUT", WithServer(func(t *testing.T, store main.Store, client *http.Client, url string) {
t.Parallel()
t.Run("cache will hit after PUT", WithHandler(func(t *testing.T, store main.Store, handler *main.Handler) {
require := require.New(t)

data := randomData(t)
req, err := http.NewRequest(http.MethodPut, url+DescriptionFoo.String(), bytes.NewReader(data))
require.NoError(err)
req := httptest.NewRequest(http.MethodPut, DescriptionFoo.String(), bytes.NewReader(data))
w := httptest.NewRecorder()
handler.ServeHTTP(w, req)

res, err := client.Do(req)
require.NoError(err)
defer res.Body.Close()
res := w.Result()
require.Equal(http.StatusOK, res.StatusCode)

ctx := context.Background()
var received bytes.Buffer
err = store.Get(ctx, DescriptionFoo, &received)
err := store.Get(context.Background(), DescriptionFoo, &received)
require.NoError(err)
require.Equal(data, received.Bytes())
}))

t.Run("405 if not readable", WithHandler(func(t *testing.T, store main.Store, handler *main.Handler) {
t.Parallel()
require := require.New(t)

server := httptest.NewServer(handler)
defer server.Close()

handler.IsWritable = false

data := randomData(t)
req, err := http.NewRequest(http.MethodPut, server.URL+DescriptionFoo.String(), bytes.NewReader(data))
require.NoError(err)
req := httptest.NewRequest(http.MethodPut, DescriptionFoo.String(), bytes.NewReader(data))
w := httptest.NewRecorder()
handler.ServeHTTP(w, req)

res, err := server.Client().Do(req)
require.NoError(err)
defer res.Body.Close()
res := w.Result()
require.Equal(http.StatusMethodNotAllowed, res.StatusCode)

ctx := context.Background()
err = store.Get(ctx, DescriptionFoo, io.Discard)
err := store.Get(context.Background(), DescriptionFoo, io.Discard)
require.ErrorIs(err, main.ErrNotExist)
}))
}

func TestServerInvalidMethod(t *testing.T) {
t.Parallel()

require := require.New(t)
methods := []string{
// http.MethodGet,
Expand Down
2 changes: 1 addition & 1 deletion store.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func (d *Description) String() string {

type Store interface {
Get(ctx context.Context, desc Description, w io.Writer) error
Head(ctx context.Context, desc Description) error
Head(ctx context.Context, desc Description) (int, error)
Put(ctx context.Context, desc Description, r io.Reader) error

Close() error
Expand Down
5 changes: 3 additions & 2 deletions store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func (s *StoreTestSuite) SetupTest() {
func (s *StoreTestSuite) TestAll() {
ctx := context.Background()

err := s.store.Head(ctx, DescriptionFoo)
_, err := s.store.Head(ctx, DescriptionFoo)
s.require.ErrorIs(err, main.ErrNotExist)

err = s.store.Get(ctx, DescriptionFoo, io.Discard)
Expand All @@ -50,8 +50,9 @@ func (s *StoreTestSuite) TestAll() {
err = s.store.Put(ctx, DescriptionFoo, bytes.NewReader(data))
s.require.NoError(err)

err = s.store.Head(ctx, DescriptionFoo)
size, err := s.store.Head(ctx, DescriptionFoo)
s.require.NoError(err)
s.require.Equal(len(data), size)

var received bytes.Buffer
err = s.store.Get(ctx, DescriptionFoo, &received)
Expand Down

0 comments on commit 89bc0da

Please sign in to comment.