Skip to content

Commit d9dc369

Browse files
snejborrrden
andauthored
JS Server work
* JS Server: Implemented snapshot & verify Also updated CBL dependency to 1.0.0-5 * JS Server: Implemented blobs for /updateDatabase * JS Server: Normalize collection names everywhere i.e. convert `_default._default` to `_default` * JS Server: Actually save doc after updating it * Disable more JS tests and a few more test server fixes 1. Make it an error to have a snapshot update to a document that doesn't exist in a snapshot 2. Only return result.document if the snapshot update type is an update (not delete or purge) 3. Sometimes we make a snapshot of a document that does not exist in the DB in order to verify that it didn't get pulled unintentionally, so check that (it will show up as an entry with an "undefined" value) 4. updateDatabase should be allowed to create documents 5. Bug in update remove properties handling (it was iterating the actual strings and sending them one character at a time) * Fix API spec for conflict resolvers and run query test * JS Server: Added auth support for replicator * JS Server: Implemented conflict resolvers * JS Server: Throw error when updating keypath fails * JS Server: Implemented push/pull filters * JS Server: Resolve relative blob URLs * JS Server: support updatedBlobs in /verifyDocuments * JS Server: Just prettified tdkSchema.ts * JS Server: Fixed transaction error in /updateDatabase Updating a blob would trigger an exception because it's illegal to make non-database async calls within a transaction. So use Collection.updateMultiple() instead. NOTE: This assumes that a /updateDatabase request does not list the same document multiple times! If so, this will probably fail. * A few small fixes 1. Normalize collection name in replicator config 2. Correct blob base URL * Correct snapshot tests and behavior Only update verifications (not delete or purge) return the document. Also, there is a distinction between null and missing for snapshot entries: null means "I want to verify this later, but it doesn't exist right now". undefined is "Not included in the snapshot and ineligible for verification" * Further correct Snapshot - Spurious `!` on line 40 messes up the test for undefined - I accidentally used `!!` (Kotlin syntax) instead of `!` on line 59 - Using `T | null` in DocumentMap is incorrect; nulls are handled in the declaration of #documents, which is `DocumentMap<cbl.CBLDocument | null>`. * Correct and error code and prettify message The TDK expects an HTTP 400 when a nonexistent blob is requested. Remove "self" from error message since it results in it being printed twice, and make the error message "returned XXX" not weirdly formatted. * Update travel JS dataset Needs two empty collections to be compatible with SGW's setup * Switch SGW certificate strategy The cert is now issued by a CA that can easily be trusted in python, as well as browser. Existing SDK cert pinning should still be fine as well. Also only copy prerelease RPM if it's not already on the remote machine (uploads are slow) * Emit "transport: ws" for Javascript topology setups * Need to separate push and pull filter Their functions are different signatures so a premade CreateFilter is not possible * Relax smoke test requirements for error on connection failure Since JS has no access to that information :( --------- Co-authored-by: Jim Borden <jim.borden@couchbase.com>
1 parent b1ee16d commit d9dc369

42 files changed

Lines changed: 1362 additions & 372 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

client/smoke_tests/test_listener.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
import aiohttp
22
import pytest
33
from cbltest import CBLPyTest
4+
from cbltest.api.cbltestclass import CBLTestClass
45
from cbltest.api.listener import Listener
5-
from cbltest.globals import CBLPyTestGlobal
6+
from cbltest.responses import ServerVariant
67

78

8-
class TestListener:
9-
def setup_method(self, method):
10-
# If writing a new test do not forget this step or the test server
11-
# will not be informed about the currently running test
12-
CBLPyTestGlobal.running_test_name = method.__name__
13-
9+
class TestListener(CBLTestClass):
1410
@pytest.mark.asyncio(loop_scope="session")
1511
async def test_start_stop_listener(self, cblpytest: CBLPyTest) -> None:
12+
await self.skip_if_not_platform(
13+
cblpytest.test_servers[0], ServerVariant.ALL & ~ServerVariant.JS
14+
)
15+
1616
dbs = await cblpytest.test_servers[0].create_and_reset_db(["db1"])
1717
db = dbs[0]
1818
listener = Listener(db, ["_default._default"], 59840)

