pyrelukko 0.5.0__tar.gz → 0.6.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.

Potentially problematic release.


This version of pyrelukko might be problematic. Click here for more details.

Files changed (33) hide show
  1. {pyrelukko-0.5.0 → pyrelukko-0.6.0}/.gitlab-ci.yml +16 -51
  2. {pyrelukko-0.5.0 → pyrelukko-0.6.0}/PKG-INFO +1 -1
  3. pyrelukko-0.6.0/cicd/run_docs_pages.sh +11 -0
  4. pyrelukko-0.6.0/cicd/run_pylint.sh +11 -0
  5. pyrelukko-0.6.0/cicd/run_pytest.sh +11 -0
  6. pyrelukko-0.6.0/cicd/run_shellcheck.sh +11 -0
  7. pyrelukko-0.6.0/cicd/tox_docs_pages.sh +17 -0
  8. pyrelukko-0.5.0/cicd/run_shellcheck.sh → pyrelukko-0.6.0/cicd/tox_shellcheck.sh +1 -1
  9. {pyrelukko-0.5.0 → pyrelukko-0.6.0}/pyproject.toml +63 -12
  10. {pyrelukko-0.5.0 → pyrelukko-0.6.0}/src/pyrelukko/pyrelukko.py +48 -20
  11. {pyrelukko-0.5.0 → pyrelukko-0.6.0}/src/pyrelukko/version.py +1 -1
  12. {pyrelukko-0.5.0 → pyrelukko-0.6.0}/tests/test_relukko.py +195 -0
  13. pyrelukko-0.5.0/cicd/build-py-rf-image.sh +0 -48
  14. pyrelukko-0.5.0/cicd/run_docs_pages.sh +0 -17
  15. pyrelukko-0.5.0/cicd/run_pylint.sh +0 -24
  16. pyrelukko-0.5.0/cicd/run_pytest.sh +0 -15
  17. pyrelukko-0.5.0/container/Containerfile +0 -5
  18. pyrelukko-0.5.0/container/requirements.txt +0 -5
  19. {pyrelukko-0.5.0 → pyrelukko-0.6.0}/LICENSE +0 -0
  20. {pyrelukko-0.5.0 → pyrelukko-0.6.0}/README.md +0 -0
  21. {pyrelukko-0.5.0 → pyrelukko-0.6.0}/src/pyrelukko/__init__.py +0 -0
  22. {pyrelukko-0.5.0 → pyrelukko-0.6.0}/src/pyrelukko/retry.py +0 -0
  23. {pyrelukko-0.5.0 → pyrelukko-0.6.0}/src/pyrelukko/testcontainers.py +0 -0
  24. {pyrelukko-0.5.0 → pyrelukko-0.6.0}/tests/cert/5d868fca.0 +0 -0
  25. {pyrelukko-0.5.0 → pyrelukko-0.6.0}/tests/cert/README.md +0 -0
  26. {pyrelukko-0.5.0 → pyrelukko-0.6.0}/tests/cert/relukko.crt +0 -0
  27. {pyrelukko-0.5.0 → pyrelukko-0.6.0}/tests/cert/relukko.csr +0 -0
  28. {pyrelukko-0.5.0 → pyrelukko-0.6.0}/tests/cert/relukko.key +0 -0
  29. {pyrelukko-0.5.0 → pyrelukko-0.6.0}/tests/cert/rootCA.crt +0 -0
  30. {pyrelukko-0.5.0 → pyrelukko-0.6.0}/tests/cert/rootCA.der +0 -0
  31. {pyrelukko-0.5.0 → pyrelukko-0.6.0}/tests/cert/rootCA.key +0 -0
  32. {pyrelukko-0.5.0 → pyrelukko-0.6.0}/tests/cert/rootCA.srl +0 -0
  33. {pyrelukko-0.5.0 → pyrelukko-0.6.0}/tests/conftest.py +0 -0
@@ -1,18 +1,11 @@
1
1
  variables:
2
2
  FF_TIMESTAMPS: true
3
- BUILD_IMAGE:
4
- description: Used in rules, if "true" and web triggered it builds the image!
3
+ RUN_PYLINT:
4
+ description: Used in rules, if "true" and web triggered run pylint.
5
5
  value: "false"
6
6
  options:
7
7
  - "false"
8
8
  - "true"
9
- IMAGE_NAME: py-rf-image
10
- IMAGE_TAG:
11
- description: >-
12
- The "tag" added to the image name for the test / lint image.
13
- Remove this when you trigger by hand an image build and want it to use
14
- the new built image with Git short sha tag (X icon on the right)!
15
- value: "latest"
16
9
  RUN_PYTEST:
