Skip to content

Commit

Permalink
test: adds tests for content create, bundle create, and tasks
Browse files Browse the repository at this point in the history
  • Loading branch information
tdstein committed Apr 26, 2024
1 parent 18da02e commit 9230d94
Show file tree
Hide file tree
Showing 7 changed files with 274 additions and 2 deletions.
8 changes: 8 additions & 0 deletions src/posit/connect/bundles.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,18 @@ def delete(self) -> None:
def deploy(self) -> tasks.Task:
"""Deploy the bundle.
Spawns an asynchronous task, which activates the bundle.
Returns
-------
tasks.Task
The task for the deployment.
Examples
--------
>>> task = bundle.deploy()
>>> task.wait_for()
None
"""
path = f"v1/content/{self.content_guid}/deploy"
url = urls.append(self.config.url, path)
Expand Down
12 changes: 11 additions & 1 deletion src/posit/connect/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from requests import Response, Session
from typing import Optional

from . import config, hooks, me, metrics, urls
from . import config, hooks, me, metrics, tasks, urls

from .auth import Auth
from .config import Config
Expand Down Expand Up @@ -77,6 +77,16 @@ def oauth(self) -> OAuthIntegration:
"""
return OAuthIntegration(config=self.config, session=self.session)

@property
def tasks(self) -> tasks.Tasks:
"""The tasks resource interface.
Returns
-------
tasks.Tasks
"""
return tasks.Tasks(self.config, self.session)

@property
def users(self) -> Users:
"""The users resource interface.
Expand Down
2 changes: 1 addition & 1 deletion src/posit/connect/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ def wait_for(self, sleep: int = 1) -> None:
Parameters
----------
sleep : int, optional
Maximum number of seconds to wait between task status checks.
Maximum number of seconds to wait between status checks.
"""
while not self.is_finished:
self.update(wait=sleep)
Expand Down
12 changes: 12 additions & 0 deletions tests/posit/connect/__api__/v1/tasks/jXhOhdm5OOSkGhJw.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"id": "jXhOhdm5OOSkGhJw",
"output": [
"Building static content...",
"Launching static content..."
],
"finished": true,
"code": 1,
"error": "Unable to render: Rendering exited abnormally: exit status 1",
"last": 2,
"result": null
}
47 changes: 47 additions & 0 deletions tests/posit/connect/test_bundles.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import requests
import responses

from responses import matchers
from unittest import mock

from posit.connect import Client
Expand Down Expand Up @@ -124,6 +125,52 @@ def test(self):
assert mock_bundle_delete.call_count == 1


class TestBundleDeploy:
@responses.activate
def test(self):
content_guid = "f2f37341-e21d-3d80-c698-a935ad614066"
bundle_id = "101"
task_id = "jXhOhdm5OOSkGhJw"

# behavior
mock_content_get = responses.get(
f"https://connect.example/__api__/v1/content/{content_guid}",
json=load_mock(f"v1/content/{content_guid}.json"),
)

mock_bundle_get = responses.get(
f"https://connect.example/__api__/v1/content/{content_guid}/bundles/{bundle_id}",
json=load_mock(
f"v1/content/{content_guid}/bundles/{bundle_id}.json"
),
)

mock_bundle_deploy = responses.post(
f"https://connect.example/__api__/v1/content/{content_guid}/deploy",
match=[matchers.json_params_matcher({"bundle_id": bundle_id})],
json={"task_id": task_id},
)

mock_tasks_get = responses.get(
f"https://connect.example/__api__/v1/tasks/{task_id}",
json=load_mock(f"v1/tasks/{task_id}.json"),
)

# setup
c = Client("12345", "https://connect.example")
bundle = c.content.get(content_guid).bundles.get(bundle_id)

# invoke
task = bundle.deploy()

# assert
task.id == task_id
assert mock_content_get.call_count == 1
assert mock_bundle_get.call_count == 1
assert mock_bundle_deploy.call_count == 1
assert mock_tasks_get.call_count == 1


class TestBundleDownload:
@mock.patch("builtins.open", new_callable=mock.mock_open)
@responses.activate
Expand Down
38 changes: 38 additions & 0 deletions tests/posit/connect/test_content.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,44 @@ def test(self):
assert mock_delete.call_count == 1


class TestContentDeploy:
@responses.activate
def test(self):
content_guid = "f2f37341-e21d-3d80-c698-a935ad614066"
bundle_id = "101"
task_id = "jXhOhdm5OOSkGhJw"

# behavior
mock_content_get = responses.get(
f"https://connect.example/__api__/v1/content/{content_guid}",
json=load_mock(f"v1/content/{content_guid}.json"),
)

mock_content_deploy = responses.post(
f"https://connect.example/__api__/v1/content/{content_guid}/deploy",
match=[matchers.json_params_matcher({"bundle_id": None})],
json={"task_id": task_id},
)

mock_tasks_get = responses.get(
f"https://connect.example/__api__/v1/tasks/{task_id}",
json=load_mock(f"v1/tasks/{task_id}.json"),
)

# setup
c = Client("12345", "https://connect.example")
content = c.content.get(content_guid)

# invoke
task = content.deploy()

# assert
task.id == task_id
assert mock_content_get.call_count == 1
assert mock_content_deploy.call_count == 1
assert mock_tasks_get.call_count == 1


class TestContentUpdate:
@responses.activate
def test_update(self):
Expand Down
157 changes: 157 additions & 0 deletions tests/posit/connect/test_tasks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
import requests
import responses

from responses import matchers

from posit import connect
from posit.connect import tasks

from .api import load_mock # type: ignore


class TestTaskAttributes:
def setup_class(cls):
cls.task = tasks.Task(
None,
None,
**load_mock("v1/tasks/jXhOhdm5OOSkGhJw.json"),
)

def test_id(self):
assert self.task.id == "jXhOhdm5OOSkGhJw"

def test_is_finished(self):
assert self.task.is_finished

def test_output(self):
assert self.task.output == [
"Building static content...",
"Launching static content...",
]

def test_error_code(self):
assert self.task.error_code == 1

def test_error_message(self):
assert (
self.task.error_message
== "Unable to render: Rendering exited abnormally: exit status 1"
)

def test_result(self):
assert self.task.result is None


class TestTaskUpdate:
@responses.activate
def test(self):
id = "jXhOhdm5OOSkGhJw"

# behavior
mock_tasks_get = [0] * 2
mock_tasks_get[0] = responses.get(
f"https://connect.example/__api__/v1/tasks/{id}",
json={**load_mock(f"v1/tasks/{id}.json"), "finished": False},
)

mock_tasks_get[1] = responses.get(
f"https://connect.example/__api__/v1/tasks/{id}",
json={**load_mock(f"v1/tasks/{id}.json"), "finished": True},
)

# setup
c = connect.Client("12345", "https://connect.example")
task = c.tasks.get(id)
assert not task.is_finished

# invoke
task.update()

# assert
assert task.is_finished
assert mock_tasks_get[0].call_count == 1
assert mock_tasks_get[1].call_count == 1

@responses.activate
def test_with_params(self):
id = "jXhOhdm5OOSkGhJw"
params = {"first": 10, "wait": 10}

# behavior
mock_tasks_get = [0] * 2
mock_tasks_get[0] = responses.get(
f"https://connect.example/__api__/v1/tasks/{id}",
json={**load_mock(f"v1/tasks/{id}.json"), "finished": False},
)

mock_tasks_get[1] = responses.get(
f"https://connect.example/__api__/v1/tasks/{id}",
json={**load_mock(f"v1/tasks/{id}.json"), "finished": True},
match=[matchers.query_param_matcher(params)],
)

# setup
c = connect.Client("12345", "https://connect.example")
task = c.tasks.get(id)
assert not task.is_finished

# invoke
task.update(**params)

# assert
assert task.is_finished
assert mock_tasks_get[0].call_count == 1
assert mock_tasks_get[1].call_count == 1


class TestTaskWaitFor:
@responses.activate
def test(self):
id = "jXhOhdm5OOSkGhJw"

# behavior
mock_tasks_get = [0] * 2
mock_tasks_get[0] = responses.get(
f"https://connect.example/__api__/v1/tasks/{id}",
json={**load_mock(f"v1/tasks/{id}.json"), "finished": False},
)

mock_tasks_get[1] = responses.get(
f"https://connect.example/__api__/v1/tasks/{id}",
json={**load_mock(f"v1/tasks/{id}.json"), "finished": True},
)

# setup
c = connect.Client("12345", "https://connect.example")
task = c.tasks.get(id)
assert not task.is_finished

# invoke
task.wait_for()

# assert
assert task.is_finished
assert mock_tasks_get[0].call_count == 1
assert mock_tasks_get[1].call_count == 1


class TestTasksGet:
@responses.activate
def test(self):
id = "jXhOhdm5OOSkGhJw"

# behavior
mock_tasks_get = responses.get(
f"https://connect.example/__api__/v1/tasks/{id}",
json={**load_mock(f"v1/tasks/{id}.json"), "finished": False},
)

# setup
c = connect.Client("12345", "https://connect.example")

# invoke
task = c.tasks.get(id)

# assert
assert task.id == id
assert mock_tasks_get.call_count == 1

0 comments on commit 9230d94

Please sign in to comment.