Skip to content

Commit f682b48

Browse files
bbrksgregns1
andauthored
[3.2.1 Backport] CBG-4151: Memory-based rev cache size (#7134)
* CBG-4023: Removal unmarshalled body on the rev cache (#7030) * CBG-4135: new stat for rev cache capacity (#7049) * CBG-4135: new stat for rev cache capacity * updated based on review * fix linter * lint again * CBG-4032: memory based rev cache implementation (#7040) * CBG-4032: memory based rev cache implementation * make test pass with default collection + missing return param * more issues with default collection test * touch ups on comment + remove unused function * updated for review * further tidy up * lint fix after refector test * fixes from rebase * updates based off review + some more refactoring * CBG-4134: link rev cache memory limit config option to rev cache (#7084) * CBG-4134: link rev cache memory limit config option to rev cache * failing tests * address commnets * fix yaml lint * fix failing test + mistake in docs Signed-off-by: Gregory Newman-Smith <gregory.newmansmith@couchbase.com> --------- Signed-off-by: Gregory Newman-Smith <gregory.newmansmith@couchbase.com> * CBG-4234: clean up rev cache work (#7113) * CBG-4234: clean up rev cache work * new test * CBG-4277: Remove unused totalBytesForHistory from getHistory (#7137) --------- Signed-off-by: Gregory Newman-Smith <gregory.newmansmith@couchbase.com> Co-authored-by: Gregory Newman-Smith <109068393+gregns1@users.noreply.github.com>
1 parent 73d6f7e commit f682b48

23 files changed

+1099
-304
lines changed

base/stats.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,12 +460,16 @@ type CacheStats struct {
460460
NumSkippedSeqs *SgwIntStat `json:"num_skipped_seqs"`
461461
// The total number of pending sequences. These are out-of-sequence entries waiting to be cached.
462462
PendingSeqLen *SgwIntStat `json:"pending_seq_len"`
463+
// Total number of items in the rev cache
464+
RevisionCacheNumItems *SgwIntStat `json:"revision_cache_num_items"`
463465
// The total number of revision cache bypass operations performed.
464466
RevisionCacheBypass *SgwIntStat `json:"rev_cache_bypass"`
465467
// The total number of revision cache hits.
466468
RevisionCacheHits *SgwIntStat `json:"rev_cache_hits"`
467469
// The total number of revision cache misses.
468470
RevisionCacheMisses *SgwIntStat `json:"rev_cache_misses"`
471+
// Total memory used by the rev cache
472+
RevisionCacheTotalMemory *SgwIntStat `json:"revision_cache_total_memory"`
469473
// The current length of the pending skipped sequence slice.
470474
SkippedSeqLen *SgwIntStat `json:"skipped_seq_len"`
471475
// The current capacity of the skipped sequence slice
@@ -1355,6 +1359,10 @@ func (d *DbStats) initCacheStats() error {
13551359
if err != nil {
13561360
return err
13571361
}
1362+
resUtil.RevisionCacheNumItems, err = NewIntStat(SubsystemCacheKey, "revision_cache_num_items", StatUnitNoUnits, RevCacheNumItemsDesc, StatAddedVersion3dot2dot1, StatDeprecatedVersionNotDeprecated, StatStabilityCommitted, labelKeys, labelVals, prometheus.GaugeValue, 0)
1363+
if err != nil {
1364+
return err
1365+
}
13581366
resUtil.RevisionCacheBypass, err = NewIntStat(SubsystemCacheKey, "rev_cache_bypass", StatUnitNoUnits, RevCacheBypassDesc, StatAddedVersion3dot0dot0, StatDeprecatedVersionNotDeprecated, StatStabilityCommitted, labelKeys, labelVals, prometheus.GaugeValue, 0)
13591367
if err != nil {
13601368
return err
@@ -1367,6 +1375,10 @@ func (d *DbStats) initCacheStats() error {
13671375
if err != nil {
13681376
return err
13691377
}
1378+
resUtil.RevisionCacheTotalMemory, err = NewIntStat(SubsystemCacheKey, "revision_cache_total_memory", StatUnitNoUnits, RevCacheMemoryDesc, StatAddedVersion3dot2dot1, StatDeprecatedVersionNotDeprecated, StatStabilityCommitted, labelKeys, labelVals, prometheus.GaugeValue, 0)
1379+
if err != nil {
1380+
return err
1381+
}
13701382
resUtil.SkippedSeqLen, err = NewIntStat(SubsystemCacheKey, "skipped_seq_len", StatUnitNoUnits, SkippedSeqLengthDesc, StatAddedVersion3dot0dot0, StatDeprecatedVersionNotDeprecated, StatStabilityCommitted, labelKeys, labelVals, prometheus.GaugeValue, 0)
13711383
if err != nil {
13721384
return err
@@ -1412,9 +1424,11 @@ func (d *DbStats) unregisterCacheStats() {
14121424
prometheus.Unregister(d.CacheStats.SkippedSeqCap)
14131425
prometheus.Unregister(d.CacheStats.NumCurrentSeqsSkipped)
14141426
prometheus.Unregister(d.CacheStats.PendingSeqLen)
1427+
prometheus.Unregister(d.CacheStats.RevisionCacheNumItems)
14151428
prometheus.Unregister(d.CacheStats.RevisionCacheBypass)
14161429
prometheus.Unregister(d.CacheStats.RevisionCacheHits)
14171430
prometheus.Unregister(d.CacheStats.RevisionCacheMisses)
1431+
prometheus.Unregister(d.CacheStats.RevisionCacheTotalMemory)
14181432
prometheus.Unregister(d.CacheStats.SkippedSeqLen)
14191433
prometheus.Unregister(d.CacheStats.ViewQueries)
14201434
}

base/stats_descriptions.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ const (
126126

127127
PendingSeqLengthDesc = "The total number of pending sequences. These are out-of-sequence entries waiting to be cached."
128128

129+
RevCacheNumItemsDesc = "The total number of items in the revision cache."
130+
129131
RevCacheBypassDesc = "The total number of revision cache bypass operations performed."
130132

131133
RevCacheHitsDesc = "The total number of revision cache hits. This metric can be used to calculate the ratio of revision cache hits: " +
@@ -134,6 +136,8 @@ const (
134136
RevCacheMissesDesc = "The total number of revision cache misses. This metric can be used to calculate the ratio of revision cache misses: " +
135137
"Rev Cache Miss Ratio = rev_cache_misses / (rev_cache_hits + rev_cache_misses)"
136138

139+
RevCacheMemoryDesc = "The approximation of total memory taken up by rev cache for documents. This is measured by the raw document body, the channels allocated to a document and its revision history."
140+
137141
SkippedSeqLengthDesc = "The current length of the pending skipped sequence slice."
138142

139143
SkippedSeqCapDesc = "The current capacity of the skipped sequence slice."

db/changes.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ func (db *DatabaseCollectionWithUser) addDocToChangeEntry(ctx context.Context, e
137137
}
138138

139139
func (db *DatabaseCollectionWithUser) AddDocToChangeEntryUsingRevCache(ctx context.Context, entry *ChangeEntry, revID string) (err error) {
140-
rev, err := db.getRev(ctx, entry.ID, revID, 0, nil, RevCacheIncludeBody)
140+
rev, err := db.getRev(ctx, entry.ID, revID, 0, nil)
141141
if err != nil {
142142
return err
143143
}
@@ -325,7 +325,7 @@ func (db *DatabaseCollectionWithUser) buildRevokedFeed(ctx context.Context, ch c
325325

326326
// UserHasDocAccess checks whether the user has access to the active revision of the document
327327
func UserHasDocAccess(ctx context.Context, collection *DatabaseCollectionWithUser, docID string) (bool, error) {
328-
currentRev, err := collection.revisionCache.GetActive(ctx, docID, false)
328+
currentRev, err := collection.revisionCache.GetActive(ctx, docID)
329329
if err != nil {
330330
if base.IsDocNotFoundError(err) {
331331
return false, nil

db/crud.go

Lines changed: 24 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ func (db *DatabaseCollectionWithUser) GetRev(ctx context.Context, docID, revID s
258258
if history {
259259
maxHistory = math.MaxInt32
260260
}
261-
return db.getRev(ctx, docID, revID, maxHistory, nil, RevCacheOmitBody)
261+
return db.getRev(ctx, docID, revID, maxHistory, nil)
262262
}
263263

264264
// Returns the body of the current revision of a document
@@ -278,7 +278,7 @@ func (db *DatabaseCollectionWithUser) Get1xRevBody(ctx context.Context, docid, r
278278

279279
// Retrieves rev with request history specified as collection of revids (historyFrom)
280280
func (db *DatabaseCollectionWithUser) Get1xRevBodyWithHistory(ctx context.Context, docid, revid string, maxHistory int, historyFrom []string, attachmentsSince []string, showExp bool) (Body, error) {
281-
rev, err := db.getRev(ctx, docid, revid, maxHistory, historyFrom, RevCacheIncludeBody)
281+
rev, err := db.getRev(ctx, docid, revid, maxHistory, historyFrom)
282282
if err != nil {
283283
return nil, err
284284
}
@@ -305,14 +305,14 @@ func (db *DatabaseCollectionWithUser) Get1xRevBodyWithHistory(ctx context.Contex
305305
// - attachmentsSince is nil to return no attachment bodies, otherwise a (possibly empty) list of
306306
// revisions for which the client already has attachments and doesn't need bodies. Any attachment
307307
// that hasn't changed since one of those revisions will be returned as a stub.
308-
func (db *DatabaseCollectionWithUser) getRev(ctx context.Context, docid, revid string, maxHistory int, historyFrom []string, includeBody bool) (revision DocumentRevision, err error) {
308+
func (db *DatabaseCollectionWithUser) getRev(ctx context.Context, docid, revid string, maxHistory int, historyFrom []string) (revision DocumentRevision, err error) {
309309
if revid != "" {
310310
// Get a specific revision body and history from the revision cache
311311
// (which will load them if necessary, by calling revCacheLoader, above)
312-
revision, err = db.revisionCache.Get(ctx, docid, revid, includeBody, RevCacheOmitDelta)
312+
revision, err = db.revisionCache.Get(ctx, docid, revid, RevCacheOmitDelta)
313313
} else {
314314
// No rev ID given, so load active revision
315-
revision, err = db.revisionCache.GetActive(ctx, docid, includeBody)
315+
revision, err = db.revisionCache.GetActive(ctx, docid)
316316
}
317317

318318
if err != nil {
@@ -373,7 +373,7 @@ func (db *DatabaseCollectionWithUser) GetDelta(ctx context.Context, docID, fromR
373373
return nil, nil, nil
374374
}
375375

376-
fromRevision, err := db.revisionCache.Get(ctx, docID, fromRevID, RevCacheOmitBody, RevCacheIncludeDelta)
376+
fromRevision, err := db.revisionCache.Get(ctx, docID, fromRevID, RevCacheIncludeDelta)
377377

378378
// If the fromRevision is a removal cache entry (no body), but the user has access to that removal, then just
379379
// return 404 missing to indicate that the body of the revision is no longer available.
@@ -413,7 +413,7 @@ func (db *DatabaseCollectionWithUser) GetDelta(ctx context.Context, docID, fromR
413413

414414
// db.DbStats.StatsDeltaSync().Add(base.StatKeyDeltaCacheMisses, 1)
415415
db.dbStats().DeltaSync().DeltaCacheMiss.Add(1)
416-
toRevision, err := db.revisionCache.Get(ctx, docID, toRevID, RevCacheOmitBody, RevCacheIncludeDelta)
416+
toRevision, err := db.revisionCache.Get(ctx, docID, toRevID, RevCacheIncludeDelta)
417417
if err != nil {
418418
return nil, nil, err
419419
}
@@ -549,38 +549,36 @@ func (col *DatabaseCollectionWithUser) authorizeDoc(doc *Document, revid string)
549549

550550
// Gets a revision of a document. If it's obsolete it will be loaded from the database if possible.
551551
// inline "_attachments" properties in the body will be extracted and returned separately if present (pre-2.5 metadata, or backup revisions)
552-
func (c *DatabaseCollection) getRevision(ctx context.Context, doc *Document, revid string) (bodyBytes []byte, body Body, attachments AttachmentsMeta, err error) {
552+
func (c *DatabaseCollection) getRevision(ctx context.Context, doc *Document, revid string) (bodyBytes []byte, attachments AttachmentsMeta, err error) {
553553
bodyBytes = doc.getRevisionBodyJSON(ctx, revid, c.RevisionBodyLoader)
554554

555555
// No inline body, so look for separate doc:
556556
if bodyBytes == nil {
557557
if !doc.History.contains(revid) {
558-
return nil, nil, nil, ErrMissing
558+
return nil, nil, ErrMissing
559559
}
560560

561561
bodyBytes, err = c.getOldRevisionJSON(ctx, doc.ID, revid)
562562
if err != nil || bodyBytes == nil {
563-
return nil, nil, nil, err
563+
return nil, nil, err
564564
}
565565
}
566566

567567
// optimistically grab the doc body and to store as a pre-unmarshalled version, as well as anticipating no inline attachments.
568568
if doc.CurrentRev == revid {
569-
body = doc._body
570569
attachments = doc.Attachments
571570
}
572571

573572
// handle backup revision inline attachments, or pre-2.5 meta
574-
if inlineAtts, cleanBodyBytes, cleanBody, err := extractInlineAttachments(bodyBytes); err != nil {
575-
return nil, nil, nil, err
573+
if inlineAtts, cleanBodyBytes, _, err := extractInlineAttachments(bodyBytes); err != nil {
574+
return nil, nil, err
576575
} else if len(inlineAtts) > 0 {
577576
// we found some inline attachments, so merge them with attachments, and update the bodies
578577
attachments = mergeAttachments(inlineAtts, attachments)
579578
bodyBytes = cleanBodyBytes
580-
body = cleanBody
581579
}
582580

583-
return bodyBytes, body, attachments, nil
581+
return bodyBytes, attachments, nil
584582
}
585583

586584
// mergeAttachments copies the docAttachments map, and merges pre25Attachments into it.
@@ -705,7 +703,7 @@ func (db *DatabaseCollectionWithUser) get1xRevFromDoc(ctx context.Context, doc *
705703
return nil, false, ErrDeleted
706704
}
707705
}
708-
if bodyBytes, _, attachments, err = db.getRevision(ctx, doc, revid); err != nil {
706+
if bodyBytes, attachments, err = db.getRevision(ctx, doc, revid); err != nil {
709707
return nil, false, err
710708
}
711709
}
@@ -742,7 +740,7 @@ func (db *DatabaseCollectionWithUser) get1xRevFromDoc(ctx context.Context, doc *
742740
// Returns the body and rev ID of the asked-for revision or the most recent available ancestor.
743741
func (db *DatabaseCollectionWithUser) getAvailableRev(ctx context.Context, doc *Document, revid string) ([]byte, string, AttachmentsMeta, error) {
744742
for ; revid != ""; revid = doc.History[revid].Parent {
745-
if bodyBytes, _, attachments, _ := db.getRevision(ctx, doc, revid); bodyBytes != nil {
743+
if bodyBytes, attachments, _ := db.getRevision(ctx, doc, revid); bodyBytes != nil {
746744
return bodyBytes, revid, attachments, nil
747745
}
748746
}
@@ -2155,15 +2153,14 @@ func (db *DatabaseCollectionWithUser) updateAndReturnDoc(ctx context.Context, do
21552153

21562154
revChannels := doc.History[newRevID].Channels
21572155
documentRevision := DocumentRevision{
2158-
DocID: docid,
2159-
RevID: newRevID,
2160-
BodyBytes: storedDocBytes,
2161-
History: encodeRevisions(ctx, docid, history),
2162-
Channels: revChannels,
2163-
Attachments: doc.Attachments,
2164-
Expiry: doc.Expiry,
2165-
Deleted: doc.History[newRevID].Deleted,
2166-
_shallowCopyBody: storedDoc.Body(ctx),
2156+
DocID: docid,
2157+
RevID: newRevID,
2158+
BodyBytes: storedDocBytes,
2159+
History: encodeRevisions(ctx, docid, history),
2160+
Channels: revChannels,
2161+
Attachments: doc.Attachments,
2162+
Expiry: doc.Expiry,
2163+
Deleted: doc.History[newRevID].Deleted,
21672164
}
21682165

21692166
if createNewRevIDSkipped {
@@ -2261,7 +2258,7 @@ func getAttachmentIDsForLeafRevisions(ctx context.Context, db *DatabaseCollectio
22612258
})
22622259

22632260
for _, leafRevision := range documentLeafRevisions {
2264-
_, _, attachmentMeta, err := db.getRevision(ctx, doc, leafRevision)
2261+
_, attachmentMeta, err := db.getRevision(ctx, doc, leafRevision)
22652262
if err != nil {
22662263
return nil, err
22672264
}

db/database_test.go

Lines changed: 81 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -402,8 +402,13 @@ func TestGetRemovedAsUser(t *testing.T) {
402402
// Manually remove the temporary backup doc from the bucket
403403
// Manually flush the rev cache
404404
// After expiry from the rev cache and removal of doc backup, try again
405-
cacheHitCounter, cacheMissCounter := db.DatabaseContext.DbStats.Cache().RevisionCacheHits, db.DatabaseContext.DbStats.Cache().RevisionCacheMisses
406-
collection.dbCtx.revisionCache = NewShardedLRURevisionCache(DefaultRevisionCacheShardCount, DefaultRevisionCacheSize, backingStoreMap, cacheHitCounter, cacheMissCounter)
405+
cacheHitCounter, cacheMissCounter, cacheNumItems, memoryCacheStat := db.DatabaseContext.DbStats.Cache().RevisionCacheHits, db.DatabaseContext.DbStats.Cache().RevisionCacheMisses, db.DatabaseContext.DbStats.Cache().RevisionCacheNumItems, db.DatabaseContext.DbStats.Cache().RevisionCacheTotalMemory
406+
cacheOptions := &RevisionCacheOptions{
407+
MaxBytes: 0,
408+
MaxItemCount: DefaultRevisionCacheSize,
409+
ShardCount: DefaultRevisionCacheShardCount,
410+
}
411+
collection.dbCtx.revisionCache = NewShardedLRURevisionCache(cacheOptions, backingStoreMap, cacheHitCounter, cacheMissCounter, cacheNumItems, memoryCacheStat)
407412
err = collection.PurgeOldRevisionJSON(ctx, "doc1", rev2id)
408413
assert.NoError(t, err, "Purge old revision JSON")
409414

@@ -514,9 +519,11 @@ func TestGetRemovalMultiChannel(t *testing.T) {
514519
_, rev1Digest := ParseRevID(ctx, rev1ID)
515520
_, rev2Digest := ParseRevID(ctx, rev2ID)
516521

522+
var interfaceListChannels []interface{}
523+
interfaceListChannels = append(interfaceListChannels, "ABC")
517524
bodyExpected := Body{
518525
"k2": "v2",
519-
"channels": []string{"ABC"},
526+
"channels": interfaceListChannels,
520527
BodyRevisions: Revisions{
521528
RevisionsStart: 2,
522529
RevisionsIds: []string{rev2Digest, rev1Digest},
@@ -752,8 +759,13 @@ func TestGetRemoved(t *testing.T) {
752759
// Manually remove the temporary backup doc from the bucket
753760
// Manually flush the rev cache
754761
// After expiry from the rev cache and removal of doc backup, try again
755-
cacheHitCounter, cacheMissCounter := db.DatabaseContext.DbStats.Cache().RevisionCacheHits, db.DatabaseContext.DbStats.Cache().RevisionCacheMisses
756-
collection.dbCtx.revisionCache = NewShardedLRURevisionCache(DefaultRevisionCacheShardCount, DefaultRevisionCacheSize, backingStoreMap, cacheHitCounter, cacheMissCounter)
762+
cacheHitCounter, cacheMissCounter, cacheNumItems, memoryCacheStat := db.DatabaseContext.DbStats.Cache().RevisionCacheHits, db.DatabaseContext.DbStats.Cache().RevisionCacheMisses, db.DatabaseContext.DbStats.Cache().RevisionCacheNumItems, db.DatabaseContext.DbStats.Cache().RevisionCacheTotalMemory
763+
cacheOptions := &RevisionCacheOptions{
764+
MaxBytes: 0,
765+
MaxItemCount: DefaultRevisionCacheSize,
766+
ShardCount: DefaultRevisionCacheShardCount,
767+
}
768+
collection.dbCtx.revisionCache = NewShardedLRURevisionCache(cacheOptions, backingStoreMap, cacheHitCounter, cacheMissCounter, cacheNumItems, memoryCacheStat)
757769
err = collection.PurgeOldRevisionJSON(ctx, "doc1", rev2id)
758770
assert.NoError(t, err, "Purge old revision JSON")
759771

@@ -821,8 +833,13 @@ func TestGetRemovedAndDeleted(t *testing.T) {
821833
// Manually remove the temporary backup doc from the bucket
822834
// Manually flush the rev cache
823835
// After expiry from the rev cache and removal of doc backup, try again
824-
cacheHitCounter, cacheMissCounter := db.DatabaseContext.DbStats.Cache().RevisionCacheHits, db.DatabaseContext.DbStats.Cache().RevisionCacheMisses
825-
collection.dbCtx.revisionCache = NewShardedLRURevisionCache(DefaultRevisionCacheShardCount, DefaultRevisionCacheSize, backingStoreMap, cacheHitCounter, cacheMissCounter)
836+
cacheHitCounter, cacheMissCounter, cacheNumItems, memoryCacheStats := db.DatabaseContext.DbStats.Cache().RevisionCacheHits, db.DatabaseContext.DbStats.Cache().RevisionCacheMisses, db.DatabaseContext.DbStats.Cache().RevisionCacheNumItems, db.DatabaseContext.DbStats.Cache().RevisionCacheTotalMemory
837+
cacheOptions := &RevisionCacheOptions{
838+
MaxBytes: 0,
839+
MaxItemCount: DefaultRevisionCacheSize,
840+
ShardCount: DefaultRevisionCacheShardCount,
841+
}
842+
collection.dbCtx.revisionCache = NewShardedLRURevisionCache(cacheOptions, backingStoreMap, cacheHitCounter, cacheMissCounter, cacheNumItems, memoryCacheStats)
826843
err = collection.PurgeOldRevisionJSON(ctx, "doc1", rev2id)
827844
assert.NoError(t, err, "Purge old revision JSON")
828845

@@ -3321,3 +3338,60 @@ func TestBadDCPStart(t *testing.T) {
33213338

33223339
dbCtx.Close(ctx)
33233340
}
3341+
3342+
func TestInject1xBodyProperties(t *testing.T) {
3343+
db, ctx := setupTestDB(t)
3344+
defer db.Close(ctx)
3345+
3346+
collection, ctx := GetSingleDatabaseCollectionWithUser(ctx, t, db)
3347+
3348+
rev1ID, _, err := collection.Put(ctx, "doc", Body{"test": "doc"})
3349+
require.NoError(t, err)
3350+
var rev2Body Body
3351+
rev2Data := `{"key":"value", "_attachments": {"hello.txt": {"data":"aGVsbG8gd29ybGQ="}}}`
3352+
require.NoError(t, base.JSONUnmarshal([]byte(rev2Data), &rev2Body))
3353+
_, rev2ID, err := collection.PutExistingRevWithBody(ctx, "doc", rev2Body, []string{"2-abc", rev1ID}, true)
3354+
require.NoError(t, err)
3355+
3356+
docRev, err := collection.GetRev(ctx, "doc", rev2ID, true, nil)
3357+
require.NoError(t, err)
3358+
3359+
// mock expiry on doc
3360+
exp := time.Now()
3361+
docRev.Expiry = &exp
3362+
3363+
newDoc, err := docRev.Inject1xBodyProperties(ctx, collection, docRev.History, nil, true)
3364+
require.NoError(t, err)
3365+
var resBody Body
3366+
require.NoError(t, resBody.Unmarshal(newDoc))
3367+
3368+
// cast to map of interface given we have injected the properties runtime has no concept of the AttachmentMeta and Revisions types
3369+
revs := resBody[BodyRevisions].(map[string]interface{})
3370+
atts := resBody[BodyAttachments].(map[string]interface{})
3371+
3372+
assert.NotNil(t, atts)
3373+
assert.NotNil(t, revs)
3374+
assert.Equal(t, "doc", resBody[BodyId])
3375+
assert.Equal(t, "2-abc", resBody[BodyRev])
3376+
assert.Equal(t, exp.Format(time.RFC3339), resBody[BodyExpiry])
3377+
assert.Equal(t, "value", resBody["key"])
3378+
3379+
// mock doc deleted
3380+
docRev.Deleted = true
3381+
3382+
newDoc, err = docRev.Inject1xBodyProperties(ctx, collection, docRev.History, []string{"2-abc"}, true)
3383+
require.NoError(t, err)
3384+
require.NoError(t, resBody.Unmarshal(newDoc))
3385+
3386+
// cast to map of interface given we have injected the properties runtime has no concept of the AttachmentMeta and Revisions types
3387+
revs = resBody[BodyRevisions].(map[string]interface{})
3388+
atts = resBody[BodyAttachments].(map[string]interface{})
3389+
3390+
assert.NotNil(t, atts)
3391+
assert.NotNil(t, revs)
3392+
assert.Equal(t, "doc", resBody[BodyId])
3393+
assert.Equal(t, "2-abc", resBody[BodyRev])
3394+
assert.Equal(t, exp.Format(time.RFC3339), resBody[BodyExpiry])
3395+
assert.Equal(t, "value", resBody["key"])
3396+
assert.True(t, resBody[BodyDeleted].(bool))
3397+
}

0 commit comments

Comments
 (0)