Skip to content

Commit

Permalink
#5 scheduled task delete commands
Browse files Browse the repository at this point in the history
  • Loading branch information
filiplajszczak authored and caseneuve committed Mar 13, 2021
1 parent ecbe478 commit 2fe20b7
Show file tree
Hide file tree
Showing 2 changed files with 139 additions and 32 deletions.
42 changes: 38 additions & 4 deletions cli/scheduled_task.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
from typing import List

import typer

from pythonanywhere.task import Task
from pythonanywhere.scripts_commons import get_task_from_id
from pythonanywhere.task import Task, TaskList

app = typer.Typer()

Expand Down Expand Up @@ -56,9 +59,40 @@ def create(
task.create_schedule()


@app.command()
def delete():
raise NotImplementedError
delete_app = typer.Typer()
app.add_typer(
delete_app, name="delete", help="Delete scheduled task(s) by id or nuke'em all."
)


@delete_app.command("nuke", help="Delete all scheduled tasks.")
def delete_all_tasks(
force: bool = typer.Option(
False, "-f", "--force", help="Turns off user confirmation before deleting tasks"
),
):
if not force:
user_response = typer.confirm(
"This will irrevocably delete all your tasks, proceed?"
)
if not user_response:
return None

for task in TaskList().tasks:
task.delete_schedule()


@delete_app.command(
"id",
help="""\b
Delete one or more scheduled tasks by id.
ID_NUMBERS may be acquired with `pa scheduled-task list`
""",
)
def delete_task_by_id(id_numbers: List[int] = typer.Argument(...)):
for task_id in id_numbers:
task = get_task_from_id(task_id, no_exit=True)
task.delete_schedule()


@app.command()
Expand Down
129 changes: 101 additions & 28 deletions tests/test_cli_scheduled_task.py
Original file line number Diff line number Diff line change
@@ -1,41 +1,114 @@
from unittest.mock import call
from unittest.mock import call, Mock

import pytest
from typer.testing import CliRunner

from cli.scheduled_task import app
from cli.scheduled_task import app, delete_app

runner = CliRunner()


def test_create_calls_all_stuff_in_right_order(mocker):
mock_task_to_be_created = mocker.patch("cli.scheduled_task.Task.to_be_created")
@pytest.fixture
def task_list(mocker):
mock_task_list = mocker.patch("cli.scheduled_task.TaskList")
mock_task_list.return_value.tasks = [Mock(task_id=1), Mock(task_id=2)]
return mock_task_list

runner.invoke(
app,
[
"create",
"--command",
"echo foo",
"--hour",
8,
"--minute",
10,
],
)

assert mock_task_to_be_created.call_args == call(
command="echo foo", hour=8, minute=10, disabled=False
)
assert mock_task_to_be_created.return_value.method_calls == [call.create_schedule()]
@pytest.fixture
def mock_confirm(mocker):
return mocker.patch("cli.scheduled_task.typer.confirm")


def test_create_validates_minutes():
result = runner.invoke(app, ["create", "-c", "echo foo", "-h", 8, "-m", 66])
assert "Invalid value" in result.stdout
assert "66 is not in the valid range of 0 to 59" in result.stdout
class TestCreate:
def test_calls_all_stuff_in_right_order(self, mocker):
mock_task_to_be_created = mocker.patch("cli.scheduled_task.Task.to_be_created")

runner.invoke(
app,
[
"create",
"--command",
"echo foo",
"--hour",
"8",
"--minute",
"10",
],
)

def test_create_validates_hours():
result = runner.invoke(app, ["create", "-c", "echo foo", "-h", 66, "-m", 1])
assert "Invalid value" in result.stdout
assert "66 is not in the valid range of 0 to 23" in result.stdout
assert mock_task_to_be_created.call_args == call(
command="echo foo", hour=8, minute=10, disabled=False
)
assert mock_task_to_be_created.return_value.method_calls == [
call.create_schedule()
]

def test_validates_minutes(self):
result = runner.invoke(app, ["create", "-c", "echo foo", "-h", "8", "-m", "66"])

assert "Invalid value" in result.stdout
assert "66 is not in the valid range of 0 to 59" in result.stdout

def test_validates_hours(self):
result = runner.invoke(app, ["create", "-c", "echo foo", "-h", "66", "-m", "1"])
assert "Invalid value" in result.stdout
assert "66 is not in the valid range of 0 to 23" in result.stdout


class TestDeleteAllTasks:
def test_deletes_all_tasks_with_user_permission(self, task_list, mock_confirm):
mock_confirm.return_value = True

runner.invoke(delete_app, ["nuke"])

assert mock_confirm.call_args == call(
"This will irrevocably delete all your tasks, proceed?"
)
assert task_list.call_count == 1
for task in task_list.return_value.tasks:
assert task.method_calls == [call.delete_schedule()]

def test_exits_when_user_changes_mind(self, task_list, mock_confirm):
mock_confirm.return_value = False

runner.invoke(
delete_app,
[
"nuke",
],
)

assert task_list.call_count == 0

def test_deletes_all_tasks_when_forced(self, task_list, mock_confirm):
runner.invoke(delete_app, ["nuke", "--force"])

assert mock_confirm.call_count == 0
assert task_list.call_count == 1
for task in task_list.return_value.tasks:
assert task.method_calls == [call.delete_schedule()]


class TestDeleteTaskById:
def test_deletes_one_task(self, mocker):
mock_task_from_id = mocker.patch("cli.scheduled_task.get_task_from_id")

runner.invoke(delete_app, ["id", "42"])

assert mock_task_from_id.call_args == call(42, no_exit=True)
assert mock_task_from_id.return_value.method_calls == [call.delete_schedule()]

def test_deletes_some_tasks(self, mocker):
mock_task_from_id = mocker.patch("cli.scheduled_task.get_task_from_id")

runner.invoke(delete_app, ["id", "24", "42"])

assert mock_task_from_id.call_args_list == [
call(24, no_exit=True),
call(42, no_exit=True),
]
assert mock_task_from_id.return_value.method_calls == [
call.delete_schedule(),
call.delete_schedule(),
]

0 comments on commit 2fe20b7

Please sign in to comment.