17
10
  description: Used in rules, if "true" and web triggered run the pytests.
18
11
  value: "false"
@@ -36,44 +29,9 @@ variables:
36
29
  # - "true"
37
30
 
38
31
 
39
- build-py-rf-image:
40
- stage: build
41
- image: docker:25
42
- services:
43
- - name: docker:25-dind
44
- alias: docker
45
- before_script:
46
- - docker info
47
- before_script:
48
- - echo "Login to Gitlab container registry"
49
- - echo "$CI_REGISTRY_PASSWORD" | docker login --username $CI_REGISTRY_USER --password-stdin $CI_REGISTRY
50
- script:
51
- - echo "Build container image..."
52
- - ./cicd/build-py-rf-image.sh
53
- - echo "Export IMAGE_TAG var to next stage!"
54
- - echo "IMAGE_TAG=${CI_COMMIT_SHORT_SHA}" > image_tag.env
55
- - echo "Build complete."
56
- artifacts:
57
- reports:
58
- dotenv: image_tag.env
59
- rules:
60
- - if: $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
61
- changes:
62
- - .gitlab-ci.yml
63
- - cicd/build-py-rf-image.sh
64
- - container/**/*
65
- - if: $CI_PIPELINE_SOURCE == "merge_request_event" && $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH
66
- changes:
67
- - .gitlab-ci.yml
68
- - cicd/build-py-rf-image.sh
69
- - container/**/*
70
- - if: $CI_PIPELINE_SOURCE == "web" && $BUILD_IMAGE == "true"
71
- when: always
72
-
73
-
74
32
  run-pylint:
75
33
  stage: test
76
- image: "${CI_REGISTRY_IMAGE}/${IMAGE_NAME}:${IMAGE_TAG}"
34
+ image: "registry.gitlab.com/relukko/py-tox-images/py-3.13-tox"
77
35
  rules:
78
36
  - if: $CI_PIPELINE_SOURCE == "merge_request_event" && $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH
79
37
  changes:
@@ -81,6 +39,8 @@ run-pylint:
81
39
  - if: $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
82
40
  changes:
83
41
  - src/**/*.py
42
+ - if: $CI_PIPELINE_SOURCE == "web" && $RUN_PYLINT == "true"
43
+ when: always
84
44
  before_script:
85
45
  - echo "Running PyLint."
86
46
  script:
@@ -135,14 +95,18 @@ run-pytest:
135
95
  when: always
136
96
  expire_in: 2 week
137
97
  paths:
138
- - pytest-junit.xml
98
+ - pytest-junit*.xml
99
+ - log*.html
100
+ - output*.xml
101
+ - xunit*.xml
139
102
  reports:
140
- junit: pytest-junit.xml
103
+ junit:
104
+ - pytest-junit*.xml
105
+ - xunit*.xml
141
106
 
142
-
143
107
  run-shellcheck:
144
108
  stage: test
145
- image: "${CI_REGISTRY_IMAGE}/${IMAGE_NAME}:${IMAGE_TAG}"
109
+ image: "registry.gitlab.com/relukko/py-tox-images/py-3.13-tox"
146
110
  rules:
147
111
  - if: $CI_PIPELINE_SOURCE == "merge_request_event" && $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH
148
112
  changes:
@@ -154,10 +118,11 @@ run-shellcheck:
154
118
  - echo "Running ShellCheck."
155
119
  script:
156
120
  - ./cicd/run_shellcheck.sh
157
-
121
+
122
+
158
123
  # pages:
159
124
  # stage: deploy
160
- # image: "${CI_REGISTRY_IMAGE}/${IMAGE_NAME}:${IMAGE_TAG}"
125
+ # image: "registry.gitlab.com/relukko/py-tox-images/py-3.13-tox"
161
126
  # rules:
162
127
  # - if: $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
163
128
  # changes:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: pyrelukko
3
- Version: 0.5.0
3
+ Version: 0.6.0
4
4
  Summary: Relukko client.
5
5
  Author-email: Reto Zingg <g.d0b3rm4n@gmail.com>
6
6
  Requires-Python: >=3.10
