|
20 | 20 | parse_info,
|
21 | 21 | )
|
22 | 22 | from redis.client import EMPTY_RESPONSE, NEVER_DECODE
|
| 23 | +from redis.commands.json.path import Path |
| 24 | +from redis.commands.search.field import TextField |
| 25 | +from redis.commands.search.query import Query |
23 | 26 | from tests.conftest import (
|
24 | 27 | assert_resp_response,
|
25 | 28 | assert_resp_response_in,
|
@@ -49,6 +52,12 @@ def factory(username):
|
49 | 52 | return r
|
50 | 53 |
|
51 | 54 | yield factory
|
| 55 | + try: |
| 56 | + current_user = await r.client_info() |
| 57 | + except exceptions.NoPermissionError: |
| 58 | + current_user = {} |
| 59 | + if "default" != current_user.get("user"): |
| 60 | + await r.auth("", "default") |
52 | 61 | for username in usernames:
|
53 | 62 | await r.acl_deluser(username)
|
54 | 63 |
|
@@ -115,12 +124,65 @@ async def test_acl_cat_no_category(self, r: redis.Redis):
|
115 | 124 | assert isinstance(categories, list)
|
116 | 125 | assert "read" in categories or b"read" in categories
|
117 | 126 |
|
| 127 | + @pytest.mark.redismod |
| 128 | + @skip_if_server_version_lt("7.9.0") |
| 129 | + async def test_acl_cat_contain_modules_no_category(self, r: redis.Redis): |
| 130 | + modules_list = [ |
| 131 | + "search", |
| 132 | + "bloom", |
| 133 | + "json", |
| 134 | + "cuckoo", |
| 135 | + "timeseries", |
| 136 | + "cms", |
| 137 | + "topk", |
| 138 | + "tdigest", |
| 139 | + ] |
| 140 | + categories = await r.acl_cat() |
| 141 | + assert isinstance(categories, list) |
| 142 | + for module_cat in modules_list: |
| 143 | + assert module_cat in categories or module_cat.encode() in categories |
| 144 | + |
118 | 145 | @skip_if_server_version_lt(REDIS_6_VERSION)
|
119 | 146 | async def test_acl_cat_with_category(self, r: redis.Redis):
|
120 | 147 | commands = await r.acl_cat("read")
|
121 | 148 | assert isinstance(commands, list)
|
122 | 149 | assert "get" in commands or b"get" in commands
|
123 | 150 |
|
| 151 | + @pytest.mark.redismod |
| 152 | + @skip_if_server_version_lt("7.9.0") |
| 153 | + async def test_acl_modules_cat_with_category(self, r: redis.Redis): |
| 154 | + search_commands = await r.acl_cat("search") |
| 155 | + assert isinstance(search_commands, list) |
| 156 | + assert "FT.SEARCH" in search_commands or b"FT.SEARCH" in search_commands |
| 157 | + |
| 158 | + bloom_commands = await r.acl_cat("bloom") |
| 159 | + assert isinstance(bloom_commands, list) |
| 160 | + assert "bf.add" in bloom_commands or b"bf.add" in bloom_commands |
| 161 | + |
| 162 | + json_commands = await r.acl_cat("json") |
| 163 | + assert isinstance(json_commands, list) |
| 164 | + assert "json.get" in json_commands or b"json.get" in json_commands |
| 165 | + |
| 166 | + cuckoo_commands = await r.acl_cat("cuckoo") |
| 167 | + assert isinstance(cuckoo_commands, list) |
| 168 | + assert "cf.insert" in cuckoo_commands or b"cf.insert" in cuckoo_commands |
| 169 | + |
| 170 | + cms_commands = await r.acl_cat("cms") |
| 171 | + assert isinstance(cms_commands, list) |
| 172 | + assert "cms.query" in cms_commands or b"cms.query" in cms_commands |
| 173 | + |
| 174 | + topk_commands = await r.acl_cat("topk") |
| 175 | + assert isinstance(topk_commands, list) |
| 176 | + assert "topk.list" in topk_commands or b"topk.list" in topk_commands |
| 177 | + |
| 178 | + tdigest_commands = await r.acl_cat("tdigest") |
| 179 | + assert isinstance(tdigest_commands, list) |
| 180 | + assert "tdigest.rank" in tdigest_commands or b"tdigest.rank" in tdigest_commands |
| 181 | + |
| 182 | + timeseries_commands = await r.acl_cat("timeseries") |
| 183 | + assert isinstance(timeseries_commands, list) |
| 184 | + assert "ts.range" in timeseries_commands or b"ts.range" in timeseries_commands |
| 185 | + |
124 | 186 | @skip_if_server_version_lt(REDIS_6_VERSION)
|
125 | 187 | async def test_acl_deluser(self, r_teardown):
|
126 | 188 | username = "redis-py-user"
|
@@ -316,6 +378,116 @@ async def test_acl_whoami(self, r: redis.Redis):
|
316 | 378 | username = await r.acl_whoami()
|
317 | 379 | assert isinstance(username, (str, bytes))
|
318 | 380 |
|
| 381 | + @pytest.mark.redismod |
| 382 | + @skip_if_server_version_lt("7.9.0") |
| 383 | + async def test_acl_modules_commands(self, r_teardown): |
| 384 | + username = "redis-py-user" |
| 385 | + password = "pass-for-test-user" |
| 386 | + |
| 387 | + r = r_teardown(username) |
| 388 | + await r.flushdb() |
| 389 | + |
| 390 | + await r.ft().create_index((TextField("txt"),)) |
| 391 | + await r.hset("doc1", mapping={"txt": "foo baz"}) |
| 392 | + await r.hset("doc2", mapping={"txt": "foo bar"}) |
| 393 | + |
| 394 | + await r.acl_setuser( |
| 395 | + username, |
| 396 | + enabled=True, |
| 397 | + reset=True, |
| 398 | + passwords=[f"+{password}"], |
| 399 | + categories=["-all"], |
| 400 | + commands=[ |
| 401 | + "+FT.SEARCH", |
| 402 | + "-FT.DROPINDEX", |
| 403 | + "+json.set", |
| 404 | + "+json.get", |
| 405 | + "-json.clear", |
| 406 | + "+bf.reserve", |
| 407 | + "-bf.info", |
| 408 | + "+cf.reserve", |
| 409 | + "+cms.initbydim", |
| 410 | + "+topk.reserve", |
| 411 | + "+tdigest.create", |
| 412 | + "+ts.create", |
| 413 | + "-ts.info", |
| 414 | + ], |
| 415 | + keys=["*"], |
| 416 | + ) |
| 417 | + |
| 418 | + await r.auth(password, username) |
| 419 | + |
| 420 | + assert await r.ft().search(Query("foo ~bar")) |
| 421 | + with pytest.raises(exceptions.NoPermissionError): |
| 422 | + await r.ft().dropindex() |
| 423 | + |
| 424 | + await r.json().set("foo", Path.root_path(), "bar") |
| 425 | + assert await r.json().get("foo") == "bar" |
| 426 | + with pytest.raises(exceptions.NoPermissionError): |
| 427 | + await r.json().clear("foo") |
| 428 | + |
| 429 | + assert await r.bf().create("bloom", 0.01, 1000) |
| 430 | + assert await r.cf().create("cuckoo", 1000) |
| 431 | + assert await r.cms().initbydim("cmsDim", 100, 5) |
| 432 | + assert await r.topk().reserve("topk", 5, 100, 5, 0.9) |
| 433 | + assert await r.tdigest().create("to-tDigest", 10) |
| 434 | + with pytest.raises(exceptions.NoPermissionError): |
| 435 | + await r.bf().info("bloom") |
| 436 | + |
| 437 | + assert await r.ts().create(1, labels={"Redis": "Labs"}) |
| 438 | + with pytest.raises(exceptions.NoPermissionError): |
| 439 | + await r.ts().info(1) |
| 440 | + |
| 441 | + @pytest.mark.redismod |
| 442 | + @skip_if_server_version_lt("7.9.0") |
| 443 | + async def test_acl_modules_category_commands(self, r_teardown): |
| 444 | + username = "redis-py-user" |
| 445 | + password = "pass-for-test-user" |
| 446 | + |
| 447 | + r = r_teardown(username) |
| 448 | + await r.flushdb() |
| 449 | + |
| 450 | + # validate modules categories acl config |
| 451 | + await r.acl_setuser( |
| 452 | + username, |
| 453 | + enabled=True, |
| 454 | + reset=True, |
| 455 | + passwords=[f"+{password}"], |
| 456 | + categories=[ |
| 457 | + "-all", |
| 458 | + "+@search", |
| 459 | + "+@json", |
| 460 | + "+@bloom", |
| 461 | + "+@cuckoo", |
| 462 | + "+@topk", |
| 463 | + "+@cms", |
| 464 | + "+@timeseries", |
| 465 | + "+@tdigest", |
| 466 | + ], |
| 467 | + keys=["*"], |
| 468 | + ) |
| 469 | + await r.ft().create_index((TextField("txt"),)) |
| 470 | + await r.hset("doc1", mapping={"txt": "foo baz"}) |
| 471 | + await r.hset("doc2", mapping={"txt": "foo bar"}) |
| 472 | + |
| 473 | + await r.auth(password, username) |
| 474 | + |
| 475 | + assert await r.ft().search(Query("foo ~bar")) |
| 476 | + assert await r.ft().dropindex() |
| 477 | + |
| 478 | + assert await r.json().set("foo", Path.root_path(), "bar") |
| 479 | + assert await r.json().get("foo") == "bar" |
| 480 | + |
| 481 | + assert await r.bf().create("bloom", 0.01, 1000) |
| 482 | + assert await r.bf().info("bloom") |
| 483 | + assert await r.cf().create("cuckoo", 1000) |
| 484 | + assert await r.cms().initbydim("cmsDim", 100, 5) |
| 485 | + assert await r.topk().reserve("topk", 5, 100, 5, 0.9) |
| 486 | + assert await r.tdigest().create("to-tDigest", 10) |
| 487 | + |
| 488 | + assert await r.ts().create(1, labels={"Redis": "Labs"}) |
| 489 | + assert await r.ts().info(1) |
| 490 | + |
319 | 491 | @pytest.mark.onlynoncluster
|
320 | 492 | async def test_client_list(self, r: redis.Redis):
|
321 | 493 | clients = await r.client_list()
|
@@ -512,6 +684,36 @@ async def test_config_set(self, r: redis.Redis):
|
512 | 684 | assert await r.config_set("timeout", 0)
|
513 | 685 | assert (await r.config_get())["timeout"] == "0"
|
514 | 686 |
|
| 687 | + @pytest.mark.redismod |
| 688 | + @skip_if_server_version_lt("7.9.0") |
| 689 | + async def test_config_get_for_modules(self, r: redis.Redis): |
| 690 | + search_module_configs = await r.config_get("search-*") |
| 691 | + assert "search-timeout" in search_module_configs |
| 692 | + |
| 693 | + ts_module_configs = await r.config_get("ts-*") |
| 694 | + assert "ts-num-threads" in ts_module_configs |
| 695 | + |
| 696 | + bf_module_configs = await r.config_get("bf-*") |
| 697 | + assert "bf-initial-size" in bf_module_configs |
| 698 | + |
| 699 | + cf_module_configs = await r.config_get("cf-*") |
| 700 | + assert "cf-max-iterations" in cf_module_configs |
| 701 | + |
| 702 | + @pytest.mark.redismod |
| 703 | + @skip_if_server_version_lt("7.9.0") |
| 704 | + async def test_config_set_for_search_module(self, r: redis.Redis): |
| 705 | + search_timeout_initial = (await r.config_get())["search-timeout"] |
| 706 | + search_timeout_new = int(search_timeout_initial) + 100 |
| 707 | + |
| 708 | + assert await r.config_set("search-timeout", search_timeout_new) |
| 709 | + assert ( |
| 710 | + int((await r.config_get("search-*"))["search-timeout"]) |
| 711 | + == search_timeout_new |
| 712 | + ) |
| 713 | + assert ( |
| 714 | + int((await r.ft().config_get("TIMEOUT"))[b"TIMEOUT"]) == search_timeout_new |
| 715 | + ) |
| 716 | + |
515 | 717 | @pytest.mark.onlynoncluster
|
516 | 718 | async def test_dbsize(self, r: redis.Redis):
|
517 | 719 | await r.set("a", "foo")
|
|
0 commit comments