func BenchmarkGraphQLQuery(b *testing.B) { rec = httptest.NewRecorder() server = handle.BuildHandler() db.Erase() db.Start() populateDB() for i := 0; i < b.N; i++ { /* BENCHMARK CODE */ r, _ = http.NewRequest("POST", "/_graphql", bytes.NewReader([]byte(`query { root:_val vehicles { desc:_val car { land, water } airplane { land, air } } }`))) r.Header.Set("Content-Type", "application/graphql") server.ServeHTTP(rec, r) /* END BENCHMARK CODE */ } db.End() }
func main() { usage := `SummaDB ` + settings.VERSION + ` Usage: summadb [--reset] [--debug] [--cors=<domains>] [--port=<port>] [--db=<dbfile>] Options: -h --help Show this screen. --version Show version. --db=<dbfile> The path of the underlying LevelDB [default: /tmp/summa.db] --port=<port> Choose the port in which the HTTP server will listen [default: 5000] --cors=<domains> Specify a list of comma-separated domains [default: *] --reset Before starting, erase all database contents and start from zero. --debug Force debug. Overrides DEBUG and LOGLEVEL environment variable. ` arguments, _ := docopt.Parse(usage, nil, true, settings.VERSION, false) settings.HandleArgs(arguments) log.WithFields(log.Fields{ "DBFILE": settings.DBFILE, "PORT": settings.PORT, "CORS_ORIGINS": settings.CORS_ORIGINS, "LOGLEVEL": settings.LOGLEVEL, }).Info("starting database server.") if reset, _ := arguments["--reset"]; reset != nil && reset.(bool) { db.Erase() } db.Start() handler := handle.BuildHandler() server := &graceful.Server{ Timeout: 2 * time.Second, Server: &http.Server{ Addr: ":" + settings.PORT, Handler: handler, }, } stop := server.StopChan() server.ListenAndServe() <-stop log.Info("Exiting...") db.End() }
func TestCouchDBSpecialEndpoints(t *testing.T) { g := Goblin(t) RegisterFailHandler(func(m string, _ ...int) { g.Fail(m) }) g.Describe("couchdb db special endpoints", func() { g.BeforeEach(func() { rec = httptest.NewRecorder() server = handle.BuildHandler() }) g.Before(func() { db.Erase() db.Start() populateDB() }) g.After(func() { db.End() }) var rev string var oldrev string var id string g.It("_all_docs for a sub db", func() { r, _ = http.NewRequest("GET", "/vehicles/_all_docs", nil) server.ServeHTTP(rec, r) var res responses.AllDocs json.Unmarshal(rec.Body.Bytes(), &res) Expect(res.Rows).To(HaveLen(3)) Expect(res.Rows[2].Id).To(Equal(res.Rows[2].Key)) rev, _ := res.Rows[2].Value.(map[string]interface{})["rev"] Expect(rev).To(HavePrefix("1-")) keys := []string{res.Rows[0].Id, res.Rows[1].Key, res.Rows[2].Id} Expect(keys).To(ConsistOf("airplane", "boat", "car")) }) g.It("_all_docs with selected keys", func() { r, _ = http.NewRequest("GET", "/vehicles/_all_docs?keys=%5B%22airplane%22,%22boat%22%5D", nil) server.ServeHTTP(rec, r) var res responses.AllDocs json.Unmarshal(rec.Body.Bytes(), &res) Expect(res.Rows).To(HaveLen(2)) keys := []string{res.Rows[0].Id, res.Rows[1].Key} Expect(keys).To(ConsistOf("airplane", "boat")) }) g.It("all_docs with include_docs -- for another sub db", func() { r, _ = http.NewRequest("GET", "/vehicles/airplane/_all_docs?include_docs=true", nil) server.ServeHTTP(rec, r) var res responses.AllDocs json.Unmarshal(rec.Body.Bytes(), &res) Expect(res.Rows).To(HaveLen(3)) docid, _ := res.Rows[1].Doc["_id"] Expect(res.Rows[1].Key).To(Equal(docid)) rev, _ := res.Rows[1].Value.(map[string]interface{})["rev"] docrev, _ := res.Rows[1].Doc["_rev"] Expect(rev).To(Equal(docrev)) keys := []string{res.Rows[0].Id, res.Rows[1].Key, res.Rows[2].Id} sort.Strings(keys) Expect(keys).To(Equal([]string{"air", "land", "water"})) docs := map[string]interface{}{ res.Rows[0].Key: res.Rows[0].Doc, res.Rows[1].Key: res.Rows[1].Doc, res.Rows[2].Key: res.Rows[2].Doc, } Expect(docs).To(HaveKey("air")) Expect(res.Rows[0].Doc).To(HaveKey("_rev")) Expect(res.Rows[0].Doc).To(HaveKeyWithValue("_id", res.Rows[0].Id)) }) g.It("_bulk_get", func() { r, _ = http.NewRequest("POST", "/vehicles/_bulk_get", bytes.NewReader([]byte(`{ "docs": [ {"id": "nonexisting-doc"}, {"id": "car"}, {"_id": "airplane"} ] }`))) server.ServeHTTP(rec, r) var res responses.BulkGet json.Unmarshal(rec.Body.Bytes(), &res) Expect(res.Results[0].Docs[0].Ok).To(BeNil()) Expect(res.Results[0].Docs[0].Error).ToNot(BeNil()) Expect(res.Results[1].Docs[0].Ok).ToNot(BeNil()) Expect(res.Results[1].Docs[0].Error).To(BeNil()) doc := *res.Results[1].Docs[0].Ok id, _ := doc["_id"] irev, _ := doc["_rev"] rev = irev.(string) water, _ := doc["water"] Expect(id.(string)).To(Equal("car")) Expect(res.Results[1].Id).To(Equal(id)) Expect(water).To(BeEquivalentTo(value(false))) Expect(res.Results[2].Docs[0].Ok).To(BeNil()) Expect(res.Results[0].Docs[0].Error).ToNot(BeNil()) }) g.It("_bulk_docs", func() { r, _ = http.NewRequest("POST", "/vehicles/_bulk_docs", bytes.NewReader([]byte(`{ "docs": [ {"everywhere": true}, {"_id": "car", "_rev": "`+rev+`", "space": false, "land": true}, {"_id": "airplane", "nowhere": false}, {"_id": "_local/.abchtru", "replication+data": "k"}, {"_id": "empty-doc"}, {"_id": "doc-with-a-rev-already-set", "_rev": "4-sa98hsa3i4", "val": 33} ] }`))) server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(201)) var res []responses.BulkDocsResult json.Unmarshal(rec.Body.Bytes(), &res) Expect(res).To(HaveLen(6)) Expect(res[0].Error).To(Equal("")) Expect(res[0].Ok).To(Equal(true)) Expect(res[0].Rev).To(HavePrefix("1-")) id = res[0].Id Expect(res[1].Id).To(Equal("car")) prevn, _ := strconv.Atoi(strings.Split(rev, "-")[0]) Expect(res[1].Rev).To(HavePrefix(fmt.Sprintf("%d-", prevn+1))) oldrev = rev rev = res[1].Rev cfe := responses.ConflictError() Expect(res[2].Error).To(Equal(cfe.Error)) Expect(res[3].Id).To(Equal("_local/.abchtru")) Expect(res[3].Ok).To(Equal(true)) Expect(res[4].Ok).To(Equal(true)) Expect(res[4].Rev).To(HavePrefix("1-")) Expect(res[5].Ok).To(Equal(true)) Expect(res[5].Rev).To(HavePrefix("5-")) }) g.It("_bulk_docs with new_edits=false", func() { r, _ = http.NewRequest("POST", "/animals/_bulk_docs", bytes.NewReader([]byte(`{ "docs": [ {"_id": "0", "_rev": "34-83fsop4", "name": "albatroz"}, {"_id": "1", "_rev": "0-a0a0a0a0", "name": "puppy"}, {"_id": "2"} ], "new_edits": false }`))) server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(201)) var res []responses.BulkDocsResult json.Unmarshal(rec.Body.Bytes(), &res) Expect(res).To(HaveLen(3)) Expect(res[0].Ok).To(Equal(true)) Expect(res[1].Ok).To(Equal(true)) Expect(res[2].Ok).To(Equal(false)) Expect(db.GetRev("/animals/0")).To(BeEquivalentTo("34-83fsop4")) Expect(db.GetRev("/animals/1")).ToNot(BeEquivalentTo("0-a0a0a0a0")) Expect(db.GetValueAt("/animals/0/name")).To(BeEquivalentTo(`"albatroz"`)) Expect(db.GetValueAt("/animals/1/name")).To(BeEquivalentTo(`"dog"`)) }) g.It("should have the correct docs saved", func() { Expect(db.GetValueAt("/vehicles/" + id + "/everywhere")).To(BeEquivalentTo("true")) Expect(db.GetLocalDocJsonAt("/vehicles/_local/.abchtru")).To(MatchJSON(`{ "_id": "_local/.abchtru", "_rev": "0-1", "replication+data": "k" }`)) }) g.It("shouldn't show _local docs on _all_docs", func() { r, _ = http.NewRequest("GET", "/vehicles/_all_docs", nil) server.ServeHTTP(rec, r) var res responses.AllDocs json.Unmarshal(rec.Body.Bytes(), &res) Expect(res.Rows).To(HaveLen(5)) }) g.It("_revs_diff", func() { r, _ = http.NewRequest("POST", "/vehicles/_revs_diff", bytes.NewReader([]byte(`{ "everywhere": ["2-invalidrev"], "car": ["`+oldrev+`", "`+rev+`", "1-invalidrev"], "airplane": ["1-nonexisting"] }`))) server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(200)) var res map[string]responses.RevsDiffResult json.Unmarshal(rec.Body.Bytes(), &res) everywhere, _ := res["everywhere"] car, _ := res["car"] airplane, _ := res["airplane"] Expect(everywhere.Missing).To(Equal([]string{"2-invalidrev"})) Expect(car.Missing).To(Equal([]string{oldrev, "1-invalidrev"})) Expect(airplane.Missing).To(Equal([]string{"1-nonexisting"})) }) }) }
func TestCouchDBDocsSpecial(t *testing.T) { g := Goblin(t) RegisterFailHandler(func(m string, _ ...int) { g.Fail(m) }) g.Describe("couchdb documents special endpoints", func() { g.BeforeEach(func() { rec = httptest.NewRecorder() server = handle.BuildHandler() }) g.Before(func() { db.Erase() db.Start() populateDB() }) g.After(func() { db.End() }) var rev string g.It("should change some values to generate revs", func() { brev, _ := db.GetValueAt("/vehicles/boat/air/_rev") r, _ = http.NewRequest("PUT", "/vehicles/boat/air/_val", bytes.NewReader([]byte("true"))) r.Header.Add("If-Match", string(brev)) server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(201)) var res responses.Success json.Unmarshal(rec.Body.Bytes(), &res) rev = res.Rev }) g.It("once more:", func() { r, _ = http.NewRequest("PATCH", "/vehicles/boat/air", bytes.NewReader([]byte(`{ "_rev": "`+rev+`", "really?": false }`))) server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(200)) }) g.It("should fetch some key with the _revisions special field", func() { r, _ = http.NewRequest("GET", "/vehicles?revs=true", nil) server.ServeHTTP(rec, r) var res map[string]interface{} json.Unmarshal(rec.Body.Bytes(), &res) irevisions, ok := res["_revisions"] Expect(ok).To(Equal(true)) revisions := irevisions.(map[string]interface{}) start, _ := revisions["start"] ids, _ := revisions["ids"] Expect(start).To(BeEquivalentTo(1)) Expect(ids).To(HaveLen(3)) }) g.It("should fetch some key with the _revs_info special field", func() { r, _ = http.NewRequest("GET", "/vehicles/boat?revs_info=true", nil) server.ServeHTTP(rec, r) var res map[string]interface{} json.Unmarshal(rec.Body.Bytes(), &res) irevsinfo, ok := res["_revs_info"] Expect(ok).To(Equal(true)) revsinfo := irevsinfo.([]interface{}) Expect(revsinfo).To(HaveLen(3)) first := revsinfo[0].(map[string]interface{}) second := revsinfo[1].(map[string]interface{}) status, _ := first["status"] Expect(status).To(BeEquivalentTo("available")) status, _ = second["status"] Expect(status).To(BeEquivalentTo("missing")) }) }) }
func TestGraphQL(t *testing.T) { g := Goblin(t) RegisterFailHandler(func(m string, _ ...int) { g.Fail(m) }) g.Describe("simple graphql queries", func() { g.BeforeEach(func() { rec = httptest.NewRecorder() server = handle.BuildHandler() }) g.Before(func() { db.Erase() db.Start() populateDB() }) g.After(func() { db.End() }) g.It("should query with type application/graphql", func() { r, _ = http.NewRequest("POST", "/_graphql", bytes.NewReader([]byte(`query { _val vehicles { _val car { land, water } airplane { land, air } } }`))) r.Header.Set("Content-Type", "application/graphql") server.ServeHTTP(rec, r) Expect(rec.Body.String()).To(MatchJSON(`{ "data": { "_val": "root", "vehicles": { "_val": "things that move", "car": { "land": true, "water": false }, "airplane": { "land": true, "air": true } } } }`)) Expect(rec.Code).To(Equal(200)) }) g.It("should query with type application/json", func() { r, _ = http.NewRequest("POST", "/_graphql", bytes.NewReader([]byte(`{ "query": "query { vehicles { runs:car { land, water }, flies:airplane { land, air } }, rootValue:_val }" }`))) r.Header.Set("Content-Type", "application/json") server.ServeHTTP(rec, r) Expect(rec.Body.String()).To(MatchJSON(`{ "data": { "rootValue": "root", "vehicles": { "runs": { "land": true, "water": false }, "flies": { "land": true, "air": true } } } }`)) Expect(rec.Code).To(Equal(200)) }) g.It("should query with type application/x-www-form-urlencoded", func() { form := url.Values{} form.Add("query", ` query { v : vehicles { rocket:flyingtorpedo { land } car { land, air, water } boat { land { _val w:wot } } } } `) r, _ = http.NewRequest("POST", "/_graphql", strings.NewReader(form.Encode())) r.Header.Set("Content-Type", "application/x-www-form-urlencoded") server.ServeHTTP(rec, r) Expect(rec.Body.String()).To(MatchJSON(`{ "data": { "v": { "rocket": { "land": null }, "car": { "land": true, "air": false, "water": false }, "boat": { "land": { "_val": false, "w": null } } } } }`)) Expect(rec.Code).To(Equal(200)) }) g.It("graphql query on a subdb", func() { r, _ = http.NewRequest("POST", "/vehicles/_graphql", strings.NewReader(`query { desc:_val car { land, water } airplane { land, air } }`)) r.Header.Set("Content-Type", "application/graphql") server.ServeHTTP(rec, r) Expect(rec.Body.String()).To(MatchJSON(`{ "data": { "desc": "things that move", "car": { "land": true, "water": false }, "airplane": { "land": true, "air": true } } }`)) Expect(rec.Code).To(Equal(200)) }) }) g.Describe("authorized and restricted graphql queries", func() { g.BeforeEach(func() { rec = httptest.NewRecorder() server = handle.BuildHandler() }) g.Before(func() { db.Erase() db.Start() populateDB() }) g.After(func() { db.End() }) g.It("should create some users and rules", func() { r, _ = http.NewRequest("POST", "/_users", bytes.NewReader([]byte(`{ "name": "vehicles_user", "password": "******" }`))) server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(201)) rec = httptest.NewRecorder() r, _ = http.NewRequest("POST", "/_users", bytes.NewReader([]byte(`{ "name": "boat_user", "password": "******" }`))) server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(201)) rec = httptest.NewRecorder() r, _ = http.NewRequest("PUT", "/vehicles/_security", bytes.NewReader([]byte(`{ "_read": "vehicles_user" }`))) server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(200)) rec = httptest.NewRecorder() r, _ = http.NewRequest("PUT", "/vehicles/boat/_security", bytes.NewReader([]byte(`{ "_read": "boat_user" }`))) server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(200)) rec = httptest.NewRecorder() r, _ = http.NewRequest("PUT", "/_security", bytes.NewReader([]byte(`{ "_read": "no-one", "_write": "no-one", "_admin": "no-one" }`))) server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(200)) }) g.It("should be authorized for the paths where the user has immediate access", func() { r, _ = http.NewRequest("POST", "/vehicles/_graphql", strings.NewReader(`query { car { land, water } }`)) r.Header.Set("Content-Type", "application/graphql") r.SetBasicAuth("vehicles_user", "12345678") server.ServeHTTP(rec, r) Expect(rec.Body.String()).To(MatchJSON(`{ "data": { "car": { "land": true, "water": false } } }`)) Expect(rec.Code).To(Equal(200)) rec = httptest.NewRecorder() r, _ = http.NewRequest("POST", "/vehicles/boat/_graphql", strings.NewReader(`query { air }`)) r.Header.Set("Content-Type", "application/graphql") r.SetBasicAuth("boat_user", "12345678") server.ServeHTTP(rec, r) Expect(rec.Body.String()).To(MatchJSON(`{ "data": { "air": false } }`)) Expect(rec.Code).To(Equal(200)) }) g.It("should be authorized for all paths below", func() { r, _ = http.NewRequest("POST", "/vehicles/boat/_graphql", strings.NewReader(`query { land water }`)) r.Header.Set("Content-Type", "application/graphql") r.SetBasicAuth("vehicles_user", "12345678") server.ServeHTTP(rec, r) Expect(rec.Body.String()).To(MatchJSON(`{ "data": { "land": false, "water": true } }`)) Expect(rec.Code).To(Equal(200)) rec = httptest.NewRecorder() r, _ = http.NewRequest("POST", "/vehicles/boat/air/_graphql", strings.NewReader(`query { flies: _val }`)) r.Header.Set("Content-Type", "application/graphql") r.SetBasicAuth("boat_user", "12345678") server.ServeHTTP(rec, r) Expect(rec.Body.String()).To(MatchJSON(`{ "data": { "flies": false } }`)) Expect(rec.Code).To(Equal(200)) }) g.It("should be unauthorized for all paths above", func() { r, _ = http.NewRequest("POST", "/_graphql", strings.NewReader(`query { root: _val vehicles { car { land } } }`)) r.Header.Set("Content-Type", "application/graphql") r.SetBasicAuth("vehicles_user", "12345678") server.ServeHTTP(rec, r) Expect(rec.Body.String()).To(MatchJSON(`{ "errors": [{ "message": "_read permission for this path needed." }] }`)) rec = httptest.NewRecorder() r, _ = http.NewRequest("POST", "/vehicles/_graphql", strings.NewReader(`query { boat { land, air } }`)) r.Header.Set("Content-Type", "application/graphql") r.SetBasicAuth("boat_user", "12345678") server.ServeHTTP(rec, r) Expect(rec.Body.String()).To(MatchJSON(`{ "errors": [{ "message": "_read permission for this path needed." }] }`)) }) g.It("should be unauthorized for neighbour paths also", func() { r, _ = http.NewRequest("POST", "/vehicles/car/_graphql", strings.NewReader(`query { land water }`)) r.Header.Set("Content-Type", "application/graphql") r.SetBasicAuth("boat_user", "12345678") server.ServeHTTP(rec, r) Expect(rec.Body.String()).To(MatchJSON(`{ "errors": [{ "message": "_read permission for this path needed." }] }`)) }) }) }
func TestAuthUsersACL(t *testing.T) { g := Goblin(t) RegisterFailHandler(func(m string, _ ...int) { g.Fail(m) }) g.Describe("auth", func() { g.BeforeEach(func() { rec = httptest.NewRecorder() server = handle.BuildHandler() }) g.Before(func() { db.Erase() db.Start() }) g.After(func() { db.End() }) g.It("database should be in admin party", func() { r, _ = http.NewRequest("GET", "/_security", nil) server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(200)) var res responses.Security json.Unmarshal(rec.Body.Bytes(), &res) Expect(res).To(BeEquivalentTo(responses.Security{"*", "*", "*"})) }) g.It("should set some rules for database", func() { r, _ = http.NewRequest("PUT", "/_security", bytes.NewReader([]byte(`{ "_read": "*", "_write": "myself", "_admin": "myself" }`))) server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(200)) Expect(db.GetReadRuleAt("/")).To(Equal("*")) Expect(db.GetWriteRuleAt("/")).To(Equal("myself")) Expect(db.GetAdminRuleAt("/")).To(Equal("myself")) }) g.It("should fail to set other rules (since _admin is a user)", func() { r, _ = http.NewRequest("PUT", "/_security", bytes.NewReader([]byte(`{ "_read": "*", "_write": "myself, others", "_admin": "myself" }`))) server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(401)) Expect(db.GetReadRuleAt("/")).To(Equal("*")) Expect(db.GetWriteRuleAt("/")).To(Equal("myself")) Expect(db.GetAdminRuleAt("/")).To(Equal("myself")) }) g.It("should fail to create accounts due to the security policy", func() { r, _ = http.NewRequest("POST", "/_users", bytes.NewReader([]byte(`{ "name": "myself", "password": "******" }`))) server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(401)) }) g.It("should change the security policy by cheating, then create accounts", func() { db.SetRulesAt("/", map[string]interface{}{"_write": "*"}) r, _ = http.NewRequest("POST", "/_users", bytes.NewReader([]byte(`{ "name": "myself", "password": "******" }`))) server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(201)) db.SetRulesAt("/", map[string]interface{}{"_write": "myself, others"}) }) g.It("should create accounts, now using the recently created and authorized user", func() { r, _ = http.NewRequest("POST", "/_users", bytes.NewReader([]byte(`{ "name": "others", "password": "******" }`))) r.SetBasicAuth("myself", "12345678") server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(201)) }) g.It("another account created", func() { r, _ = http.NewRequest("POST", "/_users", bytes.NewReader([]byte(`{ "name": "bob", "password": "******" }`))) r.SetBasicAuth("myself", "12345678") server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(201)) }) g.It("should fail to create document without a user", func() { r, _ = http.NewRequest("PUT", "/a/b/c", bytes.NewReader([]byte(`{ "doc": "iuiwebsd", "val": "woiernhoq234" }`))) server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(401)) }) g.It("should fail to create document with an unallowed user", func() { r, _ = http.NewRequest("PUT", "/a/b/c", bytes.NewReader([]byte(`{ "doc": "iuiwebsd", "val": "woiernhoq234" }`))) r.SetBasicAuth("bob", "gki48dh3w") server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(401)) }) g.It("should succeed to created document with a correct user", func() { r, _ = http.NewRequest("PUT", "/a/b/c", bytes.NewReader([]byte(`{ "doc": "iuiwebsd", "val": "woiernhoq234" }`))) r.SetBasicAuth("others", "qwerty") server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(201)) }) g.It("should change only read permission for a subpath", func() { r, _ = http.NewRequest("PUT", "/a/b/_security", bytes.NewReader([]byte(`{ "_read": "bob" }`))) r.SetBasicAuth("myself", "12345678") server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(200)) }) g.It("should be able to read with wrong user because of upper rule", func() { r, _ = http.NewRequest("GET", "/a/b/c", nil) r.SetBasicAuth("myself", "12345678") server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(200)) }) g.It("remove upper rule that allowed everybody", func() { r, _ = http.NewRequest("PUT", "/_security", bytes.NewReader([]byte(`{ "_read": "" }`))) r.SetBasicAuth("myself", "12345678") server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(200)) }) g.It("shouldn't be able to read with wrong user", func() { r, _ = http.NewRequest("GET", "/a/b/c", nil) r.SetBasicAuth("myself", "12345678") server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(401)) }) g.It("should be able to read with correct user", func() { r, _ = http.NewRequest("GET", "/a/b/c", nil) r.SetBasicAuth("bob", "gki48dh3w") server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(200)) }) g.It("change the rule again, now a lower rule will allow a different user", func() { r, _ = http.NewRequest("PUT", "/a/b/c/_security", bytes.NewReader([]byte(`{ "_read": "others" }`))) r.SetBasicAuth("myself", "12345678") server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(200)) }) g.It("should be able to read with this different user", func() { r, _ = http.NewRequest("GET", "/a/b/c", nil) r.SetBasicAuth("others", "qwerty") server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(200)) }) g.It("and again with the same user that was allowed first", func() { r, _ = http.NewRequest("GET", "/a/b/c", nil) r.SetBasicAuth("bob", "gki48dh3w") server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(200)) }) }) }
func TestBasics(t *testing.T) { g := Goblin(t) RegisterFailHandler(func(m string, _ ...int) { g.Fail(m) }) g.Describe("basics", func() { g.BeforeEach(func() { rec = httptest.NewRecorder() server = handle.BuildHandler() }) g.Before(func() { db.Erase() db.Start() populateDB() }) g.After(func() { db.End() }) var rev string g.It("should get an empty doc", func() { r, _ = http.NewRequest("GET", "/nothing/here", nil) server.ServeHTTP(rec, r) Expect(rec.Body.String()).To(MatchJSON(`{ "error": "not_found", "reason": "missing" }`)) Expect(rec.Code).To(Equal(404)) }) g.It("should create a new doc", func() { body := `{"a": "one", "dfg": {"many": 3, "which": ["d", "f", "g"]}}` jsonbody := []byte(body) r, _ = http.NewRequest("PUT", "/something/here", bytes.NewReader(jsonbody)) server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(201)) var resp responses.Success Expect(json.Unmarshal(rec.Body.Bytes(), &resp)).To(Succeed()) Expect(resp.Ok).To(BeTrue()) Expect(resp.Id).To(Equal("here")) Expect(resp.Rev).To(HavePrefix("1-")) rev = resp.Rev }) g.It("should fetch a subfield", func() { r, _ = http.NewRequest("GET", "/something/here/a/_val", nil) server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(200)) Expect(rec.Body.String()).To(Equal(`"one"`)) }) g.It("should fetch a subrev", func() { r, _ = http.NewRequest("GET", "/something/here/dfg/_rev", nil) server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(200)) rev = rec.Body.String() Expect(rev).To(HavePrefix(`1-`)) }) g.It("should fetch a subtree", func() { r, _ = http.NewRequest("GET", "/something/here/dfg", nil) server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(200)) Expect(rec.Body.String()).To(MatchJSON(`{ "_id": "dfg", "_rev": "` + rev + `", "many": {"_val": 3}, "which": { "0": {"_val": "d"}, "1": {"_val": "f"}, "2": {"_val": "g"} } }`)) }) g.It("should get the newest _rev for a path", func() { r, _ = http.NewRequest("GET", "/something/here/dfg/many/_rev", nil) server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(200)) rev = rec.Body.String() }) g.It("should delete a key (providing rev)", func() { r, _ = http.NewRequest("DELETE", "/something/here/dfg/many", nil) r.Header.Set("If-Match", rev) server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(200)) var resp responses.Success Expect(json.Unmarshal(rec.Body.Bytes(), &resp)).To(Succeed()) Expect(resp.Ok).To(BeTrue()) Expect(resp.Id).To(Equal("many")) Expect(resp.Rev).To(HavePrefix("2-")) }) g.It("should fail to fetch deleted key", func() { r, _ = http.NewRequest("GET", "/something/here/dfg/many", nil) server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(404)) }) g.It("should fail to delete a special key", func() { r, _ = http.NewRequest("DELETE", "/something/here/_rev", nil) server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(400)) }) g.It("should fail to update a special key", func() { body := `{"a": "one", "dfg": {"many": 3, "which": ["d", "f", "g"]}}` jsonbody := []byte(body) r, _ = http.NewRequest("PATCH", "/something/_rev", bytes.NewReader(jsonbody)) server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(400)) }) g.It("should fail to update a key without providing a _rev", func() { body := `{"was": "another thing"}` jsonbody := []byte(body) r, _ = http.NewRequest("PATCH", "/something", bytes.NewReader(jsonbody)) server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(409)) }) g.It("should fail to update a key providing a wrong _rev", func() { body := `{"_rev": "2-389247isdbf", "was": "another thing"}` jsonbody := []byte(body) r, _ = http.NewRequest("PATCH", "/something/here/dfg", bytes.NewReader(jsonbody)) server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(409)) }) g.It("should fail to update a deleted key when providing a mismatching revs", func() { body := `{"_rev": "3-1asd623a5", "was": "another thing"}` jsonbody := []byte(body) r, _ = http.NewRequest("PATCH", "/something/here/dfg?rev=7-sdf98h435", bytes.NewReader(jsonbody)) r.Header.Set("If-Match", rev) server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(400)) }) g.It("should fail to patch an untouched path", func() { jsonbody := []byte(`{"1": 2}`) r, _ = http.NewRequest("PATCH", "/nowhere", bytes.NewReader(jsonbody)) server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(404)) }) g.It("should get the newest _rev for a path", func() { r, _ = http.NewRequest("GET", "/something/here/_rev", nil) server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(200)) rev = rec.Body.String() }) g.It("should delete a path providing the correct rev", func() { r, _ = http.NewRequest("DELETE", "/something/here?rev="+rev, nil) server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(200)) }) g.It("should fail to patch a deleted path", func() { jsonbody := []byte(`{"1": 2}`) r, _ = http.NewRequest("PATCH", "/something/here", bytes.NewReader(jsonbody)) server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(404)) }) g.It("should put a tree on a deleted path without providing any rev", func() { body := `{"was": {"before": "another thing", "long_before": "a different thing"}}` jsonbody := []byte(body) r, _ = http.NewRequest("PUT", "/something/here", bytes.NewReader(jsonbody)) server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(201)) var resp responses.Success json.Unmarshal(rec.Body.Bytes(), &resp) rev = resp.Rev }) g.It("should update a subpath with the rev of a parent", func() { body := `{"was": {"before": "still another thing"}}` jsonbody := []byte(body) r, _ = http.NewRequest("PATCH", "/something/here?rev="+rev, bytes.NewReader(jsonbody)) server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(200)) var resp responses.Success json.Unmarshal(rec.Body.Bytes(), &resp) rev = resp.Rev }) g.It("should delete a subpath with the rev of a parent (using a tree)", func() { body := `{"was": {"long_before": null}, "_rev": "` + rev + `"}` jsonbody := []byte(body) r, _ = http.NewRequest("PATCH", "/something/here", bytes.NewReader(jsonbody)) server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(200)) }) g.It("should get the rev of the something path", func() { r, _ = http.NewRequest("GET", "/something/_rev", nil) server.ServeHTTP(rec, r) rev = rec.Body.String() }) g.It("should have the correct tree in the end", func() { r, _ = http.NewRequest("GET", "/something", nil) server.ServeHTTP(rec, r) Expect(rec.Code).To(Equal(200)) Expect(rec.Body.String()).To(MatchJSON(`{ "_id": "something", "_rev": "` + rev + `", "here": { "was": { "before": { "_val": "still another thing" } } } }`)) }) }) }