Image interface changes (#623)
@paskal * sort imports, add missing copyright * regenerate engine mock * make all image.Store interface functions public * go mod tidy * make image.Store.Load return []byte instead of io.ReadCloser * separate memory_store example RPC server to multiple files by handlers groups
This commit is contained in:
@@ -9,6 +9,7 @@ package accessor
|
||||
import (
|
||||
log "github.com/go-pkgz/lgr"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/umputun/remark/backend/app/store/admin"
|
||||
)
|
||||
|
||||
|
||||
@@ -14,9 +14,8 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/umputun/remark/backend/app/store/engine"
|
||||
|
||||
"github.com/umputun/remark/backend/app/store"
|
||||
"github.com/umputun/remark/backend/app/store/engine"
|
||||
)
|
||||
|
||||
const lastLimit = 1000
|
||||
|
||||
@@ -157,6 +157,7 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rakyll/statik v0.1.6/go.mod h1:OEi9wJV/fMUAGx1eNjq75DKDsJVuEv1U0oYdX6GX8Zs=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc=
|
||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
||||
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
@@ -220,6 +221,7 @@ golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgn
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190523035834-f03afa92d3ff/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 h1:hVwzHzIUGRjiF7EcUjqNxk3NCfkPxbDKRdnNE1Rpg0U=
|
||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2020 Umputun. All rights reserved.
|
||||
* Use of this source code is governed by a MIT-style
|
||||
* license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/go-pkgz/jrpc"
|
||||
"github.com/umputun/remark/backend/app/store/admin"
|
||||
)
|
||||
|
||||
// get admin key
|
||||
func (s *RPC) admKeyHndl(id uint64, _ json.RawMessage) (rr jrpc.Response) {
|
||||
key, err := s.adm.Key()
|
||||
if err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
return jrpc.EncodeResponse(id, key, err)
|
||||
}
|
||||
|
||||
// get admins list
|
||||
func (s *RPC) admAdminsHndl(id uint64, params json.RawMessage) (rr jrpc.Response) {
|
||||
var siteID string
|
||||
if err := json.Unmarshal(params, &siteID); err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
|
||||
admins, err := s.adm.Admins(siteID)
|
||||
if err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
return jrpc.EncodeResponse(id, admins, err)
|
||||
}
|
||||
|
||||
// get admin email
|
||||
func (s *RPC) admEmailHndl(id uint64, params json.RawMessage) (rr jrpc.Response) {
|
||||
var siteID string
|
||||
if err := json.Unmarshal(params, &siteID); err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
|
||||
email, err := s.adm.Email(siteID)
|
||||
if err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
return jrpc.EncodeResponse(id, email, err)
|
||||
}
|
||||
|
||||
// return site enabled status
|
||||
func (s *RPC) admEnabledHndl(id uint64, params json.RawMessage) (rr jrpc.Response) {
|
||||
var siteID string
|
||||
if err := json.Unmarshal(params, &siteID); err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
|
||||
ok, err := s.adm.Enabled(siteID)
|
||||
if err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
return jrpc.EncodeResponse(id, ok, err)
|
||||
}
|
||||
|
||||
// onEvent returns nothing, callback to OnEvent
|
||||
func (s *RPC) admEventHndl(id uint64, params json.RawMessage) (rr jrpc.Response) {
|
||||
var siteID string
|
||||
var ps []interface{}
|
||||
if err := json.Unmarshal(params, &ps); err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
siteID, ok := ps[0].(string)
|
||||
if !ok {
|
||||
return jrpc.Response{Error: "wrong siteID type"}
|
||||
}
|
||||
evType, ok := ps[1].(float64)
|
||||
if !ok {
|
||||
return jrpc.Response{Error: "wrong event type"}
|
||||
}
|
||||
err := s.adm.OnEvent(siteID, admin.EventType(evType))
|
||||
if err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
return jrpc.EncodeResponse(id, nil, err)
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2020 Umputun. All rights reserved.
|
||||
* Use of this source code is governed by a MIT-style
|
||||
* license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/go-pkgz/jrpc"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/umputun/remark/backend/app/store/admin"
|
||||
)
|
||||
|
||||
func TestRPC_admKeyHndl(t *testing.T) {
|
||||
_, port, teardown := prepTestStore(t)
|
||||
defer teardown()
|
||||
api := fmt.Sprintf("http://localhost:%d/test", port)
|
||||
|
||||
ra := admin.RPC{Client: jrpc.Client{API: api, Client: http.Client{Timeout: 1 * time.Second}}}
|
||||
key, err := ra.Key()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "secret", key)
|
||||
}
|
||||
|
||||
func TestRPC_admAdminsHndl(t *testing.T) {
|
||||
_, port, teardown := prepTestStore(t)
|
||||
defer teardown()
|
||||
api := fmt.Sprintf("http://localhost:%d/test", port)
|
||||
|
||||
ra := admin.RPC{Client: jrpc.Client{API: api, Client: http.Client{Timeout: 1 * time.Second}}}
|
||||
_, err := ra.Admins("bad site")
|
||||
assert.EqualError(t, err, "site bad site not found")
|
||||
|
||||
admins, err := ra.Admins("test-site")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []string{"id1", "id2"}, admins)
|
||||
}
|
||||
|
||||
func TestRPC_admEmailHndl(t *testing.T) {
|
||||
_, port, teardown := prepTestStore(t)
|
||||
defer teardown()
|
||||
api := fmt.Sprintf("http://localhost:%d/test", port)
|
||||
|
||||
ra := admin.RPC{Client: jrpc.Client{API: api, Client: http.Client{Timeout: 1 * time.Second}}}
|
||||
_, err := ra.Admins("bad site")
|
||||
assert.EqualError(t, err, "site bad site not found")
|
||||
|
||||
email, err := ra.Email("test-site")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "admin@example.com", email)
|
||||
}
|
||||
|
||||
func TestRPC_admEnabledHndl(t *testing.T) {
|
||||
_, port, teardown := prepTestStore(t)
|
||||
defer teardown()
|
||||
api := fmt.Sprintf("http://localhost:%d/test", port)
|
||||
|
||||
ra := admin.RPC{Client: jrpc.Client{API: api, Client: http.Client{Timeout: 1 * time.Second}}}
|
||||
_, err := ra.Enabled("bad site")
|
||||
assert.EqualError(t, err, "site bad site not found")
|
||||
|
||||
ok, err := ra.Enabled("test-site")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, true, ok)
|
||||
|
||||
ok, err = ra.Enabled("test-site-disabled")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, ok)
|
||||
}
|
||||
|
||||
func TestRPC_admEventHndl(t *testing.T) {
|
||||
_, port, teardown := prepTestStore(t)
|
||||
defer teardown()
|
||||
api := fmt.Sprintf("http://localhost:%d/test", port)
|
||||
|
||||
ra := admin.RPC{Client: jrpc.Client{API: api, Client: http.Client{Timeout: 1 * time.Second}}}
|
||||
err := ra.OnEvent("bad site", admin.EvCreate)
|
||||
assert.EqualError(t, err, "site bad site not found")
|
||||
|
||||
err = ra.OnEvent("test-site", admin.EvCreate)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright 2020 Umputun. All rights reserved.
|
||||
* Use of this source code is governed by a MIT-style
|
||||
* license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/go-pkgz/jrpc"
|
||||
"github.com/umputun/remark/backend/app/store"
|
||||
"github.com/umputun/remark/backend/app/store/engine"
|
||||
)
|
||||
|
||||
func (s *RPC) createHndl(id uint64, params json.RawMessage) (rr jrpc.Response) {
|
||||
comment := store.Comment{}
|
||||
if err := json.Unmarshal(params, &comment); err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
commentID, err := s.eng.Create(comment)
|
||||
return jrpc.EncodeResponse(id, commentID, err)
|
||||
}
|
||||
|
||||
// Find comments
|
||||
func (s *RPC) findHndl(id uint64, params json.RawMessage) (rr jrpc.Response) {
|
||||
req := engine.FindRequest{}
|
||||
if err := json.Unmarshal(params, &req); err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
resp, err := s.eng.Find(req)
|
||||
return jrpc.EncodeResponse(id, resp, err)
|
||||
}
|
||||
|
||||
// Get comment
|
||||
func (s *RPC) getHndl(id uint64, params json.RawMessage) (rr jrpc.Response) {
|
||||
req := engine.GetRequest{}
|
||||
if err := json.Unmarshal(params, &req); err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
comment, err := s.eng.Get(req)
|
||||
return jrpc.EncodeResponse(id, comment, err)
|
||||
}
|
||||
|
||||
// Update comment
|
||||
func (s *RPC) updateHndl(id uint64, params json.RawMessage) (rr jrpc.Response) {
|
||||
comment := store.Comment{}
|
||||
if err := json.Unmarshal(params, &comment); err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
err := s.eng.Update(comment)
|
||||
return jrpc.EncodeResponse(id, nil, err)
|
||||
}
|
||||
|
||||
// counts for site and users
|
||||
func (s *RPC) countHndl(id uint64, params json.RawMessage) (rr jrpc.Response) {
|
||||
req := engine.FindRequest{}
|
||||
if err := json.Unmarshal(params, &req); err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
count, err := s.eng.Count(req)
|
||||
return jrpc.EncodeResponse(id, count, err)
|
||||
}
|
||||
|
||||
// info get post meta info
|
||||
func (s *RPC) infoHndl(id uint64, params json.RawMessage) (rr jrpc.Response) {
|
||||
req := engine.InfoRequest{}
|
||||
if err := json.Unmarshal(params, &req); err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
info, err := s.eng.Info(req)
|
||||
return jrpc.EncodeResponse(id, info, err)
|
||||
}
|
||||
|
||||
// flagHndl get and sets flag value
|
||||
func (s *RPC) flagHndl(id uint64, params json.RawMessage) (rr jrpc.Response) {
|
||||
req := engine.FlagRequest{}
|
||||
if err := json.Unmarshal(params, &req); err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
status, err := s.eng.Flag(req)
|
||||
return jrpc.EncodeResponse(id, status, err)
|
||||
}
|
||||
|
||||
// listFlagsHndl list flags for given request
|
||||
func (s *RPC) listFlagsHndl(id uint64, params json.RawMessage) (rr jrpc.Response) {
|
||||
req := engine.FlagRequest{}
|
||||
if err := json.Unmarshal(params, &req); err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
flags, err := s.eng.ListFlags(req)
|
||||
return jrpc.EncodeResponse(id, flags, err)
|
||||
}
|
||||
|
||||
// userDetailHndl sets or gets single detail value, or gets all details for requested site.
|
||||
// userDetailHndl returns list even for single entry request is a compromise in order to have both single detail getting and setting
|
||||
// and all site's details listing under the same function (and not to extend engine interface by two separate functions).
|
||||
func (s *RPC) userDetailHndl(id uint64, params json.RawMessage) (rr jrpc.Response) {
|
||||
req := engine.UserDetailRequest{}
|
||||
if err := json.Unmarshal(params, &req); err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
value, err := s.eng.UserDetail(req)
|
||||
return jrpc.EncodeResponse(id, value, err)
|
||||
}
|
||||
|
||||
// deleteHndl delete post(s), user, comment, user details, or everything
|
||||
func (s *RPC) deleteHndl(id uint64, params json.RawMessage) (rr jrpc.Response) {
|
||||
req := engine.DeleteRequest{}
|
||||
if err := json.Unmarshal(params, &req); err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
err := s.eng.Delete(req)
|
||||
return jrpc.EncodeResponse(id, nil, err)
|
||||
}
|
||||
|
||||
// close store
|
||||
func (s *RPC) closeHndl(_ uint64, _ json.RawMessage) (rr jrpc.Response) {
|
||||
if err := s.eng.Close(); err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
return jrpc.Response{}
|
||||
}
|
||||
@@ -0,0 +1,305 @@
|
||||
/*
|
||||
* Copyright 2020 Umputun. All rights reserved.
|
||||
* Use of this source code is governed by a MIT-style
|
||||
* license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/go-pkgz/jrpc"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/umputun/remark/backend/app/store"
|
||||
"github.com/umputun/remark/backend/app/store/engine"
|
||||
)
|
||||
|
||||
func TestRPC_createHndl(t *testing.T) {
|
||||
_, port, teardown := prepTestStore(t)
|
||||
defer teardown()
|
||||
api := fmt.Sprintf("http://localhost:%d/test", port)
|
||||
|
||||
re := engine.RPC{Client: jrpc.Client{API: api, Client: http.Client{Timeout: 1 * time.Second}}}
|
||||
id, err := re.Create(store.Comment{ID: "123456", Locator: store.Locator{SiteID: "test-site", URL: "http://example.com/post1"},
|
||||
Text: "text 123", User: store.User{ID: "u1", Name: "user1"}})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "123456", id)
|
||||
}
|
||||
|
||||
func TestRPC_findHndl(t *testing.T) {
|
||||
_, port, teardown := prepTestStore(t)
|
||||
defer teardown()
|
||||
api := fmt.Sprintf("http://localhost:%d/test", port)
|
||||
|
||||
re := engine.RPC{Client: jrpc.Client{API: api, Client: http.Client{Timeout: 1 * time.Second}}}
|
||||
findReq := engine.FindRequest{Locator: store.Locator{SiteID: "test-site", URL: "http://example.com/post1"}}
|
||||
comments, err := re.Find(findReq)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 0, len(comments))
|
||||
|
||||
c := store.Comment{ID: "123456", Locator: store.Locator{SiteID: "test-site", URL: "http://example.com/post1"},
|
||||
Text: "text 123", User: store.User{ID: "u1", Name: "user1"}}
|
||||
id, err := re.Create(c)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "123456", id)
|
||||
|
||||
comments, err = re.Find(findReq)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 1, len(comments))
|
||||
assert.Equal(t, c, comments[0])
|
||||
}
|
||||
|
||||
func TestRPC_getHndl(t *testing.T) {
|
||||
_, port, teardown := prepTestStore(t)
|
||||
defer teardown()
|
||||
api := fmt.Sprintf("http://localhost:%d/test", port)
|
||||
|
||||
re := engine.RPC{Client: jrpc.Client{API: api, Client: http.Client{Timeout: 1 * time.Second}}}
|
||||
req := engine.GetRequest{
|
||||
Locator: store.Locator{SiteID: "test-site", URL: "http://example.com/post1"},
|
||||
CommentID: "123456",
|
||||
}
|
||||
|
||||
_, err := re.Get(req)
|
||||
assert.EqualError(t, err, "not found")
|
||||
|
||||
c := store.Comment{ID: "123456", Locator: store.Locator{SiteID: "test-site", URL: "http://example.com/post1"},
|
||||
Text: "text 123", User: store.User{ID: "u1", Name: "user1"}}
|
||||
_, err = re.Create(c)
|
||||
assert.NoError(t, err)
|
||||
|
||||
comment, err := re.Get(req)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, c, comment)
|
||||
}
|
||||
|
||||
func TestRPC_updateHndl(t *testing.T) {
|
||||
_, port, teardown := prepTestStore(t)
|
||||
defer teardown()
|
||||
api := fmt.Sprintf("http://localhost:%d/test", port)
|
||||
|
||||
re := engine.RPC{Client: jrpc.Client{API: api, Client: http.Client{Timeout: 1 * time.Second}}}
|
||||
|
||||
c := store.Comment{ID: "123456", Locator: store.Locator{SiteID: "test-site", URL: "http://example.com/post1"},
|
||||
Text: "text 123", User: store.User{ID: "u1", Name: "user1"}}
|
||||
err := re.Update(c)
|
||||
assert.EqualError(t, err, "not found")
|
||||
|
||||
_, err = re.Create(c)
|
||||
assert.NoError(t, err)
|
||||
|
||||
c.Text = "updates"
|
||||
err = re.Update(c)
|
||||
assert.NoError(t, err)
|
||||
|
||||
req := engine.GetRequest{
|
||||
Locator: store.Locator{SiteID: "test-site", URL: "http://example.com/post1"},
|
||||
CommentID: "123456",
|
||||
}
|
||||
comment, err := re.Get(req)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, c, comment)
|
||||
}
|
||||
|
||||
func TestRPC_countHndl(t *testing.T) {
|
||||
_, port, teardown := prepTestStore(t)
|
||||
defer teardown()
|
||||
api := fmt.Sprintf("http://localhost:%d/test", port)
|
||||
|
||||
re := engine.RPC{Client: jrpc.Client{API: api, Client: http.Client{Timeout: 1 * time.Second}}}
|
||||
findReq := engine.FindRequest{Locator: store.Locator{SiteID: "test-site", URL: "http://example.com/post1"}}
|
||||
count, err := re.Count(findReq)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 0, count)
|
||||
|
||||
c := store.Comment{ID: "123456", Locator: store.Locator{SiteID: "test-site", URL: "http://example.com/post1"},
|
||||
Text: "text 123", User: store.User{ID: "u1", Name: "user1"}}
|
||||
id, err := re.Create(c)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "123456", id)
|
||||
|
||||
count, err = re.Count(findReq)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 1, count)
|
||||
}
|
||||
|
||||
func TestRPC_infoHndl(t *testing.T) {
|
||||
_, port, teardown := prepTestStore(t)
|
||||
defer teardown()
|
||||
api := fmt.Sprintf("http://localhost:%d/test", port)
|
||||
|
||||
re := engine.RPC{Client: jrpc.Client{API: api, Client: http.Client{Timeout: 1 * time.Second}}}
|
||||
|
||||
c := store.Comment{ID: "123456", Locator: store.Locator{SiteID: "test-site", URL: "http://example.com/post1"},
|
||||
Text: "text 123", User: store.User{ID: "u1", Name: "user1"}}
|
||||
id, err := re.Create(c)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "123456", id)
|
||||
|
||||
infoReq := engine.InfoRequest{Locator: store.Locator{SiteID: "test-site", URL: "http://example.com/post1"}}
|
||||
info, err := re.Info(infoReq)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 1, len(info))
|
||||
i := info[0]
|
||||
assert.Equal(t, store.PostInfo{URL: "http://example.com/post1", Count: 1}, i)
|
||||
}
|
||||
|
||||
func TestRPC_flagHndl(t *testing.T) {
|
||||
_, port, teardown := prepTestStore(t)
|
||||
defer teardown()
|
||||
api := fmt.Sprintf("http://localhost:%d/test", port)
|
||||
|
||||
re := engine.RPC{Client: jrpc.Client{API: api, Client: http.Client{Timeout: 1 * time.Second}}}
|
||||
|
||||
c := store.Comment{ID: "123456", Locator: store.Locator{SiteID: "test-site", URL: "http://example.com/post1"},
|
||||
Text: "text 123", User: store.User{ID: "u1", Name: "user1"}}
|
||||
id, err := re.Create(c)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "123456", id)
|
||||
|
||||
flagReq := engine.FlagRequest{
|
||||
Flag: engine.Verified,
|
||||
Locator: store.Locator{
|
||||
SiteID: "test-site",
|
||||
},
|
||||
UserID: "u1",
|
||||
}
|
||||
status, err := re.Flag(flagReq)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, false, status)
|
||||
|
||||
flagReq.Update = engine.FlagTrue
|
||||
status, err = re.Flag(flagReq)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, status)
|
||||
|
||||
flagReq.Update = engine.FlagNonSet
|
||||
status, err = re.Flag(flagReq)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, status)
|
||||
}
|
||||
|
||||
func TestRPC_listFlagsHndl(t *testing.T) {
|
||||
_, port, teardown := prepTestStore(t)
|
||||
defer teardown()
|
||||
api := fmt.Sprintf("http://localhost:%d/test", port)
|
||||
|
||||
re := engine.RPC{Client: jrpc.Client{API: api, Client: http.Client{Timeout: 1 * time.Second}}}
|
||||
|
||||
c := store.Comment{ID: "123456", Locator: store.Locator{SiteID: "test-site", URL: "http://example.com/post1"},
|
||||
Text: "text 123", User: store.User{ID: "u1", Name: "user1"}}
|
||||
id, err := re.Create(c)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "123456", id)
|
||||
|
||||
flagReq := engine.FlagRequest{
|
||||
Flag: engine.Verified,
|
||||
UserID: "u1",
|
||||
Locator: store.Locator{
|
||||
SiteID: "test-site",
|
||||
},
|
||||
}
|
||||
flags, err := re.ListFlags(flagReq)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []interface{}{}, flags)
|
||||
|
||||
flagReq.Update = engine.FlagTrue
|
||||
status, err := re.Flag(flagReq)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, status)
|
||||
|
||||
flags, err = re.ListFlags(flagReq)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []interface{}{"u1"}, flags)
|
||||
}
|
||||
|
||||
func TestRPC_userDetailHndl(t *testing.T) {
|
||||
_, port, teardown := prepTestStore(t)
|
||||
defer teardown()
|
||||
api := fmt.Sprintf("http://localhost:%d/test", port)
|
||||
|
||||
re := engine.RPC{Client: jrpc.Client{API: api, Client: http.Client{Timeout: 1 * time.Second}}}
|
||||
|
||||
// add to entries to DB before we start
|
||||
result, err := re.UserDetail(engine.UserDetailRequest{Locator: store.Locator{SiteID: "test-site"}, UserID: "u1", Detail: engine.UserEmail, Update: "test@example.com"})
|
||||
assert.NoError(t, err, "No error inserting entry expected")
|
||||
assert.ElementsMatch(t, []engine.UserDetailEntry{{UserID: "u1", Email: "test@example.com"}}, result)
|
||||
result, err = re.UserDetail(engine.UserDetailRequest{Locator: store.Locator{SiteID: "test-site"}, UserID: "u2", Detail: engine.UserEmail, Update: "other@example.com"})
|
||||
assert.NoError(t, err, "No error inserting entry expected")
|
||||
assert.ElementsMatch(t, []engine.UserDetailEntry{{UserID: "u2", Email: "other@example.com"}}, result)
|
||||
|
||||
// try to change existing entry with wrong SiteID
|
||||
result, err = re.UserDetail(engine.UserDetailRequest{Locator: store.Locator{SiteID: "bad"}, UserID: "u2", Detail: engine.UserEmail, Update: "not_relevant"})
|
||||
assert.NoError(t, err, "Updating existing entry with wrong SiteID doesn't produce error")
|
||||
assert.ElementsMatch(t, []engine.UserDetailEntry{}, result, "Updating existing entry with wrong SiteID doesn't change anything")
|
||||
|
||||
// stateless tests without changing the state we set up before
|
||||
var testData = []struct {
|
||||
req engine.UserDetailRequest
|
||||
error string
|
||||
expected []engine.UserDetailEntry
|
||||
}{
|
||||
{req: engine.UserDetailRequest{Locator: store.Locator{SiteID: "test-site"}, UserID: "u1", Detail: engine.UserEmail},
|
||||
expected: []engine.UserDetailEntry{{UserID: "u1", Email: "test@example.com"}}},
|
||||
{req: engine.UserDetailRequest{Locator: store.Locator{SiteID: "bad"}, UserID: "u1", Detail: engine.UserEmail},
|
||||
expected: []engine.UserDetailEntry{}},
|
||||
{req: engine.UserDetailRequest{Locator: store.Locator{SiteID: "test-site"}, UserID: "u1xyz", Detail: engine.UserEmail},
|
||||
expected: []engine.UserDetailEntry{}},
|
||||
{req: engine.UserDetailRequest{Detail: engine.UserEmail, Update: "new_value"},
|
||||
error: `userid cannot be empty in request for single detail`},
|
||||
{req: engine.UserDetailRequest{Detail: engine.UserDetail("bad")},
|
||||
error: `unsupported detail "bad"`},
|
||||
{req: engine.UserDetailRequest{Update: "not_relevant", Detail: engine.AllUserDetails},
|
||||
error: `unsupported request with userdetail all`},
|
||||
{req: engine.UserDetailRequest{Locator: store.Locator{SiteID: "test-site"}, Detail: engine.AllUserDetails},
|
||||
expected: []engine.UserDetailEntry{{UserID: "u1", Email: "test@example.com"}, {UserID: "u2", Email: "other@example.com"}}},
|
||||
}
|
||||
|
||||
for i, x := range testData {
|
||||
result, err := re.UserDetail(x.req)
|
||||
if x.error != "" {
|
||||
assert.EqualError(t, err, x.error, "Error should match expected for case %d", i)
|
||||
} else {
|
||||
assert.NoError(t, err, "Error is not expected expected for case %d", i)
|
||||
}
|
||||
assert.ElementsMatch(t, x.expected, result, "Result should match expected for case %d", i)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRPC_deleteHndl(t *testing.T) {
|
||||
_, port, teardown := prepTestStore(t)
|
||||
defer teardown()
|
||||
api := fmt.Sprintf("http://localhost:%d/test", port)
|
||||
|
||||
re := engine.RPC{Client: jrpc.Client{API: api, Client: http.Client{Timeout: 1 * time.Second}}}
|
||||
req := engine.DeleteRequest{
|
||||
Locator: store.Locator{SiteID: "test-site", URL: "http://example.com/post1"},
|
||||
CommentID: "123456",
|
||||
}
|
||||
|
||||
err := re.Delete(req)
|
||||
assert.EqualError(t, err, "not found")
|
||||
|
||||
c := store.Comment{ID: "123456", Locator: store.Locator{SiteID: "test-site", URL: "http://example.com/post1"},
|
||||
Text: "text 123", User: store.User{ID: "u1", Name: "user1"}}
|
||||
_, err = re.Create(c)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = re.Delete(req)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestRPC_closeHndl(t *testing.T) {
|
||||
_, port, teardown := prepTestStore(t)
|
||||
defer teardown()
|
||||
api := fmt.Sprintf("http://localhost:%d/test", port)
|
||||
|
||||
re := engine.RPC{Client: jrpc.Client{API: api, Client: http.Client{Timeout: 1 * time.Second}}}
|
||||
err := re.Close()
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
@@ -1,11 +1,14 @@
|
||||
/*
|
||||
* Copyright 2020 Umputun. All rights reserved.
|
||||
* Use of this source code is governed by a MIT-style
|
||||
* license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/go-pkgz/jrpc"
|
||||
|
||||
"github.com/umputun/remark/backend/app/store"
|
||||
"github.com/umputun/remark/backend/app/store/admin"
|
||||
"github.com/umputun/remark/backend/app/store/engine"
|
||||
)
|
||||
@@ -50,185 +53,3 @@ func (s *RPC) addHandlers() {
|
||||
"event": s.admEventHndl,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *RPC) createHndl(id uint64, params json.RawMessage) (rr jrpc.Response) {
|
||||
comment := store.Comment{}
|
||||
if err := json.Unmarshal(params, &comment); err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
commentID, err := s.eng.Create(comment)
|
||||
return jrpc.EncodeResponse(id, commentID, err)
|
||||
}
|
||||
|
||||
// Find comments
|
||||
func (s *RPC) findHndl(id uint64, params json.RawMessage) (rr jrpc.Response) {
|
||||
req := engine.FindRequest{}
|
||||
if err := json.Unmarshal(params, &req); err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
resp, err := s.eng.Find(req)
|
||||
return jrpc.EncodeResponse(id, resp, err)
|
||||
}
|
||||
|
||||
// Get comment
|
||||
func (s *RPC) getHndl(id uint64, params json.RawMessage) (rr jrpc.Response) {
|
||||
req := engine.GetRequest{}
|
||||
if err := json.Unmarshal(params, &req); err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
comment, err := s.eng.Get(req)
|
||||
return jrpc.EncodeResponse(id, comment, err)
|
||||
}
|
||||
|
||||
// Update comment
|
||||
func (s *RPC) updateHndl(id uint64, params json.RawMessage) (rr jrpc.Response) {
|
||||
comment := store.Comment{}
|
||||
if err := json.Unmarshal(params, &comment); err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
err := s.eng.Update(comment)
|
||||
return jrpc.EncodeResponse(id, nil, err)
|
||||
}
|
||||
|
||||
// counts for site and users
|
||||
func (s *RPC) countHndl(id uint64, params json.RawMessage) (rr jrpc.Response) {
|
||||
req := engine.FindRequest{}
|
||||
if err := json.Unmarshal(params, &req); err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
count, err := s.eng.Count(req)
|
||||
return jrpc.EncodeResponse(id, count, err)
|
||||
}
|
||||
|
||||
// info get post meta info
|
||||
func (s *RPC) infoHndl(id uint64, params json.RawMessage) (rr jrpc.Response) {
|
||||
req := engine.InfoRequest{}
|
||||
if err := json.Unmarshal(params, &req); err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
info, err := s.eng.Info(req)
|
||||
return jrpc.EncodeResponse(id, info, err)
|
||||
}
|
||||
|
||||
// flagHndl get and sets flag value
|
||||
func (s *RPC) flagHndl(id uint64, params json.RawMessage) (rr jrpc.Response) {
|
||||
req := engine.FlagRequest{}
|
||||
if err := json.Unmarshal(params, &req); err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
status, err := s.eng.Flag(req)
|
||||
return jrpc.EncodeResponse(id, status, err)
|
||||
}
|
||||
|
||||
// listFlagsHndl list flags for given request
|
||||
func (s *RPC) listFlagsHndl(id uint64, params json.RawMessage) (rr jrpc.Response) {
|
||||
req := engine.FlagRequest{}
|
||||
if err := json.Unmarshal(params, &req); err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
flags, err := s.eng.ListFlags(req)
|
||||
return jrpc.EncodeResponse(id, flags, err)
|
||||
}
|
||||
|
||||
// userDetailHndl sets or gets single detail value, or gets all details for requested site.
|
||||
// userDetailHndl returns list even for single entry request is a compromise in order to have both single detail getting and setting
|
||||
// and all site's details listing under the same function (and not to extend engine interface by two separate functions).
|
||||
func (s *RPC) userDetailHndl(id uint64, params json.RawMessage) (rr jrpc.Response) {
|
||||
req := engine.UserDetailRequest{}
|
||||
if err := json.Unmarshal(params, &req); err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
value, err := s.eng.UserDetail(req)
|
||||
return jrpc.EncodeResponse(id, value, err)
|
||||
}
|
||||
|
||||
// deleteHndl delete post(s), user, comment, user details, or everything
|
||||
func (s *RPC) deleteHndl(id uint64, params json.RawMessage) (rr jrpc.Response) {
|
||||
req := engine.DeleteRequest{}
|
||||
if err := json.Unmarshal(params, &req); err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
err := s.eng.Delete(req)
|
||||
return jrpc.EncodeResponse(id, nil, err)
|
||||
}
|
||||
|
||||
// close store
|
||||
func (s *RPC) closeHndl(id uint64, _ json.RawMessage) (rr jrpc.Response) {
|
||||
if err := s.eng.Close(); err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
return jrpc.Response{}
|
||||
}
|
||||
|
||||
// get admin key
|
||||
func (s *RPC) admKeyHndl(id uint64, _ json.RawMessage) (rr jrpc.Response) {
|
||||
key, err := s.adm.Key()
|
||||
if err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
return jrpc.EncodeResponse(id, key, err)
|
||||
}
|
||||
|
||||
// get admins list
|
||||
func (s *RPC) admAdminsHndl(id uint64, params json.RawMessage) (rr jrpc.Response) {
|
||||
var siteID string
|
||||
if err := json.Unmarshal(params, &siteID); err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
|
||||
admins, err := s.adm.Admins(siteID)
|
||||
if err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
return jrpc.EncodeResponse(id, admins, err)
|
||||
}
|
||||
|
||||
// get admin email
|
||||
func (s *RPC) admEmailHndl(id uint64, params json.RawMessage) (rr jrpc.Response) {
|
||||
var siteID string
|
||||
if err := json.Unmarshal(params, &siteID); err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
|
||||
email, err := s.adm.Email(siteID)
|
||||
if err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
return jrpc.EncodeResponse(id, email, err)
|
||||
}
|
||||
|
||||
// return site enabled status
|
||||
func (s *RPC) admEnabledHndl(id uint64, params json.RawMessage) (rr jrpc.Response) {
|
||||
var siteID string
|
||||
if err := json.Unmarshal(params, &siteID); err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
|
||||
ok, err := s.adm.Enabled(siteID)
|
||||
if err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
return jrpc.EncodeResponse(id, ok, err)
|
||||
}
|
||||
|
||||
// onEvent returns nothing, callback to OnEvent
|
||||
func (s *RPC) admEventHndl(id uint64, params json.RawMessage) (rr jrpc.Response) {
|
||||
var siteID string
|
||||
ps := []interface{}{}
|
||||
if err := json.Unmarshal(params, &ps); err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
siteID, ok := ps[0].(string)
|
||||
if !ok {
|
||||
return jrpc.Response{Error: "wrong siteID type"}
|
||||
}
|
||||
evType, ok := ps[1].(float64)
|
||||
if !ok {
|
||||
return jrpc.Response{Error: "wrong event type"}
|
||||
}
|
||||
err := s.adm.OnEvent(siteID, admin.EventType(evType))
|
||||
if err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
return jrpc.EncodeResponse(id, nil, err)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019 Umputun. All rights reserved.
|
||||
* Copyright 2020 Umputun. All rights reserved.
|
||||
* Use of this source code is governed by a MIT-style
|
||||
* license that can be found in the LICENSE file.
|
||||
*/
|
||||
@@ -16,369 +16,11 @@ import (
|
||||
|
||||
"github.com/go-pkgz/jrpc"
|
||||
log "github.com/go-pkgz/lgr"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/umputun/remark/backend/app/store"
|
||||
"github.com/umputun/remark/backend/app/store/admin"
|
||||
"github.com/umputun/remark/backend/app/store/engine"
|
||||
|
||||
"github.com/umputun/remark/memory_store/accessor"
|
||||
)
|
||||
|
||||
func TestRPC_createHndl(t *testing.T) {
|
||||
_, port, teardown := prepTestStore(t)
|
||||
defer teardown()
|
||||
api := fmt.Sprintf("http://localhost:%d/test", port)
|
||||
|
||||
re := engine.RPC{Client: jrpc.Client{API: api, Client: http.Client{Timeout: 1 * time.Second}}}
|
||||
id, err := re.Create(store.Comment{ID: "123456", Locator: store.Locator{SiteID: "test-site", URL: "http://example.com/post1"},
|
||||
Text: "text 123", User: store.User{ID: "u1", Name: "user1"}})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "123456", id)
|
||||
}
|
||||
|
||||
func TestRPC_findHndl(t *testing.T) {
|
||||
_, port, teardown := prepTestStore(t)
|
||||
defer teardown()
|
||||
api := fmt.Sprintf("http://localhost:%d/test", port)
|
||||
|
||||
re := engine.RPC{Client: jrpc.Client{API: api, Client: http.Client{Timeout: 1 * time.Second}}}
|
||||
findReq := engine.FindRequest{Locator: store.Locator{SiteID: "test-site", URL: "http://example.com/post1"}}
|
||||
comments, err := re.Find(findReq)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 0, len(comments))
|
||||
|
||||
c := store.Comment{ID: "123456", Locator: store.Locator{SiteID: "test-site", URL: "http://example.com/post1"},
|
||||
Text: "text 123", User: store.User{ID: "u1", Name: "user1"}}
|
||||
id, err := re.Create(c)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "123456", id)
|
||||
|
||||
comments, err = re.Find(findReq)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 1, len(comments))
|
||||
assert.Equal(t, c, comments[0])
|
||||
}
|
||||
|
||||
func TestRPC_getHndl(t *testing.T) {
|
||||
_, port, teardown := prepTestStore(t)
|
||||
defer teardown()
|
||||
api := fmt.Sprintf("http://localhost:%d/test", port)
|
||||
|
||||
re := engine.RPC{Client: jrpc.Client{API: api, Client: http.Client{Timeout: 1 * time.Second}}}
|
||||
req := engine.GetRequest{
|
||||
Locator: store.Locator{SiteID: "test-site", URL: "http://example.com/post1"},
|
||||
CommentID: "123456",
|
||||
}
|
||||
|
||||
_, err := re.Get(req)
|
||||
assert.EqualError(t, err, "not found")
|
||||
|
||||
c := store.Comment{ID: "123456", Locator: store.Locator{SiteID: "test-site", URL: "http://example.com/post1"},
|
||||
Text: "text 123", User: store.User{ID: "u1", Name: "user1"}}
|
||||
_, err = re.Create(c)
|
||||
assert.NoError(t, err)
|
||||
|
||||
comment, err := re.Get(req)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, c, comment)
|
||||
}
|
||||
|
||||
func TestRPC_updateHndl(t *testing.T) {
|
||||
_, port, teardown := prepTestStore(t)
|
||||
defer teardown()
|
||||
api := fmt.Sprintf("http://localhost:%d/test", port)
|
||||
|
||||
re := engine.RPC{Client: jrpc.Client{API: api, Client: http.Client{Timeout: 1 * time.Second}}}
|
||||
|
||||
c := store.Comment{ID: "123456", Locator: store.Locator{SiteID: "test-site", URL: "http://example.com/post1"},
|
||||
Text: "text 123", User: store.User{ID: "u1", Name: "user1"}}
|
||||
err := re.Update(c)
|
||||
assert.EqualError(t, err, "not found")
|
||||
|
||||
_, err = re.Create(c)
|
||||
assert.NoError(t, err)
|
||||
|
||||
c.Text = "updates"
|
||||
err = re.Update(c)
|
||||
assert.NoError(t, err)
|
||||
|
||||
req := engine.GetRequest{
|
||||
Locator: store.Locator{SiteID: "test-site", URL: "http://example.com/post1"},
|
||||
CommentID: "123456",
|
||||
}
|
||||
comment, err := re.Get(req)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, c, comment)
|
||||
}
|
||||
|
||||
func TestRPC_countHndl(t *testing.T) {
|
||||
_, port, teardown := prepTestStore(t)
|
||||
defer teardown()
|
||||
api := fmt.Sprintf("http://localhost:%d/test", port)
|
||||
|
||||
re := engine.RPC{Client: jrpc.Client{API: api, Client: http.Client{Timeout: 1 * time.Second}}}
|
||||
findReq := engine.FindRequest{Locator: store.Locator{SiteID: "test-site", URL: "http://example.com/post1"}}
|
||||
count, err := re.Count(findReq)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 0, count)
|
||||
|
||||
c := store.Comment{ID: "123456", Locator: store.Locator{SiteID: "test-site", URL: "http://example.com/post1"},
|
||||
Text: "text 123", User: store.User{ID: "u1", Name: "user1"}}
|
||||
id, err := re.Create(c)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "123456", id)
|
||||
|
||||
count, err = re.Count(findReq)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 1, count)
|
||||
}
|
||||
|
||||
func TestRPC_infoHndl(t *testing.T) {
|
||||
_, port, teardown := prepTestStore(t)
|
||||
defer teardown()
|
||||
api := fmt.Sprintf("http://localhost:%d/test", port)
|
||||
|
||||
re := engine.RPC{Client: jrpc.Client{API: api, Client: http.Client{Timeout: 1 * time.Second}}}
|
||||
|
||||
c := store.Comment{ID: "123456", Locator: store.Locator{SiteID: "test-site", URL: "http://example.com/post1"},
|
||||
Text: "text 123", User: store.User{ID: "u1", Name: "user1"}}
|
||||
id, err := re.Create(c)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "123456", id)
|
||||
|
||||
infoReq := engine.InfoRequest{Locator: store.Locator{SiteID: "test-site", URL: "http://example.com/post1"}}
|
||||
info, err := re.Info(infoReq)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 1, len(info))
|
||||
i := info[0]
|
||||
assert.Equal(t, store.PostInfo{URL: "http://example.com/post1", Count: 1}, i)
|
||||
}
|
||||
|
||||
func TestRPC_flagHndl(t *testing.T) {
|
||||
_, port, teardown := prepTestStore(t)
|
||||
defer teardown()
|
||||
api := fmt.Sprintf("http://localhost:%d/test", port)
|
||||
|
||||
re := engine.RPC{Client: jrpc.Client{API: api, Client: http.Client{Timeout: 1 * time.Second}}}
|
||||
|
||||
c := store.Comment{ID: "123456", Locator: store.Locator{SiteID: "test-site", URL: "http://example.com/post1"},
|
||||
Text: "text 123", User: store.User{ID: "u1", Name: "user1"}}
|
||||
id, err := re.Create(c)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "123456", id)
|
||||
|
||||
flagReq := engine.FlagRequest{
|
||||
Flag: engine.Verified,
|
||||
Locator: store.Locator{
|
||||
SiteID: "test-site",
|
||||
},
|
||||
UserID: "u1",
|
||||
}
|
||||
status, err := re.Flag(flagReq)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, false, status)
|
||||
|
||||
flagReq.Update = engine.FlagTrue
|
||||
status, err = re.Flag(flagReq)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, status)
|
||||
|
||||
flagReq.Update = engine.FlagNonSet
|
||||
status, err = re.Flag(flagReq)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, status)
|
||||
}
|
||||
|
||||
func TestRPC_listFlagsHndl(t *testing.T) {
|
||||
_, port, teardown := prepTestStore(t)
|
||||
defer teardown()
|
||||
api := fmt.Sprintf("http://localhost:%d/test", port)
|
||||
|
||||
re := engine.RPC{Client: jrpc.Client{API: api, Client: http.Client{Timeout: 1 * time.Second}}}
|
||||
|
||||
c := store.Comment{ID: "123456", Locator: store.Locator{SiteID: "test-site", URL: "http://example.com/post1"},
|
||||
Text: "text 123", User: store.User{ID: "u1", Name: "user1"}}
|
||||
id, err := re.Create(c)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "123456", id)
|
||||
|
||||
flagReq := engine.FlagRequest{
|
||||
Flag: engine.Verified,
|
||||
UserID: "u1",
|
||||
Locator: store.Locator{
|
||||
SiteID: "test-site",
|
||||
},
|
||||
}
|
||||
flags, err := re.ListFlags(flagReq)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []interface{}{}, flags)
|
||||
|
||||
flagReq.Update = engine.FlagTrue
|
||||
status, err := re.Flag(flagReq)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, status)
|
||||
|
||||
flags, err = re.ListFlags(flagReq)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []interface{}{"u1"}, flags)
|
||||
}
|
||||
|
||||
func TestRPC_userDetailHndl(t *testing.T) {
|
||||
_, port, teardown := prepTestStore(t)
|
||||
defer teardown()
|
||||
api := fmt.Sprintf("http://localhost:%d/test", port)
|
||||
|
||||
re := engine.RPC{Client: jrpc.Client{API: api, Client: http.Client{Timeout: 1 * time.Second}}}
|
||||
|
||||
// add to entries to DB before we start
|
||||
result, err := re.UserDetail(engine.UserDetailRequest{Locator: store.Locator{SiteID: "test-site"}, UserID: "u1", Detail: engine.UserEmail, Update: "test@example.com"})
|
||||
assert.NoError(t, err, "No error inserting entry expected")
|
||||
assert.ElementsMatch(t, []engine.UserDetailEntry{{UserID: "u1", Email: "test@example.com"}}, result)
|
||||
result, err = re.UserDetail(engine.UserDetailRequest{Locator: store.Locator{SiteID: "test-site"}, UserID: "u2", Detail: engine.UserEmail, Update: "other@example.com"})
|
||||
assert.NoError(t, err, "No error inserting entry expected")
|
||||
assert.ElementsMatch(t, []engine.UserDetailEntry{{UserID: "u2", Email: "other@example.com"}}, result)
|
||||
|
||||
// try to change existing entry with wrong SiteID
|
||||
result, err = re.UserDetail(engine.UserDetailRequest{Locator: store.Locator{SiteID: "bad"}, UserID: "u2", Detail: engine.UserEmail, Update: "not_relevant"})
|
||||
assert.NoError(t, err, "Updating existing entry with wrong SiteID doesn't produce error")
|
||||
assert.ElementsMatch(t, []engine.UserDetailEntry{}, result, "Updating existing entry with wrong SiteID doesn't change anything")
|
||||
|
||||
// stateless tests without changing the state we set up before
|
||||
var testData = []struct {
|
||||
req engine.UserDetailRequest
|
||||
error string
|
||||
expected []engine.UserDetailEntry
|
||||
}{
|
||||
{req: engine.UserDetailRequest{Locator: store.Locator{SiteID: "test-site"}, UserID: "u1", Detail: engine.UserEmail},
|
||||
expected: []engine.UserDetailEntry{{UserID: "u1", Email: "test@example.com"}}},
|
||||
{req: engine.UserDetailRequest{Locator: store.Locator{SiteID: "bad"}, UserID: "u1", Detail: engine.UserEmail},
|
||||
expected: []engine.UserDetailEntry{}},
|
||||
{req: engine.UserDetailRequest{Locator: store.Locator{SiteID: "test-site"}, UserID: "u1xyz", Detail: engine.UserEmail},
|
||||
expected: []engine.UserDetailEntry{}},
|
||||
{req: engine.UserDetailRequest{Detail: engine.UserEmail, Update: "new_value"},
|
||||
error: `userid cannot be empty in request for single detail`},
|
||||
{req: engine.UserDetailRequest{Detail: engine.UserDetail("bad")},
|
||||
error: `unsupported detail "bad"`},
|
||||
{req: engine.UserDetailRequest{Update: "not_relevant", Detail: engine.AllUserDetails},
|
||||
error: `unsupported request with userdetail all`},
|
||||
{req: engine.UserDetailRequest{Locator: store.Locator{SiteID: "test-site"}, Detail: engine.AllUserDetails},
|
||||
expected: []engine.UserDetailEntry{{UserID: "u1", Email: "test@example.com"}, {UserID: "u2", Email: "other@example.com"}}},
|
||||
}
|
||||
|
||||
for i, x := range testData {
|
||||
result, err := re.UserDetail(x.req)
|
||||
if x.error != "" {
|
||||
assert.EqualError(t, err, x.error, "Error should match expected for case %d", i)
|
||||
} else {
|
||||
assert.NoError(t, err, "Error is not expected expected for case %d", i)
|
||||
}
|
||||
assert.ElementsMatch(t, x.expected, result, "Result should match expected for case %d", i)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRPC_deleteHndl(t *testing.T) {
|
||||
_, port, teardown := prepTestStore(t)
|
||||
defer teardown()
|
||||
api := fmt.Sprintf("http://localhost:%d/test", port)
|
||||
|
||||
re := engine.RPC{Client: jrpc.Client{API: api, Client: http.Client{Timeout: 1 * time.Second}}}
|
||||
req := engine.DeleteRequest{
|
||||
Locator: store.Locator{SiteID: "test-site", URL: "http://example.com/post1"},
|
||||
CommentID: "123456",
|
||||
}
|
||||
|
||||
err := re.Delete(req)
|
||||
assert.EqualError(t, err, "not found")
|
||||
|
||||
c := store.Comment{ID: "123456", Locator: store.Locator{SiteID: "test-site", URL: "http://example.com/post1"},
|
||||
Text: "text 123", User: store.User{ID: "u1", Name: "user1"}}
|
||||
_, err = re.Create(c)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = re.Delete(req)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestRPC_closeHndl(t *testing.T) {
|
||||
_, port, teardown := prepTestStore(t)
|
||||
defer teardown()
|
||||
api := fmt.Sprintf("http://localhost:%d/test", port)
|
||||
|
||||
re := engine.RPC{Client: jrpc.Client{API: api, Client: http.Client{Timeout: 1 * time.Second}}}
|
||||
err := re.Close()
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
func TestRPC_admKeyHndl(t *testing.T) {
|
||||
_, port, teardown := prepTestStore(t)
|
||||
defer teardown()
|
||||
api := fmt.Sprintf("http://localhost:%d/test", port)
|
||||
|
||||
ra := admin.RPC{Client: jrpc.Client{API: api, Client: http.Client{Timeout: 1 * time.Second}}}
|
||||
key, err := ra.Key()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "secret", key)
|
||||
}
|
||||
|
||||
func TestRPC_admAdminsHndl(t *testing.T) {
|
||||
_, port, teardown := prepTestStore(t)
|
||||
defer teardown()
|
||||
api := fmt.Sprintf("http://localhost:%d/test", port)
|
||||
|
||||
ra := admin.RPC{Client: jrpc.Client{API: api, Client: http.Client{Timeout: 1 * time.Second}}}
|
||||
_, err := ra.Admins("bad site")
|
||||
assert.EqualError(t, err, "site bad site not found")
|
||||
|
||||
admins, err := ra.Admins("test-site")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []string{"id1", "id2"}, admins)
|
||||
}
|
||||
|
||||
func TestRPC_admEmailHndl(t *testing.T) {
|
||||
_, port, teardown := prepTestStore(t)
|
||||
defer teardown()
|
||||
api := fmt.Sprintf("http://localhost:%d/test", port)
|
||||
|
||||
ra := admin.RPC{Client: jrpc.Client{API: api, Client: http.Client{Timeout: 1 * time.Second}}}
|
||||
_, err := ra.Admins("bad site")
|
||||
assert.EqualError(t, err, "site bad site not found")
|
||||
|
||||
email, err := ra.Email("test-site")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "admin@example.com", email)
|
||||
}
|
||||
|
||||
func TestRPC_admEnabledHndl(t *testing.T) {
|
||||
_, port, teardown := prepTestStore(t)
|
||||
defer teardown()
|
||||
api := fmt.Sprintf("http://localhost:%d/test", port)
|
||||
|
||||
ra := admin.RPC{Client: jrpc.Client{API: api, Client: http.Client{Timeout: 1 * time.Second}}}
|
||||
_, err := ra.Enabled("bad site")
|
||||
assert.EqualError(t, err, "site bad site not found")
|
||||
|
||||
ok, err := ra.Enabled("test-site")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, true, ok)
|
||||
|
||||
ok, err = ra.Enabled("test-site-disabled")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, ok)
|
||||
}
|
||||
|
||||
func TestRPC_admEventHndl(t *testing.T) {
|
||||
_, port, teardown := prepTestStore(t)
|
||||
defer teardown()
|
||||
api := fmt.Sprintf("http://localhost:%d/test", port)
|
||||
|
||||
ra := admin.RPC{Client: jrpc.Client{API: api, Client: http.Client{Timeout: 1 * time.Second}}}
|
||||
err := ra.OnEvent("bad site", admin.EvCreate)
|
||||
assert.EqualError(t, err, "site bad site not found")
|
||||
|
||||
err = ra.OnEvent("test-site", admin.EvCreate)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func chooseRandomUnusedPort() (port int) {
|
||||
for i := 0; i < 10; i++ {
|
||||
port = 40000 + int(rand.Int31n(10000))
|
||||
|
||||
Reference in New Issue
Block a user