Skip to content

Commit

Permalink
Merge pull request #13 from tarent/ajax-and-x-no-composition-caching
Browse files Browse the repository at this point in the history
Ajax-requests and X-No-Composition-header responses are now cached
  • Loading branch information
domano committed Jul 11, 2016
2 parents 83573b9 + bae4484 commit 69845bb
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 359 deletions.
27 changes: 26 additions & 1 deletion composition/cache_loader.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package composition

import (
"bytes"
"github.com/tarent/lib-compose/logging"
"io"
"io/ioutil"
"strings"
)

Expand Down Expand Up @@ -30,7 +33,20 @@ func (loader *CachingContentLoader) Load(fd *FetchDefinition) (Content, error) {
c, err := loader.load(fd)
if err == nil {
if fd.IsCachable(c.HttpStatusCode(), c.HttpHeader()) {
loader.cache.Set(hash, fd.URL, c.MemorySize(), c)
if c.Reader() != nil {
var streamBytes []byte
streamBytes, err = ioutil.ReadAll(c.Reader())
if err == nil {
cw := &ContentWrapper{
Content: c,
streamBytes: streamBytes,
}
loader.cache.Set(hash, fd.URL, c.MemorySize(), cw)
return cw, nil
}
} else {
loader.cache.Set(hash, fd.URL, c.MemorySize(), c)
}
}
}
return c, err
Expand All @@ -42,3 +58,12 @@ func (loader *CachingContentLoader) load(fd *FetchDefinition) (Content, error) {
}
return loader.httpContentLoader.Load(fd)
}

type ContentWrapper struct {
Content
streamBytes []byte
}

func (cw *ContentWrapper) Reader() io.ReadCloser {
return ioutil.NopCloser(bytes.NewReader(cw.streamBytes))
}
82 changes: 82 additions & 0 deletions composition/cache_loader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ package composition
import (
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
"io"
"io/ioutil"
"reflect"
"strings"
"testing"
)

Expand Down Expand Up @@ -75,3 +79,81 @@ func Test_CacheLoader_NotFound(t *testing.T) {
ctrl.Finish()
}
}

func Test_CacheLoader_NotFound_With_Stream(t *testing.T) {
tests := []struct {
url string
method string
reader io.ReadCloser
cachable bool
}{
{"http://example.de", "GET", ioutil.NopCloser(strings.NewReader("foobar")), true},
{"file:///some/file", "GET", ioutil.NopCloser(strings.NewReader("foobar")), true},
}
for _, test := range tests {
ctrl := gomock.NewController(t)
a := assert.New(t)

// given:
c := NewMemoryContent()
c.url = test.url
c.httpStatusCode = 200
c.reader = test.reader
fd := NewFetchDefinition(c.url)
fd.Method = test.method

// and a cache returning nothing
cacheMocK := NewMockCache(ctrl)
cacheMocK.EXPECT().Get(gomock.Any()).Return(nil, false)
if test.cachable {
cacheMocK.EXPECT().Set(fd.Hash(), fd.URL, c.MemorySize(), CWMatcher{})
}
// and a loader delegating to
loaderMock := NewMockContentLoader(ctrl)
loaderMock.EXPECT().Load(gomock.Any()).Return(c, nil)

// when: we load the object
loader := NewCachingContentLoader(cacheMocK)
if test.url == "file:///some/file" {
loader.fileContentLoader = loaderMock
} else {
loader.httpContentLoader = loaderMock
}

// it is returned
result, err := loader.Load(fd)
resultbytes, err := ioutil.ReadAll(result.Reader())
resultstring := string(resultbytes)
a.NoError(err)
a.Equal("foobar", resultstring)
ctrl.Finish()
}
}

func Test_Content_Wrapper_Reader(t *testing.T) {
//given
toTest := &ContentWrapper{streamBytes: []byte("foobar")}

//when
result, err := ioutil.ReadAll(toTest.Reader())
resultStr := string(result)

//then
assert.NoError(t, err)
assert.Equal(t, "foobar", resultStr)

}

type CWMatcher struct {
}

//Checks if a given object is a ContentWrapper
func (CWMatcher) Matches(cw interface{}) bool {
if reflect.TypeOf(cw) == reflect.TypeOf(&ContentWrapper{}) {
return true
}
return false
}
func (CWMatcher) String() string {
return "is a ContentWrapper"
}
10 changes: 9 additions & 1 deletion composition/interface_mocks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ package composition

import (
gomock "github.com/golang/mock/gomock"

io "io"
http "net/http"
)
Expand Down Expand Up @@ -194,6 +194,14 @@ func (_mr *_MockContentRecorder) RequiredContent() *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "RequiredContent")
}

func (_m *MockContent) SetReader(_param0 io.ReadCloser) {
_m.ctrl.Call(_m, "SetReader", _param0)
}

func (_mr *_MockContentRecorder) SetReader(arg0 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "SetReader", arg0)
}

func (_m *MockContent) Tail() Fragment {
ret := _m.ctrl.Call(_m, "Tail")
ret0, _ := ret[0].(Fragment)
Expand Down
Loading

0 comments on commit 69845bb

Please sign in to comment.