22# Copyright (c) Microsoft Corporation. All rights reserved.
33
44import unittest
5+ import os
56
67import pytest
78
@@ -38,7 +39,7 @@ def test_validate_session_token_parsing_from_empty_string(self):
3839 session_token = ""
3940 self .assertIsNone (VectorSessionToken .create (session_token ))
4041
41- def test_validate_session_token_comparison (self ):
42+ def _different_merge_scenarios (self ):
4243 # valid session token
4344 session_token1 = VectorSessionToken .create ("1#100#1=20#2=5#3=30" )
4445 session_token2 = VectorSessionToken .create ("2#105#4=10#2=5#3=30" )
@@ -73,11 +74,29 @@ def test_validate_session_token_comparison(self):
7374 self .assertIsNotNone (session_token_merged )
7475 self .assertTrue (session_token_merged .equals (session_token1 .merge (session_token2 )))
7576
77+ # same vector clock version with global lsn increase (no failover)
78+ session_token1 = VectorSessionToken .create ("1#100#1=20#2=5" )
79+ session_token2 = VectorSessionToken .create ("1#197#1=20#2=5" )
80+ self .assertIsNotNone (session_token1 )
81+ self .assertIsNotNone (session_token2 )
82+
83+ self .assertTrue (session_token1 .merge (session_token2 ).equals (
84+ VectorSessionToken .create ("1#197#1=20#2=5" )))
85+
86+ # same vector clock version with global lsn increase and local lsn increase
87+ session_token1 = VectorSessionToken .create ("1#100#1=20#2=5" )
88+ session_token2 = VectorSessionToken .create ("1#197#1=23#2=15" )
89+ self .assertIsNotNone (session_token1 )
90+ self .assertIsNotNone (session_token2 )
91+
92+ self .assertTrue (session_token1 .merge (session_token2 ).equals (
93+ VectorSessionToken .create ("1#197#1=23#2=15" )))
94+
95+ # different number of regions with same region should throw error
7696 session_token1 = VectorSessionToken .create ("1#101#1=20#2=5#3=30" )
7797 session_token2 = VectorSessionToken .create ("1#100#1=20#2=5#3=30#4=40" )
7898 self .assertIsNotNone (session_token1 )
7999 self .assertIsNotNone (session_token2 )
80-
81100 try :
82101 session_token1 .merge (session_token2 )
83102 self .fail ("Region progress can not be different when version is same" )
@@ -86,6 +105,69 @@ def test_validate_session_token_comparison(self):
86105 "Status code: 500\n Compared session tokens '1#101#1=20#2=5#3=30' "
87106 "and '1#100#1=20#2=5#3=30#4=40' have unexpected regions." )
88107
108+ # same version with different region progress should throw error
109+ session_token1 = VectorSessionToken .create ("1#101#1=20#2=5#3=30" )
110+ session_token2 = VectorSessionToken .create ("1#100#4=20#2=5#3=30" )
111+ self .assertIsNotNone (session_token1 )
112+ self .assertIsNotNone (session_token2 )
113+
114+ try :
115+ session_token1 .merge (session_token2 )
116+ self .fail ("Region progress can not be different when version is same" )
117+ except CosmosHttpResponseError as e :
118+ self .assertEqual (str (e ),
119+ "Status code: 500\n Compared session tokens '1#101#1=20#2=5#3=30' "
120+ "and '1#100#4=20#2=5#3=30' have unexpected regions." )
121+
122+ def test_validate_session_token_comparison (self ):
123+ self ._different_merge_scenarios ()
124+ os .environ ["AZURE_COSMOS_SESSION_TOKEN_FALSE_PROGRESS_MERGE" ] = "false"
125+ self ._different_merge_scenarios ()
126+ del os .environ ["AZURE_COSMOS_SESSION_TOKEN_FALSE_PROGRESS_MERGE" ]
127+
128+ def test_session_token_false_progress_merge (self ):
129+ for false_progress_enabled in [True , False ]:
130+ self .validate_different_session_token_false_progress_merge_scenarios (false_progress_enabled )
131+
132+ def validate_different_session_token_false_progress_merge_scenarios (self , false_progress_enabled : bool ):
133+ # Test that false progress merge is enabled by default and that global lsn is used from higher version token
134+ # when enabled
135+ os .environ ["AZURE_COSMOS_SESSION_TOKEN_FALSE_PROGRESS_MERGE" ] = str (false_progress_enabled )
136+ session_token1 = VectorSessionToken .create ("1#200#1=20#2=5#3=30" )
137+ session_token2 = VectorSessionToken .create ("2#100#1=10#2=8#3=30" )
138+ self .assertIsNotNone (session_token1 )
139+ self .assertIsNotNone (session_token2 )
140+ if false_progress_enabled :
141+ expected_session_token = "2#100#1=20#2=8#3=30"
142+ else :
143+ expected_session_token = "2#200#1=20#2=8#3=30"
144+ self .assertTrue (session_token1 .merge (session_token2 ).equals (
145+ VectorSessionToken .create (expected_session_token )))
146+
147+ # vector clock version increase with removed region progress should merge
148+ session_token1 = VectorSessionToken .create ("1#200#1=20#2=5#3=30" )
149+ session_token2 = VectorSessionToken .create ("2#100#1=10#2=5" )
150+ self .assertIsNotNone (session_token1 )
151+ self .assertIsNotNone (session_token2 )
152+
153+ if false_progress_enabled :
154+ expected_session_token = "2#100#1=20#2=5"
155+ else :
156+ expected_session_token = "2#200#1=20#2=5"
157+ self .assertTrue (session_token1 .merge (session_token2 ).equals (
158+ VectorSessionToken .create (expected_session_token )))
159+
160+ # vector clock version increase with new region progress should merge
161+ session_token1 = VectorSessionToken .create ("1#200#1=20#2=5" )
162+ session_token2 = VectorSessionToken .create ("2#100#1=10#2=5#3=30" )
163+ self .assertIsNotNone (session_token1 )
164+ self .assertIsNotNone (session_token2 )
165+ if false_progress_enabled :
166+ expected_session_token = "2#100#1=20#2=5#3=30"
167+ else :
168+ expected_session_token = "2#200#1=20#2=5#3=30"
169+ self .assertTrue (session_token1 .merge (session_token2 ).equals (
170+ VectorSessionToken .create (expected_session_token )))
89171
90172if __name__ == '__main__' :
91173 unittest .main ()
0 commit comments