From ef790161db19e16ddf5c6514593b0d3da70c7bd9 Mon Sep 17 00:00:00 2001 From: Umputun Date: Sat, 9 Jun 2018 13:12:04 -0500 Subject: [PATCH] lock on votes, fix #77 --- app/store/service/service.go | 6 ++++++ app/store/service/service_test.go | 32 +++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/app/store/service/service.go b/app/store/service/service.go index b2b3c47d..c2ff0fe1 100644 --- a/app/store/service/service.go +++ b/app/store/service/service.go @@ -1,6 +1,7 @@ package service import ( + "sync" "time" "github.com/google/uuid" @@ -16,6 +17,8 @@ type DataStore struct { EditDuration time.Duration Secret string MaxCommentSize int + + lock sync.Mutex } const defaultCommentMaxSize = 2000 @@ -53,6 +56,9 @@ func (s *DataStore) SetPin(locator store.Locator, commentID string, status bool) // Vote for comment by id and locator func (s *DataStore) Vote(locator store.Locator, commentID string, userID string, val bool) (comment store.Comment, err error) { + s.lock.Lock() + defer s.lock.Unlock() + comment, err = s.Get(locator, commentID) if err != nil { return comment, err diff --git a/app/store/service/service_test.go b/app/store/service/service_test.go index 94b18ce3..bbc66eb6 100644 --- a/app/store/service/service_test.go +++ b/app/store/service/service_test.go @@ -170,7 +170,39 @@ func TestService_VoteAggressive(t *testing.T) { assert.Equal(t, 3, len(res)) t.Logf("%+v %d", res[0], res[0].Score) assert.True(t, res[0].Score >= 0 && res[0].Score <= 2, "unexpected score %d", res[0].Score) +} +func TestService_VoteConcurrent(t *testing.T) { + + defer os.Remove(testDb) + b := DataStore{Interface: prepStoreEngine(t)} + + comment := store.Comment{ + Text: "text", + User: store.User{IP: "192.168.1.1", ID: "user", Name: "name"}, + Locator: store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, + } + _, err := b.Create(comment) + assert.NoError(t, err) + res, err := b.Last("radio-t", 0) + require.Nil(t, err) + + // concurrent vote +1 as multiple users for the same comment + var wg sync.WaitGroup + for i := 0; i < 1000; i++ { + wg.Add(1) + i := i + go func() { + defer wg.Done() + b.Vote(store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, res[0].ID, fmt.Sprintf("user1-%d", i), true) + }() + } + wg.Wait() + res, err = b.Last("radio-t", 0) + require.NoError(t, err) + t.Logf("%+v %d", res[0], res[0].Score) + assert.Equal(t, 1000, res[0].Score, "should have 1000 score") + assert.Equal(t, 1000, len(res[0].Votes), "should have 1000 votes") } func TestService_Pin(t *testing.T) {