Browse Source

cli: fail if select username not in config file or ambiguous

Fabian Peter Hammerle 4 years ago
parent
commit
9789ac2889
3 changed files with 99 additions and 25 deletions
  1. 20 15
      CHANGELOG.md
  2. 65 0
      tests/test_cli.py
  3. 14 10
      tooncher/_cli.py

+ 20 - 15
CHANGELOG.md

@@ -9,23 +9,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 - path to tootown engine may be provided via env var `$TOONCHER_ENGINE_PATH`
 
 ### Changed
-- install command line interface via `setuptools.setup(entry_points=…)`
-- now private:
-  - `tooncher.LOGIN_API_URL`
-  - `tooncher.LoginDelayed`
-  - `tooncher.LoginSuccessful`
-  - `tooncher.TOONTOWN_ENGINE_DEFAULT_PATH`
-  - `tooncher.api_request`
-  - `tooncher.login`
-- `start_engine` & `launch`: expected `isinstance(engine_path, pathlib.Path)`
-  (instead of `str`)
+- command line interface:
+  - fail if selected username was not found in config
+  - fail if selected username has multiple entries in config
+  - install via `setuptools.setup(entry_points=…)`
+- python interface:
+  - now private:
+    - `tooncher.LOGIN_API_URL`
+    - `tooncher.LoginDelayed`
+    - `tooncher.LoginSuccessful`
+    - `tooncher.TOONTOWN_ENGINE_DEFAULT_PATH`
+    - `tooncher.api_request`
+    - `tooncher.login`
+  - `start_engine` & `launch`: expected `isinstance(engine_path, pathlib.Path)`
+    (instead of `str`)
 
 ### Removed
-- `argcomplete`
-- `tooncher.INVASIONS_API_URL`
-- `tooncher.InvasionProgress`
-- `tooncher.TOONTOWN_LIBRARY_PATH`
-- `tooncher.request_active_invasions`
+- python interface:
+  - `argcomplete`
+  - `tooncher.INVASIONS_API_URL`
+  - `tooncher.InvasionProgress`
+  - `tooncher.TOONTOWN_LIBRARY_PATH`
+  - `tooncher.request_active_invasions`
 
 ### Fixed
 - mac: `$DYLD_LIBRARY_PATH` & `$DYLD_FRAMEWORK_PATH` relative to engine path

+ 65 - 0
tests/test_cli.py

@@ -2,6 +2,9 @@ import pathlib
 import subprocess
 from unittest.mock import patch
 
+import pytest
+import yaml
+
 # pylint: disable=protected-access
 import tooncher._cli
 
@@ -88,3 +91,65 @@ def test_engine_path_env_config(launch_mock, tmpdir):
     args, kwargs = launch_mock.call_args
     assert not args
     assert kwargs["engine_path"] == pathlib.Path("/opt/ttr/TTREnvine")
+
+
+@patch("tooncher.launch")
+def test_account(launch_mock, tmpdir):
+    config_file = tmpdir.join("config")
+    config_file.write(
+        yaml.safe_dump(
+            {
+                "engine_path": "/opt/conf/TTR",
+                "accounts": [
+                    {"username": "someone", "password": "secret"},
+                    {"username": "toon", "password": "town"},
+                ],
+            }
+        )
+    )
+    with patch("sys.argv", ["", "--config", config_file.strpath, "toon"]):
+        tooncher._cli.main()
+    launch_mock.assert_called_once_with(
+        engine_path=pathlib.Path("/opt/conf/TTR"),
+        username="toon",
+        password="town",
+        validate_ssl_certs=True,
+        cpu_limit_percent=None,
+    )
+
+
+def test_account_duplicate_username(tmpdir):
+    config_file = tmpdir.join("config")
+    config_file.write(
+        yaml.safe_dump(
+            {
+                "engine_path": "/opt/conf/TTR",
+                "accounts": [
+                    {"username": "someone", "password": "secret"},
+                    {"username": "toon", "password": "town"},
+                    {"username": "toon", "password": "town2"},
+                ],
+            }
+        )
+    )
+    with patch("sys.argv", ["", "--config", config_file.strpath, "toon"]):
+        with pytest.raises(ValueError, match=r"multiple .* username"):
+            tooncher._cli.main()
+
+
+def test_account_unknown_username(tmpdir):
+    config_file = tmpdir.join("config")
+    config_file.write(
+        yaml.safe_dump(
+            {
+                "engine_path": "/opt/conf/TTR",
+                "accounts": [
+                    {"username": "someone", "password": "secret"},
+                    {"username": "toon", "password": "town"},
+                ],
+            }
+        )
+    )
+    with patch("sys.argv", ["", "--config", config_file.strpath, "player"]):
+        with pytest.raises(ValueError, match=r"not found"):
+            tooncher._cli.main()

+ 14 - 10
tooncher/_cli.py

@@ -41,16 +41,20 @@ def run(
             "missing path to toontown engine\n"
             + "pass --engine-path, set $TOONCHER_ENGINE_PATH, or add to config file"
         )
-    accounts = config["accounts"] if "accounts" in config else []
-    for account in accounts:
-        if account["username"] == username:
-            tooncher.launch(
-                engine_path=pathlib.Path(engine_path),
-                username=account["username"],
-                password=account["password"],
-                validate_ssl_certs=validate_ssl_certs,
-                cpu_limit_percent=cpu_limit_percent,
-            )
+    accounts = [a for a in config.get("accounts", []) if a["username"] == username]
+    if not accounts:
+        raise ValueError("username {!r} was not found in config file".format(username))
+    if len(accounts) > 1:
+        raise ValueError(
+            "multiple entries for username {!r} in config file".format(username)
+        )
+    tooncher.launch(
+        engine_path=pathlib.Path(engine_path),
+        username=accounts[0]["username"],
+        password=accounts[0]["password"],
+        validate_ssl_certs=validate_ssl_certs,
+        cpu_limit_percent=cpu_limit_percent,
+    )
 
 
 class _EnvDefaultArgparser(argparse.ArgumentParser):