Skip to content

Commit

Permalink
Merge a69bb12 into a20264d
Browse files Browse the repository at this point in the history
  • Loading branch information
denge90 committed Aug 1, 2016
2 parents a20264d + a69bb12 commit 8d99b96
Show file tree
Hide file tree
Showing 8 changed files with 134 additions and 3 deletions.
20 changes: 19 additions & 1 deletion cache/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,6 @@ func (c *Cache) PurgeOldEntries() {
c.lock.RLock()
keys := c.lruBackend.Keys()
c.lock.RUnlock()

purged := 0
for _, key := range keys {
c.lock.RLock()
Expand All @@ -163,7 +162,26 @@ func (c *Cache) PurgeOldEntries() {
logging.Logger.
WithFields(logrus.Fields(c.stats)).
Infof("purged %v out of %v cache entries", purged, len(keys))
}

// Purge Entries with a specific hash
func (c *Cache) PurgeEntries(keys []string) {
purged := 0
for _, key := range keys {
c.lock.RLock()
_, found := c.lruBackend.Peek(key)
c.lock.RUnlock()

if found {
c.lock.Lock()
c.lruBackend.Remove(key)
c.lock.Unlock()
purged++
}
}
logging.Logger.
WithFields(logrus.Fields(c.stats)).
Infof("purged %v out of %v cache entries", purged, len(keys))
}

func (c *Cache) Invalidate() {
Expand Down
16 changes: 16 additions & 0 deletions cache/cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,22 @@ func Test_Cache_PurgeOldEntries(t *testing.T) {
a.Equal(84, c.SizeByte())
}

func Test_Cache_PurgeEntries(t *testing.T) {
a := assert.New(t)

c := NewCache("my-cache", 100, 100, time.Millisecond)
c.Set("hashStringToPurge", "", 1, nil)
c.Set("hashStringToStay", "", 1, nil)

c.PurgeEntries([]string{"hashStringToPurge"})

_, foundInCachePurge := c.Get("hashStringToPurge")
_, foundInCacheStay := c.Get("hashStringToStay")

a.False(foundInCachePurge)
a.True(foundInCacheStay)
}

func Test_Cache_Invalidation(t *testing.T) {
a := assert.New(t)

Expand Down
15 changes: 15 additions & 0 deletions composition/composition_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type ContentFetcherFactory func(r *http.Request) FetchResultSupplier
type CompositionHandler struct {
contentFetcherFactory ContentFetcherFactory
contentMergerFactory func(metaJSON map[string]interface{}) ContentMerger
cache Cache
}

// NewCompositionHandler creates a new Handler with the supplied defualtData,
Expand All @@ -25,6 +26,17 @@ func NewCompositionHandler(contentFetcherFactory ContentFetcherFactory) *Composi
contentMergerFactory: func(metaJSON map[string]interface{}) ContentMerger {
return NewContentMerge(metaJSON)
},
cache: nil,
}
}

func NewCompositionHandlerWithCache(contentFetcherFactory ContentFetcherFactory, cache Cache) *CompositionHandler {
return &CompositionHandler{
contentFetcherFactory: contentFetcherFactory,
contentMergerFactory: func(metaJSON map[string]interface{}) ContentMerger {
return NewContentMerge(metaJSON)
},
cache: cache,
}
}

Expand Down Expand Up @@ -89,6 +101,9 @@ func (agg *CompositionHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)

html, err := mergeContext.GetHtml()
if err != nil {
if agg.cache != nil {
agg.cache.PurgeEntries(mergeContext.GetHashes())
}
logging.Application(r.Header).Error(err.Error())
http.Error(w, "Internal Server Error: "+err.Error(), 500)
return
Expand Down
42 changes: 41 additions & 1 deletion composition/composition_handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ import (
"errors"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
"github.com/tarent/lib-compose/cache"
"io/ioutil"
"net/http"
"net/http/httptest"
"net/url"
"strings"
"testing"
"time"
)

func Test_CompositionHandler_PositiveCase(t *testing.T) {
Expand Down Expand Up @@ -159,12 +161,51 @@ func Test_CompositionHandler_ErrorInMerging(t *testing.T) {

resp := httptest.NewRecorder()
r, _ := http.NewRequest("GET", "http://example.com", nil)

aggregator.ServeHTTP(resp, r)

a.Equal("Internal Server Error: an error\n", string(resp.Body.Bytes()))
a.Equal(500, resp.Code)
}

func Test_CompositionHandler_ErrorInMergingWithCache(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
a := assert.New(t)

contentFetcherFactory := func(r *http.Request) FetchResultSupplier {
return MockFetchResultSupplier{
&FetchResult{
Def: NewFetchDefinition("/foo"),
Content: &MemoryContent{},
Err: nil,
Hash: "hashString",
},
}
}

aggregator := NewCompositionHandlerWithCache(ContentFetcherFactory(contentFetcherFactory), cache.NewCache("my-cache", 100, 100, time.Millisecond))
aggregator.cache.Set("hashString", "", 1, nil)
aggregator.contentMergerFactory = func(jsonData map[string]interface{}) ContentMerger {
merger := NewMockContentMerger(ctrl)
merger.EXPECT().AddContent(gomock.Any())
merger.EXPECT().GetHtml().Return(nil, errors.New("an error"))
merger.EXPECT().GetHashes().Return([]string{"hashString"})
return merger
}

resp := httptest.NewRecorder()
r, _ := http.NewRequest("GET", "http://example.com", nil)

aggregator.ServeHTTP(resp, r)

_, foundInCache := aggregator.cache.Get("hashString")

a.False(foundInCache)
a.Equal("Internal Server Error: an error\n", string(resp.Body.Bytes()))
a.Equal(500, resp.Code)
}

func Test_CompositionHandler_ErrorInFetching(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
Expand Down Expand Up @@ -287,4 +328,3 @@ func (m MockFetchResultSupplier) MetaJSON() map[string]interface{} {
func (m MockFetchResultSupplier) Empty() bool {
return len([]*FetchResult(m)) == 0
}

13 changes: 13 additions & 0 deletions composition/content_merge.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ type ContentMerge struct {
Body map[string]Fragment
Tail []Fragment
Buffered bool
FdHashes []string
}

// NewContentMerge creates a new buffered ContentMerge
Expand All @@ -32,6 +33,7 @@ func NewContentMerge(metaJSON map[string]interface{}) *ContentMerge {
Body: make(map[string]Fragment),
Tail: make([]Fragment, 0, 0),
Buffered: true,
FdHashes: make([]string, 0, 0),
}
return cntx
}
Expand Down Expand Up @@ -88,6 +90,11 @@ func (cntx *ContentMerge) AddContent(fetchResult *FetchResult) {
cntx.addBodyAttributes(fetchResult.Content.BodyAttributes())
cntx.addBody(fetchResult.Def.URL, fetchResult.Content.Body())
cntx.addTail(fetchResult.Content.Tail())
cntx.addFdHash(fetchResult.Hash)
}

func (cntx *ContentMerge) GetHashes() []string {
return cntx.FdHashes
}

func (cntx *ContentMerge) addHead(f Fragment) {
Expand Down Expand Up @@ -116,6 +123,12 @@ func (cntx *ContentMerge) addTail(f Fragment) {
}
}

func (cntx *ContentMerge) addFdHash(hash string) {
if hash != "" {
cntx.FdHashes = append(cntx.FdHashes, hash)
}
}

// Returns a name from a url, which has template placeholders eliminated
func urlToFragmentName(url string) string {
url = strings.Replace(url, `§[`, `\§\[`, -1)
Expand Down
8 changes: 8 additions & 0 deletions composition/content_merge_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,14 @@ func Test_ContentMerge_MainFragmentDoesNotExist(t *testing.T) {
a.Equal("Fragment does not exist: . Existing fragments: ", err.Error())
}

func Test_ContentMerge_FdHashes(t *testing.T) {
a := assert.New(t)
cm := NewContentMerge(nil)

cm.addFdHash("testHash")
a.Equal(cm.GetHashes()[0], "testHash")
}

type closedWriterMock struct {
}

Expand Down
19 changes: 18 additions & 1 deletion composition/interface_mocks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ package composition
import (
gomock "github.com/golang/mock/gomock"
io "io"

http "net/http"
)

Expand Down Expand Up @@ -243,6 +242,16 @@ func (_mr *_MockContentMergerRecorder) AddContent(arg0 interface{}) *gomock.Call
return _mr.mock.ctrl.RecordCall(_mr.mock, "AddContent", arg0)
}

func (_m *MockContentMerger) GetHashes() []string {
ret := _m.ctrl.Call(_m, "GetHashes")
ret0, _ := ret[0].([]string)
return ret0
}

func (_mr *_MockContentMergerRecorder) GetHashes() *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "GetHashes")
}

func (_m *MockContentMerger) GetHtml() ([]byte, error) {
ret := _m.ctrl.Call(_m, "GetHtml")
ret0, _ := ret[0].([]byte)
Expand Down Expand Up @@ -356,6 +365,14 @@ func (_mr *_MockCacheRecorder) Invalidate() *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "Invalidate")
}

func (_m *MockCache) PurgeEntries(_param0 []string) {
_m.ctrl.Call(_m, "PurgeEntries", _param0)
}

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

func (_m *MockCache) Set(_param0 string, _param1 string, _param2 int, _param3 interface{}) {
_m.ctrl.Call(_m, "Set", _param0, _param1, _param2, _param3)
}
Expand Down
4 changes: 4 additions & 0 deletions composition/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ type ContentMerger interface {

// Return the html as byte array
GetHtml() ([]byte, error)

// Return initial hashes related to the given contents
GetHashes() []string
}

type ResponseProcessor interface {
Expand All @@ -110,4 +113,5 @@ type Cache interface {
Get(hash string) (cacheObject interface{}, found bool)
Set(hash string, label string, memorySize int, cacheObject interface{})
Invalidate()
PurgeEntries(keys []string)
}

0 comments on commit 8d99b96

Please sign in to comment.