remote client adjusted to new engine flavour

This commit is contained in:
Umputun
2019-06-25 20:06:30 -05:00
parent 3aba348e87
commit c2b56eae30
3 changed files with 118 additions and 55 deletions
+21 -18
View File
@@ -22,7 +22,7 @@ type Interface interface {
Find(req FindRequest) ([]store.Comment, error) // find comments for locator or site
Info(req InfoRequest) ([]store.PostInfo, error) // get post(s) meta info
Count(req FindRequest) (int, error) // get count for post or user
Delete(req DeleteRequest) error // delete post(s) by id or by userID
Delete(req DeleteRequest) error // delete post(s) by id or by userID
Flag(req FlagRequest) (bool, error) // set and get flags
ListFlags(siteID string, flag Flag) ([]interface{}, error) // get list of flagged keys, like blocked & verified user
Close() error // close storage engine
@@ -30,25 +30,28 @@ type Interface interface {
// FindRequest is the input for all find operations
type FindRequest struct {
Locator store.Locator // lack of URL means site operation
UserID string // presence of UserID treated as user-related find
Sort string // sort order with +/-field syntax
Since time.Time // time limit for found results
Limit, Skip int
Locator store.Locator `json:"locator"` // lack of URL means site operation
UserID string `json:"user_id,omitempty"` // presence of UserID treated as user-related find
Sort string `json:"sort,omitempty"` // sort order with +/-field syntax
Since time.Time `json:"since,omitempty"` // time limit for found results
Limit int `json:"limit,omitempty"`
Skip int `json:"skip,omitempty"`
}
// InfoRequest is the input of Info operation used to get meta data about posts
type InfoRequest struct {
Locator store.Locator
Limit, Skip int
ReadOnlyAge int
Locator store.Locator `json:"locator"`
Limit int `json:"limit,omitempty"`
Skip int `json:"skip,omitempty"`
ReadOnlyAge int `json:"ro_age,omitempty"`
}
// DeleteRequest is the input for all delete operations (comments, sites, users)
type DeleteRequest struct {
Locator store.Locator // lack of URL means site operation
CommentID string
UserID string
DeleteMode store.DeleteMode
Locator store.Locator `json:"locator"` // lack of URL means site operation
CommentID string `json:"comment_id,omitempty"`
UserID string `json:"user_id,omitempty"`
DeleteMode store.DeleteMode `json:"del_mode"`
}
// Flag defines type of binary attribute
@@ -73,11 +76,11 @@ const (
// FlagRequest is the input for both get/set for flags, like blocked, verified and so on
type FlagRequest struct {
Flag Flag // flag type
Locator store.Locator // post locator
UserID string // for flags setting user status
Update FlagStatus // if FlagNonSet it will be get op, if set will set the value
TTL time.Duration // ttl for time-sensitive flags only, like blocked for some period
Flag Flag `json:"flag"` // flag type
Locator store.Locator `json:"locator"` // post locator
UserID string `json:"user_id,omitempty"` // for flags setting user status
Update FlagStatus `json:"update,omitempty"` // if FlagNonSet it will be get op, if set will set the value
TTL time.Duration `json:"ttl,omitempty"` // ttl for time-sensitive flags only, like blocked for some period
}
const (
+44 -22
View File
@@ -4,11 +4,11 @@ import (
"bytes"
"encoding/json"
"net/http"
"time"
"github.com/pkg/errors"
"github.com/umputun/remark/backend/app/store"
"github.com/umputun/remark/backend/app/store/engine"
)
// Client implements remote engine and delegates all calls to remote http server
@@ -54,45 +54,55 @@ func (r *Client) Get(locator store.Locator, commentID string) (comment store.Com
return comment, err
}
// Put updates comment, mutable parts only
func (r *Client) Put(locator store.Locator, comment store.Comment) error {
_, err := r.call("put", locator, comment)
// Update comment, mutable parts only
func (r *Client) Update(locator store.Locator, comment store.Comment) error {
_, err := r.call("update", locator, comment)
return err
}
// Find comments for locator
func (r *Client) Find(locator store.Locator, sort string) (comments []store.Comment, err error) {
resp, err := r.call("find", locator, sort)
func (r *Client) Find(req engine.FindRequest) (comments []store.Comment, err error) {
resp, err := r.call("find", req)
if err != nil {
return []store.Comment{}, err
return nil, err
}
err = json.Unmarshal(*resp.Result, &comments)
return comments, err
}
// Last comments for given site, sorted by time
func (r *Client) Last(siteID string, limit int, since time.Time) (comments []store.Comment, err error) {
resp, err := r.call("last", siteID, limit, since)
// Info returns post(s) meta info
func (r *Client) Info(req engine.InfoRequest) (info []store.PostInfo, err error) {
resp, err := r.call("info", req)
if err != nil {
return []store.Comment{}, err
return nil, err
}
err = json.Unmarshal(*resp.Result, &comments)
return comments, err
err = json.Unmarshal(*resp.Result, &info)
return info, err
}
// User get comments by user, sorted by time
func (r *Client) User(siteID, userID string, limit, skip int) (comments []store.Comment, err error) {
resp, err := r.call("user", siteID, userID, limit, skip)
// Flag sets and gets flags
func (r *Client) Flag(req engine.FlagRequest) (status bool, err error) {
resp, err := r.call("flag", req)
if err != nil {
return []store.Comment{}, err
return false, err
}
err = json.Unmarshal(*resp.Result, &comments)
return comments, err
err = json.Unmarshal(*resp.Result, &status)
return status, err
}
// UserCount gets comments count by user
func (r *Client) UserCount(siteID, userID string) (count int, err error) {
resp, err := r.call("user_count", siteID, userID)
// ListFlags get list of flagged keys, like blocked & verified user
func (r *Client) ListFlags(siteID string, flag engine.Flag) (list []interface{}, err error) {
resp, err := r.call("list_flags", siteID, flag)
if err != nil {
return nil, err
}
err = json.Unmarshal(*resp.Result, &list)
return list, err
}
// Count gets comments count by user or site
func (r *Client) Count(req engine.FindRequest) (count int, err error) {
resp, err := r.call("count", req)
if err != nil {
return 0, err
}
@@ -100,6 +110,18 @@ func (r *Client) UserCount(siteID, userID string) (count int, err error)
return count, err
}
// Delete post(s) by id or by userID
func (r *Client) Delete(req engine.DeleteRequest) error {
_, err := r.call("delete", req)
return err
}
// Close storage engine
func (r *Client) Close() error {
_, err := r.call("close")
return err
}
func (r *Client) call(method string, args ...interface{}) (*Response, error) {
b, err := json.Marshal(Request{Method: method, Params: args})
+53 -15
View File
@@ -13,6 +13,7 @@ import (
"github.com/stretchr/testify/require"
"github.com/umputun/remark/backend/app/store"
"github.com/umputun/remark/backend/app/store/engine"
)
func TestClient_Create(t *testing.T) {
@@ -79,47 +80,84 @@ func TestClient_FailedStatus(t *testing.T) {
assert.EqualError(t, err, "bad status 400 for get")
}
func TestClient_Put(t *testing.T) {
ts := testServer(t, `{"method":"put","params":[{"url":"http://example.com/url"},{"id":"123","pid":"","text":"msg","user":{"name":"","id":"","picture":"","admin":false},"locator":{"site":"site123","url":"http://example.com/url"},"score":0,"vote":0,"time":"0001-01-01T00:00:00Z"}]}`, `{}`)
func TestClient_Update(t *testing.T) {
ts := testServer(t, `{"method":"update","params":[{"url":"http://example.com/url"},{"id":"123","pid":"","text":"msg","user":{"name":"","id":"","picture":"","admin":false},"locator":{"site":"site123","url":"http://example.com/url"},"score":0,"vote":0,"time":"0001-01-01T00:00:00Z"}]}`, `{}`)
defer ts.Close()
c := Client{API: ts.URL, Client: http.Client{}}
err := c.Put(store.Locator{URL: "http://example.com/url"}, store.Comment{ID: "123",
err := c.Update(store.Locator{URL: "http://example.com/url"}, store.Comment{ID: "123",
Locator: store.Locator{URL: "http://example.com/url", SiteID: "site123"}, Text: "msg"})
assert.NoError(t, err)
}
func TestClient_Find(t *testing.T) {
ts := testServer(t, `{"method":"find","params":[{"url":"http://example.com/url"},""]}`,
`{"result":[{"text":"1"},{"text":"2"}]}`)
ts := testServer(t, `{"method":"find","params":[{"locator":{"url":"http://example.com/url"},"sort":"-time","since":"0001-01-01T00:00:00Z","limit":10}]}`, `{"result":[{"text":"1"},{"text":"2"}]}`)
defer ts.Close()
c := Client{API: ts.URL, Client: http.Client{}}
res, err := c.Find(store.Locator{URL: "http://example.com/url"}, "")
res, err := c.Find(engine.FindRequest{Locator: store.Locator{URL: "http://example.com/url"}, Sort: "-time", Limit: 10})
assert.NoError(t, err)
assert.Equal(t, []store.Comment{{Text: "1"}, {Text: "2"}}, res)
}
func TestClient_Last(t *testing.T) {
ts := testServer(t, `{"method":"last","params":["site1",100,"2019-06-06T19:34:10Z"]}`,
`{"result":[{"text":"1"},{"text":"2"}]}`)
func TestClient_Info(t *testing.T) {
ts := testServer(t, `{"method":"info","params":[{"locator":{"url":"http://example.com/url"},"limit":10,"skip":5,"ro_age":10}]}`, `{"result":[{"url":"u1","count":22},{"url":"u2","count":33}]}`)
defer ts.Close()
c := Client{API: ts.URL, Client: http.Client{}}
res, err := c.Last("site1", 100, time.Date(2019, 6, 6, 19, 34, 10, 0, time.UTC))
res, err := c.Info(engine.InfoRequest{Locator: store.Locator{URL: "http://example.com/url"},
Limit: 10, Skip: 5, ReadOnlyAge: 10})
assert.NoError(t, err)
assert.Equal(t, []store.Comment{{Text: "1"}, {Text: "2"}}, res)
assert.Equal(t, []store.PostInfo{{URL: "u1", Count: 22}, {URL: "u2", Count: 33}}, res)
}
func TestClient_User(t *testing.T) {
ts := testServer(t, `{"method":"user","params":["site1","u1",100,4]}`, `{"result":[{"text":"1"},{"text":"2"}]}`)
func TestClient_Flag(t *testing.T) {
ts := testServer(t, `{"method":"flag","params":[{"flag":"verified","locator":{"url":"http://example.com/url"}}]}`,
`{"result":false}`)
defer ts.Close()
c := Client{API: ts.URL, Client: http.Client{}}
res, err := c.User("site1", "u1", 100, 4)
res, err := c.Flag(engine.FlagRequest{Locator: store.Locator{URL: "http://example.com/url"}, Flag: engine.Verified})
assert.NoError(t, err)
assert.Equal(t, false, res)
}
func TestClient_ListFlag(t *testing.T) {
ts := testServer(t, `{"method":"list_flags","params":["site_id","blocked"]}`, `{"result":[{"ID":"id1"},{"ID":"id2"}]}`)
defer ts.Close()
c := Client{API: ts.URL, Client: http.Client{}}
res, err := c.ListFlags("site_id", engine.Blocked)
assert.NoError(t, err)
assert.Equal(t, []interface{}{map[string]interface{}{"ID": "id1"}, map[string]interface{}{"ID": "id2"}}, res)
}
func TestClient_Count(t *testing.T) {
ts := testServer(t, `{"method":"count","params":[{"locator":{"url":"http://example.com/url"},"since":"0001-01-01T00:00:00Z"}]}`,
`{"result":11}`)
defer ts.Close()
c := Client{API: ts.URL, Client: http.Client{}}
res, err := c.Count(engine.FindRequest{Locator: store.Locator{URL: "http://example.com/url"}})
assert.NoError(t, err)
assert.Equal(t, 11, res)
}
func TestClient_Delete(t *testing.T) {
ts := testServer(t, `{"method":"delete","params":[{"locator":{"url":"http://example.com/url"},"del_mode":0}]}`, `{}`)
defer ts.Close()
c := Client{API: ts.URL, Client: http.Client{}}
err := c.Delete(engine.DeleteRequest{Locator: store.Locator{URL: "http://example.com/url"}})
assert.NoError(t, err)
}
func TestClient_Close(t *testing.T) {
ts := testServer(t, `{"method":"close","params":null}`, `{}`)
defer ts.Close()
c := Client{API: ts.URL, Client: http.Client{}}
err := c.Close()
assert.NoError(t, err)
assert.Equal(t, []store.Comment{{Text: "1"}, {Text: "2"}}, res)
}
func testServer(t *testing.T, req, resp string) *httptest.Server {