420 lines
12 KiB
Go
420 lines
12 KiB
Go
package server
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"local/dndex/storage/entity"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"path"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestEntities(t *testing.T) {
|
|
rest, authit, clean := testREST(t)
|
|
defer clean()
|
|
|
|
t.Run("create+get1+delete+404", func(t *testing.T) {
|
|
w := testEntitiesMethod(t, authit, rest, http.MethodPost, "/", `{"name":"myname"}`)
|
|
if w.Code != http.StatusOK {
|
|
t.Fatal(w.Code)
|
|
}
|
|
id := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
|
return one.Name == "myname"
|
|
})
|
|
|
|
w = testEntitiesMethod(t, authit, rest, http.MethodGet, "/"+id+"?md", ``)
|
|
if w.Code != http.StatusOK {
|
|
t.Fatal(w.Code)
|
|
}
|
|
b := w.Body.Bytes()
|
|
var markdowned map[string]struct {
|
|
MD string `json:"md"`
|
|
}
|
|
if err := json.Unmarshal(b, &markdowned); err != nil {
|
|
t.Fatal(err)
|
|
} else if len(markdowned) != 1 {
|
|
t.Fatal(len(markdowned))
|
|
} else if len(markdowned[id].MD) == 0 {
|
|
t.Fatal(markdowned, string(b))
|
|
}
|
|
id2 := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
|
return one.Name == "myname"
|
|
})
|
|
if id2 != id {
|
|
t.Fatal(id, id2)
|
|
}
|
|
|
|
w = testEntitiesMethod(t, authit, rest, http.MethodDelete, "/"+id, ``)
|
|
if w.Code != http.StatusOK {
|
|
t.Fatal(w.Code)
|
|
}
|
|
|
|
w = testEntitiesMethod(t, authit, rest, http.MethodGet, "/"+id, ``)
|
|
if w.Code != http.StatusNotFound {
|
|
t.Fatal(w.Code)
|
|
}
|
|
})
|
|
|
|
t.Run("get1 404", func(t *testing.T) {
|
|
w := testEntitiesMethod(t, authit, rest, http.MethodGet, "/abc123", ``)
|
|
if w.Code != http.StatusNotFound {
|
|
t.Fatal(w.Code)
|
|
}
|
|
})
|
|
|
|
t.Run("create+get0", func(t *testing.T) {
|
|
w := testEntitiesMethod(t, authit, rest, http.MethodPost, "/", `{"name":"my friend"}`)
|
|
if w.Code != http.StatusOK {
|
|
t.Fatal(w.Code)
|
|
}
|
|
friend := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
|
return one.Name == "my friend"
|
|
})
|
|
|
|
w = testEntitiesMethod(t, authit, rest, http.MethodPost, "/", `{"name":"myname", "attachments": {"abc": {}}, "connections": {"`+friend+`": {"relationship": "ghi"}}}`)
|
|
if w.Code != http.StatusOK {
|
|
t.Fatal(w.Code)
|
|
}
|
|
id := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
|
return one.Name == "myname" && len(one.Attachments) == 1 && len(one.Connections) == 1 && one.Connections[friend].Relationship == "ghi"
|
|
})
|
|
|
|
w = testEntitiesMethod(t, authit, rest, http.MethodGet, "/", ``)
|
|
if w.Code != http.StatusOK {
|
|
t.Fatal(w.Code)
|
|
}
|
|
testEntitiesGetNResponse(t, w.Body, func(one shortEntity) bool {
|
|
return one.Name == "myname" && one.ID == id
|
|
})
|
|
})
|
|
|
|
t.Run("create+replace+get1", func(t *testing.T) {
|
|
check := func(one entity.One) bool {
|
|
return one.Name == "myname"
|
|
}
|
|
|
|
w := testEntitiesMethod(t, authit, rest, http.MethodPost, "/", `{"name":"myname"}`)
|
|
if w.Code != http.StatusOK {
|
|
t.Fatal(w.Code)
|
|
}
|
|
id := testEntitiesGetOneResponse(t, w.Body, check)
|
|
|
|
w = testEntitiesMethod(t, authit, rest, http.MethodPut, "/"+id, `{"name":"newname"}`)
|
|
if w.Code != http.StatusOK {
|
|
t.Fatal(w.Code)
|
|
}
|
|
|
|
w = testEntitiesMethod(t, authit, rest, http.MethodGet, "/"+id, ``)
|
|
if w.Code != http.StatusOK {
|
|
t.Fatal(w.Code)
|
|
}
|
|
id2 := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
|
return one.Name == "newname"
|
|
})
|
|
if id2 != id {
|
|
t.Fatal(id, id2)
|
|
}
|
|
})
|
|
|
|
t.Run("create+get.title", func(t *testing.T) {
|
|
w := testEntitiesMethod(t, authit, rest, http.MethodPost, "/", `{"name":"myname", "title": "mytitle"}`)
|
|
if w.Code != http.StatusOK {
|
|
t.Fatal(w.Code)
|
|
}
|
|
id := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
|
return one.Name == "myname" && one.Title == "mytitle"
|
|
})
|
|
|
|
w = testEntitiesMethod(t, authit, rest, http.MethodGet, "/"+id+"/title", ``)
|
|
if w.Code != http.StatusOK {
|
|
t.Fatal(w.Code)
|
|
}
|
|
testEntitiesGetOneSubResponse(t, w.Body, func(v interface{}) bool {
|
|
return fmt.Sprint(v) == "mytitle"
|
|
})
|
|
})
|
|
|
|
t.Run("create+update/replace", func(t *testing.T) {
|
|
for _, method := range []string{http.MethodPut, http.MethodPatch} {
|
|
w := testEntitiesMethod(t, authit, rest, http.MethodPost, "/", `{"name":"myname", "title": "mytitle"}`)
|
|
if w.Code != http.StatusOK {
|
|
t.Fatal(w.Code)
|
|
}
|
|
id := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
|
return one.Name == "myname" && one.Title == "mytitle"
|
|
})
|
|
|
|
w = testEntitiesMethod(t, authit, rest, method, "/"+id, `{"name": "newname"}`)
|
|
if w.Code != http.StatusOK {
|
|
t.Fatalf("%v: %s", w.Code, w.Body.Bytes())
|
|
}
|
|
id2 := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
|
return one.Name == "newname" && one.Title == ""
|
|
})
|
|
|
|
if id != id2 {
|
|
t.Fatal(id, id2)
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("create+update/replace.name", func(t *testing.T) {
|
|
for _, method := range []string{http.MethodPut, http.MethodPatch} {
|
|
w := testEntitiesMethod(t, authit, rest, http.MethodPost, "/", `{"name":"myname", "title": "mytitle"}`)
|
|
if w.Code != http.StatusOK {
|
|
t.Fatal(w.Code)
|
|
}
|
|
id := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
|
return one.Name == "myname" && one.Title == "mytitle"
|
|
})
|
|
|
|
w = testEntitiesMethod(t, authit, rest, method, "/"+id+"/name", `"newname"`)
|
|
if w.Code != http.StatusOK {
|
|
t.Fatal(w.Code)
|
|
}
|
|
id2 := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
|
return one.Name == "newname" && one.Title == "mytitle"
|
|
})
|
|
|
|
if id != id2 {
|
|
t.Fatal(id, id2)
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("create+update/replace.connection.abc.relationship", func(t *testing.T) {
|
|
w := testEntitiesMethod(t, authit, rest, http.MethodPost, "/", `{"name": "my friend"}`)
|
|
if w.Code != http.StatusOK {
|
|
t.Fatal(w.Code)
|
|
}
|
|
friend := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
|
return one.Name == "my friend"
|
|
})
|
|
|
|
for _, method := range []string{http.MethodPut, http.MethodPatch} {
|
|
w := testEntitiesMethod(t, authit, rest, http.MethodPost, "/", `{"connections": {"`+friend+`": {"relationship": "def"}}}`)
|
|
if w.Code != http.StatusOK {
|
|
t.Fatal(w.Code)
|
|
}
|
|
id := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
|
return one.Connections[friend].Relationship == "def"
|
|
})
|
|
|
|
w = testEntitiesMethod(t, authit, rest, method, "/"+id+"/connections/"+friend+"/relationship", `"new"`)
|
|
if w.Code != http.StatusOK {
|
|
t.Fatal(w.Code)
|
|
}
|
|
id2 := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
|
return one.Connections[friend].Relationship == "new"
|
|
})
|
|
|
|
if id != id2 {
|
|
t.Fatal(id, id2)
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("create+update/replace.connection.abc", func(t *testing.T) {
|
|
w := testEntitiesMethod(t, authit, rest, http.MethodPost, "/", `{"name": "my friend"}`)
|
|
if w.Code != http.StatusOK {
|
|
t.Fatal(w.Code)
|
|
}
|
|
friend := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
|
return one.Name == "my friend"
|
|
})
|
|
|
|
for _, method := range []string{http.MethodPut, http.MethodPatch} {
|
|
w := testEntitiesMethod(t, authit, rest, http.MethodPost, "/", `{"connections": {"`+friend+`": {"relationship": "def"}}}`)
|
|
if w.Code != http.StatusOK {
|
|
t.Fatal(w.Code)
|
|
}
|
|
id := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
|
return one.Connections[friend].Relationship == "def"
|
|
})
|
|
|
|
w = testEntitiesMethod(t, authit, rest, method, "/"+id+"/connections/"+friend, `{"relationship": "new"}`)
|
|
if w.Code != http.StatusOK {
|
|
t.Fatal(w.Code)
|
|
}
|
|
id2 := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
|
return one.Connections[friend].Relationship == "new"
|
|
})
|
|
|
|
if id != id2 {
|
|
t.Fatal(id, id2)
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("create+delete.name", func(t *testing.T) {
|
|
w := testEntitiesMethod(t, authit, rest, http.MethodPost, "/", `{"name":"myname", "title": "mytitle"}`)
|
|
if w.Code != http.StatusOK {
|
|
t.Fatal(w.Code)
|
|
}
|
|
id := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
|
return one.Name == "myname" && one.Title == "mytitle"
|
|
})
|
|
|
|
w = testEntitiesMethod(t, authit, rest, http.MethodDelete, "/"+id+"/name", ``)
|
|
if w.Code != http.StatusOK {
|
|
t.Fatalf("%v: %s", w.Code, w.Body.Bytes())
|
|
}
|
|
id2 := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
|
return one.Name == "" && one.Title == "mytitle"
|
|
})
|
|
|
|
if id != id2 {
|
|
t.Fatal(id, id2)
|
|
}
|
|
})
|
|
|
|
t.Run("create w connection.abc+delete.connections.abc", func(t *testing.T) {
|
|
w := testEntitiesMethod(t, authit, rest, http.MethodPost, "/", `{"name": "my friend"}`)
|
|
if w.Code != http.StatusOK {
|
|
t.Fatal(w.Code)
|
|
}
|
|
friend := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
|
return one.Name == "my friend"
|
|
})
|
|
|
|
w = testEntitiesMethod(t, authit, rest, http.MethodPost, "/", `{"name":"myname", "title": "mytitle", "connections": {"`+friend+`": {"relationship": "good"}}}`)
|
|
if w.Code != http.StatusOK {
|
|
t.Fatalf("%v: %s", w.Code, w.Body.Bytes())
|
|
}
|
|
id := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
|
friended, ok := one.Connections[friend]
|
|
return one.Name == "myname" && one.Title == "mytitle" && ok && friended.Relationship == "good"
|
|
})
|
|
|
|
w = testEntitiesMethod(t, authit, rest, http.MethodDelete, "/"+id+"/connections/"+friend, ``)
|
|
if w.Code != http.StatusOK {
|
|
t.Fatalf("%v: %s", w.Code, w.Body.Bytes())
|
|
}
|
|
id2 := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
|
return one.Name == "myname" && one.Title == "mytitle" && len(one.Connections) == 0
|
|
})
|
|
|
|
if id != id2 {
|
|
t.Fatal(id, id2)
|
|
}
|
|
})
|
|
|
|
t.Run("create w connection.abc.relationship+delete.connections.abc.relationship", func(t *testing.T) {
|
|
w := testEntitiesMethod(t, authit, rest, http.MethodPost, "/", `{"name": "my friend"}`)
|
|
if w.Code != http.StatusOK {
|
|
t.Fatal(w.Code)
|
|
}
|
|
friend := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
|
return one.Name == "my friend"
|
|
})
|
|
|
|
w = testEntitiesMethod(t, authit, rest, http.MethodPost, "/", `{"connections": {"`+friend+`": {"relationship": "good"}}}`)
|
|
if w.Code != http.StatusOK {
|
|
t.Fatalf("%v: %s", w.Code, w.Body.Bytes())
|
|
}
|
|
id := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
|
friended, ok := one.Connections[friend]
|
|
return ok && friended.Relationship == "good"
|
|
})
|
|
|
|
w = testEntitiesMethod(t, authit, rest, http.MethodDelete, "/"+id+"/connections/"+friend+"/relationship", ``)
|
|
if w.Code != http.StatusOK {
|
|
t.Fatalf("%v: %s", w.Code, w.Body.Bytes())
|
|
}
|
|
id2 := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
|
return len(one.Connections) == 1 && one.Connections[friend].Relationship == ""
|
|
})
|
|
|
|
if id != id2 {
|
|
t.Fatal(id, id2)
|
|
}
|
|
})
|
|
}
|
|
|
|
func testEntitiesMethod(t *testing.T, authit func(*http.Request), rest *REST, method, p, body string) *httptest.ResponseRecorder {
|
|
r := httptest.NewRequest(method, p, strings.NewReader(body))
|
|
if !strings.HasPrefix(r.URL.Path, "/entities") {
|
|
r.URL.Path = path.Join("/entities", r.URL.Path)
|
|
}
|
|
w := httptest.NewRecorder()
|
|
authit(r)
|
|
rest.scoped(rest.shift(rest.entities))(w, r)
|
|
return w
|
|
}
|
|
|
|
func testEntitiesGetNResponse(t *testing.T, body io.Reader, check func(shortEntity) bool) {
|
|
var resp map[string][]shortEntity
|
|
if err := json.NewDecoder(body).Decode(&resp); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(resp) != 1 {
|
|
t.Fatal("excess found in db")
|
|
}
|
|
for k := range resp {
|
|
contents := resp[k]
|
|
if len(contents) < 1 {
|
|
t.Fatal(len(contents))
|
|
}
|
|
for i := range contents {
|
|
if check(contents[i]) {
|
|
return
|
|
}
|
|
}
|
|
t.Fatal(contents)
|
|
}
|
|
}
|
|
|
|
func testEntitiesGetOneResponse(t *testing.T, body io.Reader, check func(entity.One) bool) string {
|
|
b, err := ioutil.ReadAll(body)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var resp map[string]entity.One
|
|
if err := json.Unmarshal(b, &resp); err != nil {
|
|
t.Fatalf("%v: %s", err, b)
|
|
}
|
|
if len(resp) != 1 {
|
|
t.Fatal(len(resp))
|
|
}
|
|
for k := range resp {
|
|
one := resp[k]
|
|
if one.ID != k {
|
|
t.Fatal(k, one.ID)
|
|
}
|
|
if one.Modified == 0 {
|
|
t.Fatal(one.Modified)
|
|
}
|
|
if !check(one) {
|
|
t.Fatal(one)
|
|
}
|
|
return one.ID
|
|
}
|
|
panic("somehow no keys found")
|
|
}
|
|
|
|
func testEntitiesGetOneSubResponse(t *testing.T, body io.Reader, check func(interface{}) bool) {
|
|
b, err := ioutil.ReadAll(body)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var resp map[string]interface{}
|
|
if err := json.Unmarshal(b, &resp); err != nil {
|
|
t.Fatalf("%v: %s", err, b)
|
|
}
|
|
if len(resp) != 1 {
|
|
t.Fatal(len(resp))
|
|
}
|
|
for k := range resp {
|
|
one := resp[k]
|
|
if !check(one) {
|
|
t.Fatal(one)
|
|
}
|
|
return
|
|
}
|
|
panic("somehow no keys found")
|
|
}
|