Skip to content

Commit 86089e3

Browse files
authored
Smoketests can run against remote servers (#3012)
# Description of Changes This enables smoketests to run against remote servers, such as maincloud / maincloud staging. I also added a `--spacetime-login` param, for servers that require a "proper" spacetime login (such as both servers above). Usage: ```bash python3 -m smoketests \ --remote-server https://maincloud.staging.spacetimedb.com \ --spacetime-login \ -x replication # for some reason this is required, even though I swear it should be disabled by not passing `--docker` ``` # API and ABI breaking changes None. CI only. # Expected complexity level and risk 1 # Testing - [x] Smoketests pass on this PR - [x] Smoketests pass when run against maincloud staging (using the instructions above) - [x] Manual review to check whether I've accidentally de-fanged any "test for negative case" tests --------- Co-authored-by: Zeke Foppa <[email protected]>
1 parent 0a46cf5 commit 86089e3

File tree

8 files changed

+55
-21
lines changed

8 files changed

+55
-21
lines changed

smoketests/__init__.py

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,14 @@
3737
# and a dotnet installation is detected
3838
HAVE_DOTNET = False
3939

40+
# When we pass --spacetime-login, we are running against a server that requires "real" spacetime logins (rather than `--server-issued-login`).
41+
# This is used to skip tests that don't work with that.
42+
USE_SPACETIME_LOGIN = False
43+
44+
# If we pass `--remote-server`, the server address will be something other than the default. This is used to skip tests that rely on use
45+
# having the default localhost server.
46+
REMOTE_SERVER = False
47+
4048
# default value can be overridden by `--compose-file` flag
4149
COMPOSE_FILE = "./docker-compose.yml"
4250

@@ -61,6 +69,15 @@ def requires_dotnet(item):
6169
return item
6270
return unittest.skip("dotnet 8.0 not available")(item)
6371

72+
def requires_anonymous_login(item):
73+
if USE_SPACETIME_LOGIN:
74+
return unittest.skip("using `spacetime login`")(item)
75+
return item
76+
77+
def requires_local_server(item):
78+
if REMOTE_SERVER:
79+
return unittest.skip("running against a remote server")(item)
80+
return item
6481

6582
def build_template_target():
6683
if not TEMPLATE_TARGET_DIR.exists():
@@ -260,9 +277,20 @@ def run():
260277
def api_call(self, method, path, body = None, headers = {}):
261278
with open(self.config_path, "rb") as f:
262279
config = tomllib.load(f)
263-
host = config['default_server']
264280
token = config['spacetimedb_token']
265-
conn = http.client.HTTPConnection(host)
281+
server_name = config['default_server']
282+
server_config = next((c for c in config['server_configs'] if c['nickname'] == server_name), None)
283+
if server_config is None:
284+
raise Exception(f"Unable to find server in config with nickname {server_name}")
285+
host = server_config['host']
286+
protocol = server_config['protocol']
287+
conn = None
288+
if protocol == "http":
289+
conn = http.client.HTTPConnection(host)
290+
elif protocol == "https":
291+
conn = http.client.HTTPSConnection(host)
292+
else:
293+
raise Exception(f"Unknown protocol: {protocol}")
266294
auth = {"Authorization": f'Bearer {token}'}
267295
headers.update(auth)
268296
log_cmd([method, path])

smoketests/__main__.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ def main():
7272
parser.add_argument("-x", dest="exclude", nargs="*", default=[])
7373
parser.add_argument("--no-build-cli", action="store_true", help="don't cargo build the cli")
7474
parser.add_argument("--list", action="store_true", help="list the tests that would be run, but don't run them")
75+
parser.add_argument("--remote-server", action="store", help="Run against a remote server")
76+
parser.add_argument("--spacetime-login", action="store_true", help="Use `spacetime login` for these tests (and disable tests that don't work with that)")
7577
args = parser.parse_args()
7678

7779
if not args.no_build_cli:
@@ -110,7 +112,16 @@ def main():
110112
subprocess.Popen(["docker", "logs", "-f", docker_container])
111113
smoketests.HAVE_DOCKER = True
112114

113-
smoketests.new_identity(TEST_DIR / 'config.toml')
115+
if args.remote_server is not None:
116+
smoketests.spacetime("--config-path", TEST_DIR / 'config.toml', "server", "edit", "localhost", "--url", args.remote_server, "--yes")
117+
smoketests.REMOTE_SERVER = True
118+
119+
if args.spacetime_login:
120+
smoketests.spacetime("--config-path", TEST_DIR / 'config.toml', "logout")
121+
smoketests.spacetime("--config-path", TEST_DIR / 'config.toml', "login")
122+
smoketests.USE_SPACETIME_LOGIN = True
123+
else:
124+
smoketests.new_identity(TEST_DIR / 'config.toml')
114125

115126
if not args.skip_dotnet:
116127
smoketests.HAVE_DOTNET = check_dotnet()

smoketests/config.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
default_server = "127.0.0.1:3000"
1+
default_server = "localhost"
22
spacetimedb_token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJoZXhfaWRlbnRpdHkiOiJjMjAwYzc3NDY1NTE5MDM2MTE4M2JiNjFmMWMxYzY3NDUzMzYzY2MxMTY4MmM1NTUwNWZiNjdlYzI0ZWMyMWViIiwic3ViIjoiOTJlMmNkOGQtNTk5Ny00NjZlLWIwNmYtZDNjOGQ1NzU3ODI4IiwiaXNzIjoibG9jYWxob3N0IiwiYXVkIjpbInNwYWNldGltZWRiIl0sImlhdCI6MTc1MjA0NjgwMCwiZXhwIjpudWxsfQ.dgefoxC7eCOONVUufu2JTVFo9876zQ4Mqwm0ivZ0PQK7Hacm3Ip_xqyav4bilZ0vIEf8IM8AB0_xawk8WcbvMg"
33

44
[[server_configs]]

smoketests/tests/energy.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
from .. import Smoketest
1+
from .. import Smoketest, requires_anonymous_login
22
import time
33

44
class EnergyFlow(Smoketest):
55

6+
@requires_anonymous_login
67
def test_energy_balance(self):
78
"""Test getting energy balance."""
89

smoketests/tests/new_user_flow.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from .. import Smoketest
1+
from .. import Smoketest, requires_anonymous_login
22
import time
33

44
class NewUserFlow(Smoketest):
@@ -25,6 +25,7 @@ class NewUserFlow(Smoketest):
2525
}
2626
"""
2727

28+
@requires_anonymous_login
2829
def test_new_user_flow(self):
2930
"""Test the entirety of the new user flow."""
3031

smoketests/tests/permissions.py

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ def setUp(self):
1010
def test_call(self):
1111
"""Ensure that anyone has the permission to call any standard reducer"""
1212

13-
self.new_identity()
14-
1513
self.publish_module()
1614

1715
self.call("say_hello", anon=True)
@@ -21,28 +19,22 @@ def test_call(self):
2119
def test_delete(self):
2220
"""Ensure that you cannot delete a database that you do not own"""
2321

24-
self.new_identity()
25-
2622
self.publish_module()
2723

28-
self.reset_config()
24+
self.new_identity()
2925
with self.assertRaises(Exception):
3026
self.spacetime("delete", self.database_identity)
3127

3228
def test_describe(self):
3329
"""Ensure that anyone can describe any database"""
3430

35-
self.new_identity()
3631
self.publish_module()
3732

38-
self.reset_config()
39-
self.new_identity()
40-
self.spacetime("describe", "--json", self.database_identity)
33+
self.spacetime("describe", "--anonymous", "--json", self.database_identity)
4134

4235
def test_logs(self):
4336
"""Ensure that we are not able to view the logs of a module that we don't have permission to view"""
4437

