diff --git a/integration/Makefile b/integration/Makefile index 9c0eaabb..af636a25 100644 --- a/integration/Makefile +++ b/integration/Makefile @@ -138,4 +138,4 @@ help: # on local network. test: mkdir -p logs - CONNECT_VERSION=${CONNECT_VERSION} CONNECT_API_KEY="$(shell rsconnect bootstrap -i -s http://connect:3939 --raw)" $(PYTHON) -m pytest --junit-xml=./reports/$(CONNECT_VERSION).xml > ./logs/$(CONNECT_VERSION).log + CONNECT_VERSION=${CONNECT_VERSION} CONNECT_API_KEY="$(shell rsconnect bootstrap -i -s http://connect:3939 --raw)" $(PYTHON) -m pytest -s --junit-xml=./reports/$(CONNECT_VERSION).xml | tee ./logs/$(CONNECT_VERSION).log diff --git a/integration/tests/posit/connect/test_client.py b/integration/tests/posit/connect/test_client.py index 1352007f..e7ac3647 100644 --- a/integration/tests/posit/connect/test_client.py +++ b/integration/tests/posit/connect/test_client.py @@ -1,6 +1,3 @@ -import os -import pytest - from posit import connect diff --git a/integration/tests/posit/connect/test_content.py b/integration/tests/posit/connect/test_content.py new file mode 100644 index 00000000..d7fa2fbd --- /dev/null +++ b/integration/tests/posit/connect/test_content.py @@ -0,0 +1,33 @@ +from posit import connect + + +class TestContent: + def setup_class(cls): + cls.client = connect.Client() + cls.item = cls.client.content.create( + name="Sample", + description="Simple sample content for testing", + access_type="acl", + ) + + def test_count(self): + assert self.client.content.count() == 1 + + def test_get(self): + assert self.client.content.get(self.item.guid) == self.item + + def test_find(self): + assert self.client.content.find() + + def test_find_one(self): + assert self.client.content.find_one() + + def test_content_item_owner(self): + item = self.client.content.find_one(include=None) + owner = item.owner + assert owner.guid == self.client.me.guid + + def test_content_item_owner_from_include(self): + item = self.client.content.find_one(include="owner") + owner = item.owner + assert owner.guid == self.client.me.guid diff --git a/src/posit/connect/content.py b/src/posit/connect/content.py index 188c6a4c..50c3963b 100644 --- a/src/posit/connect/content.py +++ b/src/posit/connect/content.py @@ -13,6 +13,7 @@ from .bundles import Bundles from .permissions import Permissions from .resources import Resources, Resource +from .users import Users class ContentItemOwner(Resource): @@ -146,6 +147,17 @@ def bundles(self) -> Bundles: def permissions(self) -> Permissions: return Permissions(self.config, self.session, self.guid) + @property + def owner(self) -> ContentItemOwner: + if "owner" not in self: + # It is possible to get a content item that does not contain owner. + # "owner" is an optional additional request param. + # If it's not included, we can retrieve the information by `owner_guid` + self["owner"] = Users(self.config, self.session).get( + self.owner_guid + ) + return ContentItemOwner(self.config, self.session, **self["owner"]) + # Properties @property @@ -308,10 +320,6 @@ def run_as_current_user(self) -> bool: def owner_guid(self) -> str: return self.get("owner_guid") # type: ignore - @property - def owner(self) -> ContentItemOwner: - return self.get("owner", {}) # type: ignore - @property def content_url(self) -> str: return self.get("content_url") # type: ignore diff --git a/tests/posit/connect/__api__/v1/content/f2f37341-e21d-3d80-c698-a935ad614066.json b/tests/posit/connect/__api__/v1/content/f2f37341-e21d-3d80-c698-a935ad614066.json index 07158938..48f4b8b5 100644 --- a/tests/posit/connect/__api__/v1/content/f2f37341-e21d-3d80-c698-a935ad614066.json +++ b/tests/posit/connect/__api__/v1/content/f2f37341-e21d-3d80-c698-a935ad614066.json @@ -37,7 +37,7 @@ "default_py_environment_management": null, "run_as": null, "run_as_current_user": false, - "owner_guid": "87c12c08-11cd-4de1-8da3-12a7579c4998", + "owner_guid": "20a79ce3-6e87-4522-9faf-be24228800a4", "content_url": "https://connect.example/content/f2f37341-e21d-3d80-c698-a935ad614066/", "dashboard_url": "https://connect.example/connect/#/apps/f2f37341-e21d-3d80-c698-a935ad614066", "app_role": "viewer", diff --git a/tests/posit/connect/__api__/v1/users/20a79ce3-6e87-4522-9faf-be24228800a4.json b/tests/posit/connect/__api__/v1/users/20a79ce3-6e87-4522-9faf-be24228800a4.json index 5561d5ae..8a6f6db9 100644 --- a/tests/posit/connect/__api__/v1/users/20a79ce3-6e87-4522-9faf-be24228800a4.json +++ b/tests/posit/connect/__api__/v1/users/20a79ce3-6e87-4522-9faf-be24228800a4.json @@ -10,4 +10,4 @@ "confirmed": true, "locked": false, "guid": "20a79ce3-6e87-4522-9faf-be24228800a4" -} \ No newline at end of file +} diff --git a/tests/posit/connect/test_content.py b/tests/posit/connect/test_content.py index 21c2a5b0..4980029f 100644 --- a/tests/posit/connect/test_content.py +++ b/tests/posit/connect/test_content.py @@ -5,12 +5,34 @@ from posit.connect.client import Client from posit.connect.config import Config -from posit.connect.content import ContentItem +from posit.connect.content import ContentItem, ContentItemOwner from posit.connect.permissions import Permissions from .api import load_mock # type: ignore +class TestContentOwnerAttributes: + @classmethod + def setup_class(cls): + guid = "20a79ce3-6e87-4522-9faf-be24228800a4" + config = Config(api_key="12345", url="https://connect.example/") + session = requests.Session() + fake_item = load_mock(f"v1/users/{guid}.json") + cls.item = ContentItemOwner(config, session, **fake_item) + + def test_guid(self): + assert self.item.guid == "20a79ce3-6e87-4522-9faf-be24228800a4" + + def test_username(self): + assert self.item.username == "carlos12" + + def test_first_name(self): + assert self.item.first_name == "Carlos" + + def test_last_name(self): + assert self.item.last_name == "User" + + class TestContentItemAttributes: @classmethod def setup_class(cls): @@ -138,7 +160,7 @@ def test_run_as_current_user(self): assert self.item.run_as_current_user is False def test_owner_guid(self): - assert self.item.owner_guid == "87c12c08-11cd-4de1-8da3-12a7579c4998" + assert self.item.owner_guid == "20a79ce3-6e87-4522-9faf-be24228800a4" def test_content_url(self): assert ( @@ -156,7 +178,7 @@ def test_app_role(self): assert self.item.app_role == "viewer" def test_owner(self): - assert self.item.owner == {} + assert "owner" not in self.item def test_permissions(self): assert isinstance(self.item.permissions, Permissions) @@ -165,6 +187,35 @@ def test_tags(self): assert self.item.tags == [] +class TestContentItemGetContentOwner: + @responses.activate + def test_owner(self): + mock_content = load_mock( + "v1/content/f2f37341-e21d-3d80-c698-a935ad614066.json" + ) + responses.get( + "https://connect.example/__api__/v1/content/f2f37341-e21d-3d80-c698-a935ad614066", + json=mock_content, + ) + + mock_user_get = responses.get( + f"https://connect.example/__api__/v1/users/20a79ce3-6e87-4522-9faf-be24228800a4", + json=load_mock( + f"v1/users/20a79ce3-6e87-4522-9faf-be24228800a4.json" + ), + ) + + c = Client("12345", "https://connect.example") + item = c.content.get("f2f37341-e21d-3d80-c698-a935ad614066") + owner = item.owner + assert owner.guid == "20a79ce3-6e87-4522-9faf-be24228800a4" + + # load a second time, assert tha owner is loaded from cached result + owner = item.owner + assert owner.guid == "20a79ce3-6e87-4522-9faf-be24228800a4" + assert mock_user_get.call_count == 1 + + class TestContentItemDelete: @responses.activate def test(self):