Skip to content

Commit

Permalink
dsl: Add "runtime_func" function decorator to enable a function to be…
Browse files Browse the repository at this point in the history
… invoked as an eval expression function.

Add tests for last few commits of dsl functionality.
  • Loading branch information
aszs committed Dec 17, 2024
1 parent ee525e5 commit 27f1a76
Show file tree
Hide file tree
Showing 10 changed files with 313 additions and 69 deletions.
5 changes: 3 additions & 2 deletions tests/examples/constraints.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import unfurl
import tosca
from tosca import gb
from typing_extensions import reveal_type
class ContainerService(tosca.nodes.Root):
image: str
url: str
Expand Down Expand Up @@ -40,8 +41,8 @@ def _class_init(cls) -> None:
# the proxy's backend is set to the container's url
cls.proxy.backend_url = cls.container.url
cls.proxy.hosting.name = "app"
tosca.in_range(2*gb, 20*gb).apply_constraint(cls.proxy.hosting.mem_size)
# same as:
tosca.in_range(1*gb*2, 20*gb).apply_constraint(cls.proxy.hosting.mem_size)
# the following is equivalent, but has a static type error:
# cls.proxy.hosting.mem_size = tosca.in_range(2*gb, 20*gb)

topology = App("myapp", proxy=ProxyContainerHost())
12 changes: 11 additions & 1 deletion tests/examples/dsl_relationships.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
# TESTS:
# _target
# f-strings: __str__ => "{{ 'expr' | eval }}"
# unfurl.tosca_plugins imports in safe mode
# runtime_func in safe mode

import unfurl
import tosca
from typing import Optional
from unfurl.tosca_plugins.expr import runtime_func
from unfurl.tosca_plugins.functions import to_dns_label

@runtime_func
def disk_label(label: str) -> str:
return to_dns_label(label + "_disk")

class Volume(tosca.nodes.Root):
disk_label: str
disk_size: tosca.Size = 100 * tosca.GB

class VolumeAttachment(tosca.relationships.AttachesTo):
_target: Volume
Expand All @@ -26,5 +36,5 @@ def _class_init(cls):
# XXX intent = when_expr(cls.volume_attachment, 'mount', 'skip')
intent = 'mount' if cls.volume_attachment else 'skip',
target = "HOST",
mountpoint = f"/mnt/{cls.volume_attachment._target.disk_label}",
mountpoint = f"/mnt/{disk_label(cls.volume_attachment._target.disk_label)}",
)
25 changes: 25 additions & 0 deletions tests/examples/type_errors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import unfurl
import tosca
from tosca import gb, Size
from typing_extensions import reveal_type
class ContainerService(tosca.nodes.Root):
image: str
url: str
mem_size: tosca.Size
name: str = tosca.CONSTRAINED

@classmethod
def _class_init(cls) -> None:
# the proxy's backend is set to the container's url
g: Size = 2 * gb
bar: Size = g * 2.0
baz: Size = g * 2
wrong = g * "ddd"
change_unit: Size = g * tosca.MB
mismatch = g * 2.0 * tosca.kHz
mismatch = g * tosca.HZ
tosca.in_range(2*gb*2, 2*gb*2).apply_constraint(cls.mem_size)
tosca.in_range(2*gb*2, 2*gb*2).apply_constraint(cls.url)
baz + 50*tosca.GHz
tosca.MB.as_int(baz)
tosca.GHz.as_int(baz)
38 changes: 24 additions & 14 deletions tests/test_constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,7 @@
from tosca.python2yaml import PythonToYaml
from click.testing import CliRunner
from unfurl.util import change_cwd


def _verify_mypy(path):
stdout, stderr, return_code = api.run(["--disable-error-code=override", path])
if stdout:
print(stdout)
assert "no issues found in 1 source file" in stdout
assert return_code == 0, (stderr, stdout)
from unfurl.testing import assert_no_mypy_errors


def test_constraints():
Expand Down Expand Up @@ -190,7 +183,22 @@ def test_constraints():
def test_mypy(path):
# assert mypy ok
basepath = os.path.join(os.path.dirname(__file__), "examples", path)
_verify_mypy(basepath)
assert_no_mypy_errors(basepath, "--disable-error-code=override")


@unittest.skipIf("slow" in os.getenv("UNFURL_TEST_SKIP", ""), "UNFURL_TEST_SKIP set")
def test_mypy_errors():
# assert mypy expected errors
expected = [
'error: Unsupported operand types for * ("Size" and "str") [operator]',
'Unsupported operand types for * ("Size" and "_Unit[Frequency]") [operator]',
'Argument 1 to "apply_constraint" of "DataConstraint" has incompatible type "str"; expected "Size" [arg-type]',
'Unsupported operand types for + ("Size" and "Frequency")',
'Argument 1 to "as_int" of "_Unit" has incompatible type "Size"; expected "Frequency"',
"Found 6 errors in 1 file",
]
basepath = os.path.join(os.path.dirname(__file__), "examples", "type_errors.py")
assert_no_mypy_errors(basepath, expected=expected)


constraints_yaml = """
Expand Down Expand Up @@ -301,7 +309,6 @@ def test_computed_properties():
"source": 80,
"source_range": None,
},

"a_list": [1],
"data_list": [
{
Expand All @@ -312,7 +319,7 @@ def test_computed_properties():
"source": 80,
"source_range": None,
},
"additional": 1
"additional": 1,
}
],
"extra": "extra",
Expand Down Expand Up @@ -353,15 +360,18 @@ def test_computed_properties():
"node_types": {
"Volume": {
"derived_from": "tosca.nodes.Root",
"properties": {"disk_label": {"type": "string"}},
"properties": {
"disk_label": {"type": "string"},
"disk_size": {"type": "scalar-unit.size", "default": "100 GB"},
},
},
"TestTarget": {
"derived_from": "tosca.nodes.Root",
"artifacts": {
"volume_mount": {
"type": "VolumeMountArtifact",
"properties": {
"mountpoint": "/mnt/{{ '.targets::volume_attachment::.target::disk_label' | eval }}"
"mountpoint": "/mnt/{{ {'eval': {'computed': ['service_template.dsl_relationships:disk_label', {'eval': '.targets::volume_attachment::.target::disk_label'}]}} | map_value }}",
},
"file": "",
"intent": "mount",
Expand Down Expand Up @@ -396,7 +406,7 @@ def test_computed_properties():
def test_relationships():
basepath = os.path.join(os.path.dirname(__file__), "examples/")
# loads yaml with with a json include
local = LocalEnv(basepath + "dsl-ensemble.yaml")
local = LocalEnv(basepath + "dsl-ensemble.yaml") # loads dsl_relationships.py
manifest = local.get_manifest(skip_validation=True, safe_mode=True)
service_template = manifest.manifest.expanded["spec"]["service_template"]
# pprint.pprint(service_template, indent=2)
Expand Down
1 change: 1 addition & 0 deletions tests/test_dsl.py
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,7 @@ def db_server_configure(**kw: Any) -> Any:
'''



def test_example_helloworld():
src, src_tpl = _to_python(example_helloworld_yaml)
tosca_tpl = _to_yaml(src, True)
Expand Down
Loading

0 comments on commit 27f1a76

Please sign in to comment.