crate 1.0.0__py3-none-any.whl → 1.0.0.dev1__py3-none-any.whl
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.
- crate/client/__init__.py +3 -3
- crate/client/blob.py +7 -9
- crate/client/connection.py +52 -58
- crate/client/converter.py +10 -15
- crate/client/cursor.py +51 -55
- crate/client/exceptions.py +3 -5
- crate/client/http.py +160 -192
- crate/client/test_connection.py +98 -0
- crate/client/test_cursor.py +341 -0
- crate/client/test_exceptions.py +14 -0
- crate/client/test_http.py +678 -0
- crate/client/test_util.py +69 -0
- crate/client/tests.py +340 -0
- crate/testing/__init__.py +1 -0
- crate/testing/layer.py +102 -140
- crate/testing/settings.py +51 -0
- crate/testing/test_datetime_old.py +90 -0
- crate/testing/test_layer.py +290 -0
- crate/testing/tests.py +34 -0
- crate/testing/util.py +5 -80
- crate-1.0.0.dev1-py3.9-nspkg.pth +1 -0
- {crate-1.0.0.dist-info → crate-1.0.0.dev1.dist-info}/LICENSE +70 -0
- {crate-1.0.0.dist-info → crate-1.0.0.dev1.dist-info}/METADATA +21 -19
- {crate-1.0.0.dist-info → crate-1.0.0.dev1.dist-info}/NOTICE +1 -1
- crate-1.0.0.dev1.dist-info/RECORD +29 -0
- {crate-1.0.0.dist-info → crate-1.0.0.dev1.dist-info}/WHEEL +1 -1
- crate-1.0.0.dev1.dist-info/top_level.txt +1 -0
- crate/__init__.py +0 -0
- crate-1.0.0.dist-info/RECORD +0 -18
- /crate-1.0.0.dist-info/top_level.txt → /crate-1.0.0.dev1.dist-info/namespace_packages.txt +0 -0
crate/testing/layer.py
CHANGED
@@ -19,44 +19,38 @@
|
|
19
19
|
# with Crate these terms will supersede the license and you may use the
|
20
20
|
# software solely pursuant to the terms of the relevant commercial agreement.
|
21
21
|
|
22
|
-
# ruff: noqa: S603 # `subprocess` call: check for execution of untrusted input
|
23
|
-
# ruff: noqa: S202 # Uses of `tarfile.extractall()`
|
24
|
-
|
25
|
-
import io
|
26
|
-
import json
|
27
|
-
import logging
|
28
22
|
import os
|
29
23
|
import re
|
24
|
+
import sys
|
25
|
+
import time
|
26
|
+
import json
|
27
|
+
import urllib3
|
28
|
+
import tempfile
|
30
29
|
import shutil
|
31
30
|
import subprocess
|
32
|
-
import sys
|
33
31
|
import tarfile
|
34
|
-
import
|
32
|
+
import io
|
35
33
|
import threading
|
36
|
-
import
|
37
|
-
|
38
|
-
import urllib3
|
34
|
+
import logging
|
39
35
|
|
40
36
|
try:
|
41
37
|
from urllib.request import urlopen
|
42
38
|
except ImportError:
|
43
|
-
from urllib import urlopen
|
39
|
+
from urllib import urlopen
|
44
40
|
|
45
41
|
|
46
42
|
log = logging.getLogger(__name__)
|
47
43
|
|
48
44
|
|
49
|
-
CRATE_CONFIG_ERROR =
|
50
|
-
'crate_config must point to a folder or to a file named "crate.yml"'
|
51
|
-
)
|
45
|
+
CRATE_CONFIG_ERROR = 'crate_config must point to a folder or to a file named "crate.yml"'
|
52
46
|
HTTP_ADDRESS_RE = re.compile(
|
53
|
-
r
|
54
|
-
|
55
|
-
r
|
56
|
-
r
|
57
|
-
r
|
58
|
-
r
|
59
|
-
|
47
|
+
r'.*\[(http|.*HttpServer.*)\s*] \[.*\] .*'
|
48
|
+
'publish_address {'
|
49
|
+
r'(?:inet\[[\w\d\.-]*/|\[)?'
|
50
|
+
r'(?:[\w\d\.-]+/)?'
|
51
|
+
r'(?P<addr>[\d\.:]+)'
|
52
|
+
r'(?:\])?'
|
53
|
+
'}'
|
60
54
|
)
|
61
55
|
|
62
56
|
|
@@ -67,22 +61,18 @@ def http_url_from_host_port(host, port):
|
|
67
61
|
port = int(port)
|
68
62
|
except ValueError:
|
69
63
|
return None
|
70
|
-
return
|
64
|
+
return '{}:{}'.format(prepend_http(host), port)
|
71
65
|
return None
|
72
66
|
|
73
67
|
|
74
68
|
def prepend_http(host):
|
75
|
-
if not re.match(r
|
76
|
-
return
|
69
|
+
if not re.match(r'^https?\:\/\/.*', host):
|
70
|
+
return 'http://{}'.format(host)
|
77
71
|
return host
|
78
72
|
|
79
73
|
|
80
74
|
def _download_and_extract(uri, directory):
|
81
|
-
sys.stderr.write(
|
82
|
-
"\nINFO: Downloading CrateDB archive from {} into {}".format(
|
83
|
-
uri, directory
|
84
|
-
)
|
85
|
-
)
|
75
|
+
sys.stderr.write("\nINFO: Downloading CrateDB archive from {} into {}".format(uri, directory))
|
86
76
|
sys.stderr.flush()
|
87
77
|
with io.BytesIO(urlopen(uri).read()) as tmpfile:
|
88
78
|
with tarfile.open(fileobj=tmpfile) as t:
|
@@ -92,18 +82,19 @@ def _download_and_extract(uri, directory):
|
|
92
82
|
def wait_for_http_url(log, timeout=30, verbose=False):
|
93
83
|
start = time.monotonic()
|
94
84
|
while True:
|
95
|
-
line = log.readline().decode(
|
85
|
+
line = log.readline().decode('utf-8').strip()
|
96
86
|
elapsed = time.monotonic() - start
|
97
87
|
if verbose:
|
98
|
-
sys.stderr.write(
|
88
|
+
sys.stderr.write('[{:>4.1f}s]{}\n'.format(elapsed, line))
|
99
89
|
m = HTTP_ADDRESS_RE.match(line)
|
100
90
|
if m:
|
101
|
-
return prepend_http(m.group(
|
91
|
+
return prepend_http(m.group('addr'))
|
102
92
|
elif elapsed > timeout:
|
103
93
|
return None
|
104
94
|
|
105
95
|
|
106
96
|
class OutputMonitor:
|
97
|
+
|
107
98
|
def __init__(self):
|
108
99
|
self.consumers = []
|
109
100
|
|
@@ -114,9 +105,7 @@ class OutputMonitor:
|
|
114
105
|
|
115
106
|
def start(self, proc):
|
116
107
|
self._stop_out_thread = threading.Event()
|
117
|
-
self._out_thread = threading.Thread(
|
118
|
-
target=self.consume, args=(proc.stdout,)
|
119
|
-
)
|
108
|
+
self._out_thread = threading.Thread(target=self.consume, args=(proc.stdout,))
|
120
109
|
self._out_thread.daemon = True
|
121
110
|
self._out_thread.start()
|
122
111
|
|
@@ -127,6 +116,7 @@ class OutputMonitor:
|
|
127
116
|
|
128
117
|
|
129
118
|
class LineBuffer:
|
119
|
+
|
130
120
|
def __init__(self):
|
131
121
|
self.lines = []
|
132
122
|
|
@@ -134,7 +124,7 @@ class LineBuffer:
|
|
134
124
|
self.lines.append(line.strip())
|
135
125
|
|
136
126
|
|
137
|
-
class CrateLayer:
|
127
|
+
class CrateLayer(object):
|
138
128
|
"""
|
139
129
|
This layer starts a Crate server.
|
140
130
|
"""
|
@@ -145,16 +135,14 @@ class CrateLayer:
|
|
145
135
|
wait_interval = 0.2
|
146
136
|
|
147
137
|
@staticmethod
|
148
|
-
def from_uri(
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
verbose=False,
|
157
|
-
):
|
138
|
+
def from_uri(uri,
|
139
|
+
name,
|
140
|
+
http_port='4200-4299',
|
141
|
+
transport_port='4300-4399',
|
142
|
+
settings=None,
|
143
|
+
directory=None,
|
144
|
+
cleanup=True,
|
145
|
+
verbose=False):
|
158
146
|
"""Download the Crate tarball from a URI and create a CrateLayer
|
159
147
|
|
160
148
|
:param uri: The uri that points to the Crate tarball
|
@@ -170,14 +158,11 @@ class CrateLayer:
|
|
170
158
|
"""
|
171
159
|
directory = directory or tempfile.mkdtemp()
|
172
160
|
filename = os.path.basename(uri)
|
173
|
-
crate_dir = re.sub(r
|
161
|
+
crate_dir = re.sub(r'\.tar(\.gz)?$', '', filename)
|
174
162
|
crate_home = os.path.join(directory, crate_dir)
|
175
163
|
|
176
164
|
if os.path.exists(crate_home):
|
177
|
-
sys.stderr.write(
|
178
|
-
"\nWARNING: Not extracting CrateDB tarball"
|
179
|
-
" because folder already exists"
|
180
|
-
)
|
165
|
+
sys.stderr.write("\nWARNING: Not extracting Crate tarball because folder already exists")
|
181
166
|
sys.stderr.flush()
|
182
167
|
else:
|
183
168
|
_download_and_extract(uri, directory)
|
@@ -188,33 +173,29 @@ class CrateLayer:
|
|
188
173
|
port=http_port,
|
189
174
|
transport_port=transport_port,
|
190
175
|
settings=settings,
|
191
|
-
verbose=verbose
|
192
|
-
)
|
176
|
+
verbose=verbose)
|
193
177
|
if cleanup:
|
194
178
|
tearDown = layer.tearDown
|
195
179
|
|
196
180
|
def new_teardown(*args, **kws):
|
197
181
|
shutil.rmtree(directory)
|
198
182
|
tearDown(*args, **kws)
|
199
|
-
|
200
|
-
layer.tearDown = new_teardown # type: ignore[method-assign]
|
183
|
+
layer.tearDown = new_teardown
|
201
184
|
return layer
|
202
185
|
|
203
|
-
def __init__(
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
env=None,
|
217
|
-
):
|
186
|
+
def __init__(self,
|
187
|
+
name,
|
188
|
+
crate_home,
|
189
|
+
crate_config=None,
|
190
|
+
port=None,
|
191
|
+
keepRunning=False,
|
192
|
+
transport_port=None,
|
193
|
+
crate_exec=None,
|
194
|
+
cluster_name=None,
|
195
|
+
host="127.0.0.1",
|
196
|
+
settings=None,
|
197
|
+
verbose=False,
|
198
|
+
env=None):
|
218
199
|
"""
|
219
200
|
:param name: layer name, is also used as the cluser name
|
220
201
|
:param crate_home: path to home directory of the crate installation
|
@@ -235,69 +216,52 @@ class CrateLayer:
|
|
235
216
|
self.__name__ = name
|
236
217
|
if settings and isinstance(settings, dict):
|
237
218
|
# extra settings may override host/port specification!
|
238
|
-
self.http_url = http_url_from_host_port(
|
239
|
-
|
240
|
-
settings.get("http.port", port),
|
241
|
-
)
|
219
|
+
self.http_url = http_url_from_host_port(settings.get('network.host', host),
|
220
|
+
settings.get('http.port', port))
|
242
221
|
else:
|
243
222
|
self.http_url = http_url_from_host_port(host, port)
|
244
223
|
|
245
224
|
self.process = None
|
246
225
|
self.verbose = verbose
|
247
226
|
self.env = env or {}
|
248
|
-
self.env.setdefault(
|
249
|
-
self.env.setdefault(
|
227
|
+
self.env.setdefault('CRATE_USE_IPV4', 'true')
|
228
|
+
self.env.setdefault('JAVA_HOME', os.environ.get('JAVA_HOME', ''))
|
250
229
|
self._stdout_consumers = []
|
251
230
|
self.conn_pool = urllib3.PoolManager(num_pools=1)
|
252
231
|
|
253
232
|
crate_home = os.path.abspath(crate_home)
|
254
233
|
if crate_exec is None:
|
255
|
-
start_script =
|
256
|
-
crate_exec = os.path.join(crate_home,
|
234
|
+
start_script = 'crate.bat' if sys.platform == 'win32' else 'crate'
|
235
|
+
crate_exec = os.path.join(crate_home, 'bin', start_script)
|
257
236
|
if crate_config is None:
|
258
|
-
crate_config = os.path.join(crate_home,
|
259
|
-
elif (
|
260
|
-
|
261
|
-
and os.path.basename(crate_config) != "crate.yml"
|
262
|
-
):
|
237
|
+
crate_config = os.path.join(crate_home, 'config', 'crate.yml')
|
238
|
+
elif (os.path.isfile(crate_config) and
|
239
|
+
os.path.basename(crate_config) != 'crate.yml'):
|
263
240
|
raise ValueError(CRATE_CONFIG_ERROR)
|
264
241
|
if cluster_name is None:
|
265
|
-
cluster_name = "Testing{0}".format(port or
|
266
|
-
settings = self.create_settings(
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
settings,
|
274
|
-
)
|
242
|
+
cluster_name = "Testing{0}".format(port or 'Dynamic')
|
243
|
+
settings = self.create_settings(crate_config,
|
244
|
+
cluster_name,
|
245
|
+
name,
|
246
|
+
host,
|
247
|
+
port or '4200-4299',
|
248
|
+
transport_port or '4300-4399',
|
249
|
+
settings)
|
275
250
|
# ES 5 cannot parse 'True'/'False' as booleans so convert to lowercase
|
276
|
-
start_cmd = (crate_exec,) + tuple(
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
def create_settings(
|
292
|
-
self,
|
293
|
-
crate_config,
|
294
|
-
cluster_name,
|
295
|
-
node_name,
|
296
|
-
host,
|
297
|
-
http_port,
|
298
|
-
transport_port,
|
299
|
-
further_settings=None,
|
300
|
-
):
|
251
|
+
start_cmd = (crate_exec, ) + tuple(["-C%s=%s" % ((key, str(value).lower()) if isinstance(value, bool) else (key, value))
|
252
|
+
for key, value in settings.items()])
|
253
|
+
|
254
|
+
self._wd = wd = os.path.join(CrateLayer.tmpdir, 'crate_layer', name)
|
255
|
+
self.start_cmd = start_cmd + ('-Cpath.data=%s' % wd,)
|
256
|
+
|
257
|
+
def create_settings(self,
|
258
|
+
crate_config,
|
259
|
+
cluster_name,
|
260
|
+
node_name,
|
261
|
+
host,
|
262
|
+
http_port,
|
263
|
+
transport_port,
|
264
|
+
further_settings=None):
|
301
265
|
settings = {
|
302
266
|
"discovery.type": "zen",
|
303
267
|
"discovery.initial_state_timeout": 0,
|
@@ -330,23 +294,20 @@ class CrateLayer:
|
|
330
294
|
|
331
295
|
def start(self):
|
332
296
|
self._clean()
|
333
|
-
self.process = subprocess.Popen(
|
334
|
-
|
335
|
-
|
297
|
+
self.process = subprocess.Popen(self.start_cmd,
|
298
|
+
env=self.env,
|
299
|
+
stdout=subprocess.PIPE)
|
336
300
|
returncode = self.process.poll()
|
337
301
|
if returncode is not None:
|
338
302
|
raise SystemError(
|
339
|
-
|
340
|
-
|
341
|
-
)
|
303
|
+
'Failed to start server rc={0} cmd={1}'.format(returncode,
|
304
|
+
self.start_cmd)
|
342
305
|
)
|
343
306
|
|
344
307
|
if not self.http_url:
|
345
308
|
# try to read http_url from startup logs
|
346
309
|
# this is necessary if no static port is assigned
|
347
|
-
self.http_url = wait_for_http_url(
|
348
|
-
self.process.stdout, verbose=self.verbose
|
349
|
-
)
|
310
|
+
self.http_url = wait_for_http_url(self.process.stdout, verbose=self.verbose)
|
350
311
|
|
351
312
|
self.monitor = OutputMonitor()
|
352
313
|
self.monitor.start(self.process)
|
@@ -354,10 +315,10 @@ class CrateLayer:
|
|
354
315
|
if not self.http_url:
|
355
316
|
self.stop()
|
356
317
|
else:
|
357
|
-
sys.stderr.write(
|
318
|
+
sys.stderr.write('HTTP: {}\n'.format(self.http_url))
|
358
319
|
self._wait_for_start()
|
359
320
|
self._wait_for_master()
|
360
|
-
sys.stderr.write(
|
321
|
+
sys.stderr.write('\nCrate instance ready.\n')
|
361
322
|
|
362
323
|
def stop(self):
|
363
324
|
self.conn_pool.clear()
|
@@ -391,9 +352,10 @@ class CrateLayer:
|
|
391
352
|
for line in line_buf.lines:
|
392
353
|
log.error(line)
|
393
354
|
self.stop()
|
394
|
-
raise SystemError(
|
395
|
-
|
396
|
-
|
355
|
+
raise SystemError('Failed to start Crate instance in time.')
|
356
|
+
else:
|
357
|
+
sys.stderr.write('.')
|
358
|
+
time.sleep(self.wait_interval)
|
397
359
|
|
398
360
|
self.monitor.consumers.remove(line_buf)
|
399
361
|
|
@@ -405,7 +367,7 @@ class CrateLayer:
|
|
405
367
|
# after the layer starts don't result in 503
|
406
368
|
def validator():
|
407
369
|
try:
|
408
|
-
resp = self.conn_pool.request(
|
370
|
+
resp = self.conn_pool.request('HEAD', self.http_url)
|
409
371
|
return resp.status == 200
|
410
372
|
except Exception:
|
411
373
|
return False
|
@@ -417,12 +379,12 @@ class CrateLayer:
|
|
417
379
|
|
418
380
|
def validator():
|
419
381
|
resp = self.conn_pool.urlopen(
|
420
|
-
|
421
|
-
|
422
|
-
headers={
|
423
|
-
body='{"stmt": "select master_node from sys.cluster"}'
|
382
|
+
'POST',
|
383
|
+
'{server}/_sql'.format(server=self.http_url),
|
384
|
+
headers={'Content-Type': 'application/json'},
|
385
|
+
body='{"stmt": "select master_node from sys.cluster"}'
|
424
386
|
)
|
425
|
-
data = json.loads(resp.data.decode(
|
426
|
-
return resp.status == 200 and data[
|
387
|
+
data = json.loads(resp.data.decode('utf-8'))
|
388
|
+
return resp.status == 200 and data['rows'][0][0]
|
427
389
|
|
428
390
|
self._wait_for(validator)
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# vi: set encoding=utf-8
|
2
|
+
# -*- coding: utf-8; -*-
|
3
|
+
#
|
4
|
+
# Licensed to CRATE Technology GmbH ("Crate") under one or more contributor
|
5
|
+
# license agreements. See the NOTICE file distributed with this work for
|
6
|
+
# additional information regarding copyright ownership. Crate licenses
|
7
|
+
# this file to you under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License. You may
|
9
|
+
# obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
15
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
16
|
+
# License for the specific language governing permissions and limitations
|
17
|
+
# under the License.
|
18
|
+
#
|
19
|
+
# However, if you have executed another commercial license agreement
|
20
|
+
# with Crate these terms will supersede the license and you may use the
|
21
|
+
# software solely pursuant to the terms of the relevant commercial agreement.
|
22
|
+
from __future__ import absolute_import
|
23
|
+
|
24
|
+
import os
|
25
|
+
|
26
|
+
|
27
|
+
def docs_path(*parts):
|
28
|
+
return os.path.abspath(
|
29
|
+
os.path.join(
|
30
|
+
os.path.dirname(os.path.dirname(__file__)), *parts
|
31
|
+
)
|
32
|
+
)
|
33
|
+
|
34
|
+
|
35
|
+
def project_root(*parts):
|
36
|
+
return os.path.abspath(
|
37
|
+
os.path.join(docs_path("..", ".."), *parts)
|
38
|
+
)
|
39
|
+
|
40
|
+
|
41
|
+
def crate_path(*parts):
|
42
|
+
return os.path.abspath(
|
43
|
+
project_root("parts", "crate", *parts)
|
44
|
+
)
|
45
|
+
|
46
|
+
|
47
|
+
crate_port = 44209
|
48
|
+
crate_transport_port = 44309
|
49
|
+
localhost = '127.0.0.1'
|
50
|
+
crate_host = "{host}:{port}".format(host=localhost, port=crate_port)
|
51
|
+
crate_uri = "http://%s" % crate_host
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# -*- coding: utf-8; -*-
|
2
|
+
#
|
3
|
+
# Licensed to CRATE Technology GmbH ("Crate") under one or more contributor
|
4
|
+
# license agreements. See the NOTICE file distributed with this work for
|
5
|
+
# additional information regarding copyright ownership. Crate licenses
|
6
|
+
# this file to you under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License. You may
|
8
|
+
# obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
14
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
15
|
+
# License for the specific language governing permissions and limitations
|
16
|
+
# under the License.
|
17
|
+
#
|
18
|
+
# However, if you have executed another commercial license agreement
|
19
|
+
# with Crate these terms will supersede the license and you may use the
|
20
|
+
# software solely pursuant to the terms of the relevant commercial agreement.
|
21
|
+
|
22
|
+
import os
|
23
|
+
import sys
|
24
|
+
import unittest
|
25
|
+
from datetime import datetime, date
|
26
|
+
from unittest import TestCase, mock
|
27
|
+
|
28
|
+
import time_machine
|
29
|
+
|
30
|
+
|
31
|
+
class DateTodayTest(TestCase):
|
32
|
+
"""
|
33
|
+
`date.today()` returns the current local date, as advertised in the
|
34
|
+
documentation [1]. Thus, it depends on the system time zone.
|
35
|
+
|
36
|
+
The following test cases demonstrate that the test suite previously
|
37
|
+
failed around midnight, where the UTC vs. non-UTC days overlapped,
|
38
|
+
and when running on machines with non-UTC time zone.
|
39
|
+
|
40
|
+
On the other hand, `datetime.utcnow().date()` works equally well in all
|
41
|
+
situations, so we want to use that within the SQLAlchemy test cases.
|
42
|
+
|
43
|
+
Funny enough, the problem is not observable on Linux?
|
44
|
+
|
45
|
+
[1] https://docs.python.org/3/library/datetime.html#datetime.date.today
|
46
|
+
"""
|
47
|
+
|
48
|
+
@mock.patch.dict(os.environ, {"TZ": "UTC"})
|
49
|
+
@time_machine.travel("2022-07-22T00:42:00+0200")
|
50
|
+
def test_date_today_depends_on_system_timezone_success_on_utc(self):
|
51
|
+
today_local = date.today()
|
52
|
+
today_utc = datetime.utcnow().date()
|
53
|
+
self.assertEqual(today_local, today_utc)
|
54
|
+
self.assertEqual(today_local, date(2022, 7, 21))
|
55
|
+
self.assertEqual(today_utc, date(2022, 7, 21))
|
56
|
+
|
57
|
+
@unittest.skipIf(sys.platform == "linux", "Problem not observable on Linux")
|
58
|
+
@mock.patch.dict(os.environ, {"TZ": "Europe/Prague"})
|
59
|
+
@time_machine.travel("2022-07-22T00:42:00+0200")
|
60
|
+
def test_date_today_depends_on_system_timezone_failure_on_non_utc(self):
|
61
|
+
today_local = date.today()
|
62
|
+
today_utc = datetime.utcnow().date()
|
63
|
+
self.assertNotEqual(today_local, today_utc)
|
64
|
+
self.assertEqual(today_local, date(2022, 7, 22))
|
65
|
+
self.assertEqual(today_utc, date(2022, 7, 21))
|
66
|
+
|
67
|
+
@mock.patch.dict(os.environ, {"TZ": "UTC"})
|
68
|
+
@time_machine.travel("2022-07-22T00:42:00+0200")
|
69
|
+
def test_date_today_utc(self):
|
70
|
+
today_local = date.today()
|
71
|
+
self.assertEqual(today_local, date(2022, 7, 21))
|
72
|
+
|
73
|
+
@unittest.skipIf(sys.platform == "linux", "Problem not observable on Linux")
|
74
|
+
@mock.patch.dict(os.environ, {"TZ": "Europe/Prague"})
|
75
|
+
@time_machine.travel("2022-07-22T00:42:00+0200")
|
76
|
+
def test_date_today_non_utc(self):
|
77
|
+
today_local = date.today()
|
78
|
+
self.assertEqual(today_local, date(2022, 7, 22))
|
79
|
+
|
80
|
+
@mock.patch.dict(os.environ, {"TZ": "UTC"})
|
81
|
+
@time_machine.travel("2022-07-22T00:42:00+0200")
|
82
|
+
def test_utcnow_date_utc(self):
|
83
|
+
today_utc = datetime.utcnow().date()
|
84
|
+
self.assertEqual(today_utc, date(2022, 7, 21))
|
85
|
+
|
86
|
+
@mock.patch.dict(os.environ, {"TZ": "Europe/Prague"})
|
87
|
+
@time_machine.travel("2022-07-22T00:42:00+0200")
|
88
|
+
def test_utcnow_date_non_utc(self):
|
89
|
+
today_utc = datetime.utcnow().date()
|
90
|
+
self.assertEqual(today_utc, date(2022, 7, 21))
|