// Initialize REST handlers. Call this once on launch. func InitREST(bucket *couchbase.Bucket, dbName string, serverURL string) *context { if dbName == "" { dbName = bucket.Name } dbcontext, err := db.NewDatabaseContext(dbName, bucket) if err != nil { return nil } newdb, err := db.GetDatabase(dbcontext, nil) if err != nil { return nil } newdb.ReadDesignDocument() if dbcontext.ChannelMapper == nil { log.Printf("Channel mapper undefined; using default") // Always have a channel mapper object even if it does nothing: dbcontext.ChannelMapper, _ = channels.NewDefaultChannelMapper() } if dbcontext.Validator == nil { log.Printf("Validator undefined; no validation") } c := &context{ dbcontext: dbcontext, auth: auth.NewAuthenticator(bucket), serverURL: serverURL, } http.Handle("/", createHandler(c)) return c }
func TestInvalidChannel(t *testing.T) { db := setupTestDB(t) defer tearDownTestDB(t, db) db.ChannelMapper = channels.NewDefaultChannelMapper() body := Body{"channels": []string{"bad name"}} _, err := db.Put("doc", body) assertHTTPError(t, err, 500) }
// Unit test for bug #314 func TestChangesAfterChannelAdded(t *testing.T) { base.LogKeys["Cache"] = true base.LogKeys["Changes"] = true base.LogKeys["Changes+"] = true db := setupTestDB(t) defer tearDownTestDB(t, db) db.ChannelMapper = channels.NewDefaultChannelMapper() // Create a user with access to channel ABC authenticator := db.Authenticator() user, _ := authenticator.NewUser("naomi", "letmein", channels.SetOf("ABC")) authenticator.Save(user) // Create a doc on two channels (sequence 1): revid, _ := db.Put("doc1", Body{"channels": []string{"ABC", "PBS"}}) // Modify user to have access to both channels (sequence 2): userInfo, err := db.GetPrincipal("naomi", true) assert.True(t, userInfo != nil) userInfo.ExplicitChannels = base.SetOf("ABC", "PBS") _, err = db.UpdatePrincipal(*userInfo, true, true) assertNoError(t, err, "UpdatePrincipal failed") // Check the _changes feed: db.changeCache.waitForSequence(1) db.user, _ = authenticator.GetUser("naomi") changes, err := db.GetChanges(base.SetOf("*"), ChangesOptions{Since: SequenceID{Seq: 1}}) assertNoError(t, err, "Couldn't GetChanges") assert.Equals(t, len(changes), 2) assert.DeepEquals(t, changes[0], &ChangeEntry{ Seq: SequenceID{Seq: 1, TriggeredBy: 2}, ID: "doc1", Changes: []ChangeRev{{"rev": revid}}}) assert.DeepEquals(t, changes[1], &ChangeEntry{ Seq: SequenceID{Seq: 2}, ID: "_user/naomi", Changes: []ChangeRev{}}) // Add a new doc (sequence 3): revid, _ = db.Put("doc2", Body{"channels": []string{"PBS"}}) // Check the _changes feed -- this is to make sure the changeCache properly received // sequence 2 (the user doc) and isn't stuck waiting for it. db.changeCache.waitForSequence(3) changes, err = db.GetChanges(base.SetOf("*"), ChangesOptions{Since: SequenceID{Seq: 2}}) assertNoError(t, err, "Couldn't GetChanges (2nd)") assert.Equals(t, len(changes), 1) assert.DeepEquals(t, changes[0], &ChangeEntry{ Seq: SequenceID{Seq: 3}, ID: "doc2", Changes: []ChangeRev{{"rev": revid}}}) }
// Adds a database to the serverContext given its Bucket. func (sc *serverContext) addDatabase(bucket base.Bucket, dbName string, syncFun *string, nag bool) (*context, error) { if dbName == "" { dbName = bucket.GetName() } if match, _ := regexp.MatchString(`^[a-z][-a-z0-9_$()+/]*$`, dbName); !match { return nil, fmt.Errorf("Illegal database name: %s", dbName) } if sc.databases[dbName] != nil { return nil, fmt.Errorf("Duplicate database name %q", dbName) } dbcontext, err := db.NewDatabaseContext(dbName, bucket) if err != nil { return nil, err } if syncFun != nil { if err := dbcontext.ApplySyncFun(*syncFun); err != nil { return nil, err } } if dbcontext.ChannelMapper == nil { if nag { base.Warn("Sync function undefined; using default") } // Always have a channel mapper object even if it does nothing: dbcontext.ChannelMapper, _ = channels.NewDefaultChannelMapper() } c := &context{ dbcontext: dbcontext, auth: dbcontext.Authenticator(), } sc.databases[dbName] = c return c, nil }
func TestConflicts(t *testing.T) { AlwaysCompactChangeLog = true // Makes examining the change log deterministic defer func() { AlwaysCompactChangeLog = false }() db := setupTestDB(t) defer tearDownTestDB(t, db) db.ChannelMapper = channels.NewDefaultChannelMapper() // base.LogKeys["CRUD"] = true // base.LogKeys["Changes"] = true // Create rev 1 of "doc": body := Body{"n": 1, "channels": []string{"all", "1"}} assertNoError(t, db.PutExistingRev("doc", body, []string{"1-a"}), "add 1-a") log, _ := db.GetChangeLog("all", 0) assert.Equals(t, len(log.Entries), 1) assert.Equals(t, int(log.Since), 0) // Create two conflicting changes: body["n"] = 2 body["channels"] = []string{"all", "2b"} assertNoError(t, db.PutExistingRev("doc", body, []string{"2-b", "1-a"}), "add 2-b") body["n"] = 3 body["channels"] = []string{"all", "2a"} assertNoError(t, db.PutExistingRev("doc", body, []string{"2-a", "1-a"}), "add 2-a") // Verify the change with the higher revid won: gotBody, err := db.Get("doc") assert.DeepEquals(t, gotBody, Body{"_id": "doc", "_rev": "2-b", "n": int64(2), "channels": []interface{}{"all", "2b"}}) // Verify we can still get the other two revisions: gotBody, err = db.GetRev("doc", "1-a", false, nil) assert.DeepEquals(t, gotBody, Body{"_id": "doc", "_rev": "1-a", "n": int64(1), "channels": []interface{}{"all", "1"}}) gotBody, err = db.GetRev("doc", "2-a", false, nil) assert.DeepEquals(t, gotBody, Body{"_id": "doc", "_rev": "2-a", "n": int64(3), "channels": []interface{}{"all", "2a"}}) // Verify the change-log of the "all" channel: log, _ = db.GetChangeLog("all", 0) assert.Equals(t, len(log.Entries), 3) assert.Equals(t, int(log.Since), 0) assert.DeepEquals(t, log.Entries[0], &channels.LogEntry{Sequence: 1}) assert.DeepEquals(t, log.Entries[1], &channels.LogEntry{Sequence: 2, DocID: "doc", RevID: "2-b"}) assert.DeepEquals(t, log.Entries[2], &channels.LogEntry{Sequence: 3, DocID: "doc", RevID: "2-a", Flags: channels.Hidden}) // Verify the _changes feed: changes, err := db.GetChanges(channels.SetOf("all"), ChangesOptions{Conflicts: true}) assertNoError(t, err, "Couldn't GetChanges") assert.Equals(t, len(changes), 2) // (CouchDB would merge these into one entry, but the gateway doesn't.) assert.DeepEquals(t, changes[0], &ChangeEntry{ Seq: "all:2", ID: "doc", Changes: []ChangeRev{{"rev": "2-b"}}}) assert.DeepEquals(t, changes[1], &ChangeEntry{ Seq: "all:3", ID: "doc", Changes: []ChangeRev{{"rev": "2-a"}}}) changes, err = db.GetChanges(channels.SetOf("all"), ChangesOptions{Conflicts: false}) assertNoError(t, err, "Couldn't GetChanges") assert.Equals(t, len(changes), 1) assert.DeepEquals(t, changes[0], &ChangeEntry{ Seq: "all:2", ID: "doc", Changes: []ChangeRev{{"rev": "2-b"}}}) // Delete 2-b; verify this makes 2-a current: _, err = db.DeleteDoc("doc", "2-b") assertNoError(t, err, "delete 2-b") gotBody, err = db.Get("doc") assert.DeepEquals(t, gotBody, Body{"_id": "doc", "_rev": "2-a", "n": int64(3), "channels": []interface{}{"all", "2a"}}) // Verify channel assignments are correct for channels defined by 2-a: doc, _ := db.getDoc("doc") chan2a, found := doc.Channels["2a"] assert.True(t, found) assert.True(t, chan2a == nil) // currently in 2a assert.True(t, doc.Channels["2b"] != nil) // has been removed from 2b }
func TestAllDocs(t *testing.T) { AlwaysCompactChangeLog = true // Makes examining the change log deterministic defer func() { AlwaysCompactChangeLog = false }() db := setupTestDB(t) defer tearDownTestDB(t, db) // Lower the log capacity to 50 to ensure the test will overflow, causing logs to be truncated, // so the changes feed will have to backfill from its view. oldMaxLogLength := MaxChangeLogLength MaxChangeLogLength = 50 defer func() { MaxChangeLogLength = oldMaxLogLength }() base.LogKeys["Changes"] = true defer func() { base.LogKeys["Changes"] = false }() db.ChannelMapper = channels.NewDefaultChannelMapper() ids := make([]IDAndRev, 100) for i := 0; i < 100; i++ { channels := []string{"all"} if i%10 == 0 { channels = append(channels, "KFJC") } body := Body{"serialnumber": i, "channels": channels} ids[i].DocID = fmt.Sprintf("alldoc-%02d", i) revid, err := db.Put(ids[i].DocID, body) ids[i].RevID = revid assertNoError(t, err, "Couldn't create document") } alldocs, err := db.AllDocIDs() assertNoError(t, err, "AllDocIDs failed") assert.Equals(t, len(alldocs), 100) for i, entry := range alldocs { assert.DeepEquals(t, entry, ids[i]) } // Now delete one document and try again: _, err = db.DeleteDoc(ids[23].DocID, ids[23].RevID) assertNoError(t, err, "Couldn't delete doc 23") alldocs, err = db.AllDocIDs() assertNoError(t, err, "AllDocIDs failed") assert.Equals(t, len(alldocs), 99) for i, entry := range alldocs { j := i if i >= 23 { j++ } assert.DeepEquals(t, entry, ids[j]) } // Inspect the channel log to confirm that it's only got the last 50 sequences. // There are 101 sequences overall, so the 1st one it has should be #52. log, err := db.GetChangeLog("all", 0) assertNoError(t, err, "GetChangeLog") assert.Equals(t, log.Since, uint64(51)) assert.Equals(t, len(log.Entries), 50) assert.Equals(t, int(log.Entries[0].Sequence), 52) // Now check the changes feed: var options ChangesOptions changes, err := db.GetChanges(channels.SetOf("all"), options) assertNoError(t, err, "Couldn't GetChanges") assert.Equals(t, len(changes), 100) for i, change := range changes { seq := i + 1 if i >= 23 { seq++ } assert.Equals(t, change.Seq, fmt.Sprintf("all:%d", seq)) assert.Equals(t, change.Deleted, i == 99) var removed base.Set if i == 99 { removed = channels.SetOf("all") } assert.DeepEquals(t, change.Removed, removed) } options.IncludeDocs = true changes, err = db.GetChanges(channels.SetOf("KFJC"), options) assertNoError(t, err, "Couldn't GetChanges") assert.Equals(t, len(changes), 10) for i, change := range changes { assert.Equals(t, change.Seq, fmt.Sprintf("KFJC:%d", 10*i+1)) assert.Equals(t, change.ID, ids[10*i].DocID) assert.Equals(t, change.Deleted, false) assert.DeepEquals(t, change.Removed, base.Set(nil)) assert.Equals(t, change.Doc["serialnumber"], int64(10*i)) } // Trying to add the existing log should fail with no error added, err := db.AddChangeLog("all", log) assertNoError(t, err, "add channel log") assert.False(t, added) // Delete the channel log to test if it can be rebuilt: assertNoError(t, db.Bucket.Delete(channelLogDocID("all")), "delete channel log") // Get the changes feed; result should still be correct: changes, err = db.GetChanges(channels.SetOf("all"), options) assertNoError(t, err, "Couldn't GetChanges") assert.Equals(t, len(changes), 100) // Verify it was rebuilt log, err = db.GetChangeLog("all", 0) assertNoError(t, err, "GetChangeLog") assert.Equals(t, len(log.Entries), 50) assert.Equals(t, int(log.Entries[0].Sequence), 52) }
func TestConflicts(t *testing.T) { db := setupTestDB(t) defer tearDownTestDB(t, db) db.ChannelMapper = channels.NewDefaultChannelMapper() //base.LogKeys["Cache"] = true // base.LogKeys["CRUD"] = true // base.LogKeys["Changes"] = true // Create rev 1 of "doc": body := Body{"n": 1, "channels": []string{"all", "1"}} assertNoError(t, db.PutExistingRev("doc", body, []string{"1-a"}), "add 1-a") time.Sleep(50 * time.Millisecond) // Wait for tap feed to catch up log := db.GetChangeLog("all", 0) assert.Equals(t, len(log), 1) // Create two conflicting changes: body["n"] = 2 body["channels"] = []string{"all", "2b"} assertNoError(t, db.PutExistingRev("doc", body, []string{"2-b", "1-a"}), "add 2-b") body["n"] = 3 body["channels"] = []string{"all", "2a"} assertNoError(t, db.PutExistingRev("doc", body, []string{"2-a", "1-a"}), "add 2-a") time.Sleep(50 * time.Millisecond) // Wait for tap feed to catch up // Verify the change with the higher revid won: gotBody, err := db.Get("doc") assert.DeepEquals(t, gotBody, Body{"_id": "doc", "_rev": "2-b", "n": int64(2), "channels": []interface{}{"all", "2b"}}) // Verify we can still get the other two revisions: gotBody, err = db.GetRev("doc", "1-a", false, nil) assert.DeepEquals(t, gotBody, Body{"_id": "doc", "_rev": "1-a", "n": 1, "channels": []string{"all", "1"}}) gotBody, err = db.GetRev("doc", "2-a", false, nil) assert.DeepEquals(t, gotBody, Body{"_id": "doc", "_rev": "2-a", "n": 3, "channels": []string{"all", "2a"}}) // Verify the change-log of the "all" channel: db.changeCache.waitForSequence(3) log = db.GetChangeLog("all", 0) assert.Equals(t, len(log), 1) assert.Equals(t, log[0].Sequence, uint64(3)) assert.Equals(t, log[0].DocID, "doc") assert.Equals(t, log[0].RevID, "2-b") assert.Equals(t, log[0].Flags, uint8(channels.Hidden|channels.Branched|channels.Conflict)) // Verify the _changes feed: options := ChangesOptions{ Conflicts: true, } changes, err := db.GetChanges(channels.SetOf("all"), options) assertNoError(t, err, "Couldn't GetChanges") assert.Equals(t, len(changes), 1) assert.DeepEquals(t, changes[0], &ChangeEntry{ Seq: SequenceID{Seq: 3}, ID: "doc", Changes: []ChangeRev{{"rev": "2-b"}, {"rev": "2-a"}}, branched: true}) // Delete 2-b; verify this makes 2-a current: rev3, err := db.DeleteDoc("doc", "2-b") assertNoError(t, err, "delete 2-b") gotBody, err = db.Get("doc") assert.DeepEquals(t, gotBody, Body{"_id": "doc", "_rev": "2-a", "n": int64(3), "channels": []interface{}{"all", "2a"}}) // Verify channel assignments are correct for channels defined by 2-a: doc, _ := db.GetDoc("doc") chan2a, found := doc.Channels["2a"] assert.True(t, found) assert.True(t, chan2a == nil) // currently in 2a assert.True(t, doc.Channels["2b"] != nil) // has been removed from 2b // Verify the _changes feed: db.changeCache.waitForSequence(4) changes, err = db.GetChanges(channels.SetOf("all"), options) assertNoError(t, err, "Couldn't GetChanges") assert.Equals(t, len(changes), 1) assert.DeepEquals(t, changes[0], &ChangeEntry{ Seq: SequenceID{Seq: 4}, ID: "doc", Changes: []ChangeRev{{"rev": "2-a"}, {"rev": rev3}}, branched: true}) }
func TestAllDocs(t *testing.T) { // base.LogKeys["Cache"] = true // base.LogKeys["Changes"] = true db := setupTestDB(t) defer tearDownTestDB(t, db) // Lower the log expiration time to zero so no more than 50 items will be kept. oldChannelCacheAge := ChannelCacheAge ChannelCacheAge = 0 defer func() { ChannelCacheAge = oldChannelCacheAge }() /* base.LogKeys["Changes"] = true base.LogKeys["Changes+"] = true defer func() { base.LogKeys["Changes"] = false base.LogKeys["Changes+"] = false }() */ db.ChannelMapper = channels.NewDefaultChannelMapper() ids := make([]AllDocsEntry, 100) for i := 0; i < 100; i++ { channels := []string{"all"} if i%10 == 0 { channels = append(channels, "KFJC") } body := Body{"serialnumber": i, "channels": channels} ids[i].DocID = fmt.Sprintf("alldoc-%02d", i) revid, err := db.Put(ids[i].DocID, body) ids[i].RevID = revid ids[i].Sequence = uint64(i + 1) ids[i].Channels = channels assertNoError(t, err, "Couldn't create document") } alldocs, err := allDocIDs(db) assertNoError(t, err, "AllDocIDs failed") assert.Equals(t, len(alldocs), 100) for i, entry := range alldocs { assert.True(t, entry.Equal(ids[i])) } // Now delete one document and try again: _, err = db.DeleteDoc(ids[23].DocID, ids[23].RevID) assertNoError(t, err, "Couldn't delete doc 23") alldocs, err = allDocIDs(db) assertNoError(t, err, "AllDocIDs failed") assert.Equals(t, len(alldocs), 99) for i, entry := range alldocs { j := i if i >= 23 { j++ } assert.True(t, entry.Equal(ids[j])) } // Inspect the channel log to confirm that it's only got the last 50 sequences. // There are 101 sequences overall, so the 1st one it has should be #52. db.changeCache.waitForSequence(101) log := db.GetChangeLog("all", 0) assert.Equals(t, len(log), 50) assert.Equals(t, int(log[0].Sequence), 52) // Now check the changes feed: var options ChangesOptions options.Terminator = make(chan bool) defer close(options.Terminator) changes, err := db.GetChanges(channels.SetOf("all"), options) assertNoError(t, err, "Couldn't GetChanges") assert.Equals(t, len(changes), 100) for i, change := range changes { seq := i + 1 if i >= 23 { seq++ } assert.Equals(t, change.Seq, SequenceID{Seq: uint64(seq)}) assert.Equals(t, change.Deleted, i == 99) var removed base.Set if i == 99 { removed = channels.SetOf("all") } assert.DeepEquals(t, change.Removed, removed) } options.IncludeDocs = true changes, err = db.GetChanges(channels.SetOf("KFJC"), options) assertNoError(t, err, "Couldn't GetChanges") assert.Equals(t, len(changes), 10) for i, change := range changes { assert.Equals(t, change.Seq, SequenceID{Seq: uint64(10*i + 1)}) assert.Equals(t, change.ID, ids[10*i].DocID) assert.Equals(t, change.Deleted, false) assert.DeepEquals(t, change.Removed, base.Set(nil)) assert.Equals(t, change.Doc["serialnumber"], int64(10*i)) } }
func TestAllDocs(t *testing.T) { db := setupTestDB(t) defer tearDownTestDB(t, db) db.ChannelMapper, _ = channels.NewDefaultChannelMapper() ids := make([]IDAndRev, 100) for i := 0; i < 100; i++ { channels := []string{"all"} if i%10 == 0 { channels = append(channels, "KFJC") } body := Body{"serialnumber": i, "channels": channels} ids[i].DocID = fmt.Sprintf("alldoc-%02d", i) revid, err := db.Put(ids[i].DocID, body) ids[i].RevID = revid assertNoError(t, err, "Couldn't create document") } alldocs, err := db.AllDocIDs() assertNoError(t, err, "AllDocIDs failed") assert.Equals(t, len(alldocs), 100) for i, entry := range alldocs { assert.DeepEquals(t, entry, ids[i]) } // Now delete one document and try again: _, err = db.DeleteDoc(ids[23].DocID, ids[23].RevID) assertNoError(t, err, "Couldn't delete doc 23") alldocs, err = db.AllDocIDs() assertNoError(t, err, "AllDocIDs failed") assert.Equals(t, len(alldocs), 99) for i, entry := range alldocs { j := i if i >= 23 { j++ } assert.DeepEquals(t, entry, ids[j]) } // Now check the changes feed: var options ChangesOptions changes, err := db.GetChanges(channels.SetOf("all"), options) assertNoError(t, err, "Couldn't GetChanges") assert.Equals(t, len(changes), 100) for i, change := range changes { seq := i + 1 if i >= 23 { seq++ } assert.Equals(t, int(change.Seq), seq) assert.Equals(t, change.Deleted, false) var removed channels.Set if i == 99 { removed = channels.SetOf("all") } assert.DeepEquals(t, change.Removed, removed) } changes, err = db.GetChanges(channels.SetOf("KFJC"), options) assertNoError(t, err, "Couldn't GetChanges") assert.Equals(t, len(changes), 10) for i, change := range changes { assert.Equals(t, int(change.Seq), 10*i+1) assert.Equals(t, change.ID, ids[10*i].DocID) assert.Equals(t, change.Deleted, false) assert.DeepEquals(t, change.Removed, channels.Set(nil)) } }