@@ -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
)
@@ -1867,3 +1868,181 @@ func TestPutExistingCurrentVersionWithNoExistingDoc(t *testing.T) {
1867
1868
assert .True (t , reflect .DeepEqual (syncData .HLV .PreviousVersions , pv ))
1868
1869
assert .Equal (t , "1-3a208ea66e84121b528f05b5457d1134" , syncData .CurrentRev )
1869
1870
}
1871
+
1872
+ // TestGetCVWithDocResidentInCache:
1873
+ // - Two test cases, one with doc a user will have access to, one without
1874
+ // - Purpose is to have a doc that is resident in rev cache and use the GetCV function to retrieve these docs
1875
+ // - Assert that the doc the user has access to is corrected fetched
1876
+ // - Assert the doc the user doesn't have access to is fetched but correctly redacted
1877
+ func TestGetCVWithDocResidentInCache (t * testing.T ) {
1878
+ const docID = "doc1"
1879
+
1880
+ testCases := []struct {
1881
+ name string
1882
+ docChannels []string
1883
+ access bool
1884
+ }{
1885
+ {
1886
+ name : "getCVWithUserAccess" ,
1887
+ docChannels : []string {"A" },
1888
+ access : true ,
1889
+ },
1890
+ {
1891
+ name : "getCVWithoutUserAccess" ,
1892
+ docChannels : []string {"B" },
1893
+ access : false ,
1894
+ },
1895
+ }
1896
+ for _ , testCase := range testCases {
1897
+ t .Run (testCase .name , func (t * testing.T ) {
1898
+ db , ctx := setupTestDB (t )
1899
+ defer db .Close (ctx )
1900
+ collection := GetSingleDatabaseCollectionWithUser (t , db )
1901
+ collection .ChannelMapper = channels .NewChannelMapper (ctx , channels .DocChannelsSyncFunction , db .Options .JavascriptTimeout )
1902
+
1903
+ // Create a user with access to channel A
1904
+ authenticator := db .Authenticator (base .TestCtx (t ))
1905
+ user , err := authenticator .NewUser ("alice" , "letmein" , channels .BaseSetOf (t , "A" ))
1906
+ require .NoError (t , err )
1907
+ require .NoError (t , authenticator .Save (user ))
1908
+ collection .user , err = authenticator .GetUser ("alice" )
1909
+ require .NoError (t , err )
1910
+
1911
+ // create doc with the channels for the test case
1912
+ docBody := Body {"channels" : testCase .docChannels }
1913
+ rev , doc , err := collection .Put (ctx , docID , docBody )
1914
+ require .NoError (t , err )
1915
+
1916
+ vrs := doc .HLV .Version
1917
+ src := doc .HLV .SourceID
1918
+ sv := & Version {Value : vrs , SourceID : src }
1919
+ revision , err := collection .GetCV (ctx , docID , sv , true )
1920
+ require .NoError (t , err )
1921
+ if testCase .access {
1922
+ assert .Equal (t , rev , revision .RevID )
1923
+ assert .Equal (t , sv , revision .CV )
1924
+ assert .Equal (t , docID , revision .DocID )
1925
+ assert .Equal (t , []byte (`{"channels":["A"]}` ), revision .BodyBytes )
1926
+ } else {
1927
+ assert .Equal (t , rev , revision .RevID )
1928
+ assert .Equal (t , sv , revision .CV )
1929
+ assert .Equal (t , docID , revision .DocID )
1930
+ assert .Equal (t , []byte (RemovedRedactedDocument ), revision .BodyBytes )
1931
+ }
1932
+ })
1933
+ }
1934
+ }
1935
+
1936
+ // TestGetByCVForDocNotResidentInCache:
1937
+ // - Setup db with rev cache size of 1
1938
+ // - Put two docs forcing eviction of the first doc
1939
+ // - Use GetCV function to fetch the first doc, forcing the rev cache to load the doc from bucket
1940
+ // - Assert the doc revision fetched is correct to the first doc we created
1941
+ func TestGetByCVForDocNotResidentInCache (t * testing.T ) {
1942
+ db , ctx := SetupTestDBWithOptions (t , DatabaseContextOptions {
1943
+ RevisionCacheOptions : & RevisionCacheOptions {
1944
+ Size : 1 ,
1945
+ },
1946
+ })
1947
+ defer db .Close (ctx )
1948
+ collection := GetSingleDatabaseCollectionWithUser (t , db )
1949
+ collection .ChannelMapper = channels .NewChannelMapper (ctx , channels .DocChannelsSyncFunction , db .Options .JavascriptTimeout )
1950
+
1951
+ // Create a user with access to channel A
1952
+ authenticator := db .Authenticator (base .TestCtx (t ))
1953
+ user , err := authenticator .NewUser ("alice" , "letmein" , channels .BaseSetOf (t , "A" ))
1954
+ require .NoError (t , err )
1955
+ require .NoError (t , authenticator .Save (user ))
1956
+ collection .user , err = authenticator .GetUser ("alice" )
1957
+ require .NoError (t , err )
1958
+
1959
+ const (
1960
+ doc1ID = "doc1"
1961
+ doc2ID = "doc2"
1962
+ )
1963
+
1964
+ revBody := Body {"channels" : []string {"A" }}
1965
+ rev , doc , err := collection .Put (ctx , doc1ID , revBody )
1966
+ require .NoError (t , err )
1967
+
1968
+ // put another doc that should evict first doc from cache
1969
+ _ , _ , err = collection .Put (ctx , doc2ID , revBody )
1970
+ require .NoError (t , err )
1971
+
1972
+ // get by CV should force a load from bucket and have a cache miss
1973
+ vrs := doc .HLV .Version
1974
+ src := doc .HLV .SourceID
1975
+ sv := & Version {Value : vrs , SourceID : src }
1976
+ revision , err := collection .GetCV (ctx , doc1ID , sv , true )
1977
+ require .NoError (t , err )
1978
+
1979
+ // assert the fetched doc is the first doc we added and assert that we did in fact get cache miss
1980
+ assert .Equal (t , int64 (1 ), db .DbStats .Cache ().RevisionCacheMisses .Value ())
1981
+ assert .Equal (t , rev , revision .RevID )
1982
+ assert .Equal (t , sv , revision .CV )
1983
+ assert .Equal (t , doc1ID , revision .DocID )
1984
+ assert .Equal (t , []byte (`{"channels":["A"]}` ), revision .BodyBytes )
1985
+ }
1986
+
1987
+ // TestGetCVActivePathway:
1988
+ // - Two test cases, one with doc a user will have access to, one without
1989
+ // - Purpose is top specify nil CV to the GetCV function to force the GetActive code pathway
1990
+ // - Assert doc that is created is fetched correctly when user has access to doc
1991
+ // - Assert that correct error is returned when user has no access to the doc
1992
+ func TestGetCVActivePathway (t * testing.T ) {
1993
+ const docID = "doc1"
1994
+
1995
+ testCases := []struct {
1996
+ name string
1997
+ docChannels []string
1998
+ access bool
1999
+ }{
2000
+ {
2001
+ name : "activeFetchWithUserAccess" ,
2002
+ docChannels : []string {"A" },
2003
+ access : true ,
2004
+ },
2005
+ {
2006
+ name : "activeFetchWithoutUserAccess" ,
2007
+ docChannels : []string {"B" },
2008
+ access : false ,
2009
+ },
2010
+ }
2011
+ for _ , testCase := range testCases {
2012
+ t .Run (testCase .name , func (t * testing.T ) {
2013
+ db , ctx := setupTestDB (t )
2014
+ defer db .Close (ctx )
2015
+ collection := GetSingleDatabaseCollectionWithUser (t , db )
2016
+ collection .ChannelMapper = channels .NewChannelMapper (ctx , channels .DocChannelsSyncFunction , db .Options .JavascriptTimeout )
2017
+
2018
+ // Create a user with access to channel A
2019
+ authenticator := db .Authenticator (base .TestCtx (t ))
2020
+ user , err := authenticator .NewUser ("alice" , "letmein" , channels .BaseSetOf (t , "A" ))
2021
+ require .NoError (t , err )
2022
+ require .NoError (t , authenticator .Save (user ))
2023
+ collection .user , err = authenticator .GetUser ("alice" )
2024
+ require .NoError (t , err )
2025
+
2026
+ // test get active path by specifying nil cv
2027
+ revBody := Body {"channels" : testCase .docChannels }
2028
+ rev , doc , err := collection .Put (ctx , docID , revBody )
2029
+ require .NoError (t , err )
2030
+ revision , err := collection .GetCV (ctx , docID , nil , true )
2031
+
2032
+ if testCase .access == true {
2033
+ require .NoError (t , err )
2034
+ vrs := doc .HLV .Version
2035
+ src := doc .HLV .SourceID
2036
+ sv := & Version {Value : vrs , SourceID : src }
2037
+ assert .Equal (t , rev , revision .RevID )
2038
+ assert .Equal (t , sv , revision .CV )
2039
+ assert .Equal (t , docID , revision .DocID )
2040
+ assert .Equal (t , []byte (`{"channels":["A"]}` ), revision .BodyBytes )
2041
+ } else {
2042
+ require .Error (t , err )
2043
+ assert .ErrorContains (t , err , ErrForbidden .Error ())
2044
+ assert .Equal (t , DocumentRevision {}, revision )
2045
+ }
2046
+ })
2047
+ }
2048
+ }
0 commit comments