@@ -0,0 +1,11 @@
1
+ #!/bin/bash
2
+
3
+ # Main script execution
4
+ main() {
5
+ tox run -e docs
6
+ }
7
+
8
+ # Execute the main function
9
+ main
10
+
11
+ # vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
@@ -0,0 +1,11 @@
1
+ #!/bin/bash
2
+
3
+ # Main script execution
4
+ main() {
5
+ tox run -e pylint
6
+ }
7
+
8
+ # Execute the main function
9
+ main
10
+
11
+ # vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
@@ -0,0 +1,11 @@
1
+ #!/bin/bash
2
+
3
+ # Main script execution
4
+ main() {
5
+ tox run --skip-missing-interpreters --skip-env 'pylint|shellcheck|docs'
6
+ }
7
+
8
+ # Execute the main function
9
+ main
10
+
11
+ # vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
@@ -0,0 +1,11 @@
1
+ #!/bin/bash
2
+
3
+ # Main script execution
4
+ main() {
5
+ tox run -e shellcheck
6
+ }
7
+
8
+ # Execute the main function
9
+ main
10
+
11
+ # vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
@@ -0,0 +1,17 @@
1
+ #!/bin/bash
2
+
3
+ # SCRIPT_DIR=$(dirname "$(readlink -f "$0")")
4
+ # REPO_DIR="$(readlink -f "${SCRIPT_DIR}/..")"
5
+ # PUBLIC_DIR="${REPO_DIR}/public"
6
+
7
+ # Main script execution
8
+ main() {
9
+ # mkdir -p "${PUBLIC_DIR}"
10
+ # libdoc --pythonpath ./src Relukko "${PUBLIC_DIR}/index.html"
11
+ echo "Not Implemented yet"
12
+ }
13
+
14
+ # Execute the main function
15
+ main
16
+
17
+ # vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
@@ -1,7 +1,7 @@
1
1
  #!/bin/bash
2
2
 
3
3
  SCRIPT_DIR=$(dirname "$(readlink -f "$0")")
4
- REPO_DIR="${SCRIPT_DIR}/.."
4
+ REPO_DIR="$(readlink -f "${SCRIPT_DIR}/..")"
5
5
 
6
6
  # Main script execution
