Skip to content

Commit a0f406c

Browse files
committed
PYCBC-1930: Raise on an option value the getter cannot interpret
Changes -------- * Raise InvalidArgumentException from the six request-option getters that handled None and str and then fell off the end, returning None from a signature declaring a non-optional enum: consistency, order and on_error on the view query, consistency and profile on the query, and consistency on the search builder * Raise from ViewScanConsistency.from_str, which returned None for any string it did not recognise, matching QueryStatus.from_str * Add tests to the view, query and search param suites driving an uninterpretable value in through set_option, which does no verification, and reading the property back Change-Id: I1f8b6138b8d1e7dc6ee449d953381290ca1d58b1 Reviewed-on: https://review.couchbase.org/c/couchbase-python-client/+/252044 Reviewed-by: Sergey Avseyev <sergey.avseyev@gmail.com> Tested-by: Build Bot <build@couchbase.com>
1 parent 51af71a commit a0f406c

6 files changed

Lines changed: 54 additions & 0 deletions

File tree

couchbase/logic/n1ql.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,9 @@ def consistency(self) -> QueryScanConsistency:
444444
return QueryScanConsistency.NOT_BOUNDED
445445
if isinstance(value, str):
446446
return QueryScanConsistency.REQUEST_PLUS if value == 'request_plus' else QueryScanConsistency.NOT_BOUNDED
447+
raise InvalidArgumentException(
448+
message=(f"{value} is not a valid QueryScanConsistency option. "
449+
"Expected str representation of type QueryScanConsistency."))
447450