45-
self.new_identity()
4638
self.publish_module()
4739

4840
self.reset_config()
@@ -57,10 +49,9 @@ def test_logs(self):
5749
def test_publish(self):
5850
"""This test checks to make sure that you cannot publish to an identity that you do not own."""
5951

60-
self.new_identity()
6152
self.publish_module()
6253

63-
self.reset_config()
54+
self.new_identity()
6455

6556
with self.assertRaises(Exception):
6657
# TODO: This raises for the wrong reason - `--clear-database` doesn't exist anymore!
@@ -73,11 +64,10 @@ def test_publish(self):
7364
def test_replace_names(self):
7465
"""Test that you can't replace names of a database you don't own"""
7566

76-
self.new_identity()
7767
name = random_string()
7868
self.publish_module(name)
7969

80-
self.reset_config()
70+
self.new_identity()
8171

8272
with self.assertRaises(Exception):
8373
self.api_call(

smoketests/tests/replication.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ def tearDown(self):
229229
self.docker.compose("up", "-d")
230230
super().tearDown()
231231

232+
# TODO: This function seems to run even when `--docker` is not passed, leading to errors unless `-x replication` is passed, due to the docker-related code below.
232233
def __init__(self, *args, **kwargs):
233234
super().__init__(*args, **kwargs)
234235

smoketests/tests/servers.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
from .. import Smoketest, extract_field
1+
from .. import Smoketest, extract_field, requires_local_server
22
import re
33

4+
# We require a local server because these tests have hardcoded server addresses.
5+
@requires_local_server
46
class Servers(Smoketest):
57
AUTOPUBLISH = False
68

0 commit comments

Comments
 (0)