crate 0.35.1__py2.py3-none-any.whl → 1.0.0.dev0__py2.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 +1 -1
- crate/testing/test_datetime_old.py +90 -0
- crate-1.0.0.dev0-py3.11-nspkg.pth +1 -0
- {crate-0.35.1.dist-info → crate-1.0.0.dev0.dist-info}/METADATA +15 -19
- crate-1.0.0.dev0.dist-info/RECORD +26 -0
- {crate-0.35.1.dist-info → crate-1.0.0.dev0.dist-info}/WHEEL +1 -1
- crate/client/sqlalchemy/__init__.py +0 -50
- crate/client/sqlalchemy/compat/__init__.py +0 -0
- crate/client/sqlalchemy/compat/api13.py +0 -156
- crate/client/sqlalchemy/compat/core10.py +0 -264
- crate/client/sqlalchemy/compat/core14.py +0 -359
- crate/client/sqlalchemy/compat/core20.py +0 -447
- crate/client/sqlalchemy/compiler.py +0 -318
- crate/client/sqlalchemy/dialect.py +0 -369
- crate/client/sqlalchemy/predicates/__init__.py +0 -99
- crate/client/sqlalchemy/sa_version.py +0 -28
- crate/client/sqlalchemy/support.py +0 -62
- crate/client/sqlalchemy/tests/__init__.py +0 -59
- crate/client/sqlalchemy/tests/array_test.py +0 -111
- crate/client/sqlalchemy/tests/bulk_test.py +0 -256
- crate/client/sqlalchemy/tests/compiler_test.py +0 -434
- crate/client/sqlalchemy/tests/connection_test.py +0 -129
- crate/client/sqlalchemy/tests/create_table_test.py +0 -313
- crate/client/sqlalchemy/tests/datetime_test.py +0 -90
- crate/client/sqlalchemy/tests/dialect_test.py +0 -156
- crate/client/sqlalchemy/tests/dict_test.py +0 -460
- crate/client/sqlalchemy/tests/function_test.py +0 -47
- crate/client/sqlalchemy/tests/insert_from_select_test.py +0 -85
- crate/client/sqlalchemy/tests/match_test.py +0 -137
- crate/client/sqlalchemy/tests/query_caching.py +0 -143
- crate/client/sqlalchemy/tests/update_test.py +0 -115
- crate/client/sqlalchemy/tests/warnings_test.py +0 -64
- crate/client/sqlalchemy/types.py +0 -277
- crate/client/tests.py +0 -416
- crate/testing/tests.py +0 -34
- crate-0.35.1-py3.11-nspkg.pth +0 -1
- crate-0.35.1.dist-info/RECORD +0 -55
- crate-0.35.1.dist-info/entry_points.txt +0 -2
- {crate-0.35.1.dist-info → crate-1.0.0.dev0.dist-info}/LICENSE +0 -0
- {crate-0.35.1.dist-info → crate-1.0.0.dev0.dist-info}/NOTICE +0 -0
- {crate-0.35.1.dist-info → crate-1.0.0.dev0.dist-info}/namespace_packages.txt +0 -0
- {crate-0.35.1.dist-info → crate-1.0.0.dev0.dist-info}/top_level.txt +0 -0
crate/client/sqlalchemy/types.py
DELETED
@@ -1,277 +0,0 @@
|
|
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
|
-
import warnings
|
22
|
-
|
23
|
-
import sqlalchemy.types as sqltypes
|
24
|
-
from sqlalchemy.sql import operators, expression
|
25
|
-
from sqlalchemy.sql import default_comparator
|
26
|
-
from sqlalchemy.ext.mutable import Mutable
|
27
|
-
|
28
|
-
import geojson
|
29
|
-
|
30
|
-
|
31
|
-
class MutableList(Mutable, list):
|
32
|
-
|
33
|
-
@classmethod
|
34
|
-
def coerce(cls, key, value):
|
35
|
-
""" Convert plain list to MutableList """
|
36
|
-
if not isinstance(value, MutableList):
|
37
|
-
if isinstance(value, list):
|
38
|
-
return MutableList(value)
|
39
|
-
elif value is None:
|
40
|
-
return value
|
41
|
-
else:
|
42
|
-
return MutableList([value])
|
43
|
-
else:
|
44
|
-
return value
|
45
|
-
|
46
|
-
def __init__(self, initval=None):
|
47
|
-
list.__init__(self, initval or [])
|
48
|
-
|
49
|
-
def __setitem__(self, key, value):
|
50
|
-
list.__setitem__(self, key, value)
|
51
|
-
self.changed()
|
52
|
-
|
53
|
-
def __eq__(self, other):
|
54
|
-
return list.__eq__(self, other)
|
55
|
-
|
56
|
-
def append(self, item):
|
57
|
-
list.append(self, item)
|
58
|
-
self.changed()
|
59
|
-
|
60
|
-
def insert(self, idx, item):
|
61
|
-
list.insert(self, idx, item)
|
62
|
-
self.changed()
|
63
|
-
|
64
|
-
def extend(self, iterable):
|
65
|
-
list.extend(self, iterable)
|
66
|
-
self.changed()
|
67
|
-
|
68
|
-
def pop(self, index=-1):
|
69
|
-
list.pop(self, index)
|
70
|
-
self.changed()
|
71
|
-
|
72
|
-
def remove(self, item):
|
73
|
-
list.remove(self, item)
|
74
|
-
self.changed()
|
75
|
-
|
76
|
-
|
77
|
-
class MutableDict(Mutable, dict):
|
78
|
-
|
79
|
-
@classmethod
|
80
|
-
def coerce(cls, key, value):
|
81
|
-
"Convert plain dictionaries to MutableDict."
|
82
|
-
|
83
|
-
if not isinstance(value, MutableDict):
|
84
|
-
if isinstance(value, dict):
|
85
|
-
return MutableDict(value)
|
86
|
-
|
87
|
-
# this call will raise ValueError
|
88
|
-
return Mutable.coerce(key, value)
|
89
|
-
else:
|
90
|
-
return value
|
91
|
-
|
92
|
-
def __init__(self, initval=None, to_update=None, root_change_key=None):
|
93
|
-
initval = initval or {}
|
94
|
-
self._changed_keys = set()
|
95
|
-
self._deleted_keys = set()
|
96
|
-
self._overwrite_key = root_change_key
|
97
|
-
self.to_update = self if to_update is None else to_update
|
98
|
-
for k in initval:
|
99
|
-
initval[k] = self._convert_dict(initval[k],
|
100
|
-
overwrite_key=k if self._overwrite_key is None else self._overwrite_key
|
101
|
-
)
|
102
|
-
dict.__init__(self, initval)
|
103
|
-
|
104
|
-
def __setitem__(self, key, value):
|
105
|
-
value = self._convert_dict(value, key if self._overwrite_key is None else self._overwrite_key)
|
106
|
-
dict.__setitem__(self, key, value)
|
107
|
-
self.to_update.on_key_changed(
|
108
|
-
key if self._overwrite_key is None else self._overwrite_key
|
109
|
-
)
|
110
|
-
|
111
|
-
def __delitem__(self, key):
|
112
|
-
dict.__delitem__(self, key)
|
113
|
-
# add the key to the deleted keys if this is the root object
|
114
|
-
# otherwise update on root object
|
115
|
-
if self._overwrite_key is None:
|
116
|
-
self._deleted_keys.add(key)
|
117
|
-
self.changed()
|
118
|
-
else:
|
119
|
-
self.to_update.on_key_changed(self._overwrite_key)
|
120
|
-
|
121
|
-
def on_key_changed(self, key):
|
122
|
-
self._deleted_keys.discard(key)
|
123
|
-
self._changed_keys.add(key)
|
124
|
-
self.changed()
|
125
|
-
|
126
|
-
def _convert_dict(self, value, overwrite_key):
|
127
|
-
if isinstance(value, dict) and not isinstance(value, MutableDict):
|
128
|
-
return MutableDict(value, self.to_update, overwrite_key)
|
129
|
-
return value
|
130
|
-
|
131
|
-
def __eq__(self, other):
|
132
|
-
return dict.__eq__(self, other)
|
133
|
-
|
134
|
-
|
135
|
-
class ObjectTypeImpl(sqltypes.UserDefinedType, sqltypes.JSON):
|
136
|
-
|
137
|
-
__visit_name__ = "OBJECT"
|
138
|
-
|
139
|
-
cache_ok = False
|
140
|
-
none_as_null = False
|
141
|
-
|
142
|
-
|
143
|
-
# Designated name to refer to. `Object` is too ambiguous.
|
144
|
-
ObjectType = MutableDict.as_mutable(ObjectTypeImpl)
|
145
|
-
|
146
|
-
# Backward-compatibility aliases.
|
147
|
-
_deprecated_Craty = ObjectType
|
148
|
-
_deprecated_Object = ObjectType
|
149
|
-
|
150
|
-
# https://www.lesinskis.com/deprecating-module-scope-variables.html
|
151
|
-
deprecated_names = ["Craty", "Object"]
|
152
|
-
|
153
|
-
|
154
|
-
def __getattr__(name):
|
155
|
-
if name in deprecated_names:
|
156
|
-
warnings.warn(f"{name} is deprecated and will be removed in future releases. "
|
157
|
-
f"Please use ObjectType instead.", DeprecationWarning)
|
158
|
-
return globals()[f"_deprecated_{name}"]
|
159
|
-
raise AttributeError(f"module {__name__} has no attribute {name}")
|
160
|
-
|
161
|
-
|
162
|
-
class Any(expression.ColumnElement):
|
163
|
-
"""Represent the clause ``left operator ANY (right)``. ``right`` must be
|
164
|
-
an array expression.
|
165
|
-
|
166
|
-
copied from postgresql dialect
|
167
|
-
|
168
|
-
.. seealso::
|
169
|
-
|
170
|
-
:class:`sqlalchemy.dialects.postgresql.ARRAY`
|
171
|
-
|
172
|
-
:meth:`sqlalchemy.dialects.postgresql.ARRAY.Comparator.any`
|
173
|
-
ARRAY-bound method
|
174
|
-
|
175
|
-
"""
|
176
|
-
__visit_name__ = 'any'
|
177
|
-
inherit_cache = True
|
178
|
-
|
179
|
-
def __init__(self, left, right, operator=operators.eq):
|
180
|
-
self.type = sqltypes.Boolean()
|
181
|
-
self.left = expression.literal(left)
|
182
|
-
self.right = right
|
183
|
-
self.operator = operator
|
184
|
-
|
185
|
-
|
186
|
-
class _ObjectArray(sqltypes.UserDefinedType):
|
187
|
-
cache_ok = True
|
188
|
-
|
189
|
-
class Comparator(sqltypes.TypeEngine.Comparator):
|
190
|
-
def __getitem__(self, key):
|
191
|
-
return default_comparator._binary_operate(self.expr,
|
192
|
-
operators.getitem,
|
193
|
-
key)
|
194
|
-
|
195
|
-
def any(self, other, operator=operators.eq):
|
196
|
-
"""Return ``other operator ANY (array)`` clause.
|
197
|
-
|
198
|
-
Argument places are switched, because ANY requires array
|
199
|
-
expression to be on the right hand-side.
|
200
|
-
|
201
|
-
E.g.::
|
202
|
-
|
203
|
-
from sqlalchemy.sql import operators
|
204
|
-
|
205
|
-
conn.execute(
|
206
|
-
select([table.c.data]).where(
|
207
|
-
table.c.data.any(7, operator=operators.lt)
|
208
|
-
)
|
209
|
-
)
|
210
|
-
|
211
|
-
:param other: expression to be compared
|
212
|
-
:param operator: an operator object from the
|
213
|
-
:mod:`sqlalchemy.sql.operators`
|
214
|
-
package, defaults to :func:`.operators.eq`.
|
215
|
-
|
216
|
-
.. seealso::
|
217
|
-
|
218
|
-
:class:`.postgresql.Any`
|
219
|
-
|
220
|
-
:meth:`.postgresql.ARRAY.Comparator.all`
|
221
|
-
|
222
|
-
"""
|
223
|
-
return Any(other, self.expr, operator=operator)
|
224
|
-
|
225
|
-
type = MutableList
|
226
|
-
comparator_factory = Comparator
|
227
|
-
|
228
|
-
def get_col_spec(self, **kws):
|
229
|
-
return "ARRAY(OBJECT)"
|
230
|
-
|
231
|
-
|
232
|
-
ObjectArray = MutableList.as_mutable(_ObjectArray)
|
233
|
-
|
234
|
-
|
235
|
-
class Geopoint(sqltypes.UserDefinedType):
|
236
|
-
cache_ok = True
|
237
|
-
|
238
|
-
class Comparator(sqltypes.TypeEngine.Comparator):
|
239
|
-
|
240
|
-
def __getitem__(self, key):
|
241
|
-
return default_comparator._binary_operate(self.expr,
|
242
|
-
operators.getitem,
|
243
|
-
key)
|
244
|
-
|
245
|
-
def get_col_spec(self):
|
246
|
-
return 'GEO_POINT'
|
247
|
-
|
248
|
-
def bind_processor(self, dialect):
|
249
|
-
def process(value):
|
250
|
-
if isinstance(value, geojson.Point):
|
251
|
-
return value.coordinates
|
252
|
-
return value
|
253
|
-
return process
|
254
|
-
|
255
|
-
def result_processor(self, dialect, coltype):
|
256
|
-
return tuple
|
257
|
-
|
258
|
-
comparator_factory = Comparator
|
259
|
-
|
260
|
-
|
261
|
-
class Geoshape(sqltypes.UserDefinedType):
|
262
|
-
cache_ok = True
|
263
|
-
|
264
|
-
class Comparator(sqltypes.TypeEngine.Comparator):
|
265
|
-
|
266
|
-
def __getitem__(self, key):
|
267
|
-
return default_comparator._binary_operate(self.expr,
|
268
|
-
operators.getitem,
|
269
|
-
key)
|
270
|
-
|
271
|
-
def get_col_spec(self):
|
272
|
-
return 'GEO_SHAPE'
|
273
|
-
|
274
|
-
def result_processor(self, dialect, coltype):
|
275
|
-
return geojson.GeoJSON.to_instance
|
276
|
-
|
277
|
-
comparator_factory = Comparator
|
crate/client/tests.py
DELETED
@@ -1,416 +0,0 @@
|
|
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
|
-
from __future__ import absolute_import
|
23
|
-
|
24
|
-
import json
|
25
|
-
import os
|
26
|
-
import socket
|
27
|
-
import sys
|
28
|
-
import unittest
|
29
|
-
import doctest
|
30
|
-
from pprint import pprint
|
31
|
-
from http.server import HTTPServer, BaseHTTPRequestHandler
|
32
|
-
import ssl
|
33
|
-
import time
|
34
|
-
import threading
|
35
|
-
import logging
|
36
|
-
|
37
|
-
import stopit
|
38
|
-
|
39
|
-
from crate.testing.layer import CrateLayer
|
40
|
-
from crate.testing.settings import \
|
41
|
-
crate_host, crate_path, crate_port, \
|
42
|
-
crate_transport_port, docs_path, localhost
|
43
|
-
from crate.client import connect
|
44
|
-
from .sqlalchemy import SA_VERSION, SA_1_4
|
45
|
-
|
46
|
-
from .test_cursor import CursorTest
|
47
|
-
from .test_connection import ConnectionTest
|
48
|
-
from .test_http import (
|
49
|
-
HttpClientTest,
|
50
|
-
ThreadSafeHttpClientTest,
|
51
|
-
KeepAliveClientTest,
|
52
|
-
ParamsTest,
|
53
|
-
RetryOnTimeoutServerTest,
|
54
|
-
RequestsCaBundleTest,
|
55
|
-
TestUsernameSentAsHeader,
|
56
|
-
TestCrateJsonEncoder,
|
57
|
-
TestDefaultSchemaHeader,
|
58
|
-
)
|
59
|
-
from .sqlalchemy.tests import test_suite_unit as sqlalchemy_test_suite_unit
|
60
|
-
from .sqlalchemy.tests import test_suite_integration as sqlalchemy_test_suite_integration
|
61
|
-
|
62
|
-
makeSuite = unittest.TestLoader().loadTestsFromTestCase
|
63
|
-
|
64
|
-
log = logging.getLogger('crate.testing.layer')
|
65
|
-
ch = logging.StreamHandler()
|
66
|
-
ch.setLevel(logging.ERROR)
|
67
|
-
log.addHandler(ch)
|
68
|
-
|
69
|
-
|
70
|
-
def cprint(s):
|
71
|
-
if isinstance(s, bytes):
|
72
|
-
s = s.decode('utf-8')
|
73
|
-
print(s)
|
74
|
-
|
75
|
-
|
76
|
-
settings = {
|
77
|
-
'udc.enabled': 'false',
|
78
|
-
'lang.js.enabled': 'true',
|
79
|
-
'auth.host_based.enabled': 'true',
|
80
|
-
'auth.host_based.config.0.user': 'crate',
|
81
|
-
'auth.host_based.config.0.method': 'trust',
|
82
|
-
'auth.host_based.config.98.user': 'trusted_me',
|
83
|
-
'auth.host_based.config.98.method': 'trust',
|
84
|
-
'auth.host_based.config.99.user': 'me',
|
85
|
-
'auth.host_based.config.99.method': 'password',
|
86
|
-
}
|
87
|
-
crate_layer = None
|
88
|
-
|
89
|
-
|
90
|
-
def ensure_cratedb_layer():
|
91
|
-
"""
|
92
|
-
In order to skip individual tests by manually disabling them within
|
93
|
-
`def test_suite()`, it is crucial make the test layer not run on each
|
94
|
-
and every occasion. So, things like this will be possible::
|
95
|
-
|
96
|
-
./bin/test -vvvv --ignore_dir=testing
|
97
|
-
|
98
|
-
TODO: Through a subsequent patch, the possibility to individually
|
99
|
-
unselect specific tests might be added to `def test_suite()`
|
100
|
-
on behalf of environment variables.
|
101
|
-
A blueprint for this kind of logic can be found at
|
102
|
-
https://github.com/crate/crate/commit/414cd833.
|
103
|
-
"""
|
104
|
-
global crate_layer
|
105
|
-
|
106
|
-
if crate_layer is None:
|
107
|
-
crate_layer = CrateLayer('crate',
|
108
|
-
crate_home=crate_path(),
|
109
|
-
port=crate_port,
|
110
|
-
host=localhost,
|
111
|
-
transport_port=crate_transport_port,
|
112
|
-
settings=settings)
|
113
|
-
return crate_layer
|
114
|
-
|
115
|
-
|
116
|
-
def setUpCrateLayerBaseline(test):
|
117
|
-
test.globs['crate_host'] = crate_host
|
118
|
-
test.globs['pprint'] = pprint
|
119
|
-
test.globs['print'] = cprint
|
120
|
-
|
121
|
-
with connect(crate_host) as conn:
|
122
|
-
cursor = conn.cursor()
|
123
|
-
|
124
|
-
with open(docs_path('testing/testdata/mappings/locations.sql')) as s:
|
125
|
-
stmt = s.read()
|
126
|
-
cursor.execute(stmt)
|
127
|
-
stmt = ("select count(*) from information_schema.tables "
|
128
|
-
"where table_name = 'locations'")
|
129
|
-
cursor.execute(stmt)
|
130
|
-
assert cursor.fetchall()[0][0] == 1
|
131
|
-
|
132
|
-
data_path = docs_path('testing/testdata/data/test_a.json')
|
133
|
-
# load testing data into crate
|
134
|
-
cursor.execute("copy locations from ?", (data_path,))
|
135
|
-
# refresh location table so imported data is visible immediately
|
136
|
-
cursor.execute("refresh table locations")
|
137
|
-
# create blob table
|
138
|
-
cursor.execute("create blob table myfiles clustered into 1 shards " +
|
139
|
-
"with (number_of_replicas=0)")
|
140
|
-
|
141
|
-
# create users
|
142
|
-
cursor.execute("CREATE USER me WITH (password = 'my_secret_pw')")
|
143
|
-
cursor.execute("CREATE USER trusted_me")
|
144
|
-
|
145
|
-
cursor.close()
|
146
|
-
|
147
|
-
|
148
|
-
def setUpCrateLayerSqlAlchemy(test):
|
149
|
-
"""
|
150
|
-
Setup tables and views needed for SQLAlchemy tests.
|
151
|
-
"""
|
152
|
-
setUpCrateLayerBaseline(test)
|
153
|
-
|
154
|
-
ddl_statements = [
|
155
|
-
"""
|
156
|
-
CREATE TABLE characters (
|
157
|
-
id STRING PRIMARY KEY,
|
158
|
-
name STRING,
|
159
|
-
quote STRING,
|
160
|
-
details OBJECT,
|
161
|
-
more_details ARRAY(OBJECT),
|
162
|
-
INDEX name_ft USING fulltext(name) WITH (analyzer = 'english'),
|
163
|
-
INDEX quote_ft USING fulltext(quote) WITH (analyzer = 'english')
|
164
|
-
)""",
|
165
|
-
"""
|
166
|
-
CREATE VIEW characters_view
|
167
|
-
AS SELECT * FROM characters
|
168
|
-
""",
|
169
|
-
"""
|
170
|
-
CREATE TABLE cities (
|
171
|
-
name STRING PRIMARY KEY,
|
172
|
-
coordinate GEO_POINT,
|
173
|
-
area GEO_SHAPE
|
174
|
-
)"""
|
175
|
-
]
|
176
|
-
_execute_statements(ddl_statements, on_error="raise")
|
177
|
-
|
178
|
-
|
179
|
-
def tearDownDropEntitiesBaseline(test):
|
180
|
-
"""
|
181
|
-
Drop all tables, views, and users created by `setUpWithCrateLayer*`.
|
182
|
-
"""
|
183
|
-
ddl_statements = [
|
184
|
-
"DROP TABLE locations",
|
185
|
-
"DROP BLOB TABLE myfiles",
|
186
|
-
"DROP USER me",
|
187
|
-
"DROP USER trusted_me",
|
188
|
-
]
|
189
|
-
_execute_statements(ddl_statements)
|
190
|
-
|
191
|
-
|
192
|
-
def tearDownDropEntitiesSqlAlchemy(test):
|
193
|
-
"""
|
194
|
-
Drop all tables, views, and users created by `setUpWithCrateLayer*`.
|
195
|
-
"""
|
196
|
-
tearDownDropEntitiesBaseline(test)
|
197
|
-
ddl_statements = [
|
198
|
-
"DROP TABLE characters",
|
199
|
-
"DROP VIEW characters_view",
|
200
|
-
"DROP TABLE cities",
|
201
|
-
]
|
202
|
-
_execute_statements(ddl_statements)
|
203
|
-
|
204
|
-
|
205
|
-
class HttpsTestServerLayer:
|
206
|
-
PORT = 65534
|
207
|
-
HOST = "localhost"
|
208
|
-
CERT_FILE = os.path.abspath(os.path.join(os.path.dirname(__file__),
|
209
|
-
"pki/server_valid.pem"))
|
210
|
-
CACERT_FILE = os.path.abspath(os.path.join(os.path.dirname(__file__),
|
211
|
-
"pki/cacert_valid.pem"))
|
212
|
-
|
213
|
-
__name__ = "httpsserver"
|
214
|
-
__bases__ = tuple()
|
215
|
-
|
216
|
-
class HttpsServer(HTTPServer):
|
217
|
-
def get_request(self):
|
218
|
-
|
219
|
-
# Prepare SSL context.
|
220
|
-
context = ssl._create_unverified_context(
|
221
|
-
protocol=ssl.PROTOCOL_TLS_SERVER,
|
222
|
-
cert_reqs=ssl.CERT_OPTIONAL,
|
223
|
-
check_hostname=False,
|
224
|
-
purpose=ssl.Purpose.CLIENT_AUTH,
|
225
|
-
certfile=HttpsTestServerLayer.CERT_FILE,
|
226
|
-
keyfile=HttpsTestServerLayer.CERT_FILE,
|
227
|
-
cafile=HttpsTestServerLayer.CACERT_FILE)
|
228
|
-
|
229
|
-
# Set minimum protocol version, TLSv1 and TLSv1.1 are unsafe.
|
230
|
-
context.minimum_version = ssl.TLSVersion.TLSv1_2
|
231
|
-
|
232
|
-
# Wrap TLS encryption around socket.
|
233
|
-
socket, client_address = HTTPServer.get_request(self)
|
234
|
-
socket = context.wrap_socket(socket, server_side=True)
|
235
|
-
|
236
|
-
return socket, client_address
|
237
|
-
|
238
|
-
class HttpsHandler(BaseHTTPRequestHandler):
|
239
|
-
|
240
|
-
payload = json.dumps({"name": "test", "status": 200, })
|
241
|
-
|
242
|
-
def do_GET(self):
|
243
|
-
self.send_response(200)
|
244
|
-
payload = self.payload.encode('UTF-8')
|
245
|
-
self.send_header("Content-Length", len(payload))
|
246
|
-
self.send_header("Content-Type", "application/json; charset=UTF-8")
|
247
|
-
self.end_headers()
|
248
|
-
self.wfile.write(payload)
|
249
|
-
|
250
|
-
def setUp(self):
|
251
|
-
self.server = self.HttpsServer(
|
252
|
-
(self.HOST, self.PORT),
|
253
|
-
self.HttpsHandler
|
254
|
-
)
|
255
|
-
thread = threading.Thread(target=self.serve_forever)
|
256
|
-
thread.daemon = True # quit interpreter when only thread exists
|
257
|
-
thread.start()
|
258
|
-
self.waitForServer()
|
259
|
-
|
260
|
-
def serve_forever(self):
|
261
|
-
print("listening on", self.HOST, self.PORT)
|
262
|
-
self.server.serve_forever()
|
263
|
-
print("server stopped.")
|
264
|
-
|
265
|
-
def tearDown(self):
|
266
|
-
self.server.shutdown()
|
267
|
-
self.server.server_close()
|
268
|
-
|
269
|
-
def isUp(self):
|
270
|
-
"""
|
271
|
-
Test if a host is up.
|
272
|
-
"""
|
273
|
-
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
274
|
-
ex = s.connect_ex((self.HOST, self.PORT))
|
275
|
-
s.close()
|
276
|
-
return ex == 0
|
277
|
-
|
278
|
-
def waitForServer(self, timeout=5):
|
279
|
-
"""
|
280
|
-
Wait for the host to be available.
|
281
|
-
"""
|
282
|
-
with stopit.ThreadingTimeout(timeout) as to_ctx_mgr:
|
283
|
-
while True:
|
284
|
-
if self.isUp():
|
285
|
-
break
|
286
|
-
time.sleep(0.001)
|
287
|
-
|
288
|
-
if not to_ctx_mgr:
|
289
|
-
raise TimeoutError("Could not properly start embedded webserver "
|
290
|
-
"within {} seconds".format(timeout))
|
291
|
-
|
292
|
-
|
293
|
-
def setUpWithHttps(test):
|
294
|
-
test.globs['crate_host'] = "https://{0}:{1}".format(
|
295
|
-
HttpsTestServerLayer.HOST, HttpsTestServerLayer.PORT
|
296
|
-
)
|
297
|
-
test.globs['pprint'] = pprint
|
298
|
-
test.globs['print'] = cprint
|
299
|
-
|
300
|
-
test.globs['cacert_valid'] = os.path.abspath(
|
301
|
-
os.path.join(os.path.dirname(__file__), "pki/cacert_valid.pem")
|
302
|
-
)
|
303
|
-
test.globs['cacert_invalid'] = os.path.abspath(
|
304
|
-
os.path.join(os.path.dirname(__file__), "pki/cacert_invalid.pem")
|
305
|
-
)
|
306
|
-
test.globs['clientcert_valid'] = os.path.abspath(
|
307
|
-
os.path.join(os.path.dirname(__file__), "pki/client_valid.pem")
|
308
|
-
)
|
309
|
-
test.globs['clientcert_invalid'] = os.path.abspath(
|
310
|
-
os.path.join(os.path.dirname(__file__), "pki/client_invalid.pem")
|
311
|
-
)
|
312
|
-
|
313
|
-
|
314
|
-
def _execute_statements(statements, on_error="ignore"):
|
315
|
-
with connect(crate_host) as conn:
|
316
|
-
cursor = conn.cursor()
|
317
|
-
for stmt in statements:
|
318
|
-
_execute_statement(cursor, stmt, on_error=on_error)
|
319
|
-
cursor.close()
|
320
|
-
|
321
|
-
|
322
|
-
def _execute_statement(cursor, stmt, on_error="ignore"):
|
323
|
-
try:
|
324
|
-
cursor.execute(stmt)
|
325
|
-
except Exception: # pragma: no cover
|
326
|
-
# FIXME: Why does this croak on statements like ``DROP TABLE cities``?
|
327
|
-
# Note: When needing to debug the test environment, you may want to
|
328
|
-
# enable this logger statement.
|
329
|
-
# log.exception("Executing SQL statement failed")
|
330
|
-
if on_error == "ignore":
|
331
|
-
pass
|
332
|
-
elif on_error == "raise":
|
333
|
-
raise
|
334
|
-
|
335
|
-
|
336
|
-
def test_suite():
|
337
|
-
suite = unittest.TestSuite()
|
338
|
-
flags = (doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS)
|
339
|
-
|
340
|
-
# Unit tests.
|
341
|
-
suite.addTest(makeSuite(CursorTest))
|
342
|
-
suite.addTest(makeSuite(HttpClientTest))
|
343
|
-
suite.addTest(makeSuite(KeepAliveClientTest))
|
344
|
-
suite.addTest(makeSuite(ThreadSafeHttpClientTest))
|
345
|
-
suite.addTest(makeSuite(ParamsTest))
|
346
|
-
suite.addTest(makeSuite(ConnectionTest))
|
347
|
-
suite.addTest(makeSuite(RetryOnTimeoutServerTest))
|
348
|
-
suite.addTest(makeSuite(RequestsCaBundleTest))
|
349
|
-
suite.addTest(makeSuite(TestUsernameSentAsHeader))
|
350
|
-
suite.addTest(makeSuite(TestCrateJsonEncoder))
|
351
|
-
suite.addTest(makeSuite(TestDefaultSchemaHeader))
|
352
|
-
suite.addTest(sqlalchemy_test_suite_unit())
|
353
|
-
suite.addTest(doctest.DocTestSuite('crate.client.connection'))
|
354
|
-
suite.addTest(doctest.DocTestSuite('crate.client.http'))
|
355
|
-
|
356
|
-
s = doctest.DocFileSuite(
|
357
|
-
'docs/by-example/connection.rst',
|
358
|
-
'docs/by-example/cursor.rst',
|
359
|
-
module_relative=False,
|
360
|
-
optionflags=flags,
|
361
|
-
encoding='utf-8'
|
362
|
-
)
|
363
|
-
suite.addTest(s)
|
364
|
-
|
365
|
-
s = doctest.DocFileSuite(
|
366
|
-
'docs/by-example/https.rst',
|
367
|
-
module_relative=False,
|
368
|
-
setUp=setUpWithHttps,
|
369
|
-
optionflags=flags,
|
370
|
-
encoding='utf-8'
|
371
|
-
)
|
372
|
-
s.layer = HttpsTestServerLayer()
|
373
|
-
suite.addTest(s)
|
374
|
-
|
375
|
-
# Integration tests.
|
376
|
-
s = doctest.DocFileSuite(
|
377
|
-
'docs/by-example/http.rst',
|
378
|
-
'docs/by-example/client.rst',
|
379
|
-
'docs/by-example/blob.rst',
|
380
|
-
module_relative=False,
|
381
|
-
setUp=setUpCrateLayerBaseline,
|
382
|
-
tearDown=tearDownDropEntitiesBaseline,
|
383
|
-
optionflags=flags,
|
384
|
-
encoding='utf-8'
|
385
|
-
)
|
386
|
-
s.layer = ensure_cratedb_layer()
|
387
|
-
suite.addTest(s)
|
388
|
-
|
389
|
-
sqlalchemy_integration_tests = [
|
390
|
-
'docs/by-example/sqlalchemy/getting-started.rst',
|
391
|
-
'docs/by-example/sqlalchemy/crud.rst',
|
392
|
-
'docs/by-example/sqlalchemy/working-with-types.rst',
|
393
|
-
'docs/by-example/sqlalchemy/advanced-querying.rst',
|
394
|
-
'docs/by-example/sqlalchemy/inspection-reflection.rst',
|
395
|
-
]
|
396
|
-
|
397
|
-
# Don't run DataFrame integration tests on SQLAlchemy 1.3 and Python 3.7.
|
398
|
-
skip_dataframe = SA_VERSION < SA_1_4 or sys.version_info < (3, 8)
|
399
|
-
if not skip_dataframe:
|
400
|
-
sqlalchemy_integration_tests += [
|
401
|
-
'docs/by-example/sqlalchemy/dataframe.rst',
|
402
|
-
]
|
403
|
-
|
404
|
-
s = doctest.DocFileSuite(
|
405
|
-
*sqlalchemy_integration_tests,
|
406
|
-
module_relative=False,
|
407
|
-
setUp=setUpCrateLayerSqlAlchemy,
|
408
|
-
tearDown=tearDownDropEntitiesSqlAlchemy,
|
409
|
-
optionflags=flags,
|
410
|
-
encoding='utf-8'
|
411
|
-
)
|
412
|
-
s.layer = ensure_cratedb_layer()
|
413
|
-
s.addTest(sqlalchemy_test_suite_integration())
|
414
|
-
suite.addTest(s)
|
415
|
-
|
416
|
-
return suite
|