Example #1
0
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()
}
Example #2
0
func TestLocalDocs(t *testing.T) {
	g := Goblin(t)
	RegisterFailHandler(func(m string, _ ...int) { g.Fail(m) })

	g.Describe("local docs", func() {
		g.Before(func() {
			db.Erase()
			db.Start()
		})

		g.After(func() {
			db.End()
		})

		g.It("should save a _local doc", func() {
			Expect(db.SaveLocalDocAt("/banana/_local/w3hnks8hr", map[string]interface{}{
				"j": 23,
				"history": []map[string]interface{}{
					map[string]interface{}{"a": "b"},
				},
			})).To(Equal("0-1"))
			Expect(db.GetLocalDocJsonAt("/banana/_local/w3hnks8hr")).To(MatchJSON(`{
                "_id": "_local/w3hnks8hr",
                "_rev": "0-1",
                "j": 23,
                "history": [{"a": "b"}]
            }`))
		})

		g.It("should update a _local doc", func() {
			Expect(db.SaveLocalDocAt("/banana/_local/w3hnks8hr", map[string]interface{}{
				"j": 77,
				"history": []map[string]interface{}{
					map[string]interface{}{"a": "b"},
					map[string]interface{}{"c": "d"},
				},
				"_rev": "0-1",
				"_id":  "_local/w3hnks8hr",
			})).To(Equal("0-2"))
			Expect(db.GetLocalDocJsonAt("/banana/_local/w3hnks8hr")).To(MatchJSON(`{
                "_id": "_local/w3hnks8hr",
                "_rev": "0-2",
                "j": 77,
                "history": [{"a": "b"}, {"c": "d"}]
            }`))
		})

		g.It("should get the _local doc rev", func() {
			Expect(db.GetLocalDocRev("/banana/_local/w3hnks8hr")).To(BeEquivalentTo("0-2"))
		})
	})
}
Example #3
0
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()
}
Example #4
0
func TestBasics(t *testing.T) {
	g := Goblin(t)
	RegisterFailHandler(func(m string, _ ...int) { g.Fail(m) })

	g.Describe("basics test", func() {

		g.Before(func() {
			db.Erase()
			db.Start()
		})

		g.After(func() {
			db.End()
		})

		g.It("should save a tree", func() {
			db.SaveTreeAt("/fruits/banana", map[string]interface{}{
				"colour":   "yellow",
				"hardness": "low",
				"_val":     "a fruit.",
			})
			Expect(db.GetValueAt("/fruits/banana")).To(BeEquivalentTo(`"a fruit."`))
			Expect(db.GetValueAt("/fruits/banana/colour")).To(BeEquivalentTo(`"yellow"`))
			Expect(db.GetValueAt("/fruits/banana/hardness")).To(BeEquivalentTo(`"low"`))
			_, err := db.GetValueAt("/fruits")
			Expect(err).To(HaveOccurred())
			Expect(db.GetTreeAt("/fruits")).To(Equal(map[string]interface{}{
				"banana": map[string]interface{}{
					"colour":   value("yellow"),
					"hardness": value("low"),
					"_val":     "a fruit.",
				},
			}))
		})

		g.It("should modify a subvalue of the tree", func() {
			db.SaveValueAt("/fruits/banana/colour", []byte(`"black-and-yellow"`))
			Expect(db.GetValueAt("/fruits/banana/colour")).To(BeEquivalentTo(`"black-and-yellow"`))
			Expect(db.GetValueAt("/fruits/banana/hardness")).To(BeEquivalentTo(`"low"`))
		})

		g.It("should add a value deeply nested in a tree that doesn't exists", func() {
			db.SaveValueAt("/fruits/mellon/season", []byte(`"spring"`))
			Expect(db.GetValueAt("/fruits/mellon/season")).To(BeEquivalentTo(`"spring"`))
			Expect(db.GetTreeAt("/fruits")).To(Equal(map[string]interface{}{
				"banana": map[string]interface{}{
					"colour":   value("black-and-yellow"),
					"hardness": value("low"),
					"_val":     "a fruit.",
				},
				"mellon": map[string]interface{}{
					"season": value("spring"),
				},
			}))
		})

		g.It("should add a tree deeply nested like the previous", func() {
			db.SaveTreeAt("/fruits/orange", map[string]interface{}{
				"colour":   "orange",
				"hardness": "medium",
				"_val":     "name == colour",
			})
			Expect(db.GetValueAt("/fruits/orange/colour")).To(BeEquivalentTo(`"orange"`))
			Expect(db.GetValueAt("/fruits/orange")).To(BeEquivalentTo(`"name == colour"`))
			Expect(db.GetTreeAt("/fruits/orange")).To(Equal(map[string]interface{}{
				"_val":     "name == colour",
				"colour":   value("orange"),
				"hardness": value("medium"),
			}))
		})

		g.It("should delete a key", func() {
			db.DeleteAt("/fruits/banana/colour")
			Expect(db.GetValueAt("/fruits/orange/colour")).To(BeEquivalentTo(`"orange"`))
			_, err := db.GetValueAt("/fruits/banana/colour")
			Expect(db.GetValueAt("/fruits/banana/colour/_deleted")).To(BeEquivalentTo(""))
			Expect(err).To(HaveOccurred())
		})

		g.It("should delete a value when setting it to null with a tree", func() {
			db.SaveTreeAt("/fruits/mellon", map[string]interface{}{
				"colour": "orange",
				"season": nil,
			})
			Expect(db.GetValueAt("/fruits/mellon/colour")).To(BeEquivalentTo(`"orange"`))
			_, err := db.GetValueAt("/fruits/mellon/season")
			Expect(err).To(HaveOccurred())

			db.SaveTreeAt("/fruits", map[string]interface{}{
				"mellon": nil,
			})
			_, err = db.GetValueAt("/fruits/mellon/colour")
			Expect(err).To(HaveOccurred())
			_, err = db.GetValueAt("/fruits/mellon")
			Expect(err).To(HaveOccurred())
		})

		g.It("should delete a tree", func() {
			db.DeleteAt("/fruits/banana")
			Expect(db.GetValueAt("/fruits/orange/colour")).To(BeEquivalentTo(`"orange"`))
			_, err := db.GetValueAt("/fruits/banana/hardness")
			Expect(err).To(HaveOccurred())

			rev, err := db.DeleteAt("/fruits")
			Expect(err).ToNot(HaveOccurred())
			Expect(rev).To(HavePrefix("9-"))
			_, err = db.GetValueAt("/fruits")
			Expect(err).To(HaveOccurred())
			Expect(db.GetValueAt("/fruits/orange/_deleted")).To(BeEquivalentTo(""))
			_, err = db.GetValueAt("/fruits/orange/colour")
			Expect(err).To(HaveOccurred())
			_, err = db.GetValueAt("/fruits/banana/hardness")
			Expect(err).To(HaveOccurred())
		})

		g.It("should error when fetching an untouched tree path", func() {
			_, err := db.GetTreeAt("/nowhere")
			Expect(err).To(HaveOccurred())
		})

		g.It("should return when fetching a deleted tree path", func() {
			tree, err := db.GetTreeAt("/fruits/banana")
			Expect(err).ToNot(HaveOccurred())
			empty := make(map[string]interface{})
			Expect(tree).To(BeEquivalentTo(empty))
		})
	})
}
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"}))
		})
	})
}
Example #6
0
func TestRevs(t *testing.T) {
	g := Goblin(t)
	RegisterFailHandler(func(m string, _ ...int) { g.Fail(m) })

	g.Describe("_rev", func() {

		g.Before(func() {
			db.Erase()
			db.Start()
		})

		g.After(func() {
			db.End()
		})

		g.It("should generate _rev for a single key", func() {
			savedrev, _ := db.SaveValueAt("/name", []byte(`"database of vehicles"`))
			gottenrev, _ := db.GetValueAt("/name/_rev")
			Expect(savedrev).To(BeEquivalentTo(gottenrev))
			Expect(gottenrev).To(HavePrefix("1-"))
		})

		g.It("should generate _rev for parent keys", func() {
			db.SaveValueAt("/vehicles/car/land", []byte("true"))
			db.SaveValueAt("/vehicles/carriage/land", []byte("true"))
			db.SaveValueAt("/vehicles/carriage/air", []byte("false"))
			Expect(db.GetValueAt("/vehicles/car/land/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/car/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/_rev")).To(HavePrefix("3-"))
			Expect(db.GetValueAt("/vehicles/carriage/land/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/carriage/_rev")).To(HavePrefix("2-"))
		})

		g.It("should bump _rev for single keys", func() {
			db.SaveValueAt("/name", []byte(`"just a database of vehicles"`))
			Expect(db.GetValueAt("/name/_rev")).To(HavePrefix("2-"))
		})

		g.It("should bump _rev for parent keys", func() {
			db.SaveValueAt("/vehicles/car/water", []byte("false"))
			Expect(db.GetValueAt("/vehicles/car/land/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/car/water/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/car/_rev")).To(HavePrefix("2-"))
			Expect(db.GetValueAt("/vehicles/_rev")).To(HavePrefix("4-"))
			Expect(db.GetValueAt("/vehicles/carriage/land/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/carriage/_rev")).To(HavePrefix("2-"))

			db.SaveValueAt("/vehicles/boat/water", []byte("true"))
			Expect(db.GetValueAt("/vehicles/car/land/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/car/water/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/boat/water/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/car/_rev")).To(HavePrefix("2-"))
			Expect(db.GetValueAt("/vehicles/boat/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/_rev")).To(HavePrefix("5-"))
		})

		g.It("on delete, should bump _rev for parents and sons", func() {
			db.DeleteAt("/vehicles/car")
			Expect(db.GetValueAt("/vehicles/car/land/_rev")).To(HavePrefix("2-"))
			Expect(db.GetValueAt("/vehicles/car/water/_rev")).To(HavePrefix("2-"))
			Expect(db.GetValueAt("/vehicles/car/_rev")).To(HavePrefix("3-"))
			Expect(db.GetValueAt("/vehicles/boat/water/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/boat/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/_rev")).To(HavePrefix("6-"))
			Expect(db.GetValueAt("/vehicles/carriage/land/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/carriage/_rev")).To(HavePrefix("2-"))
		})

		g.It("should bump rev of all parents of affected keys", func() {
			db.SaveTreeAt("/vehicles/boat", map[string]interface{}{
				"water": true,
				"land":  false,
				"air":   false,
			})
			Expect(db.GetValueAt("/vehicles/car/land/_rev")).To(HavePrefix("2-"))
			Expect(db.GetValueAt("/vehicles/car/water/_rev")).To(HavePrefix("2-"))
			Expect(db.GetValueAt("/vehicles/car/_rev")).To(HavePrefix("3-"))
			Expect(db.GetValueAt("/vehicles/boat/water/_rev")).To(HavePrefix("2-"))
			Expect(db.GetValueAt("/vehicles/boat/land/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/boat/air/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/boat/_rev")).To(HavePrefix("2-"))
			Expect(db.GetValueAt("/vehicles/_rev")).To(HavePrefix("7-"))
		})

		g.It("doing it again to make sure", func() {
			db.SaveTreeAt("/vehicles", map[string]interface{}{
				"car": map[string]interface{}{
					"water": true,
				},
				"boat": map[string]interface{}{
					"air": true,
				},
			})
			Expect(db.GetValueAt("/vehicles/car/land/_rev")).To(HavePrefix("2-"))
			Expect(db.GetValueAt("/vehicles/car/water/_rev")).To(HavePrefix("3-"))
			Expect(db.GetValueAt("/vehicles/car/_rev")).To(HavePrefix("4-"))
			Expect(db.GetValueAt("/vehicles/boat/water/_rev")).To(HavePrefix("2-"))
			Expect(db.GetValueAt("/vehicles/boat/land/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/boat/air/_rev")).To(HavePrefix("2-"))
			Expect(db.GetValueAt("/vehicles/boat/_rev")).To(HavePrefix("3-"))
			Expect(db.GetValueAt("/vehicles/_rev")).To(HavePrefix("8-"))
			Expect(db.GetValueAt("/vehicles/carriage/land/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/carriage/_rev")).To(HavePrefix("2-"))
		})

		g.It("should bump the revs correctly when a tree operation involves deleting", func() {
			db.SaveTreeAt("/vehicles", map[string]interface{}{
				"carriage": map[string]interface{}{
					"space": false,
					"land":  nil,
				},
				"boat": nil,
			})
			Expect(db.GetValueAt("/vehicles/car/_rev")).To(HavePrefix("4-"))
			Expect(db.GetValueAt("/vehicles/boat/water/_rev")).To(HavePrefix("3-"))
			Expect(db.GetValueAt("/vehicles/boat/land/_rev")).To(HavePrefix("2-"))
			Expect(db.GetValueAt("/vehicles/boat/air/_rev")).To(HavePrefix("3-"))
			Expect(db.GetValueAt("/vehicles/boat/_rev")).To(HavePrefix("4-"))
			Expect(db.GetValueAt("/vehicles/_rev")).To(HavePrefix("9-"))
			Expect(db.GetValueAt("/vehicles/carriage/land/_rev")).To(HavePrefix("2-"))
			Expect(db.GetValueAt("/vehicles/carriage/_rev")).To(HavePrefix("3-"))
		})

		g.It("should bump revs of intermediate paths when modifying a deep field", func() {
			db.SaveValueAt("/vehicles/train/land/rail", []byte("true"))
			Expect(db.GetValueAt("/vehicles/_rev")).To(HavePrefix("10-"))
			Expect(db.GetValueAt("/vehicles/train/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/train/land/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/train/land/rail/_rev")).To(HavePrefix("1-"))

			db.DeleteAt("/vehicles/train")
			Expect(db.GetValueAt("/vehicles/_rev")).To(HavePrefix("11-"))
			Expect(db.GetValueAt("/vehicles/train/_rev")).To(HavePrefix("2-"))
			Expect(db.GetValueAt("/vehicles/train/land/_rev")).To(HavePrefix("2-"))
			Expect(db.GetValueAt("/vehicles/train/land/rail/_rev")).To(HavePrefix("2-"))

			db.SaveTreeAt("", map[string]interface{}{
				"vehicles": map[string]interface{}{
					"skate": map[string]interface{}{
						"air": map[string]interface{}{
							"carried": map[string]interface{}{
								"_val": true,
							},
						},
					},
				},
			})
			Expect(db.GetValueAt("/vehicles/_rev")).To(HavePrefix("12-"))
			Expect(db.GetValueAt("/vehicles/skate/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/skate/air/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/skate/air/carried/_rev")).To(HavePrefix("1-"))

			db.SaveTreeAt("", map[string]interface{}{
				"vehicles": map[string]interface{}{
					"skate": map[string]interface{}{
						"air": map[string]interface{}{
							"carried": nil,
						},
					},
				},
			})
			Expect(db.GetValueAt("/vehicles/_rev")).To(HavePrefix("13-"))
			Expect(db.GetValueAt("/vehicles/skate/_rev")).To(HavePrefix("2-"))
			Expect(db.GetValueAt("/vehicles/skate/air/_rev")).To(HavePrefix("2-"))
			Expect(db.GetValueAt("/vehicles/skate/air/carried/_rev")).To(HavePrefix("2-"))
		})

		g.It("should return rev", func() {
			sk, err := db.GetSpecialKeysAt("/vehicles/skate")
			Expect(err).ToNot(HaveOccurred())
			Expect(sk.Rev).To(HavePrefix("2-"))
		})
	})
}
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"))
		})
	})
}
Example #8
0
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))
		})
	})
}
Example #9
0
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."
              }]
            }`))
		})
	})
}
Example #10
0
func TestIdempotent(t *testing.T) {
	g := Goblin(t)
	RegisterFailHandler(func(m string, _ ...int) { g.Fail(m) })

	g.Describe("idempotent put", func() {
		g.Before(func() {
			db.Erase()
			db.Start()
		})

		g.After(func() {
			db.End()
		})

		g.It("should put a tree", func() {
			Expect(db.ReplaceTreeAt("/fruits/banana", map[string]interface{}{
				"colour":   "yellow",
				"hardness": "low",
				"_val":     "a fruit.",
			}, false)).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/fruits/banana")).To(BeEquivalentTo(`"a fruit."`))
			Expect(db.GetValueAt("/fruits/banana/colour")).To(BeEquivalentTo(`"yellow"`))
		})

		g.It("should replace it with a totally different object with arrays", func() {
			rev, err := db.ReplaceTreeAt("", map[string]interface{}{
				"what":    "numbers",
				"numbers": []interface{}{"zero", "one", "two", "three"},
			}, false)
			Expect(err).ToNot(HaveOccurred())
			Expect(rev).To(HavePrefix("2-"))
			Expect(db.GetValueAt("/numbers/3")).To(BeEquivalentTo(`"three"`))
			_, err = db.GetValueAt("/numbers")
			Expect(err).To(HaveOccurred())
			Expect(db.GetTreeAt("")).To(Equal(map[string]interface{}{
				"what": value("numbers"),
				"numbers": map[string]interface{}{
					"0": value("zero"),
					"1": value("one"),
					"2": value("two"),
					"3": value("three"),
				},
			}))
			_, err = db.GetValueAt("/fruits")
			Expect(err).To(HaveOccurred())
		})

		g.It("should replace it again with a totally different object", func() {
			Expect(db.ReplaceTreeAt("/fruits/orange", map[string]interface{}{
				"colour": "orange",
			}, false)).To(HavePrefix("1-"))
			Expect(db.GetTreeAt("")).To(Equal(map[string]interface{}{
				"what": value("numbers"),
				"numbers": map[string]interface{}{
					"0": value("zero"),
					"1": value("one"),
					"2": value("two"),
					"3": value("three"),
				},
				"fruits": map[string]interface{}{
					"orange": map[string]interface{}{
						"colour": value("orange"),
					},
				},
			}))
		})

		g.It("should put an empty object", func() {
			rev, err := db.ReplaceTreeAt("/fruits/watermellon", map[string]interface{}{}, false)
			Expect(err).ToNot(HaveOccurred())
			Expect(rev).To(HavePrefix("1-"))
		})
	})
}
Example #11
0
func TestArrays(t *testing.T) {
	g := Goblin(t)
	RegisterFailHandler(func(m string, _ ...int) { g.Fail(m) })

	g.Describe("array values", func() {
		g.Before(func() {
			db.Erase()
			db.Start()
		})

		g.After(func() {
			db.End()
		})

		g.It("should save a tree with a simple array", func() {
			rev, err := db.SaveTreeAt("", map[string]interface{}{
				"numbers": []interface{}{"zero", "one", "two", "three"},
			})
			Expect(err).ToNot(HaveOccurred())
			Expect(rev).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/numbers/0")).To(BeEquivalentTo(`"zero"`))
			Expect(db.GetValueAt("/numbers/3")).To(BeEquivalentTo(`"three"`))
			_, err = db.GetValueAt("/numbers")
			Expect(err).To(HaveOccurred())
			Expect(db.GetTreeAt("/numbers")).To(Equal(map[string]interface{}{
				"0": value("zero"),
				"1": value("one"),
				"2": value("two"),
				"3": value("three"),
			}))
		})

		g.It("should save a tree with a complex array", func() {
			rev, err := db.SaveTreeAt("", map[string]interface{}{
				"letters": []interface{}{
					map[string]interface{}{
						"name":       "á",
						"variations": []interface{}{"a", "A"},
					},
					map[string]interface{}{
						"name":       "bê",
						"variations": []interface{}{"b", "B"},
					},
				},
			})
			Expect(err).ToNot(HaveOccurred())
			Expect(rev).To(HavePrefix("2-"))
			Expect(db.GetValueAt("/letters/0/name")).To(BeEquivalentTo(`"á"`))
			Expect(db.GetValueAt("/letters/1/variations/1")).To(BeEquivalentTo(`"B"`))
			_, err = db.GetValueAt("/letters/0/variations")
			Expect(err).To(HaveOccurred())
			Expect(db.GetTreeAt("/letters")).To(Equal(map[string]interface{}{
				"0": map[string]interface{}{
					"name": value("á"),
					"variations": map[string]interface{}{
						"0": value("a"),
						"1": value("A"),
					},
				},
				"1": map[string]interface{}{
					"name": value("bê"),
					"variations": map[string]interface{}{
						"0": value("b"),
						"1": value("B"),
					},
				},
			}))
		})
	})
}
Example #12
0
func TestSeqs(t *testing.T) {
	g := Goblin(t)
	RegisterFailHandler(func(m string, _ ...int) { g.Fail(m) })

	g.Describe("seqs getting bumped", func() {

		g.Before(func() {
			db.Erase()
			db.Start()
		})

		g.After(func() {
			db.End()
		})

		/*
		   we currently don't care a lot to the exact seqs here,
		   we only care if the values are being increased and there
		   are no conflicts.

		   later maybe we'll have to optimize all this (and conseqüently
		   change all these tests) so we don't get new the seq
		   bumped for operations that do not result in an actual _rev
		   being written (in DELETE and UNDELETE operations there are
		   temporary _revs being created and then replaced by others
		   with the same number prefix).
		*/

		g.It("should increase seqs when adding a new tree", func() {
			db.SaveTreeAt("", map[string]interface{}{
				"x": "oiwaeuriasburis",
			})
			Expect(db.GlobalUpdateSeq()).To(BeEquivalentTo(2))
			Expect(db.LastSeqAt("")).To(BeNumerically(">", uint64(0)))
			Expect(db.LastSeqAt("/x")).To(BeNumerically("==", uint64(0)))
		})

		g.It("should increase seqs when adding a new value", func() {
			db.SaveValueAt("/z", []byte("ihfiuewrhewoiruh"))
			Expect(db.GlobalUpdateSeq()).To(BeEquivalentTo(4))
			Expect(db.LastSeqAt("")).To(BeNumerically(">", uint64(2)))
			Expect(db.LastSeqAt("/x")).To(BeNumerically("==", uint64(0)))
		})

		g.It("should increase seqs when deleting a value", func() {
			db.DeleteAt("/x")
			Expect(db.GlobalUpdateSeq()).To(BeEquivalentTo(7))
			Expect(db.LastSeqAt("")).To(BeNumerically(">", uint64(5)))
			Expect(db.LastSeqAt("/x")).To(BeNumerically("==", uint64(0)))
			Expect(db.LastSeqAt("/z")).To(BeNumerically("==", uint64(0)))
		})

		g.It("should increase seqs when undeleting a value", func() {
			db.SaveValueAt("/x/xchild", []byte("skjfbslkfbskdf"))
			Expect(db.GlobalUpdateSeq()).To(BeEquivalentTo(10))
			Expect(db.LastSeqAt("")).To(BeNumerically(">", uint64(7)))
			Expect(db.LastSeqAt("/x")).To(BeNumerically(">", uint64(7)))
		})

		g.It("should increase seqs when making bizarre things", func() {
			db.ReplaceTreeAt("/x", map[string]interface{}{
				"xchild": nil,
				"other":  "saldkasndlksad",
				"_val":   "askjdasnkdjasd",
			}, false)
			db.ReplaceTreeAt("/x/xchild", map[string]interface{}{
				"ham":  "sadljkasndlksad",
				"_val": "askjdasnkdjasd",
			}, false)
			Expect(db.GlobalUpdateSeq()).To(BeEquivalentTo(19))
		})
	})
}
Example #13
0
func TestAuthUsersACL(t *testing.T) {
	g := Goblin(t)
	RegisterFailHandler(func(m string, _ ...int) { g.Fail(m) })

	g.Describe("users and permissions", func() {
		g.Before(func() {
			db.Erase()
			db.Start()
		})

		g.After(func() {
			db.End()
		})

		g.It("should start with a * permission on root", func() {
			Expect(db.GetWriteRuleAt("/")).To(Equal("*"))
			Expect(db.GetReadRuleAt("/")).To(Equal("*"))
			Expect(db.GetAdminRuleAt("")).To(Equal("*")) // "/" should equal ""
		})

		g.It("which means everybody is allowed to do anything anywhere", func() {
			Expect(db.WriteAllowedAt("/", "bob")).To(Equal(true))
			Expect(db.ReadAllowedAt("/articles", "maria")).To(Equal(true))
			Expect(db.AdminAllowedAt("/somewhere/down/on/the/path", "anyone")).To(Equal(true))
			Expect(db.WriteAllowedAt("/x/r/e/ws/sd/f/t/r/e/d/g/y", "")).To(Equal(true))
			Expect(db.ReadAllowedAt("/recipes", "anna")).To(Equal(true))
			Expect(db.AdminAllowedAt("/", "bob")).To(Equal(true))
		})

		g.It("should modify permissions arbitrarily", func() {
			Expect(db.SetRulesAt("/paper", map[string]interface{}{
				"_read":  "drawer,romancist, reader",
				"_write": "drawer, romancist",
				"_admin": "romancist",
			})).To(Succeed())
			Expect(db.SetRulesAt("/", map[string]interface{}{
				"_read":  "myself",
				"_write": "myself",
				"_admin": "myself",
			})).To(Succeed())
		})

		g.It("and allowability should reflect that", func() {
			Expect(db.WriteAllowedAt("/", "bob")).To(Equal(false))
			Expect(db.ReadAllowedAt("/articles", "maria")).To(Equal(false))
			Expect(db.AdminAllowedAt("/somewhere/down/on/the/path", "anyone")).To(Equal(false))
			Expect(db.ReadAllowedAt("/recipes", "anna")).To(Equal(false))
			Expect(db.WriteAllowedAt("/x/r/e/ws/sd/f/t/r/e/d/g/y", "")).To(Equal(false))
			Expect(db.AdminAllowedAt("/", "bob")).To(Equal(false))

			Expect(db.WriteAllowedAt("/", "myself")).To(Equal(true))
			Expect(db.WriteAllowedAt("/paper", "myself")).To(Equal(true))
			Expect(db.WriteAllowedAt("/rock", "myself")).To(Equal(true))
			Expect(db.WriteAllowedAt("/paper/planes", "myself")).To(Equal(true))
			Expect(db.WriteAllowedAt("/paper", "romancist")).To(Equal(true))
			Expect(db.WriteAllowedAt("/paper/planes", "romancist")).To(Equal(true))
			Expect(db.WriteAllowedAt("/", "romancist")).To(Equal(false))
			Expect(db.WriteAllowedAt("/paperless", "romancist")).To(Equal(false))

			Expect(db.ReadAllowedAt("/paper", "drawer")).To(Equal(true))
			Expect(db.ReadAllowedAt("/paperless", "drawer")).To(Equal(false))
			Expect(db.ReadAllowedAt("/paper/origami", "drawer")).To(Equal(true))
			Expect(db.ReadAllowedAt("/paper", "reader")).To(Equal(true))
			Expect(db.ReadAllowedAt("/paperless", "reader")).To(Equal(false))
			Expect(db.ReadAllowedAt("/paper/origami", "reader")).To(Equal(true))

			Expect(db.AdminAllowedAt("/", "myself")).To(Equal(true))
			Expect(db.AdminAllowedAt("/anywhere", "myself")).To(Equal(true))
			Expect(db.AdminAllowedAt("/paper", "myself")).To(Equal(true))
			Expect(db.AdminAllowedAt("/", "romancist")).To(Equal(false))
			Expect(db.AdminAllowedAt("/anywhere", "romancist")).To(Equal(false))
			Expect(db.AdminAllowedAt("/paper", "romancist")).To(Equal(true))
			Expect(db.AdminAllowedAt("/paper/origami", "romancist")).To(Equal(true))
			Expect(db.AdminAllowedAt("/", "reader")).To(Equal(false))
			Expect(db.AdminAllowedAt("/anywhere", "reader")).To(Equal(false))
			Expect(db.AdminAllowedAt("/paper", "reader")).To(Equal(false))
		})

		g.It("should create users", func() {
			Expect(db.SaveUser("isaiah", "12345678")).To(Succeed())
			Expect(db.SaveUser("samuel", "87654321")).To(Succeed())
			Expect(db.SaveUser("isaiah", "qwertyuu")).ToNot(Succeed())
			Expect(db.SaveUser("israel", "")).To(Succeed())
			Expect(db.SaveUser("", "asdfghjh")).ToNot(Succeed())
		})

		g.It("should validate user logins", func() {
			Expect(db.ValidUser("samuel", "87654321")).To(Equal(true))
			Expect(db.ValidUser("isaiah", "12345678")).To(Equal(true))
			Expect(db.ValidUser("isaiah", "qwertyuu")).To(Equal(false))
			Expect(db.ValidUser("israel", "")).To(Equal(true))
			Expect(db.ValidUser("", "asdfghjh")).To(Equal(false))

			Expect(db.ValidUser("", "")).To(Equal(false))
			Expect(db.ValidUser("q", "a")).To(Equal(false))
			Expect(db.ValidUser("weq", "")).To(Equal(false))
			Expect(db.ValidUser("", "ssdds")).To(Equal(false))
		})
	})
}
Example #14
0
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"
                  }
                }
              }
            }`))
		})
	})
}