@@ -20,6 +20,7 @@ import (
20
20
21
21
sgbucket "github.com/couchbase/sg-bucket"
22
22
"github.com/couchbase/sync_gateway/base"
23
+ "github.com/couchbase/sync_gateway/channels"
23
24
"github.com/stretchr/testify/assert"
24
25
"github.com/stretchr/testify/require"
25
26
)
@@ -1953,3 +1954,181 @@ func TestPutExistingCurrentVersionWithNoExistingDoc(t *testing.T) {
1953
1954
assert .True (t , reflect .DeepEqual (syncData .HLV .PreviousVersions , pv ))
1954
1955
assert .Equal (t , "1-3a208ea66e84121b528f05b5457d1134" , syncData .CurrentRev )
1955
1956
}
1957
+
1958
+ // TestGetCVWithDocResidentInCache:
1959
+ // - Two test cases, one with doc a user will have access to, one without
1960
+ // - Purpose is to have a doc that is resident in rev cache and use the GetCV function to retrieve these docs
1961
+ // - Assert that the doc the user has access to is corrected fetched
1962
+ // - Assert the doc the user doesn't have access to is fetched but correctly redacted
1963
+ func TestGetCVWithDocResidentInCache (t * testing.T ) {
1964
+ const docID = "doc1"
1965
+
1966
+ testCases := []struct {
1967
+ name string
1968
+ docChannels []string
1969
+ access bool
1970
+ }{
1971
+ {
1972
+ name : "getCVWithUserAccess" ,
1973
+ docChannels : []string {"A" },
1974
+ access : true ,
1975
+ },
1976
+ {
1977
+ name : "getCVWithoutUserAccess" ,
1978
+ docChannels : []string {"B" },
1979
+ access : false ,
1980
+ },
1981
+ }
1982
+ for _ , testCase := range testCases {
1983
+ t .Run (testCase .name , func (t * testing.T ) {
1984
+ db , ctx := setupTestDB (t )
1985
+ defer db .Close (ctx )
1986
+ collection , ctx := GetSingleDatabaseCollectionWithUser (ctx , t , db )
1987
+ collection .ChannelMapper = channels .NewChannelMapper (ctx , channels .DocChannelsSyncFunction , db .Options .JavascriptTimeout )
1988
+
1989
+ // Create a user with access to channel A
1990
+ authenticator := db .Authenticator (base .TestCtx (t ))
1991
+ user , err := authenticator .NewUser ("alice" , "letmein" , channels .BaseSetOf (t , "A" ))
1992
+ require .NoError (t , err )
1993
+ require .NoError (t , authenticator .Save (user ))
1994
+ collection .user , err = authenticator .GetUser ("alice" )
1995
+ require .NoError (t , err )
1996
+
1997
+ // create doc with the channels for the test case
1998
+ docBody := Body {"channels" : testCase .docChannels }
1999
+ rev , doc , err := collection .Put (ctx , docID , docBody )
2000
+ require .NoError (t , err )
2001
+
2002
+ vrs := doc .HLV .Version
2003
+ src := doc .HLV .SourceID
2004
+ sv := & Version {Value : vrs , SourceID : src }
2005
+ revision , err := collection .GetCV (ctx , docID , sv , true )
2006
+ require .NoError (t , err )
2007
+ if testCase .access {
2008
+ assert .Equal (t , rev , revision .RevID )
2009
+ assert .Equal (t , sv , revision .CV )
2010
+ assert .Equal (t , docID , revision .DocID )
2011
+ assert .Equal (t , []byte (`{"channels":["A"]}` ), revision .BodyBytes )
2012
+ } else {
2013
+ assert .Equal (t , rev , revision .RevID )
2014
+ assert .Equal (t , sv , revision .CV )
2015
+ assert .Equal (t , docID , revision .DocID )
2016
+ assert .Equal (t , []byte (RemovedRedactedDocument ), revision .BodyBytes )
2017
+ }
2018
+ })
2019
+ }
2020
+ }
2021
+
2022
+ // TestGetByCVForDocNotResidentInCache:
2023
+ // - Setup db with rev cache size of 1
2024
+ // - Put two docs forcing eviction of the first doc
2025
+ // - Use GetCV function to fetch the first doc, forcing the rev cache to load the doc from bucket
2026
+ // - Assert the doc revision fetched is correct to the first doc we created
2027
+ func TestGetByCVForDocNotResidentInCache (t * testing.T ) {
2028
+ db , ctx := SetupTestDBWithOptions (t , DatabaseContextOptions {
2029
+ RevisionCacheOptions : & RevisionCacheOptions {
2030
+ Size : 1 ,
2031
+ },
2032
+ })
2033
+ defer db .Close (ctx )
2034
+ collection , ctx := GetSingleDatabaseCollectionWithUser (ctx , t , db )
2035
+ collection .ChannelMapper = channels .NewChannelMapper (ctx , channels .DocChannelsSyncFunction , db .Options .JavascriptTimeout )
2036
+
2037
+ // Create a user with access to channel A
2038
+ authenticator := db .Authenticator (base .TestCtx (t ))
2039
+ user , err := authenticator .NewUser ("alice" , "letmein" , channels .BaseSetOf (t , "A" ))
2040
+ require .NoError (t , err )
2041
+ require .NoError (t , authenticator .Save (user ))
2042
+ collection .user , err = authenticator .GetUser ("alice" )
2043
+ require .NoError (t , err )
2044
+
2045
+ const (
2046
+ doc1ID = "doc1"
2047
+ doc2ID = "doc2"
2048
+ )
2049
+
2050
+ revBody := Body {"channels" : []string {"A" }}
2051
+ rev , doc , err := collection .Put (ctx , doc1ID , revBody )
2052
+ require .NoError (t , err )
2053
+
2054
+ // put another doc that should evict first doc from cache
2055
+ _ , _ , err = collection .Put (ctx , doc2ID , revBody )
2056
+ require .NoError (t , err )
2057
+
2058
+ // get by CV should force a load from bucket and have a cache miss
2059
+ vrs := doc .HLV .Version
2060
+ src := doc .HLV .SourceID
2061
+ sv := & Version {Value : vrs , SourceID : src }
2062
+ revision , err := collection .GetCV (ctx , doc1ID , sv , true )
2063
+ require .NoError (t , err )
2064
+
2065
+ // assert the fetched doc is the first doc we added and assert that we did in fact get cache miss
2066
+ assert .Equal (t , int64 (1 ), db .DbStats .Cache ().RevisionCacheMisses .Value ())
2067
+ assert .Equal (t , rev , revision .RevID )
2068
+ assert .Equal (t , sv , revision .CV )
2069
+ assert .Equal (t , doc1ID , revision .DocID )
2070
+ assert .Equal (t , []byte (`{"channels":["A"]}` ), revision .BodyBytes )
2071
+ }
2072
+
2073
+ // TestGetCVActivePathway:
2074
+ // - Two test cases, one with doc a user will have access to, one without
2075
+ // - Purpose is top specify nil CV to the GetCV function to force the GetActive code pathway
2076
+ // - Assert doc that is created is fetched correctly when user has access to doc
2077
+ // - Assert that correct error is returned when user has no access to the doc
2078
+ func TestGetCVActivePathway (t * testing.T ) {
2079
+ const docID = "doc1"
2080
+
2081
+ testCases := []struct {
2082
+ name string
2083
+ docChannels []string
2084
+ access bool
2085
+ }{
2086
+ {
2087
+ name : "activeFetchWithUserAccess" ,
2088
+ docChannels : []string {"A" },
2089
+ access : true ,
2090
+ },
2091
+ {
2092
+ name : "activeFetchWithoutUserAccess" ,
2093
+ docChannels : []string {"B" },
2094
+ access : false ,
2095
+ },
2096
+ }
2097
+ for _ , testCase := range testCases {
2098
+ t .Run (testCase .name , func (t * testing.T ) {
2099
+ db , ctx := setupTestDB (t )
2100
+ defer db .Close (ctx )
2101
+ collection , ctx := GetSingleDatabaseCollectionWithUser (ctx , t , db )
2102
+ collection .ChannelMapper = channels .NewChannelMapper (ctx , channels .DocChannelsSyncFunction , db .Options .JavascriptTimeout )
2103
+
2104
+ // Create a user with access to channel A
2105
+ authenticator := db .Authenticator (base .TestCtx (t ))
2106
+ user , err := authenticator .NewUser ("alice" , "letmein" , channels .BaseSetOf (t , "A" ))
2107
+ require .NoError (t , err )
2108
+ require .NoError (t , authenticator .Save (user ))
2109
+ collection .user , err = authenticator .GetUser ("alice" )
2110
+ require .NoError (t , err )
2111
+
2112
+ // test get active path by specifying nil cv
2113
+ revBody := Body {"channels" : testCase .docChannels }
2114
+ rev , doc , err := collection .Put (ctx , docID , revBody )
2115
+ require .NoError (t , err )
2116
+ revision , err := collection .GetCV (ctx , docID , nil , true )
2117
+
2118
+ if testCase .access == true {
2119
+ require .NoError (t , err )
2120
+ vrs := doc .HLV .Version
2121
+ src := doc .HLV .SourceID
2122
+ sv := & Version {Value : vrs , SourceID : src }
2123
+ assert .Equal (t , rev , revision .RevID )
2124
+ assert .Equal (t , sv , revision .CV )
2125
+ assert .Equal (t , docID , revision .DocID )
2126
+ assert .Equal (t , []byte (`{"channels":["A"]}` ), revision .BodyBytes )
2127
+ } else {
2128
+ require .Error (t , err )
2129
+ assert .ErrorContains (t , err , ErrForbidden .Error ())
2130
+ assert .Equal (t , DocumentRevision {}, revision )
2131
+ }
2132
+ })
2133
+ }
2134
+ }
0 commit comments