weaviate-cli 3.1.4__tar.gz → 3.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- weaviate_cli-3.2.0/.github/workflows/main.yaml +132 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/PKG-INFO +6 -3
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/README.md +1 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/requirements-dev.txt +2 -1
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/setup.cfg +2 -1
- weaviate_cli-3.2.0/test/integration/test_auth_integration.py +56 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/test/integration/test_integration.py +1 -6
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/test/unittests/test_defaults.py +17 -5
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/test/unittests/test_managers/test_data_manager.py +1 -0
- weaviate_cli-3.2.0/test/unittests/test_managers/test_user_manager.py +325 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/test/unittests/test_utils.py +16 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/weaviate_cli/commands/assign.py +12 -2
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/weaviate_cli/commands/create.py +90 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/weaviate_cli/commands/delete.py +47 -2
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/weaviate_cli/commands/get.py +53 -15
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/weaviate_cli/commands/query.py +7 -1
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/weaviate_cli/commands/revoke.py +12 -2
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/weaviate_cli/commands/update.py +127 -2
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/weaviate_cli/defaults.py +31 -9
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/weaviate_cli/managers/collection_manager.py +19 -4
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/weaviate_cli/managers/config_manager.py +24 -1
- weaviate_cli-3.2.0/weaviate_cli/managers/data_manager.py +1245 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/weaviate_cli/managers/role_manager.py +18 -5
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/weaviate_cli/managers/tenant_manager.py +56 -48
- weaviate_cli-3.2.0/weaviate_cli/managers/user_manager.py +173 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/weaviate_cli/utils.py +29 -11
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/weaviate_cli.egg-info/PKG-INFO +6 -3
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/weaviate_cli.egg-info/SOURCES.txt +2 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/weaviate_cli.egg-info/requires.txt +2 -1
- weaviate_cli-3.1.4/.github/workflows/main.yaml +0 -77
- weaviate_cli-3.1.4/weaviate_cli/managers/data_manager.py +0 -637
- weaviate_cli-3.1.4/weaviate_cli/managers/user_manager.py +0 -54
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/.github/dependabot.yml +0 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/.github/workflows/release.yaml +0 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/.gitignore +0 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/.pre-commit-config.yaml +0 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/CONTRIBUTING.md +0 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/Dockerfile +0 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/LICENSE +0 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/MANIFEST.in +0 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/Makefile +0 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/cli.py +0 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/publish.md +0 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/pyproject.toml +0 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/setup.py +0 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/test/README.md +0 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/test/__init__.py +0 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/test/unittests/conftest.py +0 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/test/unittests/test_cli.py +0 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/test/unittests/test_managers/test_collection_manager.py +0 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/test/unittests/test_managers/test_config_manager.py +0 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/test/unittests/test_managers/test_node_manager.py +0 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/test/unittests/test_managers/test_shard_manager.py +0 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/weaviate_cli/__init__.py +0 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/weaviate_cli/commands/__init__.py +0 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/weaviate_cli/commands/cancel.py +0 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/weaviate_cli/commands/restore.py +0 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/weaviate_cli/completion/__init__.py +0 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/weaviate_cli/completion/complete.py +0 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/weaviate_cli/datasets/__init__.py +0 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/weaviate_cli/datasets/movies.json +0 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/weaviate_cli/managers/__init__.py +0 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/weaviate_cli/managers/backup_manager.py +0 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/weaviate_cli/managers/node_manager.py +0 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/weaviate_cli/managers/shard_manager.py +0 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/weaviate_cli/types/models.py +0 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/weaviate_cli.egg-info/dependency_links.txt +0 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/weaviate_cli.egg-info/entry_points.txt +0 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/weaviate_cli.egg-info/not-zip-safe +0 -0
- {weaviate_cli-3.1.4 → weaviate_cli-3.2.0}/weaviate_cli.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
name: Main
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
pull_request:
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
lint-and-format:
|
|
11
|
+
name: Run Linter and Formatter
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
- uses: actions/setup-python@v5
|
|
16
|
+
with:
|
|
17
|
+
python-version: "3.11"
|
|
18
|
+
- run: pip install -r requirements-dev.txt
|
|
19
|
+
- name: "Black"
|
|
20
|
+
run: black --check cli.py weaviate_cli test
|
|
21
|
+
- name: "Check release for pypi"
|
|
22
|
+
run: |
|
|
23
|
+
python -m build
|
|
24
|
+
python -m twine check dist/*
|
|
25
|
+
|
|
26
|
+
unit-tests:
|
|
27
|
+
name: Run Unit Tests
|
|
28
|
+
needs: [lint-and-format]
|
|
29
|
+
runs-on: ubuntu-latest
|
|
30
|
+
strategy:
|
|
31
|
+
matrix:
|
|
32
|
+
version: [ "3.9", "3.10", "3.11", "3.12", "3.13" ]
|
|
33
|
+
steps:
|
|
34
|
+
- uses: actions/checkout@v4
|
|
35
|
+
- uses: actions/setup-python@v5
|
|
36
|
+
with:
|
|
37
|
+
python-version: ${{ matrix.version }}
|
|
38
|
+
- run: pip install -e .
|
|
39
|
+
- name: Run unit tests with pytest
|
|
40
|
+
run: |
|
|
41
|
+
pip install pytest-html
|
|
42
|
+
pytest test/unittests --html=test-report-${{ matrix.version }}.html --self-contained-html
|
|
43
|
+
- name: Upload test results
|
|
44
|
+
if: always()
|
|
45
|
+
uses: actions/upload-artifact@v4
|
|
46
|
+
with:
|
|
47
|
+
name: test-results-${{ matrix.version }}
|
|
48
|
+
path: test-report-${{ matrix.version }}.html
|
|
49
|
+
|
|
50
|
+
get-latest-weaviate-version:
|
|
51
|
+
runs-on: ubuntu-latest
|
|
52
|
+
needs: [unit-tests]
|
|
53
|
+
name: Get latest Weaviate version
|
|
54
|
+
outputs:
|
|
55
|
+
LATEST_WEAVIATE_VERSION: ${{ steps.latest-version.outputs.latest_weaviate_version }}
|
|
56
|
+
steps:
|
|
57
|
+
- name: Retrieve latest Weaviate version
|
|
58
|
+
id: latest-version
|
|
59
|
+
uses: weaviate/github-common-actions/.github/actions/get-latest-weaviate-version@main
|
|
60
|
+
|
|
61
|
+
integration-tests:
|
|
62
|
+
needs: [unit-tests, get-latest-weaviate-version]
|
|
63
|
+
env:
|
|
64
|
+
WEAVIATE_VERSION: ${{ needs.get-latest-weaviate-version.outputs.LATEST_WEAVIATE_VERSION }}
|
|
65
|
+
MODULES: "text2vec-transformers,text2vec-contextionary"
|
|
66
|
+
name: Run Integration Tests
|
|
67
|
+
runs-on: ubuntu-latest
|
|
68
|
+
strategy:
|
|
69
|
+
matrix:
|
|
70
|
+
version: [ "3.9", "3.10", "3.11", "3.12", "3.13" ]
|
|
71
|
+
steps:
|
|
72
|
+
- uses: actions/checkout@v4
|
|
73
|
+
- uses: actions/setup-python@v5
|
|
74
|
+
with:
|
|
75
|
+
python-version: ${{ matrix.version }}
|
|
76
|
+
- run: pip install -e .
|
|
77
|
+
- name: Start up Weaviate cluster
|
|
78
|
+
uses: weaviate/weaviate-local-k8s@v2
|
|
79
|
+
with:
|
|
80
|
+
workers: 1
|
|
81
|
+
replicas: 1
|
|
82
|
+
weaviate-version: ${{ env.WEAVIATE_VERSION }}
|
|
83
|
+
modules: ${{ env.MODULES }}
|
|
84
|
+
enable-backup: true
|
|
85
|
+
dynamic-users: true
|
|
86
|
+
- name: Run integration tests with pytest
|
|
87
|
+
run: |
|
|
88
|
+
pip install pytest-html
|
|
89
|
+
pytest test/integration/test_integration.py --html=test-report-${{ matrix.version }}.html --self-contained-html
|
|
90
|
+
integration-auth-tests:
|
|
91
|
+
needs: [unit-tests, get-latest-weaviate-version]
|
|
92
|
+
env:
|
|
93
|
+
WEAVIATE_VERSION: ${{ needs.get-latest-weaviate-version.outputs.LATEST_WEAVIATE_VERSION }}
|
|
94
|
+
MODULES: "text2vec-transformers,text2vec-contextionary"
|
|
95
|
+
name: Run Integration Tests Auth
|
|
96
|
+
runs-on: ubuntu-latest
|
|
97
|
+
strategy:
|
|
98
|
+
matrix:
|
|
99
|
+
version: [ "3.9", "3.10", "3.11", "3.12", "3.13" ]
|
|
100
|
+
steps:
|
|
101
|
+
- uses: actions/checkout@v4
|
|
102
|
+
- uses: actions/setup-python@v5
|
|
103
|
+
with:
|
|
104
|
+
python-version: ${{ matrix.version }}
|
|
105
|
+
- run: pip install -e .
|
|
106
|
+
- name: Start up Weaviate cluster
|
|
107
|
+
uses: weaviate/weaviate-local-k8s@v2
|
|
108
|
+
with:
|
|
109
|
+
workers: 1
|
|
110
|
+
replicas: 1
|
|
111
|
+
weaviate-version: ${{ env.WEAVIATE_VERSION }}
|
|
112
|
+
modules: ${{ env.MODULES }}
|
|
113
|
+
enable-backup: true
|
|
114
|
+
rbac: true
|
|
115
|
+
dynamic-users: true
|
|
116
|
+
- name: Create config directory
|
|
117
|
+
run: mkdir -p ~/.config/weaviate
|
|
118
|
+
- name: Create config file
|
|
119
|
+
run: |
|
|
120
|
+
echo '{
|
|
121
|
+
"host": "localhost",
|
|
122
|
+
"http_port": "8080",
|
|
123
|
+
"grpc_port": "50051",
|
|
124
|
+
"auth": {
|
|
125
|
+
"type": "api_key",
|
|
126
|
+
"api_key": "admin-key"
|
|
127
|
+
}
|
|
128
|
+
}' > ~/.config/weaviate/config.json
|
|
129
|
+
- name: Run integration auth tests with pytest
|
|
130
|
+
run: |
|
|
131
|
+
pip install pytest-html
|
|
132
|
+
pytest test/integration/test_auth_integration.py --html=test-auth-report-${{ matrix.version }}.html --self-contained-html
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: weaviate-cli
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.2.0
|
|
4
4
|
Summary: Command line interface to interact with weaviate
|
|
5
5
|
Home-page: https://github.com/weaviate/weaviate-cli
|
|
6
6
|
Download-URL: https://github.com/weaviate/weaviate-cli
|
|
@@ -28,13 +28,15 @@ Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
|
28
28
|
Requires-Python: >=3.9
|
|
29
29
|
Description-Content-Type: text/markdown
|
|
30
30
|
License-File: LICENSE
|
|
31
|
-
Requires-Dist: weaviate-client>=4.
|
|
31
|
+
Requires-Dist: weaviate-client>=4.12.0
|
|
32
32
|
Requires-Dist: click==8.1.7
|
|
33
33
|
Requires-Dist: semver>=3.0.2
|
|
34
34
|
Requires-Dist: numpy>=1.24.0
|
|
35
35
|
Requires-Dist: importlib-resources>=5.0.0
|
|
36
36
|
Requires-Dist: prettytable>=3.1.0
|
|
37
|
+
Requires-Dist: faker>=20.0.0
|
|
37
38
|
Dynamic: download-url
|
|
39
|
+
Dynamic: license-file
|
|
38
40
|
|
|
39
41
|
# Weaviate CLI
|
|
40
42
|
|
|
@@ -118,6 +120,7 @@ The configuration file should be a JSON file with the following structure:
|
|
|
118
120
|
"host": "your-weaviate-host",
|
|
119
121
|
"http_port": "your-http-port",
|
|
120
122
|
"grpc_port": "your-grpc-port",
|
|
123
|
+
"grpc_host": "your-grpc-host",
|
|
121
124
|
"auth": {
|
|
122
125
|
"type": "api_key",
|
|
123
126
|
"api_key": "your-api-key"
|
|
@@ -80,6 +80,7 @@ The configuration file should be a JSON file with the following structure:
|
|
|
80
80
|
"host": "your-weaviate-host",
|
|
81
81
|
"http_port": "your-http-port",
|
|
82
82
|
"grpc_port": "your-grpc-port",
|
|
83
|
+
"grpc_host": "your-grpc-host",
|
|
83
84
|
"auth": {
|
|
84
85
|
"type": "api_key",
|
|
85
86
|
"api_key": "your-api-key"
|
|
@@ -36,12 +36,13 @@ classifiers =
|
|
|
36
36
|
include_package_data = True
|
|
37
37
|
python_requires = >=3.9
|
|
38
38
|
install_requires =
|
|
39
|
-
weaviate-client>=4.
|
|
39
|
+
weaviate-client>=4.12.0
|
|
40
40
|
click==8.1.7
|
|
41
41
|
semver>=3.0.2
|
|
42
42
|
numpy>=1.24.0
|
|
43
43
|
importlib-resources>=5.0.0
|
|
44
44
|
prettytable>=3.1.0
|
|
45
|
+
faker>=20.0.0
|
|
45
46
|
setup_requires =
|
|
46
47
|
pip
|
|
47
48
|
setuptools
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
import weaviate
|
|
3
|
+
import click
|
|
4
|
+
from click.testing import CliRunner
|
|
5
|
+
from weaviate_cli.managers.collection_manager import CollectionManager
|
|
6
|
+
from weaviate_cli.managers.config_manager import ConfigManager
|
|
7
|
+
from weaviate_cli.managers.user_manager import UserManager
|
|
8
|
+
import weaviate.classes.config as wvc
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@pytest.fixture
|
|
12
|
+
def client() -> weaviate.Client:
|
|
13
|
+
config = ConfigManager()
|
|
14
|
+
return config.get_client()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@pytest.fixture
|
|
18
|
+
def collection_manager(client: weaviate.Client) -> CollectionManager:
|
|
19
|
+
return CollectionManager(client)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@pytest.fixture
|
|
23
|
+
def user_manager(client: weaviate.Client) -> UserManager:
|
|
24
|
+
return UserManager(client)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def test_user_lifecycle(user_manager: UserManager):
|
|
28
|
+
try:
|
|
29
|
+
user_name = "test_user"
|
|
30
|
+
# Create user
|
|
31
|
+
api_key = user_manager.create_user(user_name=user_name)
|
|
32
|
+
assert user_name in [user.user_id for user in user_manager.get_all_users()]
|
|
33
|
+
assert api_key is not None
|
|
34
|
+
|
|
35
|
+
# Update user
|
|
36
|
+
new_api_key = user_manager.update_user(user_name=user_name, rotate_api_key=True)
|
|
37
|
+
assert new_api_key is not None
|
|
38
|
+
assert new_api_key != api_key
|
|
39
|
+
|
|
40
|
+
# Deactivate user
|
|
41
|
+
user_manager.update_user(user_name=user_name, deactivate=True)
|
|
42
|
+
user = user_manager.get_user(user_name=user_name)
|
|
43
|
+
assert not user.active
|
|
44
|
+
|
|
45
|
+
# Activate user
|
|
46
|
+
user_manager.update_user(user_name=user_name, activate=True)
|
|
47
|
+
user = user_manager.get_user(user_name=user_name)
|
|
48
|
+
assert user.active
|
|
49
|
+
|
|
50
|
+
# Print user
|
|
51
|
+
user_manager.print_user(user=user_name)
|
|
52
|
+
|
|
53
|
+
finally:
|
|
54
|
+
# Delete user
|
|
55
|
+
user_manager.delete_user(user_name=user_name)
|
|
56
|
+
assert user_name not in [user.user_id for user in user_manager.get_all_users()]
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import pytest
|
|
2
2
|
import weaviate
|
|
3
|
-
import click
|
|
4
3
|
from click.testing import CliRunner
|
|
5
4
|
from weaviate_cli.managers.collection_manager import CollectionManager
|
|
6
5
|
from weaviate_cli.managers.config_manager import ConfigManager
|
|
@@ -12,11 +11,7 @@ import weaviate.classes.config as wvc
|
|
|
12
11
|
@pytest.fixture
|
|
13
12
|
def client() -> weaviate.Client:
|
|
14
13
|
config = ConfigManager()
|
|
15
|
-
return
|
|
16
|
-
host=config.config["host"],
|
|
17
|
-
port=int(config.config["http_port"]),
|
|
18
|
-
grpc_port=int(config.config["grpc_port"]),
|
|
19
|
-
)
|
|
14
|
+
return config.get_client()
|
|
20
15
|
|
|
21
16
|
|
|
22
17
|
@pytest.fixture
|
|
@@ -92,7 +92,7 @@ def test_create_tenants_defaults(runner):
|
|
|
92
92
|
mock_collection.tenants.get.return_value = empty_tenants
|
|
93
93
|
|
|
94
94
|
mock_tenants = {
|
|
95
|
-
f"{CreateTenantsDefaults.tenant_suffix}{i}": MagicMock(
|
|
95
|
+
f"{CreateTenantsDefaults.tenant_suffix}-{i}": MagicMock(
|
|
96
96
|
activity_status=TenantActivityStatus.ACTIVE
|
|
97
97
|
)
|
|
98
98
|
for i in range(CreateTenantsDefaults.number_tenants)
|
|
@@ -134,7 +134,19 @@ def test_create_data_defaults(runner):
|
|
|
134
134
|
# Create mock context with config
|
|
135
135
|
ctx = click.Context(create_data_cli)
|
|
136
136
|
ctx.obj = {"config": MagicMock()}
|
|
137
|
-
|
|
137
|
+
mock_client = MagicMock()
|
|
138
|
+
mock_client.collections.exists.return_value = True
|
|
139
|
+
|
|
140
|
+
# Mock collection object
|
|
141
|
+
mock_collection = MagicMock()
|
|
142
|
+
mock_client.collections.get.return_value = mock_collection
|
|
143
|
+
|
|
144
|
+
# Mock multi-tenancy config
|
|
145
|
+
mock_config = MagicMock()
|
|
146
|
+
mock_config.multi_tenancy_config.enabled = False
|
|
147
|
+
mock_collection.config.get.return_value = mock_config
|
|
148
|
+
|
|
149
|
+
ctx.obj["config"].get_client.return_value = mock_client
|
|
138
150
|
|
|
139
151
|
result = runner.invoke(create_data_cli, obj=ctx.obj)
|
|
140
152
|
assert result.exit_code == 0, result.output
|
|
@@ -179,7 +191,7 @@ def test_delete_tenants_defaults(runner):
|
|
|
179
191
|
|
|
180
192
|
# Mock tenants with side effect to return different values on subsequent calls
|
|
181
193
|
mock_tenants = {
|
|
182
|
-
f"{DeleteTenantsDefaults.tenant_suffix}{i}": MagicMock()
|
|
194
|
+
f"{DeleteTenantsDefaults.tenant_suffix}-{i}": MagicMock()
|
|
183
195
|
for i in range(1, DeleteTenantsDefaults.number_tenants + 1)
|
|
184
196
|
}
|
|
185
197
|
empty_tenants = {}
|
|
@@ -365,7 +377,7 @@ def test_update_tenants_defaults(runner):
|
|
|
365
377
|
|
|
366
378
|
# Mock tenants with side effect to return different values on subsequent calls
|
|
367
379
|
mock_tenants = {
|
|
368
|
-
f"{UpdateTenantsDefaults.tenant_suffix}{i}": MagicMock(
|
|
380
|
+
f"{UpdateTenantsDefaults.tenant_suffix}-{i}": MagicMock(
|
|
369
381
|
activity_status=TenantActivityStatus.ACTIVE
|
|
370
382
|
)
|
|
371
383
|
for i in range(UpdateTenantsDefaults.number_tenants)
|
|
@@ -373,7 +385,7 @@ def test_update_tenants_defaults(runner):
|
|
|
373
385
|
mock_collection.tenants.get.return_value = mock_tenants
|
|
374
386
|
|
|
375
387
|
updated_tenants = {
|
|
376
|
-
f"{UpdateTenantsDefaults.tenant_suffix}{i}": MagicMock(
|
|
388
|
+
f"{UpdateTenantsDefaults.tenant_suffix}-{i}": MagicMock(
|
|
377
389
|
activity_status=TenantActivityStatus.ACTIVE
|
|
378
390
|
)
|
|
379
391
|
for i in range(UpdateTenantsDefaults.number_tenants)
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from unittest.mock import Mock, patch
|
|
3
|
+
from weaviate_cli.managers.user_manager import UserManager
|
|
4
|
+
from weaviate.exceptions import WeaviateConnectionError
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@pytest.fixture
|
|
8
|
+
def mock_client():
|
|
9
|
+
client = Mock()
|
|
10
|
+
return client
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@pytest.fixture
|
|
14
|
+
def user_manager(mock_client):
|
|
15
|
+
return UserManager(mock_client)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def test_get_user_from_role_success(user_manager):
|
|
19
|
+
# Arrange
|
|
20
|
+
role_name = "test_role"
|
|
21
|
+
expected_users = ["user1", "user2"]
|
|
22
|
+
user_manager.client.roles.get_assigned_user_ids.return_value = expected_users
|
|
23
|
+
|
|
24
|
+
# Act
|
|
25
|
+
result = user_manager.get_user_from_role(role_name)
|
|
26
|
+
|
|
27
|
+
# Assert
|
|
28
|
+
assert result == expected_users
|
|
29
|
+
user_manager.client.roles.get_assigned_user_ids.assert_called_once_with(
|
|
30
|
+
role_name=role_name
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def test_get_user_from_role_error(user_manager):
|
|
35
|
+
# Arrange
|
|
36
|
+
role_name = "test_role"
|
|
37
|
+
user_manager.client.roles.get_assigned_user_ids.side_effect = Exception(
|
|
38
|
+
"Test error"
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
# Act & Assert
|
|
42
|
+
with pytest.raises(Exception) as exc_info:
|
|
43
|
+
user_manager.get_user_from_role(role_name)
|
|
44
|
+
assert (
|
|
45
|
+
str(exc_info.value) == f"Error getting users for role '{role_name}': Test error"
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def test_create_user_success(user_manager):
|
|
50
|
+
# Arrange
|
|
51
|
+
user_name = "test_user"
|
|
52
|
+
expected_api_key = "test_api_key"
|
|
53
|
+
user_manager.client.users.db.create.return_value = expected_api_key
|
|
54
|
+
|
|
55
|
+
# Act
|
|
56
|
+
result = user_manager.create_user(user_name)
|
|
57
|
+
|
|
58
|
+
# Assert
|
|
59
|
+
assert result == expected_api_key
|
|
60
|
+
user_manager.client.users.db.create.assert_called_once_with(user_id=user_name)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def test_create_user_no_name(user_manager):
|
|
64
|
+
# Act & Assert
|
|
65
|
+
with pytest.raises(Exception) as exc_info:
|
|
66
|
+
user_manager.create_user(None)
|
|
67
|
+
assert str(exc_info.value) == "User name is required."
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def test_create_user_error(user_manager):
|
|
71
|
+
# Arrange
|
|
72
|
+
user_name = "test_user"
|
|
73
|
+
user_manager.client.users.db.create.side_effect = Exception("Test error")
|
|
74
|
+
|
|
75
|
+
# Act & Assert
|
|
76
|
+
with pytest.raises(Exception) as exc_info:
|
|
77
|
+
user_manager.create_user(user_name)
|
|
78
|
+
assert str(exc_info.value) == f"Error creating user '{user_name}': Test error"
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def test_update_user_rotate_key_success(user_manager):
|
|
82
|
+
# Arrange
|
|
83
|
+
user_name = "test_user"
|
|
84
|
+
expected_api_key = "new_api_key"
|
|
85
|
+
user_manager.client.users.db.rotate_key.return_value = expected_api_key
|
|
86
|
+
|
|
87
|
+
# Act
|
|
88
|
+
result = user_manager.update_user(user_name=user_name, rotate_api_key=True)
|
|
89
|
+
|
|
90
|
+
# Assert
|
|
91
|
+
assert result == expected_api_key
|
|
92
|
+
user_manager.client.users.db.rotate_key.assert_called_once_with(user_id=user_name)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def test_update_user_activate_success(user_manager):
|
|
96
|
+
# Arrange
|
|
97
|
+
user_name = "test_user"
|
|
98
|
+
user_manager.client.users.db.activate.return_value = None
|
|
99
|
+
|
|
100
|
+
# Act
|
|
101
|
+
result = user_manager.update_user(user_name=user_name, activate=True)
|
|
102
|
+
|
|
103
|
+
# Assert
|
|
104
|
+
assert result is None
|
|
105
|
+
user_manager.client.users.db.activate.assert_called_once_with(user_id=user_name)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def test_update_user_deactivate_success(user_manager):
|
|
109
|
+
# Arrange
|
|
110
|
+
user_name = "test_user"
|
|
111
|
+
user_manager.client.users.db.deactivate.return_value = None
|
|
112
|
+
|
|
113
|
+
# Act
|
|
114
|
+
result = user_manager.update_user(user_name=user_name, deactivate=True)
|
|
115
|
+
|
|
116
|
+
# Assert
|
|
117
|
+
assert result is None
|
|
118
|
+
user_manager.client.users.db.deactivate.assert_called_once_with(user_id=user_name)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def test_update_user_invalid_combination(user_manager):
|
|
122
|
+
# Arrange
|
|
123
|
+
user_name = "test_user"
|
|
124
|
+
|
|
125
|
+
# Act & Assert
|
|
126
|
+
with pytest.raises(Exception) as exc_info:
|
|
127
|
+
user_manager.update_user(
|
|
128
|
+
user_name=user_name, rotate_api_key=True, activate=True
|
|
129
|
+
)
|
|
130
|
+
assert (
|
|
131
|
+
str(exc_info.value)
|
|
132
|
+
== "Cannot rotate api key and activate or deactivate user at the same time."
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def test_update_user_activate_deactivate(user_manager):
|
|
137
|
+
# Arrange
|
|
138
|
+
user_name = "test_user"
|
|
139
|
+
|
|
140
|
+
# Act & Assert
|
|
141
|
+
with pytest.raises(Exception) as exc_info:
|
|
142
|
+
user_manager.update_user(user_name=user_name, activate=True, deactivate=True)
|
|
143
|
+
assert (
|
|
144
|
+
str(exc_info.value) == "Cannot activate and deactivate user at the same time."
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def test_update_user_no_name(user_manager):
|
|
149
|
+
# Act & Assert
|
|
150
|
+
with pytest.raises(Exception) as exc_info:
|
|
151
|
+
user_manager.update_user(None)
|
|
152
|
+
assert str(exc_info.value) == "User name is required."
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def test_update_user_error(user_manager):
|
|
156
|
+
# Arrange
|
|
157
|
+
user_name = "test_user"
|
|
158
|
+
user_manager.client.users.db.rotate_key.side_effect = Exception("Test error")
|
|
159
|
+
|
|
160
|
+
# Act & Assert
|
|
161
|
+
with pytest.raises(Exception) as exc_info:
|
|
162
|
+
user_manager.update_user(user_name=user_name, rotate_api_key=True)
|
|
163
|
+
assert str(exc_info.value) == f"Error updating user '{user_name}': Test error"
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def test_delete_user_success(user_manager):
|
|
167
|
+
# Arrange
|
|
168
|
+
user_name = "test_user"
|
|
169
|
+
|
|
170
|
+
# Act
|
|
171
|
+
user_manager.delete_user(user_name)
|
|
172
|
+
|
|
173
|
+
# Assert
|
|
174
|
+
user_manager.client.users.db.delete.assert_called_once_with(user_id=user_name)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def test_delete_user_no_name(user_manager):
|
|
178
|
+
# Act & Assert
|
|
179
|
+
with pytest.raises(Exception) as exc_info:
|
|
180
|
+
user_manager.delete_user(None)
|
|
181
|
+
assert str(exc_info.value) == "User name is required."
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def test_delete_user_error(user_manager):
|
|
185
|
+
# Arrange
|
|
186
|
+
user_name = "test_user"
|
|
187
|
+
user_manager.client.users.db.delete.side_effect = Exception("Test error")
|
|
188
|
+
|
|
189
|
+
# Act & Assert
|
|
190
|
+
with pytest.raises(Exception) as exc_info:
|
|
191
|
+
user_manager.delete_user(user_name)
|
|
192
|
+
assert str(exc_info.value) == f"Error deleting user '{user_name}': Test error"
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def test_add_role_db_success(user_manager):
|
|
196
|
+
# Arrange
|
|
197
|
+
role_name = ("test_role",)
|
|
198
|
+
user_name = "test_user"
|
|
199
|
+
user_manager.client.get_meta.return_value = {"version": "1.30.0"}
|
|
200
|
+
|
|
201
|
+
# Act
|
|
202
|
+
user_manager.add_role(role_name, user_name, "db")
|
|
203
|
+
|
|
204
|
+
# Assert
|
|
205
|
+
user_manager.client.users.db.assign_roles.assert_called_once_with(
|
|
206
|
+
user_id=user_name, role_names=list(role_name)
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def test_add_role_db_success_pre_130(user_manager):
|
|
211
|
+
# Arrange
|
|
212
|
+
role_name = ("test_role",)
|
|
213
|
+
user_name = "test_user"
|
|
214
|
+
user_manager.client.get_meta.return_value = {"version": "1.29.0"}
|
|
215
|
+
|
|
216
|
+
# Act
|
|
217
|
+
user_manager.add_role(role_name, user_name, "db")
|
|
218
|
+
|
|
219
|
+
# Assert
|
|
220
|
+
user_manager.client.users.assign_roles.assert_called_once_with(
|
|
221
|
+
user_id=user_name, role_names=list(role_name)
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def test_add_role_oidc_success(user_manager):
|
|
226
|
+
# Arrange
|
|
227
|
+
role_name = ("test_role",)
|
|
228
|
+
user_name = "test_user"
|
|
229
|
+
user_manager.client.get_meta.return_value = {"version": "1.30.0"}
|
|
230
|
+
|
|
231
|
+
# Act
|
|
232
|
+
user_manager.add_role(role_name, user_name, "oidc")
|
|
233
|
+
|
|
234
|
+
# Assert
|
|
235
|
+
user_manager.client.users.oidc.assign_roles.assert_called_once_with(
|
|
236
|
+
user_id=user_name, role_names=list(role_name)
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def test_add_role_error(user_manager):
|
|
241
|
+
# Arrange
|
|
242
|
+
role_name = ("test_role",)
|
|
243
|
+
user_name = "test_user"
|
|
244
|
+
user_manager.client.get_meta.return_value = {"version": "1.30.0"}
|
|
245
|
+
user_manager.client.users.db.assign_roles.side_effect = Exception("Test error")
|
|
246
|
+
|
|
247
|
+
# Act & Assert
|
|
248
|
+
with pytest.raises(Exception) as exc_info:
|
|
249
|
+
user_manager.add_role(role_name, user_name, "db")
|
|
250
|
+
assert (
|
|
251
|
+
str(exc_info.value)
|
|
252
|
+
== f"Error assigning db role '{role_name}' to user '{user_name}': Test error"
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def test_revoke_role_db_success(user_manager):
|
|
257
|
+
# Arrange
|
|
258
|
+
role_name = ("test_role",)
|
|
259
|
+
user_name = "test_user"
|
|
260
|
+
user_manager.client.get_meta.return_value = {"version": "1.30.0"}
|
|
261
|
+
|
|
262
|
+
# Act
|
|
263
|
+
user_manager.revoke_role(role_name, user_name, "db")
|
|
264
|
+
|
|
265
|
+
# Assert
|
|
266
|
+
user_manager.client.users.db.revoke_roles.assert_called_once_with(
|
|
267
|
+
user_id=user_name, role_names=list(role_name)
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
def test_revoke_role_db_success_pre_130(user_manager):
|
|
272
|
+
# Arrange
|
|
273
|
+
role_name = ("test_role",)
|
|
274
|
+
user_name = "test_user"
|
|
275
|
+
user_manager.client.get_meta.return_value = {"version": "1.29.0"}
|
|
276
|
+
|
|
277
|
+
# Act
|
|
278
|
+
user_manager.revoke_role(role_name, user_name, "db")
|
|
279
|
+
|
|
280
|
+
# Assert
|
|
281
|
+
user_manager.client.users.revoke_roles.assert_called_once_with(
|
|
282
|
+
user_id=user_name, role_names=list(role_name)
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def test_revoke_role_oidc_success(user_manager):
|
|
287
|
+
# Arrange
|
|
288
|
+
role_name = ("test_role",)
|
|
289
|
+
user_name = "test_user"
|
|
290
|
+
user_manager.client.get_meta.return_value = {"version": "1.30.0"}
|
|
291
|
+
# Act
|
|
292
|
+
user_manager.revoke_role(role_name, user_name, "oidc")
|
|
293
|
+
|
|
294
|
+
# Assert
|
|
295
|
+
user_manager.client.users.oidc.revoke_roles.assert_called_once_with(
|
|
296
|
+
user_id=user_name, role_names=list(role_name)
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
def test_revoke_role_error(user_manager):
|
|
301
|
+
# Arrange
|
|
302
|
+
role_name = ("test_role",)
|
|
303
|
+
user_name = "test_user"
|
|
304
|
+
user_manager.client.users.db.revoke_roles.side_effect = Exception("Test error")
|
|
305
|
+
user_manager.client.get_meta.return_value = {"version": "1.30.0"}
|
|
306
|
+
|
|
307
|
+
# Act & Assert
|
|
308
|
+
with pytest.raises(Exception) as exc_info:
|
|
309
|
+
user_manager.revoke_role(role_name, user_name, "db")
|
|
310
|
+
assert (
|
|
311
|
+
str(exc_info.value)
|
|
312
|
+
== f"Error revoking db role '{role_name}' from user '{user_name}': Test error"
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
def test_print_user(user_manager, capsys):
|
|
317
|
+
# Arrange
|
|
318
|
+
user = "test_user"
|
|
319
|
+
|
|
320
|
+
# Act
|
|
321
|
+
user_manager.print_user(user)
|
|
322
|
+
|
|
323
|
+
# Assert
|
|
324
|
+
captured = capsys.readouterr()
|
|
325
|
+
assert captured.out == f"User: {user}\n"
|
|
@@ -222,10 +222,26 @@ def test_parse_permission_roles():
|
|
|
222
222
|
|
|
223
223
|
|
|
224
224
|
def test_parse_permission_users():
|
|
225
|
+
assert parse_permission("create_users:admin") == Permissions.users(
|
|
226
|
+
user="admin", create=True
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
assert parse_permission("crud_users:admin") == Permissions.users(
|
|
230
|
+
user="admin", create=True, read=True, update=True, delete=True
|
|
231
|
+
)
|
|
232
|
+
|
|
225
233
|
assert parse_permission("assign_and_revoke_users:admin") == Permissions.users(
|
|
226
234
|
user="admin", assign_and_revoke=True
|
|
227
235
|
)
|
|
228
236
|
|
|
237
|
+
assert parse_permission("cr_users:admin1,admin2,viewer1") == Permissions.users(
|
|
238
|
+
user=["admin1", "admin2", "viewer1"],
|
|
239
|
+
create=True,
|
|
240
|
+
read=True,
|
|
241
|
+
update=False,
|
|
242
|
+
delete=False,
|
|
243
|
+
)
|
|
244
|
+
|
|
229
245
|
assert parse_permission(
|
|
230
246
|
"assign_and_revoke_users:admin,admin1,admin2"
|
|
231
247
|
) == Permissions.users(user=["admin", "admin1", "admin2"], assign_and_revoke=True)
|