client/smoke_tests/test_log_endpoint.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,17 @@
33
import pytest
44
import requests
55
from cbltest import CBLPyTest
6-
from cbltest.globals import CBLPyTestGlobal
6+
from cbltest.api.cbltestclass import CBLTestClass
77
from cbltest.logging import LogSlurpHandler, _cbl_log
8+
from cbltest.responses import ServerVariant
89

910

10-
class TestLogEndpoint:
11-
def setup_method(self, method):
12-
# If writing a new test do not forget this step or the test server
13-
# will not be informed about the currently running test
14-
CBLPyTestGlobal.running_test_name = method.__name__
15-
11+
class TestLogEndpoint(CBLTestClass):
1612
@pytest.mark.asyncio(loop_scope="session")
1713
async def test_log_message(self, cblpytest: CBLPyTest) -> None:
14+
await self.skip_if_not_platform(
15+
cblpytest.test_servers[0], ServerVariant.ALL & ~ServerVariant.JS
16+
)
1817
if cblpytest.config.logslurp_url is None:
1918
pytest.skip(
2019
"No LogSlurp server configured (required to check functionality)"

client/smoke_tests/test_multipeer.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,20 @@
22

33
import pytest
44
from cbltest import CBLPyTest
5+
from cbltest.api.cbltestclass import CBLTestClass
56
from cbltest.api.multipeer_replicator import MultipeerReplicator
67
from cbltest.api.replicator_types import ReplicatorCollectionEntry
7-
from cbltest.globals import CBLPyTestGlobal
8+
from cbltest.responses import ServerVariant
89

910

10-
class TestMultipeerReplicator:
11-
def setup_method(self, method):
12-
# If writing a new test do not forget this step or the test server
13-
# will not be informed about the currently running test
14-
CBLPyTestGlobal.running_test_name = method.__name__
15-
11+
class TestMultipeerReplicator(CBLTestClass):
1612
@pytest.mark.asyncio(loop_scope="session")
1713
async def test_start_stop_multipeer(self, cblpytest: CBLPyTest) -> None:
14+
await self.skip_if_not_platform(
15+
cblpytest.test_servers[0], ServerVariant.ALL & ~ServerVariant.JS
16+
)
17+
await self.skip_if_cbl_not(cblpytest.test_servers[0], ">= 3.3.0")
18+
1819
dbs = await cblpytest.test_servers[0].create_and_reset_db(["db1"])
1920
db = dbs[0]
2021
multipeer = MultipeerReplicator(

client/smoke_tests/test_perform_maintenance.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import pytest
22
from cbltest import CBLPyTest
3+
from cbltest.api.cbltestclass import CBLTestClass
34
from cbltest.api.database_types import MaintenanceType
5+
from cbltest.responses import ServerVariant
46

57

6-
class TestPerformMaintenance:
8+
class TestPerformMaintenance(CBLTestClass):
79
@pytest.mark.asyncio(loop_scope="session")
810
@pytest.mark.parametrize(
911
"maintenance_type",
@@ -17,6 +19,11 @@ class TestPerformMaintenance:
1719
async def test_perform_maintenance_endpoint(
1820
self, cblpytest: CBLPyTest, maintenance_type: MaintenanceType
1921
) -> None:
22+
if maintenance_type != MaintenanceType.COMPACT:
23+
await self.skip_if_not_platform(
24+
cblpytest.test_servers[0], ServerVariant.ALL & ~ServerVariant.JS
25+
)
26+
2027
dbs = await cblpytest.test_servers[0].create_and_reset_db(
2128
["db1"], dataset="names"
2229
)

client/smoke_tests/test_run_query.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@ async def test_run_query(self, cblpytest: CBLPyTest):
1414
db = await cblpytest.test_servers[0].create_and_reset_db(
1515
["db1"], dataset="names"
1616
)
17-
results = await db[0].run_query("select meta().id from _ LIMIT 5")
17+
results = await db[0].run_query(
18+
"select meta().id from _ ORDER BY meta().id LIMIT 5"
19+
)
1820
assert results is not None, "The query should return a result"
1921
assert len(results) == 5, "The query should return five results"
2022
i = 1
21-
for r in results:
23+
expected = ["name_1", "name_10", "name_100", "name_11", "name_12"]
24+
for i, r in enumerate(results):
2225
assert "id" in r, "The result should have an ID column"
23-
assert r["id"] == f"name_{i}", f"The result ID should be name_{i}"
24-
i += 1
26+
assert r["id"] == expected[i], f"The result ID should be {expected[i]}"

client/smoke_tests/test_start_replicator.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
from cbltest import CBLPyTest
33
from cbltest.api.database import Database
44
from cbltest.api.error import CblTestServerBadResponseError
5-
from cbltest.api.error_types import ErrorDomain
65
from cbltest.api.replicator import Replicator
76
from cbltest.api.replicator_types import (
87
ReplicatorActivityLevel,
@@ -35,11 +34,7 @@ async def test_bad_endpoint(self, cblpytest: CBLPyTest) -> None:
3534
repl.add_default_collection()
3635
await repl.start()
3736
status = await repl.wait_for(ReplicatorActivityLevel.STOPPED)
38-
assert (
39-
status.error is not None
40-
and ErrorDomain.equal(status.error.domain, ErrorDomain.CBL)
41-
and status.error.code == 5002
42-
)
37+
assert status.error is not None
4338

4439
@pytest.mark.asyncio(loop_scope="session")
4540
@pytest.mark.parametrize(

client/src/cbltest/api/error.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,14 @@ def response(self) -> TestServerResponse:
2121
"""Gets the body of the response that had the bad status"""
2222
return self.__response
2323

24-
def __init__(self, code: int, response: TestServerResponse, *args):
24+
def __init__(self, code: int, response: TestServerResponse, message: str):
2525
self.__code = code
2626
self.__response = response
27-
super().__init__(args)
27+
self.__message = message
28+
super().__init__(message)
29+
30+
def __str__(self) -> str:
31+
return self.__message
2832

2933

3034
class CblTimeoutError(Exception):

client/src/cbltest/api/syncgateway.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,41 @@
1919
from cbltest.utils import assert_not_null
2020
from cbltest.version import VERSION
2121

22+
# This is copied from environment/aws/sgw_setup/cert/ca_cert.pem
23+
# So if that file ever changes, change this too.
24+
_SGW_CA_CERT: str = """-----BEGIN CERTIFICATE-----
25+
MIIFWTCCA0GgAwIBAgIUBdrc0OhquX8RnXtZ6AiOY+57C18wDQYJKoZIhvcNAQEL
26+
BQAwPDEZMBcGA1UEAwwQSW50ZXJuYWwgVGVzdCBDQTESMBAGA1UECgwJQ291Y2hi
27+
YXNlMQswCQYDVQQGEwJVUzAeFw0yNTEwMjkwMTAzMDBaFw0yNzEwMjkwMTAzMDBa
28+
MDwxGTAXBgNVBAMMEEludGVybmFsIFRlc3QgQ0ExEjAQBgNVBAoMCUNvdWNoYmFz
29+
ZTELMAkGA1UEBhMCVVMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCl
30+
vMLIQDFfEcttEUSzBKkzoRSSLJ3Z/73xmJxBenCtZ9HasLhF3iJxwyQK09nD7sLv
31+
RRwLeRfY8QObr/F/qJAa1cQtVA/5UxIiKsjDk+TrUibg4p6NFSgKUEg+08D0tRHG
32+
CF3CF/3qcM/10A+Pg2K1COaAtPrYjslOv8DoDBzwOBxibaheDZmtBdPEeHghDXZr
33+
DWYDe2770XGzKYqINCEDxNdyDUBdiNSzuX2h/YeZi6vGTtpAt3Iti2SIerRrCiah
34+
UOlykQoqiDVh4JPXts79Xhszw0oDK6YWHEBBfXmYDUdYAyF97XC6hZc+6HxiCVTB
35+
887mkyLCuKMGfB3dabyCqJ31fXm7gmufOs8voCfi/sKjLgcdZQUY4Gw345oYI3Yw
36+
O41ig/uR04KW2xASba38vXt0fEl9/50+AO3xAy9oaY36nLSnBwTV72VbvTlvevGf
37+
zSHbVIbtzcuovpudghYizmIqMEFguc8VsGgmwZb8mkypzB80SOoED3nJRziIK1ym
38+
e+NuO0DIG6xMPUhputNhwqaeYXuSmcUH5YcmLN//ewMIjzxoH33H1cwcADHFioR/
39+
YfIraSgVZCUhrN9aJlXdDOzDuhbVpXYJMbh5PfAiNLHPCXmo685Utf3ID+nFW1wd
40+
WOIyuE3aJ5KVtG8hjlgKARV7eEqtxHjIl41QtsxalwIDAQABo1MwUTAdBgNVHQ4E
41+
FgQUs2WdMu1wh9pJ5dPN80yN1NPAkSswHwYDVR0jBBgwFoAUs2WdMu1wh9pJ5dPN
42+
80yN1NPAkSswDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAhiYP
43+
a9dvAv/33u9vBKzUo045RRrfEpv80DSZQb4ttyulrIfbaLFHxaDcf2+S+mywAgoW
44+
tf9SAwWO41qU7sfIBnFdCh982nP1dD707GDAZIe8ZNpl/Vu3hWY3TRQAp9ufA51w
45+
wxn0m2tOS18UXpv5BNX1kVaLlAiOzRzmP1ghx08v9yd8eBgnjJ89D2m1U+qFS1Xk
46+
egiyw66HHc3bG+eo523/l4RDqTx6KkhYnD3Bz89IxMaeK7CuynCY3VyVWPeIUfBr
47+
clkDBqZa4o7fD3xV6Wiu/NHZsWJx3wog1wwelvlsyOVM+mfd4IOsPGVCCdDGtpoq
48+
sT+f9mPDXXHKuDER8a7HiCgGK8rAQtCm/P5UFp2HUEIru/psWCXc3vh9HYVX9W79
49+
TwS+AVAlkeVogs1ugqAXOuGmstnevj6XzA8PszCKDSIV+t1PJSSOtypUyN4gbGGx
50+
sk1s9bwqy7bw2cMh3tt7HromGOoLnPxnsbQCs5HsqNdiEsPABWnI6m7epm0tFjCe
51+
gHDyw1LdmZlZ3R7DT+CwfyhxL6hktfs8h7goR1vkmS2q0Alxmw9faKVVpDyWnsZC
52+
qv6PMC0fI7jhvrr2Uf2Hhw9SQlBFwZ7LjjLqjuuJkclM4VooDElsLbPjSUbA+c5h
53+
WCKJ0c94mrl9GwwBmcSIKJBvd6u7uAta2fREJeE=
54+
-----END CERTIFICATE-----
55+
"""
56+
2257

2358
class _CollectionMap(JSONSerializable):
2459
@property
@@ -344,7 +379,7 @@ def _create_session(
344379
self, secure: bool, scheme: str, url: str, port: int, auth: BasicAuth | None
345380
) -> ClientSession:
346381
if secure:
347-
ssl_context = ssl.create_default_context(cadata=self.tls_cert())
382+
ssl_context = ssl.create_default_context(cadata=_SGW_CA_CERT)
348383
# Disable hostname check so that the pre-generated SG can be used on any machines.
349384
ssl_context.check_hostname = False
350385
return ClientSession(

client/src/cbltest/requests_transport.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ async def send(
8585
cbl_trace(f"Received {ret_val} from {self.__url}")
8686
if not resp.ok:
8787
raise CblTestServerBadResponseError(
88-
resp.status, ret_val, f"{self} returned {resp.status}"
88+
resp.status, ret_val, f"returned {resp.status}"
8989
)
9090

9191
return ret_val
@@ -167,7 +167,7 @@ async def send(
167167
cbl_trace(f"Received {ret_val} from {self.__url}")
168168
if ret_val.status_code != 200:
169169
raise CblTestServerBadResponseError(
170-
ret_val.status_code, ret_val, f"{self} returned {ret_val.status_code}"
170+
ret_val.status_code, ret_val, f"returned {ret_val.status_code}"
171171
)
172172

173173
return ret_val

dataset/server/dbs/js/travel/index.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
"name": "travel",
33
"collections": [
44
"travel.airlines",
5+
"travel.airports",
56
"travel.hotels",
7+
"travel.landmarks",
68
"travel.routes"
79
]
810
}

0 commit comments

Comments
 (0)