add DataService.ResubmitStagingImages function call on server start

This commit is contained in:
Dmitry Verkhoturov
2020-04-23 00:55:13 +02:00
parent 5ae6dcf652
commit 8cb274934e
3 changed files with 128 additions and 0 deletions
+5
View File
@@ -487,6 +487,11 @@ func (a *serverApp) run(ctx context.Context) error {
go a.devAuth.Run(context.Background()) // dev oauth2 server on :8084
}
// staging images resubmit after restart of the app
if e := a.dataService.ResubmitStagingImages(a.Sites); e != nil {
log.Printf("[WARN] failed to resubmit comments with staging images, %s", e)
}
go a.imageService.Cleanup(ctx) // pictures cleanup for staging images
a.restSrv.Run(a.Port)
+23
View File
@@ -200,6 +200,29 @@ func (s *DataStore) DeleteUserDetail(siteID string, userID string, detail engine
})
}
// ResubmitStagingImages retrieves timestamp of the oldest image in staging and
// calls s.submitImages on all comments newer than it
func (s *DataStore) ResubmitStagingImages(sites []string) error {
info, err := s.ImageService.Info()
if err != nil {
return err
}
ts := info.FirstStagingImageTS
if ts.IsZero() {
return nil
}
result := new(multierror.Error)
for _, site := range sites {
locator := store.Locator{SiteID: site}
comments, err := s.FindSince(locator, "time", store.User{}, ts)
result = multierror.Append(result, errors.Wrapf(err, "problem finding comments for site %s", site))
for _, c := range comments {
s.submitImages(c.Locator, c.ID)
}
}
return result.ErrorOrNil()
}
// submitImages initiated delayed commit of all images from the comment uploaded to remark42
func (s *DataStore) submitImages(locator store.Locator, commentID string) {
+100
View File
@@ -1,6 +1,7 @@
package service
import (
"context"
"fmt"
"io/ioutil"
"math/rand"
@@ -1302,6 +1303,105 @@ func TestService_submitImages(t *testing.T) {
time.Sleep(250 * time.Millisecond)
}
func TestService_ResubmitStagingImages(t *testing.T) {
mockStore := image.MockStore{}
imgSvc := image.NewService(&mockStore,
image.ServiceParams{
EditDuration: 10 * time.Millisecond,
ImageAPI: "http://127.0.0.1:8080/api/v1/picture/",
})
defer imgSvc.Close(context.TODO())
eng, teardown := prepStoreEngine(t)
defer teardown()
b := DataStore{Engine: eng, EditDuration: 10 * time.Millisecond, ImageService: imgSvc}
// create comment with three images without preparing it properly
comment := store.Comment{
ID: "id-0",
Text: `<img src="http://127.0.0.1:8080/api/v1/picture/dev_user/bqf122eq9r8ad657n3ng" alt="startrails_01.jpg"><br/>
<img src="http://127.0.0.1:8080/api/v1/picture/dev_user/bqf321eq9r8ad657n3ng" alt="cat.png"><br/>
<img src="https://homepages.cae.wisc.edu/~ece533/images/boat.png" alt="boat.png">`,
Timestamp: time.Date(2017, 12, 20, 15, 18, 22, 0, time.Local),
Locator: store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"},
User: store.User{ID: "user1", Name: "user name"},
}
_, err := b.Engine.Create(comment)
require.NoError(t, err)
// resubmit single comment with three images, of which two are in staging storage
mockStore.On("Info").Once().Return(image.StoreInfo{FirstStagingImageTS: time.Time{}.Add(time.Second)}, nil)
err = b.ResubmitStagingImages([]string{"radio-t"})
assert.NoError(t, err)
// wait for Submit goroutine to commit image
mockStore.On("Commit", "dev_user/bqf122eq9r8ad657n3ng").Once().Return(nil)
mockStore.On("Commit", "dev_user/bqf321eq9r8ad657n3ng").Once().Return(nil)
time.Sleep(time.Millisecond * 100)
mockStore.AssertNumberOfCalls(t, "Info", 1)
mockStore.AssertNumberOfCalls(t, "Commit", 2)
// empty answer
mockStoreEmpty := image.MockStore{}
imgSvcEmpty := image.NewService(&mockStoreEmpty,
image.ServiceParams{
EditDuration: 10 * time.Millisecond,
ImageAPI: "http://127.0.0.1:8080/api/v1/picture/",
})
defer imgSvcEmpty.Close(context.TODO())
bEmpty := DataStore{Engine: eng, EditDuration: 10 * time.Millisecond, ImageService: imgSvcEmpty}
// resubmit receive empty timestamp and should do nothing
mockStoreEmpty.On("Info").Once().Return(image.StoreInfo{FirstStagingImageTS: time.Time{}}, nil)
err = bEmpty.ResubmitStagingImages([]string{"radio-t", "non_existent"})
assert.NoError(t, err)
mockStoreEmpty.AssertNumberOfCalls(t, "Info", 1)
// error from image storage
mockStoreError := image.MockStore{}
imgSvcError := image.NewService(&mockStoreError,
image.ServiceParams{
EditDuration: 10 * time.Millisecond,
ImageAPI: "http://127.0.0.1:8080/api/v1/picture/",
})
defer imgSvcError.Close(context.TODO())
bError := DataStore{Engine: eng, EditDuration: 10 * time.Millisecond, ImageService: imgSvcError}
// resubmit will receive error from image storage and should return it
mockStoreError.On("Info").Once().Return(image.StoreInfo{}, errors.New("mock_err"))
err = bError.ResubmitStagingImages([]string{"radio-t"})
assert.EqualError(t, err, "mock_err")
mockStoreError.AssertNumberOfCalls(t, "Info", 1)
}
func TestService_ResubmitStagingImages_EngineError(t *testing.T) {
mockStore := image.MockStore{}
imgSvc := image.NewService(&mockStore,
image.ServiceParams{
EditDuration: 10 * time.Millisecond,
ImageAPI: "http://127.0.0.1:8080/api/v1/picture/",
})
defer imgSvc.Close(context.TODO())
engineMock := engine.MockInterface{}
site1Req := engine.FindRequest{Locator: store.Locator{SiteID: "site1", URL: ""}, Sort: "time", Since: time.Time{}.Add(time.Second)}
site2Req := engine.FindRequest{Locator: store.Locator{SiteID: "site2", URL: ""}, Sort: "time", Since: time.Time{}.Add(time.Second)}
engineMock.On("Find", site1Req).Return(nil, nil)
engineMock.On("Find", site2Req).Return(nil, errors.New("mockError"))
b := DataStore{Engine: &engineMock, EditDuration: 10 * time.Millisecond, ImageService: imgSvc}
// One call without error and one with error
mockStore.On("Info").Once().Return(image.StoreInfo{FirstStagingImageTS: time.Time{}.Add(time.Second)}, nil)
err := b.ResubmitStagingImages([]string{"site1", "site2"})
assert.Error(t, err)
assert.Contains(t, err.Error(), "problem finding comments for site site2: mockError")
mockStore.AssertNumberOfCalls(t, "Info", 1)
}
func TestService_alterComment(t *testing.T) {
engineMock := engine.MockInterface{}