448451
@consistency.setter
449452
def consistency(self, value # type: Union[QueryScanConsistency, str]
@@ -559,6 +562,9 @@ def profile(self) -> QueryProfile:
559562
return QueryProfile.PHASES
560563
else:
561564
return QueryProfile.TIMINGS
565+
raise InvalidArgumentException(
566+
message=(f"{value} is not a valid QueryProfile option. "
567+
"Expected str representation of type QueryProfile."))
562568

563569
@profile.setter
564570
def profile(self, value # type: Union[QueryProfile, str]

couchbase/logic/search.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1150,6 +1150,9 @@ def consistency(self) -> SearchScanConsistency:
11501150
return SearchScanConsistency.NOT_BOUNDED
11511151
if isinstance(value, str):
11521152
return SearchScanConsistency.REQUEST_PLUS if value == 'request_plus' else SearchScanConsistency.NOT_BOUNDED
1153+
raise InvalidArgumentException(
1154+
message=(f"{value} is not a valid SearchScanConsistency option. "
1155+
"Expected str representation of type SearchScanConsistency."))
11531156

11541157
@consistency.setter
11551158
def consistency(self, value # type: Union[SearchScanConsistency, str]

couchbase/logic/views.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ def from_str(cls, value: str) -> ViewScanConsistency:
6060
return cls.NOT_BOUNDED
6161
elif value == 'update_after':
6262
return cls.UPDATE_AFTER
63+
raise InvalidArgumentException(
64+
message=(f"{value} is not a valid ViewScanConsistency option. "
65+
"Expected str representation of type ViewScanConsistency."))
6366

6467

6568
class ViewOrdering(Enum):
@@ -237,6 +240,9 @@ def consistency(self) -> ViewScanConsistency:
237240
return ViewScanConsistency.NOT_BOUNDED
238241
if isinstance(value, str):
239242
return ViewScanConsistency.from_str(value)
243+
raise InvalidArgumentException(
244+
message=(f"{value} is not a valid ViewScanConsistency option. "
245+
"Expected str representation of type ViewScanConsistency."))
240246

241247
@consistency.setter
242248
def consistency(self, value # type: Union[ViewScanConsistency, str]
@@ -352,6 +358,9 @@ def order(self) -> ViewOrdering:
352358
return ViewOrdering.DESCENDING
353359
if isinstance(value, str):
354360
return ViewOrdering.from_str(value)
361+
raise InvalidArgumentException(
362+
message=(f"{value} is not a valid ViewOrdering option. "
363+
"Expected str representation of type ViewOrdering."))
355364

356365
@order.setter
357366
def order(self, value # type: Union[ViewOrdering, str]
@@ -374,6 +383,9 @@ def on_error(self) -> ViewErrorMode:
374383
return ViewErrorMode.STOP
375384
if isinstance(value, str):
376385
return ViewErrorMode.from_str(value)
386+
raise InvalidArgumentException(
387+
message=(f"{value} is not a valid ViewErrorMode option. "
388+
"Expected str representation of type ViewErrorMode."))
377389

378390
@on_error.setter
379391
def on_error(self, value # type: Union[ViewErrorMode, str]

couchbase/tests/query_params_t.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ class QueryParamTestSuite:
4848
'test_params_scan_wait',
4949
'test_params_serializer',
5050
'test_params_timeout',
51+
'test_params_uninterpretable_enum_option',
5152
'test_params_use_replica',
5253
]
5354

@@ -313,6 +314,14 @@ def test_params_serializer(self, base_opts):
313314
exp_opts['serializer'] = serializer
314315
assert query.params == exp_opts
315316

317+
def test_params_uninterpretable_enum_option(self):
318+
# set_option does no verification, so the getter is where an unusable value surfaces
319+
for option, prop in (('scan_consistency', 'consistency'), ('profile', 'profile')):
320+
query = N1QLQuery.create_query_object('SELECT * FROM default', QueryOptions())
321+
query.set_option(option, 5)
322+
with pytest.raises(InvalidArgumentException):
323+
getattr(query, prop)
324+
316325
def test_params_timeout(self, base_opts):
317326
q_str = 'SELECT * FROM default'
318327
q_opts = QueryOptions(timeout=timedelta(seconds=20))

couchbase/tests/search_params_t.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ class SearchParamTestSuite:
6464
'test_params_limit',
6565
'test_params_logging',
6666
'test_params_scan_consistency',
67+
'test_params_uninterpretable_enum_option',
6768
'test_params_scope_collections',
6869
'test_params_serializer',
6970
'test_params_show_request',
@@ -941,6 +942,16 @@ def test_params_scan_consistency(self, cb_env, base_query_opts):
941942
assert search_query.params == exp_opts
942943
assert search_query.consistency == search.SearchScanConsistency.REQUEST_PLUS
943944

945+
def test_params_uninterpretable_enum_option(self, cb_env, base_query_opts):
946+
# set_option does no verification, so the getter is where an unusable value surfaces
947+
q, _ = base_query_opts
948+
search_query = search.SearchQueryBuilder.create_search_query_object(
949+
cb_env.TEST_INDEX_NAME, q, SearchOptions()
950+
)
951+
search_query.set_option('scan_consistency', 5)
952+
with pytest.raises(InvalidArgumentException):
953+
search_query.consistency
954+
944955
def test_params_scope_collections(self, cb_env, base_query_opts):
945956
q, base_opts = base_query_opts
946957
opts = SearchOptions(scope_name='test-scope', collections=['test-collection-1', 'test-collection-2'])

couchbase/tests/views_params_t.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import pytest
2020

21+
from couchbase.exceptions import InvalidArgumentException
2122
from couchbase.management.views import DesignDocumentNamespace
2223
from couchbase.options import ViewOptions
2324
from couchbase.serializer import DefaultJsonSerializer
@@ -52,6 +53,7 @@ class ViewsParamSuite:
5253
'test_params_startkey',
5354
'test_params_startkey_docid',
5455
'test_params_timeout',
56+
'test_params_uninterpretable_enum_option',
5557
]
5658

5759
@pytest.fixture(scope='class')
@@ -209,6 +211,17 @@ def test_params_scan_consistency(self, cb_env, base_opts):
209211
assert params == exp_opts
210212
assert query.consistency == ViewScanConsistency.REQUEST_PLUS
211213

214+
def test_params_uninterpretable_enum_option(self, cb_env, base_opts):
215+
# set_option does no verification, so the getter is where an unusable value surfaces
216+
for option, prop in (('scan_consistency', 'consistency'), ('order', 'order'), ('on_error', 'on_error')):
217+
query = ViewQuery.create_view_query_object('default', cb_env.DOCNAME, cb_env.TEST_VIEW_NAME)
218+
query.set_option(option, 5)
219+
with pytest.raises(InvalidArgumentException):
220+
getattr(query, prop)
221+
222+
with pytest.raises(InvalidArgumentException):
223+
ViewScanConsistency.from_str('not_a_scan_consistency')
224+
212225
def test_params_serializer(self, cb_env, base_opts):
213226
serializer = DefaultJsonSerializer()
214227
opts = ViewOptions(serializer=serializer)

0 commit comments

Comments
 (0)