7
7
  main() {
@@ -23,6 +23,21 @@ dependencies = [
23
23
  "websockets >= 14.1",
24
24
  ]
25
25
 
26
+ [dependency-groups]
27
+ test = [
28
+ "httpx",
29
+ "pytest >= 8",
30
+ "requests-mock >= 1.12",
31
+ "testcontainers",
32
+ ]
33
+ lint = [
34
+ "pylint >= 3",
35
+ "pylint-json2html"
36
+ ]
37
+ coverage = [
38
+ "pytest-cov"
39
+ ]
40
+
26
41
  [tool.flit.sdist]
27
42
  exclude = [".gitignore", "demo.py"]
28
43
 
@@ -34,6 +49,16 @@ Issues = "https://gitlab.com/relukko/pyrelukko/-/issues"
34
49
  requires = ["flit_core >=3.2,<4", "semantic-version >= 2.10"]
35
50
  build-backend = "flit_core.buildapi"
36
51
 
52
+ [tool.pylint.main]
53
+ # Files or directories to be skipped. They should be base names, not paths.
54
+ ignore = ["LICENSE", "pyproject.toml", "version.py",
55
+ "README.md", "demo.py", "conftest.py", ".tox"]
56
+
57
+ # Files or directories matching the regular expression patterns are skipped. The
58
+ # regex matches against base names, not paths. The default value ignores Emacs
59
+ # file locks
60
+ ignore-patterns = ["^\\.#", "^test_"]
61
+
37
62
  [tool.pytest.ini_options]
38
63
  testpaths = [
39
64
  "tests",
@@ -41,24 +66,50 @@ testpaths = [
41
66
  pythonpath = [
42
67
  "src",
43
68
  ]
69
+ log_cli = "True"
44
70
 
45
71
  [tool.tox]
46
72
  requires = ["tox>=4.23"]
47
- env_list = ["3.11", "3.12", "3.13"]
73
+ env_list = [
74
+ "3.11",
75
+ "3.12",
76
+ "3.13",
77
+ "pylint",
78
+ "shellcheck",
79
+ "docs"
80
+ ]
48
81
 
49
82
  [tool.tox.env_run_base]
50
83
  description = "Run test under {base_python}"
51
- commands = [["pytest", "--junit-xml", "pytest-junit.xml"]]
52
- deps = ["httpx", "pytest", "testcontainers"]
53
- # set_env = { VIRTUALENV_DISCOVERY = "pyenv" }
84
+ commands = [["pytest", "--junit-xml", "pytest-junit-{env_name}.xml", "--junit-prefix", "{env_name}"]]
54
85
  pass_env = [ "TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE", "DOCKER_HOST", "CI_HAS_RELUKKO", "CI_RELUKKO_*" ]
86
+ dependency_groups = [ "test" ]
55
87
 
56
- [tool.pylint.main]
57
- # Files or directories to be skipped. They should be base names, not paths.
58
- ignore = ["LICENSE", "pyproject.toml", "version.py",
59
- "README.md", "demo.py", "conftest.py", ".tox"]
88
+ [tool.tox.env.pylint]
89
+ description = "Run PyLint with {base_python}"
90
+ dependency_groups = [ "lint" ]
91
+ commands = [[
92
+ "pylint",
93
+ "--verbose",
94
+ "--rcfile",
95
+ "./pyproject.toml",
96
+ "--output-format=json:{tox_root}/pylint.out.json,parseable:{tox_root}/pylint.out.txt,text",
97
+ ".",
98
+ ]
99
+ ]
100
+ commands_post = [
101
+ [
102
+ "pylint-json2html",
103
+ "-o",
104
+ "{tox_root}/pylint.out.html",
105
+ "{tox_root}/pylint.out.json",
106
+ ]
107
+ ]
60
108
 
61
- # Files or directories matching the regular expression patterns are skipped. The
62
- # regex matches against base names, not paths. The default value ignores Emacs
63
- # file locks
64
- ignore-patterns = ["^\\.#", "^test_"]
109
+ [tool.tox.env.shellcheck]
110
+ allowlist_externals = ["shellcheck", "{tox_root}/cicd/tox_shellcheck.sh"]
111
+ commands = [[ "{tox_root}/cicd/tox_shellcheck.sh" ]]
112
+
113
+ [tool.tox.env.docs]
114
+ allowlist_externals = ["{tox_root}/cicd/tox_docs_pages.sh"]
115
+ commands = [[ "{tox_root}/cicd/tox_docs_pages.sh" ]]
@@ -39,6 +39,8 @@ RETRY_KWARGS = [
39
39
  OWN_KWARGS = [
40
40
  'acquire_wait_for_timeout',
41
41
  'acquire_modulo',
42
+ 'disable_websocket',
43
+ 'raise_when_acquire_fails',
42
44
  'ws_ping_interval',
43
45
  'ws_ping_timeout',
44
46
  'ws_wait_for_timeout',
@@ -75,11 +77,13 @@ class RelukkoClient:
75
77
  )
76
78
  self._setup_session(api_key, **kwargs)
77
79
  self._setup_http_adapters_retry(**kwargs)
78
- self.ws_wait_for_timeout = 2
80
+ self.acquire_modulo = 100
81
+ self.acquire_wait_for_timeout = 2
82
+ self.disable_websocket = False
83
+ self.raise_when_acquire_fails = True
79
84
  self.ws_ping_interval = 60
80
85
  self.ws_ping_timeout = 20
81
- self.acquire_wait_for_timeout = 2
82
- self.acquire_modulo = 100
86
+ self.ws_wait_for_timeout = 2
83
87
  self._setup_pyrelukko_kwargs(**kwargs)
84
88
 
85
89
  self.base_url = self._setup_base_url(base_url)
@@ -224,22 +228,29 @@ class RelukkoClient:
224
228
  if elapsed_time > max_run_time:
225
229
  self.ws_running.clear()
226
230
  _thread_store.insert(0, None)
227
- return
231
+ break
228
232
  # If self.message_recieved is True try to get lock ASAP!
229
233
  # Otherwise only in every Xth run in case websocket broke.
230
234
  if got_message or loop_counter % self.acquire_modulo == 0:
231
- res = self._make_request(
232
- url=url, method="POST", payload=payload)
235
+ try:
236
+ res = self._make_request(
237
+ url=url, method="POST", payload=payload)
238
+ except (
239
+ *self.exceptions, RuntimeError, requests.HTTPError) as e:
240
+ logger.warning("Last exception was: %s!\nGiving up!", e)
241
+ _thread_store.insert(0, e)
242
+ break
233
243
  loop_counter += 1
234
244
  if res is None:
235
245
  # Conflict 409
236
246
  got_message = self.message_received.wait(
237
247
  timeout=self.acquire_wait_for_timeout)
238
248
  self.message_received.clear()
239
- else:
240
- _thread_store.insert(0, res)
241
- self.ws_running.clear()
242
- return
249
+ continue
250
+
251
+ _thread_store.insert(0, res)
252
+ self.ws_running.clear()
253
+ break
243
254
 
244
255
  def _check_response(self, response: requests.Response):
245
256
  match response.status_code:
@@ -247,20 +258,27 @@ class RelukkoClient:
247
258
  return response.json()
248
259
  case 400 | 403:
249
260
  err = response.json()
250
- logger.warning(err.get('status'), err.get('message'))
261
+ logger.warning("4xx HTTP Error [%d](%s) - %s:%s",
262
+ response.status_code, response.reason,
263
+ str(err.get('status')), err.get('message'))
251
264
  response.raise_for_status()
252
265
  case 409:
253
266
  err = response.json()
254
- logger.info(err.get('status'), err.get('message'))
267
+ logger.warning("409 HTTP Error [%d](%s) - %s:%s",
268
+ response.status_code, response.reason,
269
+ str(err.get('status')), err.get('message'))
255
270
  return None
256
271
  case 500 | 502 | 503 | 504:
257
272
  logger.warning("[%d](%s) %s",
258
273
  response.status_code, response.reason, response.text)
259
- raise RelukkoDoRetry()
274
+ raise RelukkoDoRetry(
275
+ f"5xx HTTP Error: [{response.status_code}]"
276
+ f"({response.reason})")
260
277
  case _:
261
278
  logger.warning("[%d](%s) %s",
262
279
  response.status_code, response.reason, response.text)
263
- raise RuntimeError()
280
+ raise RuntimeError(
281
+ f"Give up: [{response.status_code}]({response.reason})")
264
282
 
265
283
  def _make_request(
266
284
  self,
@@ -293,10 +311,11 @@ class RelukkoClient:
293
311
 
294
312
  url = f"{self.base_url}/v1/locks/"
295
313
 
296
- self.ws_running.set()
297
- self.ws_listener = threading.Thread(
298
- target=asyncio.run, args=(self._websocket_listener(),))
299
- self.ws_listener.start()
314
+ if not self.disable_websocket:
315
+ self.ws_running.set()
316
+ self.ws_listener = threading.Thread(
317
+ target=asyncio.run, args=(self._websocket_listener(),))
318
+ self.ws_listener.start()
300
319
 
301
320
  thread_store = []
302
321
  http_thread = threading.Thread(
@@ -304,9 +323,18 @@ class RelukkoClient:
304
323
  args=(url, max_run_time, payload, thread_store))
305
324
  http_thread.start()
306
325
  http_thread.join()
307
- self.ws_listener.join()
308
326
 
309
- return thread_store[0]
327
+ if not self.disable_websocket:
328
+ self.ws_listener.join()
329
+
330
+ if thread_store:
331
+ if (
332
+ self.raise_when_acquire_fails
333
+ and isinstance(thread_store[0], Exception)
334
+ ):
335
+ raise thread_store[0]
336
+ return thread_store[0]
337
+ return None
310
338
 
311
339
  def get_lock(self, lock_id: str) -> Dict:
312
340
  """
@@ -1,2 +1,2 @@
1
1
  # pylint: disable=all
2
- __version__ = "0.5.0"
2
+ __version__ = "0.6.0"
@@ -8,6 +8,7 @@ from typing import Dict
8
8
 
9
9
  import pytest
10
10
  import requests
11
+ from requests_mock import ANY
11
12
  from requests.adapters import HTTPAdapter
12
13
  from requests.cookies import cookiejar_from_dict
13
14
  from urllib3.util import parse_url
@@ -19,6 +20,8 @@ from pyrelukko.retry import retry
19
20
 
20
21
  SCRIPT_DIR = Path(__file__).parent.absolute()
21
22
 
23
+ logging.basicConfig()
24
+ logging.getLogger().setLevel(logging.DEBUG)
22
25
  logger = logging.getLogger(__name__)
23
26
 
24
27
 
@@ -64,6 +67,8 @@ def test_init_relukko_client():
64
67
  assert relukko.ws_ping_timeout == 20
65
68
  assert relukko.acquire_wait_for_timeout == 2
66
69
  assert relukko.acquire_modulo == 100
70
+ assert relukko.disable_websocket == False
71
+ assert relukko.raise_when_acquire_fails == True
67
72
 
68
73
  with pytest.raises(ValueError):
69
74
  RelukkoClient(base_url=1000, api_key="")
@@ -179,6 +184,8 @@ def test_reconfigure_relukko_client():
179
184
  assert relukko.ws_ping_timeout == 20
180
185
  assert relukko.acquire_wait_for_timeout == 2
181
186
  assert relukko.acquire_modulo == 100
187
+ assert relukko.disable_websocket == False
188
+ assert relukko.raise_when_acquire_fails == True
182
189
 
183
190
 
184
191
  def test_reconfigure_relukko_client_extended():
@@ -204,6 +211,7 @@ def test_reconfigure_relukko_client_extended():
204
211
  ws_wait_for_timeout=ws_wait_for_timeout, acquire_modulo=acquire_modulo,
205
212
  ws_ping_interval=ws_ping_interval, ws_ping_timeout=ws_ping_timeout,
206
213
  acquire_wait_for_timeout=acquire_wait_for_timeout,
214
+ disable_websocket=True, raise_when_acquire_fails=False,
207
215
  )
208
216
 
209
217
  assert relukko.session.trust_env == False
@@ -241,6 +249,8 @@ def test_reconfigure_relukko_client_extended():
241
249
  assert relukko.ws_ping_timeout == ws_ping_timeout
242
250
  assert relukko.acquire_wait_for_timeout == acquire_wait_for_timeout
243
251
  assert relukko.acquire_modulo == acquire_modulo
252
+ assert relukko.disable_websocket == True
253
+ assert relukko.raise_when_acquire_fails == False
244
254
 
245
255
 
246
256
  def test_init_relukko_client_extented():
@@ -259,6 +269,7 @@ def test_init_relukko_client_extented():
259
269
  ws_wait_for_timeout=ws_wait_for_timeout, acquire_modulo=acquire_modulo,
260
270
  ws_ping_interval=ws_ping_interval, ws_ping_timeout=ws_ping_timeout,
261
271
  acquire_wait_for_timeout=acquire_wait_for_timeout,
272
+ disable_websocket=True, raise_when_acquire_fails=False,
262
273
  )
263
274
 
264
275
  assert relukko.session.trust_env == False
@@ -289,6 +300,8 @@ def test_init_relukko_client_extented():
289
300
  assert relukko.ws_ping_timeout == ws_ping_timeout
290
301
  assert relukko.acquire_wait_for_timeout == acquire_wait_for_timeout
291
302
  assert relukko.acquire_modulo == acquire_modulo
303
+ assert relukko.disable_websocket == True
304
+ assert relukko.raise_when_acquire_fails == False
292
305
 
293
306
 
294
307
  def test_init_relukko_client_ssl_ctx():
@@ -378,6 +391,188 @@ def test_reconfigre_relukko_client_retry():
378
391
  assert relukko.exceptions == exceptions
379
392
 
380
393
 
394
+ def test_aqcuire_http_status_code_400_with_raise(requests_mock):
395
+ requests_mock.register_uri(
396
+ ANY,
397
+ ANY,
398
+ status_code=400,
399
+ reason="Bad Request",
400
+ json={"status": 400, "message": "Bad Request"},
401
+ )
402
+
403
+ relukko = RelukkoClient(
404
+ base_url="http://relukko", api_key="key",
405
+ delay=1, backoff=1.01, disable_websocket=True,
406
+ )
407
+ with pytest.raises(requests.HTTPError):
408
+ relukko.acquire_relukko("400Lock", "PyTest", 300)
409
+
410
+
411
+ def test_aqcuire_http_status_code_400_without_raise(requests_mock):
412
+ requests_mock.register_uri(
413
+ ANY,
414
+ ANY,
415
+ status_code=400,
416
+ reason="Bad Request",
417
+ json={"status": 400, "message": "Bad Request"},
418
+ )
419
+
420
+ relukko = RelukkoClient(
421
+ base_url="http://relukko", api_key="key",disable_websocket=True,
422
+ delay=1, backoff=1.01, raise_when_acquire_fails=False,
423
+ )
424
+ lock = relukko.acquire_relukko("500Lock", "PyTest", 300)
425
+ assert isinstance(lock, requests.exceptions.HTTPError)
426
+
427
+
428
+ def test_aqcuire_http_status_code_418_with_raise(requests_mock):
429
+ requests_mock.register_uri(
430
+ ANY,
431
+ ANY,
432
+ status_code=418,
433
+ reason="I'm a teapot",
434
+ text="The server refuses the attempt to brew coffee with a teapot.",
435
+ )
436
+
437
+ relukko = RelukkoClient(
438
+ base_url="http://relukko", api_key="key",
439
+ delay=1, backoff=1.01, disable_websocket=True,
440
+ )
441
+ with pytest.raises(RuntimeError):
442
+ relukko.acquire_relukko("418Lock", "PyTest", 300)
443
+
444
+
445
+ def test_aqcuire_http_status_code_418_without_raise(requests_mock):
446
+ requests_mock.register_uri(
447
+ ANY,
448
+ ANY,
449
+ status_code=418,
450
+ reason="I'm a teapot",
451
+ text="The server refuses the attempt to brew coffee with a teapot.",
452
+ )
453
+
454
+ relukko = RelukkoClient(
455
+ base_url="http://relukko", api_key="key",disable_websocket=True,
456
+ delay=1, backoff=1.01, raise_when_acquire_fails=False,
457
+ )
458
+ lock = relukko.acquire_relukko("418Lock", "PyTest", 300)
459
+ assert isinstance(lock, RuntimeError)
460
+
461
+
462
+ def test_aqcuire_http_status_code_500_with_raise(requests_mock):
463
+ requests_mock.register_uri(
464
+ ANY,
465
+ ANY,
466
+ status_code=500,
467
+ reason="Internal Server Error",
468
+ )
469
+
470
+ relukko = RelukkoClient(
471
+ base_url="http://relukko", api_key="key",
472
+ delay=1, backoff=1.01, disable_websocket=True,
473
+ )
474
+ with pytest.raises(RelukkoDoRetry):
475
+ relukko.acquire_relukko("500Lock", "PyTest", 300)
476
+
477
+
478
+ def test_aqcuire_http_status_code_500_without_raise(requests_mock):
479
+ requests_mock.register_uri(
480
+ ANY,
481
+ ANY,
482
+ status_code=500,
483
+ reason="Internal Server Error",
484
+ )
485
+
486
+ relukko = RelukkoClient(
487
+ base_url="http://relukko", api_key="key",disable_websocket=True,
488
+ delay=1, backoff=1.01, raise_when_acquire_fails=False,
489
+ )
490
+ lock = relukko.acquire_relukko("500Lock", "PyTest", 300)
491
+ assert isinstance(lock, RelukkoDoRetry)
492
+
493
+
494
+ def test_aqcuire_relukko_retry_with_max_delay(requests_mock, caplog):
495
+ requests_mock.register_uri(
496
+ ANY,
497
+ ANY,
498
+ status_code=500,
499
+ reason="Internal Server Error",
500
+ )
501
+
502
+ relukko = RelukkoClient(
503
+ base_url="http://relukko", api_key="key",disable_websocket=True,
504
+ delay=1, backoff=3, raise_when_acquire_fails=False,
505
+ max_delay=2,
506
+ )
507
+
508
+ lock = relukko.acquire_relukko("MaxDelayLock", "PyTest", 300)
509
+
510
+ one_sec_count = 0
511
+ two_sec_count = 0
512
+ for record in caplog.records:
513
+ if "Retrying in 2 seconds..." in record.message:
514
+ two_sec_count += 1
515
+ elif "Retrying in 1 seconds..." in record.message:
516
+ one_sec_count += 1
517
+
518
+ assert one_sec_count == 1
519
+ assert two_sec_count == 2
520
+ assert isinstance(lock, RelukkoDoRetry)
521
+
522
+
523
+ def test_get_relukko_retry_400(requests_mock):
524
+ requests_mock.register_uri(
525
+ ANY,
526
+ ANY,
527
+ status_code=400,
528
+ reason="Bad Request",
529
+ json={"status": 400, "message": "Bad Request"},
530
+ )
531
+
532
+ relukko = RelukkoClient(
533
+ base_url="http://relukko", api_key="key",disable_websocket=True,
534
+ delay=1, backoff=0.5, raise_when_acquire_fails=False,
535
+ )
536
+
537
+ with pytest.raises(requests.HTTPError):
538
+ relukko.get_lock("GetLock400")
539
+
540
+
541
+ def test_get_relukko_retry_418(requests_mock):
542
+ requests_mock.register_uri(
543
+ ANY,
544
+ ANY,
545
+ status_code=418,
546
+ reason="I'm a teapot",
547
+ text="The server refuses the attempt to brew coffee with a teapot.",
548
+ )
549
+
550
+ relukko = RelukkoClient(
551
+ base_url="http://relukko", api_key="key",disable_websocket=True,
552
+ delay=1, backoff=0.5, raise_when_acquire_fails=False,
553
+ )
554
+
555
+ with pytest.raises(RuntimeError):
556
+ relukko.get_lock("GetLock418")
557
+
558
+
559
+ def test_get_relukko_retry_500(requests_mock):
560
+ requests_mock.register_uri(
561
+ ANY,
562
+ ANY,
563
+ status_code=500,
564
+ reason="Internal Server Error",
565
+ )
566
+
567
+ relukko = RelukkoClient(
568
+ base_url="http://relukko", api_key="key",disable_websocket=True,
569
+ delay=1, backoff=0.5, raise_when_acquire_fails=False,
570
+ )
571
+
572
+ with pytest.raises(RelukkoDoRetry):
573
+ relukko.get_lock("GetLock500")
574
+
575
+
381
576
  def test_acquire_relukko(relukko_backend):
382
577
  relukko, _ = relukko_backend
383
578
 
@@ -1,48 +0,0 @@
1
- #!/bin/sh
2
-
3
- set -e
4
-
5
- SCRIPT_DIR=$(dirname "$(readlink -f "$0")")
6
- REPO_DIR="${SCRIPT_DIR}/.."
7
- CONTAINER_DIR="${REPO_DIR}/container"
8
- CONTAINER_CMD="docker"
9
-
10
- # IMAGE_NAME should normally come from .gitlab-ci.yml file,
11
- # set default for local usage.
12
- if [ -z "${IMAGE_NAME+x}" ]; then
13
- IMAGE_NAME=py-rf-image-local
14
- fi
15
-
16
- cd "${CONTAINER_DIR}" || exit
17
-
18
- ${CONTAINER_CMD} build -t "${IMAGE_NAME}:latest" --file Containerfile .
19
-
20
- ${CONTAINER_CMD} images
21
-
22
- if [ -n "${CI_REGISTRY_IMAGE}" ]; then
23
- # In Gitlab
24
-
25
- # Tag with Git commit short sha and push
26
- IMAGE_WITH_GIT_SHA="${CI_REGISTRY_IMAGE}/${IMAGE_NAME}:${CI_COMMIT_SHORT_SHA}"
27
- echo "IMAGE_WITH_GIT_SHA: ${IMAGE_WITH_GIT_SHA}"
28
-
29
- ${CONTAINER_CMD} tag "${IMAGE_NAME}:latest" "${IMAGE_WITH_GIT_SHA}"
30
- ${CONTAINER_CMD} push "${IMAGE_WITH_GIT_SHA}"
31
-
32
- if [ "${CI_COMMIT_BRANCH}" = "${CI_DEFAULT_BRANCH}" ]; then
33
- # We run in default branch, also tag with latest
34
- # Tag with "latest" (overwrites last 'latest' in registry) and push
35
- IMAGE_WITH_LATEST="${CI_REGISTRY_IMAGE}/${IMAGE_NAME}:latest"
36
-
37
- echo "Tag image with as 'latest': ${IMAGE_WITH_LATEST}"
38
-
39
- ${CONTAINER_CMD} tag "${IMAGE_NAME}:latest" "${IMAGE_WITH_LATEST}"
40
- ${CONTAINER_CMD} push "${IMAGE_WITH_LATEST}"
41
- fi
42
- else
43
- echo "Runs locally, no pushing!"
44
- fi
45
-
46
- cd -
47
-
48
- # vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
@@ -1,17 +0,0 @@
1
- #!/bin/bash
2
-
3
- SCRIPT_DIR=$(dirname "$(readlink -f "$0")")
4
- REPO_DIR="${SCRIPT_DIR}/.."
5
- PUBLIC_DIR="${REPO_DIR}/public"
6
-
7
- # Main script execution
8
- main() {
9
- mkdir -p "${PUBLIC_DIR}"
10
- # libdoc --pythonpath ./src Relukko "${PUBLIC_DIR}/index.html"
11
- echo "Not Implemented yet"
12
- }
13
-
14
- # Execute the main function
15
- main
16
-
17
- # vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
@@ -1,24 +0,0 @@
1
- #!/bin/bash
2
-
3
- SCRIPT_DIR=$(dirname "$(readlink -f "$0")")
4
- REPO_DIR="${SCRIPT_DIR}/.."
5
-
6
- # Main script execution
7
- main() {
8
- pylint --verbose \
9
- --rcfile "${REPO_DIR}/pyproject.toml" \
10
- --output-format=json:pylint.out.json,parseable:pylint.out.txt,text \
11
- "${REPO_DIR}"
12
- pylint_exit_code=$?
13
-
14
- pylint-json2html \
15
- -o "${REPO_DIR}/pylint.out.html" \
16
- "${REPO_DIR}/pylint.out.json"
17
-
18
- return ${pylint_exit_code}
19
- }
20
-
21
- # Execute the main function
22
- main
23
-
24
- # vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
@@ -1,15 +0,0 @@
1
- #!/bin/bash
2
-
3
- # SCRIPT_DIR=$(dirname "$(readlink -f "$0")")
4
- # REPO_DIR="${SCRIPT_DIR}/.."
5
-
6
- # Main script execution
7
- main() {
8
- # pytest --junit-xml "${REPO_DIR}/pytest-junit.xml"
9
- tox run --skip-missing-interpreters
10
- }
11
-
12
- # Execute the main function
13
- main
14
-
15
- # vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
@@ -1,5 +0,0 @@
1
- FROM python:3.13-alpine
2
-
3
- RUN apk add --no-cache bash shellcheck
4
- COPY requirements.txt /opt/requirements.txt
5
- RUN pip install --no-cache-dir -r /opt/requirements.txt
@@ -1,5 +0,0 @@
1
- pylint==3.3.1
2
- pylint-json2html==0.5.0
3
- pytest==8.3.3
4
- requests==2.32.3
5
- websockets==13.1
File without changes
File without changes
File without changes