-
Notifications
You must be signed in to change notification settings - Fork 2
chore(xtest): Improve tool use output capture #323
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -262,14 +262,13 @@ def __init__(self, otdfctl_path: str | None = None): | |
| def kas_registry_list(self) -> list[KasEntry]: | ||
| cmd = self.otdfctl + "policy kas-registry list".split() | ||
| logger.info(f"kr-ls [{' '.join(cmd)}]") | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE) | ||
| code = process.wait() | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | ||
| out, err = process.communicate() | ||
| if err: | ||
| print(err, file=sys.stderr) | ||
| if out: | ||
| print(out) | ||
| assert code == 0 | ||
| assert process.returncode == 0 | ||
| o = json.loads(out) | ||
| if not o: | ||
| return [] | ||
|
|
@@ -285,7 +284,7 @@ def kas_registry_create( | |
| if public_key: | ||
| cmd += [f"--public-keys={public_key.model_dump_json()}"] | ||
| logger.info(f"kr-create [{' '.join(cmd)}]") | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE) | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| out, err = process.communicate() | ||
| if err: | ||
| print(err, file=sys.stderr) | ||
|
|
@@ -308,7 +307,7 @@ def kas_registry_keys_list(self, kas: KasEntry) -> list[KasKey]: | |
| cmd = self.otdfctl + "policy kas-registry key list".split() | ||
| cmd += [f"--kas={kas.uri}"] | ||
| logger.info(f"kr-keys-ls [{' '.join(cmd)}]") | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE) | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| out, err = process.communicate() | ||
| if err: | ||
| print(err, file=sys.stderr) | ||
|
|
@@ -338,7 +337,7 @@ def kas_registry_create_public_key_only( | |
| f"--key-id={public_key.kid}", | ||
| f"--algorithm={public_key.algStr}", | ||
| ] | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE) | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| out, err = process.communicate() | ||
| if err: | ||
| print(err, file=sys.stderr) | ||
|
|
@@ -355,7 +354,7 @@ def key_assign_ns(self, key: KasKey, ns: Namespace) -> NamespaceKey: | |
| f"--namespace={ns.id}", | ||
| ] | ||
| logger.info(f"key-assign [{' '.join(cmd)}]") | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE) | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| out, err = process.communicate() | ||
| if err: | ||
| print(err, file=sys.stderr) | ||
|
|
@@ -372,14 +371,13 @@ def grant_assign_ns(self, kas: KasEntry, ns: Namespace) -> KasGrantNamespace: | |
| f"--namespace-id={ns.id}", | ||
| ] | ||
| logger.info(f"grant-update [{' '.join(cmd)}]") | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE) | ||
| code = process.wait() | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| out, err = process.communicate() | ||
| if err: | ||
| print(err, file=sys.stderr) | ||
| if out: | ||
| print(out) | ||
| assert code == 0 | ||
| assert process.returncode == 0 | ||
| return KasGrantNamespace.model_validate_json(out) | ||
|
|
||
| def key_assign_attr(self, key: KasKey, attr: Attribute) -> AttributeKey: | ||
|
|
@@ -389,7 +387,7 @@ def key_assign_attr(self, key: KasKey, attr: Attribute) -> AttributeKey: | |
| f"--attribute={attr.id}", | ||
| ] | ||
| logger.info(f"key-assign [{' '.join(cmd)}]") | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE) | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| out, err = process.communicate() | ||
| if err: | ||
| print(err, file=sys.stderr) | ||
|
|
@@ -406,14 +404,13 @@ def grant_assign_attr(self, kas: KasEntry, attr: Attribute) -> KasGrantAttribute | |
| f"--attribute-id={attr.id}", | ||
| ] | ||
| logger.info(f"grant-update [{' '.join(cmd)}]") | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE) | ||
| code = process.wait() | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| out, err = process.communicate() | ||
| if err: | ||
| print(err, file=sys.stderr) | ||
| if out: | ||
| print(out) | ||
| assert code == 0 | ||
| assert process.returncode == 0 | ||
| return KasGrantAttribute.model_validate_json(out) | ||
|
|
||
| def key_assign_value(self, key: KasKey, val: AttributeValue) -> ValueKey: | ||
|
|
@@ -423,7 +420,7 @@ def key_assign_value(self, key: KasKey, val: AttributeValue) -> ValueKey: | |
| f"--value={val.id}", | ||
| ] | ||
| logger.info(f"key-assign [{' '.join(cmd)}]") | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE) | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| out, err = process.communicate() | ||
| if err: | ||
| print(err, file=sys.stderr) | ||
|
|
@@ -440,14 +437,13 @@ def grant_assign_value(self, kas: KasEntry, val: AttributeValue) -> KasGrantValu | |
| f"--value-id={val.id}", | ||
| ] | ||
| logger.info(f"grant-update [{' '.join(cmd)}]") | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE) | ||
| code = process.wait() | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| out, err = process.communicate() | ||
| if err: | ||
| print(err, file=sys.stderr) | ||
| if out: | ||
| print(out) | ||
| assert code == 0 | ||
| assert process.returncode == 0 | ||
| return KasGrantValue.model_validate_json(out) | ||
|
|
||
| def key_unassign_ns(self, key: KasKey, ns: Namespace) -> NamespaceKey: | ||
|
|
@@ -457,14 +453,13 @@ def key_unassign_ns(self, key: KasKey, ns: Namespace) -> NamespaceKey: | |
| f"--namespace={ns.id}", | ||
| ] | ||
| logger.info(f"key-assign [{' '.join(cmd)}]") | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE) | ||
| code = process.wait() | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| out, err = process.communicate() | ||
| if err: | ||
| print(err, file=sys.stderr) | ||
| if out: | ||
| print(out) | ||
| assert code == 0 | ||
| assert process.returncode == 0 | ||
| return NamespaceKey.model_validate_json(out) | ||
|
|
||
| # Deprecated in otdfctl 0.22 | ||
|
|
@@ -475,14 +470,13 @@ def grant_unassign_ns(self, kas: KasEntry, ns: Namespace) -> KasGrantNamespace: | |
| f"--namespace-id={ns.id}", | ||
| ] | ||
| logger.info(f"grant-update [{' '.join(cmd)}]") | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE) | ||
| code = process.wait() | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| out, err = process.communicate() | ||
| if err: | ||
| print(err, file=sys.stderr) | ||
| if out: | ||
| print(out) | ||
| assert code == 0 | ||
| assert process.returncode == 0 | ||
| return KasGrantNamespace.model_validate_json(out) | ||
|
|
||
| def key_unassign_attr(self, key: KasKey, attr: Attribute) -> AttributeKey: | ||
|
|
@@ -492,7 +486,7 @@ def key_unassign_attr(self, key: KasKey, attr: Attribute) -> AttributeKey: | |
| f"--attribute={attr.id}", | ||
| ] | ||
| logger.info(f"key-assign [{' '.join(cmd)}]") | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE) | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| out, err = process.communicate() | ||
| if err: | ||
| print(err, file=sys.stderr) | ||
|
|
@@ -509,14 +503,13 @@ def grant_unassign_attr(self, kas: KasEntry, attr: Attribute) -> KasGrantAttribu | |
| f"--attribute-id={attr.id}", | ||
| ] | ||
| logger.info(f"grant-update [{' '.join(cmd)}]") | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE) | ||
| code = process.wait() | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| out, err = process.communicate() | ||
| if err: | ||
| print(err, file=sys.stderr) | ||
| if out: | ||
| print(out) | ||
| assert code == 0 | ||
| assert process.returncode == 0 | ||
| return KasGrantAttribute.model_validate_json(out) | ||
|
|
||
| def key_unassign_value(self, key: KasKey, val: AttributeValue) -> ValueKey: | ||
|
|
@@ -526,7 +519,7 @@ def key_unassign_value(self, key: KasKey, val: AttributeValue) -> ValueKey: | |
| f"--value={val.id}", | ||
| ] | ||
| logger.info(f"key-assign [{' '.join(cmd)}]") | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE) | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| out, err = process.communicate() | ||
| if err: | ||
| print(err, file=sys.stderr) | ||
|
|
@@ -543,27 +536,25 @@ def grant_unassign_value(self, kas: KasEntry, val: AttributeValue) -> KasGrantVa | |
| f"--value-id={val.id}", | ||
| ] | ||
| logger.info(f"grant-update [{' '.join(cmd)}]") | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE) | ||
| code = process.wait() | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| out, err = process.communicate() | ||
| if err: | ||
| print(err, file=sys.stderr) | ||
| if out: | ||
| print(out) | ||
| assert code == 0 | ||
| assert process.returncode == 0 | ||
| return KasGrantValue.model_validate_json(out) | ||
|
|
||
| def namespace_list(self) -> list[Namespace]: | ||
| cmd = self.otdfctl + "policy attributes namespaces list".split() | ||
| logger.info(f"ns-ls [{' '.join(cmd)}]") | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE) | ||
| code = process.wait() | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | ||
| out, err = process.communicate() | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| if err: | ||
| print(err, file=sys.stderr, flush=code != 0) | ||
| print(err, file=sys.stderr, flush=True) | ||
| if out: | ||
| print(out, flush=code != 0) | ||
| assert code == 0 | ||
| print(out, flush=True) | ||
| assert process.returncode == 0 | ||
| o = json.loads(out) | ||
| if not o: | ||
| return [] | ||
|
|
@@ -573,14 +564,13 @@ def namespace_create(self, name: str) -> Namespace: | |
| cmd = self.otdfctl + "policy attributes namespaces create".split() | ||
| cmd += [f"--name={name}"] | ||
| logger.info(f"ns-create [{' '.join(cmd)}]") | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE) | ||
| code = process.wait() | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| out, err = process.communicate() | ||
| if err: | ||
| print(err, file=sys.stderr, flush=code != 0) | ||
| print(err, file=sys.stderr, flush=True) | ||
| if out: | ||
| print(out, flush=code != 0) | ||
| assert code == 0 | ||
| print(out, flush=True) | ||
| assert process.returncode == 0 | ||
| return Namespace.model_validate_json(out) | ||
|
|
||
| def attribute_create( | ||
|
|
@@ -596,14 +586,13 @@ def attribute_create( | |
| if values: | ||
| cmd += [f"--value={','.join(values)}"] | ||
| logger.info(f"attr-create [{' '.join(cmd)}]") | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE) | ||
| code = process.wait() | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| out, err = process.communicate() | ||
| if err: | ||
| print(err, file=sys.stderr, flush=code != 0) | ||
| print(err, file=sys.stderr, flush=True) | ||
| if out: | ||
| print(out, flush=code != 0) | ||
| assert code == 0 | ||
| print(out, flush=True) | ||
| assert process.returncode == 0 | ||
| return Attribute.model_validate_json(out) | ||
|
|
||
| def scs_create(self, scs: list[SubjectSet]) -> SubjectConditionSet: | ||
|
|
@@ -612,14 +601,13 @@ def scs_create(self, scs: list[SubjectSet]) -> SubjectConditionSet: | |
| cmd += [f"--subject-sets=[{','.join([s.model_dump_json() for s in scs])}]"] | ||
|
|
||
| logger.info(f"scs-create [{' '.join(cmd)}]") | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE) | ||
| code = process.wait() | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| out, err = process.communicate() | ||
| if err: | ||
| print(err, file=sys.stderr, flush=code != 0) | ||
| print(err, file=sys.stderr, flush=True) | ||
| if out: | ||
| print(out, flush=code != 0) | ||
| assert code == 0 | ||
| print(out, flush=True) | ||
| assert process.returncode == 0 | ||
| return SubjectConditionSet.model_validate_json(out) | ||
|
|
||
| def scs_map( | ||
|
|
@@ -638,20 +626,19 @@ def scs_map( | |
| ] | ||
|
|
||
| logger.info(f"sm-create [{' '.join(cmd)}]") | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE) | ||
| code = process.wait() | ||
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| out, err = process.communicate() | ||
| if err: | ||
| print(err, file=sys.stderr) | ||
| if out: | ||
| print(out) | ||
| if ( | ||
| code != 0 | ||
| process.returncode != 0 | ||
| and not self.flag_scs_map_action_standard | ||
| and err.find(b"--action-standard") >= 0 | ||
| and err and err.find(b"--action-standard") >= 0 | ||
| ): | ||
| self.flag_scs_map_action_standard = True | ||
| return self.scs_map(sc, value) | ||
|
|
||
| assert code == 0 | ||
| assert process.returncode == 0 | ||
| return SubjectMapping.model_validate_json(out) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,14 +7,43 @@ | |
| import secrets | ||
| import assertions | ||
| import json | ||
| import logging | ||
| import sys | ||
| from cryptography.hazmat.primitives.asymmetric import rsa | ||
| from cryptography.hazmat.primitives import serialization | ||
| from pathlib import Path | ||
| from pydantic_core import to_jsonable_python | ||
|
|
||
| import abac | ||
| import tdfs | ||
| from typing import cast | ||
| from typing import cast, Any | ||
|
|
||
|
|
||
| # Configure pytest to capture all subprocess output | ||
| @pytest.hookimpl(trylast=True) | ||
| def pytest_configure(config: Any) -> None: | ||
| # Set log capture level to debug to ensure all logs are captured | ||
| if hasattr(config, "option"): | ||
| config.option.log_cli = True | ||
| config.option.log_cli_level = "DEBUG" | ||
| config.option.log_cli_format = ( | ||
| "%(asctime)s - %(name)s - %(levelname)s - %(message)s" | ||
| ) | ||
|
|
||
| # Configure logging to ensure we see everything from subprocesses | ||
| logging.basicConfig( | ||
| level=logging.DEBUG, | ||
| format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", | ||
| stream=sys.stdout, # Ensure output goes to stdout for pytest capture | ||
| ) | ||
| # Make sure subprocess logger is set to DEBUG level | ||
| logging.getLogger("subprocess").setLevel(logging.DEBUG) | ||
|
|
||
| # Set environment variable to make sure Python doesn't buffer stdout/stderr | ||
| os.environ["PYTHONUNBUFFERED"] = "1" | ||
|
|
||
| # Set buffering mode for subprocess to line buffered | ||
| os.environ["PYTHONFAULTHANDLER"] = "1" | ||
|
Comment on lines
+23
to
+46
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This
|
||
|
|
||
|
|
||
| def englist(s: tuple[str]) -> str: | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| [pytest] | ||
| # Display all logs during test runs | ||
| log_cli = True | ||
| log_cli_level = DEBUG | ||
| log_cli_format = %(asctime)s - %(name)s - %(levelname)s - %(message)s | ||
|
|
||
| # Configure subprocess settings for better output capture | ||
| pythonpath = . | ||
| python_files = test_*.py | ||
| python_classes = Test* | ||
| python_functions = test_* | ||
|
|
||
| # Log all test activity including setup and teardown | ||
| log_level = DEBUG | ||
|
|
||
| # Set buffer size to 0 for immediate output | ||
| env = | ||
| PYTHONUNBUFFERED=1 | ||
| PYTHONFAULTHANDLER=1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider logging the error output using the logger instead of printing to stderr. This allows for consistent logging and easier debugging.[^1]