2
2
# Copyright (c) Microsoft Corporation. All rights reserved.
3
3
4
4
import unittest
5
+ import os
5
6
6
7
import pytest
7
8
@@ -38,7 +39,7 @@ def test_validate_session_token_parsing_from_empty_string(self):
38
39
session_token = ""
39
40
self .assertIsNone (VectorSessionToken .create (session_token ))
40
41
41
- def test_validate_session_token_comparison (self ):
42
+ def _different_merge_scenarios (self ):
42
43
# valid session token
43
44
session_token1 = VectorSessionToken .create ("1#100#1=20#2=5#3=30" )
44
45
session_token2 = VectorSessionToken .create ("2#105#4=10#2=5#3=30" )
@@ -73,11 +74,29 @@ def test_validate_session_token_comparison(self):
73
74
self .assertIsNotNone (session_token_merged )
74
75
self .assertTrue (session_token_merged .equals (session_token1 .merge (session_token2 )))
75
76
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
76
96
session_token1 = VectorSessionToken .create ("1#101#1=20#2=5#3=30" )
77
97
session_token2 = VectorSessionToken .create ("1#100#1=20#2=5#3=30#4=40" )
78
98
self .assertIsNotNone (session_token1 )
79
99
self .assertIsNotNone (session_token2 )
80
-
81
100
try :
82
101
session_token1 .merge (session_token2 )
83
102
self .fail ("Region progress can not be different when version is same" )
@@ -86,6 +105,69 @@ def test_validate_session_token_comparison(self):
86
105
"Status code: 500\n Compared session tokens '1#101#1=20#2=5#3=30' "
87
106
"and '1#100#1=20#2=5#3=30#4=40' have unexpected regions." )
88
107
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 )))
89
171
90
172
if __name__ == '__main__' :
91
173
unittest .main ()
0 commit comments