diff --git a/tableauserverclient/models/schedule_item.py b/tableauserverclient/models/schedule_item.py
index a2118e3d6..794d9883b 100644
--- a/tableauserverclient/models/schedule_item.py
+++ b/tableauserverclient/models/schedule_item.py
@@ -1,6 +1,6 @@
import xml.etree.ElementTree as ET
from datetime import datetime
-from typing import Optional, Union
+from typing import Optional, Union, TYPE_CHECKING
from defusedxml.ElementTree import fromstring
@@ -16,6 +16,10 @@
property_is_enum,
)
+if TYPE_CHECKING:
+ from requests import Response
+
+
Interval = Union[HourlyInterval, DailyInterval, WeeklyInterval, MonthlyInterval]
@@ -407,3 +411,8 @@ def _read_warnings(parsed_response, ns):
for warning_xml in all_warning_xml:
warnings.append(warning_xml.get("message", None))
return warnings
+
+
+def parse_batch_schedule_state(response: "Response", ns) -> list[str]:
+ xml = fromstring(response.content)
+ return [text for tag in xml.findall(".//t:scheduleLuid", namespaces=ns) if (text := tag.text)]
diff --git a/tableauserverclient/server/endpoint/schedules_endpoint.py b/tableauserverclient/server/endpoint/schedules_endpoint.py
index 090d400b6..8984af407 100644
--- a/tableauserverclient/server/endpoint/schedules_endpoint.py
+++ b/tableauserverclient/server/endpoint/schedules_endpoint.py
@@ -1,13 +1,15 @@
+from collections.abc import Iterable
import copy
import logging
import warnings
from collections import namedtuple
-from typing import TYPE_CHECKING, Callable, Optional, Union
+from typing import TYPE_CHECKING, Any, Callable, Literal, Optional, Union, overload
from .endpoint import Endpoint, api, parameter_added_in
from .exceptions import MissingRequiredFieldError
from tableauserverclient.server import RequestFactory
from tableauserverclient.models import PaginationItem, ScheduleItem, TaskItem, ExtractItem
+from tableauserverclient.models.schedule_item import parse_batch_schedule_state
from tableauserverclient.helpers.logging import logger
@@ -279,3 +281,48 @@ def get_extract_refresh_tasks(
extract_items = ExtractItem.from_response(server_response.content, self.parent_srv.namespace)
return extract_items, pagination_item
+
+ @overload
+ def batch_update_state(
+ self,
+ schedules: Iterable[ScheduleItem | str],
+ state: Literal["active", "suspended"],
+ update_all: Literal[False] = False,
+ ) -> list[str]: ...
+
+ @overload
+ def batch_update_state(
+ self, schedules: Any, state: Literal["active", "suspended"], update_all: Literal[True]
+ ) -> list[str]: ...
+
+ @api(version="3.27")
+ def batch_update_state(self, schedules, state, update_all=False) -> list[str]:
+ """
+ Batch update the status of one or more scheudles. If update_all is set,
+ all schedules on the Tableau Server are affected.
+
+ Parameters
+ ----------
+ schedules: Iterable[ScheudleItem | str] | Any
+ The schedules to be updated. If update_all=True, this is ignored.
+
+ state: Literal["active", "suspended"]
+ The state of the schedules, whether active or suspended.
+
+ update_all: bool
+ Whether or not to apply the status to all schedules.
+
+ Returns
+ -------
+ List[str]
+ The IDs of the affected schedules.
+ """
+ params = {"state": state}
+ if update_all:
+ params["updateAll"] = "true"
+ payload = RequestFactory.Empty.empty_req()
+ else:
+ payload = RequestFactory.Schedule.batch_update_state(schedules)
+
+ response = self.put_request(self.baseurl, payload, parameters={"params": params})
+ return parse_batch_schedule_state(response, self.parent_srv.namespace)
diff --git a/tableauserverclient/server/request_factory.py b/tableauserverclient/server/request_factory.py
index 66071bbeb..e05ccb8c8 100644
--- a/tableauserverclient/server/request_factory.py
+++ b/tableauserverclient/server/request_factory.py
@@ -643,6 +643,16 @@ def add_datasource_req(self, id_: Optional[str], task_type: str = TaskItem.Type.
def add_flow_req(self, id_: Optional[str], task_type: str = TaskItem.Type.RunFlow) -> bytes:
return self._add_to_req(id_, "flow", task_type)
+ @_tsrequest_wrapped
+ def batch_update_state(self, xml: ET.Element, schedules: Iterable[ScheduleItem | str]) -> None:
+ luids = ET.SubElement(xml, "scheduleLuids")
+ for schedule in schedules:
+ luid = getattr(schedule, "id", schedule)
+ if not isinstance(luid, str):
+ continue
+ luid_tag = ET.SubElement(luids, "scheduleLuid")
+ luid_tag.text = luid
+
class SiteRequest:
def update_req(self, site_item: "SiteItem", parent_srv: Optional["Server"] = None):
diff --git a/test/assets/schedule_batch_update_state.xml b/test/assets/schedule_batch_update_state.xml
new file mode 100644
index 000000000..7749a3eeb
--- /dev/null
+++ b/test/assets/schedule_batch_update_state.xml
@@ -0,0 +1,7 @@
+
+
+ 593d2ebf-0d18-4deb-9d21-b113a4902583
+ cecbb71e-def0-4030-8068-5ae50f51db1c
+ f39a6e7d-405e-4c07-8c18-95845f9da80e
+
+
diff --git a/test/test_datasource.py b/test/test_datasource.py
index 7f4cca759..56eb11ab7 100644
--- a/test/test_datasource.py
+++ b/test/test_datasource.py
@@ -895,7 +895,8 @@ def test_publish_description(server: TSC.Server) -> None:
ds_elem = body.find(".//datasource")
assert ds_elem is not None
assert ds_elem.attrib["description"] == "Sample description"
-
+
+
def test_get_datasource_no_owner(server: TSC.Server) -> None:
with requests_mock.mock() as m:
m.get(server.datasources.baseurl, text=GET_NO_OWNER.read_text())
diff --git a/test/test_schedule.py b/test/test_schedule.py
index 4fcc85e18..2a9235d3c 100644
--- a/test/test_schedule.py
+++ b/test/test_schedule.py
@@ -1,425 +1,479 @@
-import os
-import unittest
+from pathlib import Path
from datetime import time
+from defusedxml.ElementTree import fromstring
+import pytest
import requests_mock
import tableauserverclient as TSC
from tableauserverclient.datetime_helpers import format_datetime
-TEST_ASSET_DIR = os.path.join(os.path.dirname(__file__), "assets")
-
-GET_XML = os.path.join(TEST_ASSET_DIR, "schedule_get.xml")
-GET_BY_ID_XML = os.path.join(TEST_ASSET_DIR, "schedule_get_by_id.xml")
-GET_HOURLY_ID_XML = os.path.join(TEST_ASSET_DIR, "schedule_get_hourly_id.xml")
-GET_DAILY_ID_XML = os.path.join(TEST_ASSET_DIR, "schedule_get_daily_id.xml")
-GET_MONTHLY_ID_XML = os.path.join(TEST_ASSET_DIR, "schedule_get_monthly_id.xml")
-GET_MONTHLY_ID_2_XML = os.path.join(TEST_ASSET_DIR, "schedule_get_monthly_id_2.xml")
-GET_EMPTY_XML = os.path.join(TEST_ASSET_DIR, "schedule_get_empty.xml")
-CREATE_HOURLY_XML = os.path.join(TEST_ASSET_DIR, "schedule_create_hourly.xml")
-CREATE_DAILY_XML = os.path.join(TEST_ASSET_DIR, "schedule_create_daily.xml")
-CREATE_WEEKLY_XML = os.path.join(TEST_ASSET_DIR, "schedule_create_weekly.xml")
-CREATE_MONTHLY_XML = os.path.join(TEST_ASSET_DIR, "schedule_create_monthly.xml")
-UPDATE_XML = os.path.join(TEST_ASSET_DIR, "schedule_update.xml")
-ADD_WORKBOOK_TO_SCHEDULE = os.path.join(TEST_ASSET_DIR, "schedule_add_workbook.xml")
-ADD_WORKBOOK_TO_SCHEDULE_WITH_WARNINGS = os.path.join(TEST_ASSET_DIR, "schedule_add_workbook_with_warnings.xml")
-ADD_DATASOURCE_TO_SCHEDULE = os.path.join(TEST_ASSET_DIR, "schedule_add_datasource.xml")
-ADD_FLOW_TO_SCHEDULE = os.path.join(TEST_ASSET_DIR, "schedule_add_flow.xml")
-GET_EXTRACT_TASKS_XML = os.path.join(TEST_ASSET_DIR, "schedule_get_extract_refresh_tasks.xml")
-
-WORKBOOK_GET_BY_ID_XML = os.path.join(TEST_ASSET_DIR, "workbook_get_by_id.xml")
-DATASOURCE_GET_BY_ID_XML = os.path.join(TEST_ASSET_DIR, "datasource_get_by_id.xml")
-FLOW_GET_BY_ID_XML = os.path.join(TEST_ASSET_DIR, "flow_get_by_id.xml")
-
-
-class ScheduleTests(unittest.TestCase):
- def setUp(self) -> None:
- self.server = TSC.Server("http://test", False)
-
- # Fake Signin
- self.server._site_id = "dad65087-b08b-4603-af4e-2887b8aafc67"
- self.server._auth_token = "j80k54ll2lfMZ0tv97mlPvvSCRyD0DOM"
-
- self.baseurl = self.server.schedules.baseurl
-
- def test_get(self) -> None:
- with open(GET_XML, "rb") as f:
- response_xml = f.read().decode("utf-8")
- with requests_mock.mock() as m:
- m.get(self.baseurl, text=response_xml)
- all_schedules, pagination_item = self.server.schedules.get()
-
- extract = all_schedules[0]
- subscription = all_schedules[1]
- flow = all_schedules[2]
- system = all_schedules[3]
-
- self.assertEqual(2, pagination_item.total_available)
- self.assertEqual("c9cff7f9-309c-4361-99ff-d4ba8c9f5467", extract.id)
- self.assertEqual("Weekday early mornings", extract.name)
- self.assertEqual("Active", extract.state)
- self.assertEqual(50, extract.priority)
- self.assertEqual("2016-07-06T20:19:00Z", format_datetime(extract.created_at))
- self.assertEqual("2016-09-13T11:00:32Z", format_datetime(extract.updated_at))
- self.assertEqual("Extract", extract.schedule_type)
- self.assertEqual("2016-09-14T11:00:00Z", format_datetime(extract.next_run_at))
-
- self.assertEqual("bcb79d07-6e47-472f-8a65-d7f51f40c36c", subscription.id)
- self.assertEqual("Saturday night", subscription.name)
- self.assertEqual("Active", subscription.state)
- self.assertEqual(80, subscription.priority)
- self.assertEqual("2016-07-07T20:19:00Z", format_datetime(subscription.created_at))
- self.assertEqual("2016-09-12T16:39:38Z", format_datetime(subscription.updated_at))
- self.assertEqual("Subscription", subscription.schedule_type)
- self.assertEqual("2016-09-18T06:00:00Z", format_datetime(subscription.next_run_at))
-
- self.assertEqual("f456e8f2-aeb2-4a8e-b823-00b6f08640f0", flow.id)
- self.assertEqual("First of the month 1:00AM", flow.name)
- self.assertEqual("Active", flow.state)
- self.assertEqual(50, flow.priority)
- self.assertEqual("2019-02-19T18:52:19Z", format_datetime(flow.created_at))
- self.assertEqual("2019-02-19T18:55:51Z", format_datetime(flow.updated_at))
- self.assertEqual("Flow", flow.schedule_type)
- self.assertEqual("2019-03-01T09:00:00Z", format_datetime(flow.next_run_at))
-
- self.assertEqual("3cfa4713-ce7c-4fa7-aa2e-f752bfc8dd04", system.id)
- self.assertEqual("First of the month 2:00AM", system.name)
- self.assertEqual("Active", system.state)
- self.assertEqual(30, system.priority)
- self.assertEqual("2019-02-19T18:52:19Z", format_datetime(system.created_at))
- self.assertEqual("2019-02-19T18:55:51Z", format_datetime(system.updated_at))
- self.assertEqual("System", system.schedule_type)
- self.assertEqual("2019-03-01T09:00:00Z", format_datetime(system.next_run_at))
-
- def test_get_empty(self) -> None:
- with open(GET_EMPTY_XML, "rb") as f:
- response_xml = f.read().decode("utf-8")
- with requests_mock.mock() as m:
- m.get(self.baseurl, text=response_xml)
- all_schedules, pagination_item = self.server.schedules.get()
-
- self.assertEqual(0, pagination_item.total_available)
- self.assertEqual([], all_schedules)
-
- def test_get_by_id(self) -> None:
- self.server.version = "3.8"
- with open(GET_BY_ID_XML, "rb") as f:
- response_xml = f.read().decode("utf-8")
- with requests_mock.mock() as m:
- schedule_id = "c9cff7f9-309c-4361-99ff-d4ba8c9f5467"
- baseurl = f"{self.server.baseurl}/schedules/{schedule_id}"
- m.get(baseurl, text=response_xml)
- schedule = self.server.schedules.get_by_id(schedule_id)
- self.assertIsNotNone(schedule)
- self.assertEqual(schedule_id, schedule.id)
- self.assertEqual("Weekday early mornings", schedule.name)
- self.assertEqual("Active", schedule.state)
-
- def test_get_hourly_by_id(self) -> None:
- self.server.version = "3.8"
- with open(GET_HOURLY_ID_XML, "rb") as f:
- response_xml = f.read().decode("utf-8")
- with requests_mock.mock() as m:
- schedule_id = "c9cff7f9-309c-4361-99ff-d4ba8c9f5467"
- baseurl = f"{self.server.baseurl}/schedules/{schedule_id}"
- m.get(baseurl, text=response_xml)
- schedule = self.server.schedules.get_by_id(schedule_id)
- self.assertIsNotNone(schedule)
- self.assertEqual(schedule_id, schedule.id)
- self.assertEqual("Hourly schedule", schedule.name)
- self.assertEqual("Active", schedule.state)
- self.assertEqual(("Monday", 0.5), schedule.interval_item.interval)
-
- def test_get_daily_by_id(self) -> None:
- self.server.version = "3.8"
- with open(GET_DAILY_ID_XML, "rb") as f:
- response_xml = f.read().decode("utf-8")
- with requests_mock.mock() as m:
- schedule_id = "c9cff7f9-309c-4361-99ff-d4ba8c9f5467"
- baseurl = f"{self.server.baseurl}/schedules/{schedule_id}"
- m.get(baseurl, text=response_xml)
- schedule = self.server.schedules.get_by_id(schedule_id)
- self.assertIsNotNone(schedule)
- self.assertEqual(schedule_id, schedule.id)
- self.assertEqual("Daily schedule", schedule.name)
- self.assertEqual("Active", schedule.state)
- self.assertEqual(("Monday", 2.0), schedule.interval_item.interval)
-
- def test_get_monthly_by_id(self) -> None:
- self.server.version = "3.8"
- with open(GET_MONTHLY_ID_XML, "rb") as f:
- response_xml = f.read().decode("utf-8")
- with requests_mock.mock() as m:
- schedule_id = "c9cff7f9-309c-4361-99ff-d4ba8c9f5467"
- baseurl = f"{self.server.baseurl}/schedules/{schedule_id}"
- m.get(baseurl, text=response_xml)
- schedule = self.server.schedules.get_by_id(schedule_id)
- self.assertIsNotNone(schedule)
- self.assertEqual(schedule_id, schedule.id)
- self.assertEqual("Monthly multiple days", schedule.name)
- self.assertEqual("Active", schedule.state)
- self.assertEqual(("1", "2"), schedule.interval_item.interval)
-
- def test_get_monthly_by_id_2(self) -> None:
- self.server.version = "3.15"
- with open(GET_MONTHLY_ID_2_XML, "rb") as f:
- response_xml = f.read().decode("utf-8")
- with requests_mock.mock() as m:
- schedule_id = "8c5caf33-6223-4724-83c3-ccdc1e730a07"
- baseurl = f"{self.server.baseurl}/schedules/{schedule_id}"
- m.get(baseurl, text=response_xml)
- schedule = self.server.schedules.get_by_id(schedule_id)
- self.assertIsNotNone(schedule)
- self.assertEqual(schedule_id, schedule.id)
- self.assertEqual("Monthly First Monday!", schedule.name)
- self.assertEqual("Active", schedule.state)
- self.assertEqual(("Monday", "First"), schedule.interval_item.interval)
-
- def test_delete(self) -> None:
- with requests_mock.mock() as m:
- m.delete(self.baseurl + "/c9cff7f9-309c-4361-99ff-d4ba8c9f5467", status_code=204)
- self.server.schedules.delete("c9cff7f9-309c-4361-99ff-d4ba8c9f5467")
-
- def test_create_hourly(self) -> None:
- with open(CREATE_HOURLY_XML, "rb") as f:
- response_xml = f.read().decode("utf-8")
- with requests_mock.mock() as m:
- m.post(self.baseurl, text=response_xml)
- hourly_interval = TSC.HourlyInterval(start_time=time(2, 30), end_time=time(23, 0), interval_value=2)
- new_schedule = TSC.ScheduleItem(
- "hourly-schedule-1",
- 50,
- TSC.ScheduleItem.Type.Extract,
- TSC.ScheduleItem.ExecutionOrder.Parallel,
- hourly_interval,
- )
- new_schedule = self.server.schedules.create(new_schedule)
-
- self.assertEqual("5f42be25-8a43-47ba-971a-63f2d4e7029c", new_schedule.id)
- self.assertEqual("hourly-schedule-1", new_schedule.name)
- self.assertEqual("Active", new_schedule.state)
- self.assertEqual(50, new_schedule.priority)
- self.assertEqual("2016-09-15T20:47:33Z", format_datetime(new_schedule.created_at))
- self.assertEqual("2016-09-15T20:47:33Z", format_datetime(new_schedule.updated_at))
- self.assertEqual(TSC.ScheduleItem.Type.Extract, new_schedule.schedule_type)
- self.assertEqual("2016-09-16T01:30:00Z", format_datetime(new_schedule.next_run_at))
- self.assertEqual(TSC.ScheduleItem.ExecutionOrder.Parallel, new_schedule.execution_order)
- self.assertEqual(time(2, 30), new_schedule.interval_item.start_time)
- self.assertEqual(time(23), new_schedule.interval_item.end_time) # type: ignore[union-attr]
- self.assertEqual(("8",), new_schedule.interval_item.interval) # type: ignore[union-attr]
-
- def test_create_daily(self) -> None:
- with open(CREATE_DAILY_XML, "rb") as f:
- response_xml = f.read().decode("utf-8")
- with requests_mock.mock() as m:
- m.post(self.baseurl, text=response_xml)
- daily_interval = TSC.DailyInterval(time(4, 50))
- new_schedule = TSC.ScheduleItem(
- "daily-schedule-1",
- 90,
- TSC.ScheduleItem.Type.Subscription,
- TSC.ScheduleItem.ExecutionOrder.Serial,
- daily_interval,
- )
- new_schedule = self.server.schedules.create(new_schedule)
-
- self.assertEqual("907cae38-72fd-417c-892a-95540c4664cd", new_schedule.id)
- self.assertEqual("daily-schedule-1", new_schedule.name)
- self.assertEqual("Active", new_schedule.state)
- self.assertEqual(90, new_schedule.priority)
- self.assertEqual("2016-09-15T21:01:09Z", format_datetime(new_schedule.created_at))
- self.assertEqual("2016-09-15T21:01:09Z", format_datetime(new_schedule.updated_at))
- self.assertEqual(TSC.ScheduleItem.Type.Subscription, new_schedule.schedule_type)
- self.assertEqual("2016-09-16T11:45:00Z", format_datetime(new_schedule.next_run_at))
- self.assertEqual(TSC.ScheduleItem.ExecutionOrder.Serial, new_schedule.execution_order)
- self.assertEqual(time(4, 45), new_schedule.interval_item.start_time)
-
- def test_create_weekly(self) -> None:
- with open(CREATE_WEEKLY_XML, "rb") as f:
- response_xml = f.read().decode("utf-8")
- with requests_mock.mock() as m:
- m.post(self.baseurl, text=response_xml)
- weekly_interval = TSC.WeeklyInterval(
- time(9, 15), TSC.IntervalItem.Day.Monday, TSC.IntervalItem.Day.Wednesday, TSC.IntervalItem.Day.Friday
- )
- new_schedule = TSC.ScheduleItem(
- "weekly-schedule-1",
- 80,
- TSC.ScheduleItem.Type.Extract,
- TSC.ScheduleItem.ExecutionOrder.Parallel,
- weekly_interval,
- )
- new_schedule = self.server.schedules.create(new_schedule)
-
- self.assertEqual("1adff386-6be0-4958-9f81-a35e676932bf", new_schedule.id)
- self.assertEqual("weekly-schedule-1", new_schedule.name)
- self.assertEqual("Active", new_schedule.state)
- self.assertEqual(80, new_schedule.priority)
- self.assertEqual("2016-09-15T21:12:50Z", format_datetime(new_schedule.created_at))
- self.assertEqual("2016-09-15T21:12:50Z", format_datetime(new_schedule.updated_at))
- self.assertEqual(TSC.ScheduleItem.Type.Extract, new_schedule.schedule_type)
- self.assertEqual("2016-09-16T16:15:00Z", format_datetime(new_schedule.next_run_at))
- self.assertEqual(TSC.ScheduleItem.ExecutionOrder.Parallel, new_schedule.execution_order)
- self.assertEqual(time(9, 15), new_schedule.interval_item.start_time)
- self.assertEqual(("Monday", "Wednesday", "Friday"), new_schedule.interval_item.interval)
- self.assertEqual(2, len(new_schedule.warnings))
- self.assertEqual("warning 1", new_schedule.warnings[0])
- self.assertEqual("warning 2", new_schedule.warnings[1])
-
- def test_create_monthly(self) -> None:
- with open(CREATE_MONTHLY_XML, "rb") as f:
- response_xml = f.read().decode("utf-8")
- with requests_mock.mock() as m:
- m.post(self.baseurl, text=response_xml)
- monthly_interval = TSC.MonthlyInterval(time(7), 12)
- new_schedule = TSC.ScheduleItem(
- "monthly-schedule-1",
- 20,
- TSC.ScheduleItem.Type.Extract,
- TSC.ScheduleItem.ExecutionOrder.Serial,
- monthly_interval,
- )
- new_schedule = self.server.schedules.create(new_schedule)
-
- self.assertEqual("e06a7c75-5576-4f68-882d-8909d0219326", new_schedule.id)
- self.assertEqual("monthly-schedule-1", new_schedule.name)
- self.assertEqual("Active", new_schedule.state)
- self.assertEqual(20, new_schedule.priority)
- self.assertEqual("2016-09-15T21:16:56Z", format_datetime(new_schedule.created_at))
- self.assertEqual("2016-09-15T21:16:56Z", format_datetime(new_schedule.updated_at))
- self.assertEqual(TSC.ScheduleItem.Type.Extract, new_schedule.schedule_type)
- self.assertEqual("2016-10-12T14:00:00Z", format_datetime(new_schedule.next_run_at))
- self.assertEqual(TSC.ScheduleItem.ExecutionOrder.Serial, new_schedule.execution_order)
- self.assertEqual(time(7), new_schedule.interval_item.start_time)
- self.assertEqual(("12",), new_schedule.interval_item.interval) # type: ignore[union-attr]
-
- def test_update(self) -> None:
- with open(UPDATE_XML, "rb") as f:
- response_xml = f.read().decode("utf-8")
- with requests_mock.mock() as m:
- m.put(self.baseurl + "/7bea1766-1543-4052-9753-9d224bc069b5", text=response_xml)
- new_interval = TSC.WeeklyInterval(time(7), TSC.IntervalItem.Day.Monday, TSC.IntervalItem.Day.Friday)
- single_schedule = TSC.ScheduleItem(
- "weekly-schedule-1",
- 90,
- TSC.ScheduleItem.Type.Extract,
- TSC.ScheduleItem.ExecutionOrder.Parallel,
- new_interval,
- )
- single_schedule._id = "7bea1766-1543-4052-9753-9d224bc069b5"
- single_schedule.state = TSC.ScheduleItem.State.Suspended
- single_schedule = self.server.schedules.update(single_schedule)
-
- self.assertEqual("7bea1766-1543-4052-9753-9d224bc069b5", single_schedule.id)
- self.assertEqual("weekly-schedule-1", single_schedule.name)
- self.assertEqual(90, single_schedule.priority)
- self.assertEqual("2016-09-15T23:50:02Z", format_datetime(single_schedule.updated_at))
- self.assertEqual(TSC.ScheduleItem.Type.Extract, single_schedule.schedule_type)
- self.assertEqual("2016-09-16T14:00:00Z", format_datetime(single_schedule.next_run_at))
- self.assertEqual(TSC.ScheduleItem.ExecutionOrder.Parallel, single_schedule.execution_order)
- self.assertEqual(time(7), single_schedule.interval_item.start_time)
- self.assertEqual(("Monday", "Friday"), single_schedule.interval_item.interval) # type: ignore[union-attr]
- self.assertEqual(TSC.ScheduleItem.State.Suspended, single_schedule.state)
-
- # Tests calling update with a schedule item returned from the server
- def test_update_after_get(self) -> None:
- with open(GET_XML, "rb") as f:
- get_response_xml = f.read().decode("utf-8")
- with open(UPDATE_XML, "rb") as f:
- update_response_xml = f.read().decode("utf-8")
-
- # Get a schedule
- with requests_mock.mock() as m:
- m.get(self.baseurl, text=get_response_xml)
- all_schedules, pagination_item = self.server.schedules.get()
- schedule_item = all_schedules[0]
- self.assertEqual(TSC.ScheduleItem.State.Active, schedule_item.state)
- self.assertEqual("Weekday early mornings", schedule_item.name)
-
- # Update the schedule
- with requests_mock.mock() as m:
- m.put(self.baseurl + "/c9cff7f9-309c-4361-99ff-d4ba8c9f5467", text=update_response_xml)
- schedule_item.state = TSC.ScheduleItem.State.Suspended
- schedule_item.name = "newName"
- schedule_item = self.server.schedules.update(schedule_item)
-
- self.assertEqual(TSC.ScheduleItem.State.Suspended, schedule_item.state)
- self.assertEqual("weekly-schedule-1", schedule_item.name)
-
- def test_add_workbook(self) -> None:
- self.server.version = "2.8"
- baseurl = f"{self.server.baseurl}/sites/{self.server.site_id}/schedules"
-
- with open(WORKBOOK_GET_BY_ID_XML, "rb") as f:
- workbook_response = f.read().decode("utf-8")
- with open(ADD_WORKBOOK_TO_SCHEDULE, "rb") as f:
- add_workbook_response = f.read().decode("utf-8")
- with requests_mock.mock() as m:
- m.get(self.server.workbooks.baseurl + "/bar", text=workbook_response)
- m.put(baseurl + "/foo/workbooks", text=add_workbook_response)
- workbook = self.server.workbooks.get_by_id("bar")
- result = self.server.schedules.add_to_schedule("foo", workbook=workbook)
- self.assertEqual(0, len(result), "Added properly")
-
- def test_add_workbook_with_warnings(self) -> None:
- self.server.version = "2.8"
- baseurl = f"{self.server.baseurl}/sites/{self.server.site_id}/schedules"
-
- with open(WORKBOOK_GET_BY_ID_XML, "rb") as f:
- workbook_response = f.read().decode("utf-8")
- with open(ADD_WORKBOOK_TO_SCHEDULE_WITH_WARNINGS, "rb") as f:
- add_workbook_response = f.read().decode("utf-8")
- with requests_mock.mock() as m:
- m.get(self.server.workbooks.baseurl + "/bar", text=workbook_response)
- m.put(baseurl + "/foo/workbooks", text=add_workbook_response)
- workbook = self.server.workbooks.get_by_id("bar")
- result = self.server.schedules.add_to_schedule("foo", workbook=workbook)
- self.assertEqual(1, len(result), "Not added properly")
- self.assertEqual(2, len(result[0].warnings))
-
- def test_add_datasource(self) -> None:
- self.server.version = "2.8"
- baseurl = f"{self.server.baseurl}/sites/{self.server.site_id}/schedules"
-
- with open(DATASOURCE_GET_BY_ID_XML, "rb") as f:
- datasource_response = f.read().decode("utf-8")
- with open(ADD_DATASOURCE_TO_SCHEDULE, "rb") as f:
- add_datasource_response = f.read().decode("utf-8")
- with requests_mock.mock() as m:
- m.get(self.server.datasources.baseurl + "/bar", text=datasource_response)
- m.put(baseurl + "/foo/datasources", text=add_datasource_response)
- datasource = self.server.datasources.get_by_id("bar")
- result = self.server.schedules.add_to_schedule("foo", datasource=datasource)
- self.assertEqual(0, len(result), "Added properly")
-
- def test_add_flow(self) -> None:
- self.server.version = "3.3"
- baseurl = f"{self.server.baseurl}/sites/{self.server.site_id}/schedules"
-
- with open(FLOW_GET_BY_ID_XML, "rb") as f:
- flow_response = f.read().decode("utf-8")
- with open(ADD_FLOW_TO_SCHEDULE, "rb") as f:
- add_flow_response = f.read().decode("utf-8")
- with requests_mock.mock() as m:
- m.get(self.server.flows.baseurl + "/bar", text=flow_response)
- m.put(baseurl + "/foo/flows", text=flow_response)
- flow = self.server.flows.get_by_id("bar")
- result = self.server.schedules.add_to_schedule("foo", flow=flow)
- self.assertEqual(0, len(result), "Added properly")
-
- def test_get_extract_refresh_tasks(self) -> None:
- self.server.version = "2.3"
-
- with open(GET_EXTRACT_TASKS_XML, "rb") as f:
- response_xml = f.read().decode("utf-8")
- with requests_mock.mock() as m:
- schedule_id = "c9cff7f9-309c-4361-99ff-d4ba8c9f5467"
- baseurl = f"{self.server.baseurl}/sites/{self.server.site_id}/schedules/{schedule_id}/extracts"
- m.get(baseurl, text=response_xml)
-
- extracts = self.server.schedules.get_extract_refresh_tasks(schedule_id)
-
- self.assertIsNotNone(extracts)
- self.assertIsInstance(extracts[0], list)
- self.assertEqual(2, len(extracts[0]))
- self.assertEqual("task1", extracts[0][0].id)
+TEST_ASSET_DIR = Path(__file__).parent / "assets"
+
+GET_XML = TEST_ASSET_DIR / "schedule_get.xml"
+GET_BY_ID_XML = TEST_ASSET_DIR / "schedule_get_by_id.xml"
+GET_HOURLY_ID_XML = TEST_ASSET_DIR / "schedule_get_hourly_id.xml"
+GET_DAILY_ID_XML = TEST_ASSET_DIR / "schedule_get_daily_id.xml"
+GET_MONTHLY_ID_XML = TEST_ASSET_DIR / "schedule_get_monthly_id.xml"
+GET_MONTHLY_ID_2_XML = TEST_ASSET_DIR / "schedule_get_monthly_id_2.xml"
+GET_EMPTY_XML = TEST_ASSET_DIR / "schedule_get_empty.xml"
+CREATE_HOURLY_XML = TEST_ASSET_DIR / "schedule_create_hourly.xml"
+CREATE_DAILY_XML = TEST_ASSET_DIR / "schedule_create_daily.xml"
+CREATE_WEEKLY_XML = TEST_ASSET_DIR / "schedule_create_weekly.xml"
+CREATE_MONTHLY_XML = TEST_ASSET_DIR / "schedule_create_monthly.xml"
+UPDATE_XML = TEST_ASSET_DIR / "schedule_update.xml"
+ADD_WORKBOOK_TO_SCHEDULE = TEST_ASSET_DIR / "schedule_add_workbook.xml"
+ADD_WORKBOOK_TO_SCHEDULE_WITH_WARNINGS = TEST_ASSET_DIR / "schedule_add_workbook_with_warnings.xml"
+ADD_DATASOURCE_TO_SCHEDULE = TEST_ASSET_DIR / "schedule_add_datasource.xml"
+ADD_FLOW_TO_SCHEDULE = TEST_ASSET_DIR / "schedule_add_flow.xml"
+GET_EXTRACT_TASKS_XML = TEST_ASSET_DIR / "schedule_get_extract_refresh_tasks.xml"
+BATCH_UPDATE_STATE = TEST_ASSET_DIR / "schedule_batch_update_state.xml"
+
+WORKBOOK_GET_BY_ID_XML = TEST_ASSET_DIR / "workbook_get_by_id.xml"
+DATASOURCE_GET_BY_ID_XML = TEST_ASSET_DIR / "datasource_get_by_id.xml"
+FLOW_GET_BY_ID_XML = TEST_ASSET_DIR / "flow_get_by_id.xml"
+
+
+@pytest.fixture(scope="function")
+def server():
+ """Fixture to create a TSC.Server instance for testing."""
+ server = TSC.Server("http://test", False)
+
+ # Fake signin
+ server._site_id = "dad65087-b08b-4603-af4e-2887b8aafc67"
+ server._auth_token = "j80k54ll2lfMZ0tv97mlPvvSCRyD0DOM"
+
+ return server
+
+
+def test_get(server: TSC.Server) -> None:
+ response_xml = GET_XML.read_text()
+ with requests_mock.mock() as m:
+ m.get(server.schedules.baseurl, text=response_xml)
+ all_schedules, pagination_item = server.schedules.get()
+
+ extract = all_schedules[0]
+ subscription = all_schedules[1]
+ flow = all_schedules[2]
+ system = all_schedules[3]
+
+ assert 2 == pagination_item.total_available
+ assert "c9cff7f9-309c-4361-99ff-d4ba8c9f5467" == extract.id
+ assert "Weekday early mornings" == extract.name
+ assert "Active" == extract.state
+ assert 50 == extract.priority
+ assert "2016-07-06T20:19:00Z" == format_datetime(extract.created_at)
+ assert "2016-09-13T11:00:32Z" == format_datetime(extract.updated_at)
+ assert "Extract" == extract.schedule_type
+ assert "2016-09-14T11:00:00Z" == format_datetime(extract.next_run_at)
+
+ assert "bcb79d07-6e47-472f-8a65-d7f51f40c36c" == subscription.id
+ assert "Saturday night" == subscription.name
+ assert "Active" == subscription.state
+ assert 80 == subscription.priority
+ assert "2016-07-07T20:19:00Z" == format_datetime(subscription.created_at)
+ assert "2016-09-12T16:39:38Z" == format_datetime(subscription.updated_at)
+ assert "Subscription" == subscription.schedule_type
+ assert "2016-09-18T06:00:00Z" == format_datetime(subscription.next_run_at)
+
+ assert "f456e8f2-aeb2-4a8e-b823-00b6f08640f0" == flow.id
+ assert "First of the month 1:00AM" == flow.name
+ assert "Active" == flow.state
+ assert 50 == flow.priority
+ assert "2019-02-19T18:52:19Z" == format_datetime(flow.created_at)
+ assert "2019-02-19T18:55:51Z" == format_datetime(flow.updated_at)
+ assert "Flow" == flow.schedule_type
+ assert "2019-03-01T09:00:00Z" == format_datetime(flow.next_run_at)
+
+ assert "3cfa4713-ce7c-4fa7-aa2e-f752bfc8dd04" == system.id
+ assert "First of the month 2:00AM" == system.name
+ assert "Active" == system.state
+ assert 30 == system.priority
+ assert "2019-02-19T18:52:19Z" == format_datetime(system.created_at)
+ assert "2019-02-19T18:55:51Z" == format_datetime(system.updated_at)
+ assert "System" == system.schedule_type
+ assert "2019-03-01T09:00:00Z" == format_datetime(system.next_run_at)
+
+
+def test_get_empty(server: TSC.Server) -> None:
+ response_xml = GET_EMPTY_XML.read_text()
+ with requests_mock.mock() as m:
+ m.get(server.schedules.baseurl, text=response_xml)
+ all_schedules, pagination_item = server.schedules.get()
+
+ assert 0 == pagination_item.total_available
+ assert [] == all_schedules
+
+
+def test_get_by_id(server: TSC.Server) -> None:
+ server.version = "3.8"
+ response_xml = GET_BY_ID_XML.read_text()
+ with requests_mock.mock() as m:
+ schedule_id = "c9cff7f9-309c-4361-99ff-d4ba8c9f5467"
+ baseurl = f"{server.baseurl}/schedules/{schedule_id}"
+ m.get(baseurl, text=response_xml)
+ schedule = server.schedules.get_by_id(schedule_id)
+ assert schedule is not None
+ assert schedule_id == schedule.id
+ assert "Weekday early mornings" == schedule.name
+ assert "Active" == schedule.state
+
+
+def test_get_hourly_by_id(server: TSC.Server) -> None:
+ server.version = "3.8"
+ response_xml = GET_HOURLY_ID_XML.read_text()
+ with requests_mock.mock() as m:
+ schedule_id = "c9cff7f9-309c-4361-99ff-d4ba8c9f5467"
+ baseurl = f"{server.baseurl}/schedules/{schedule_id}"
+ m.get(baseurl, text=response_xml)
+ schedule = server.schedules.get_by_id(schedule_id)
+ assert schedule is not None
+ assert schedule_id == schedule.id
+ assert "Hourly schedule" == schedule.name
+ assert "Active" == schedule.state
+ assert ("Monday", 0.5) == schedule.interval_item.interval
+
+
+def test_get_daily_by_id(server: TSC.Server) -> None:
+ server.version = "3.8"
+ response_xml = GET_DAILY_ID_XML.read_text()
+ with requests_mock.mock() as m:
+ schedule_id = "c9cff7f9-309c-4361-99ff-d4ba8c9f5467"
+ baseurl = f"{server.baseurl}/schedules/{schedule_id}"
+ m.get(baseurl, text=response_xml)
+ schedule = server.schedules.get_by_id(schedule_id)
+ assert schedule is not None
+ assert schedule_id == schedule.id
+ assert "Daily schedule" == schedule.name
+ assert "Active" == schedule.state
+ assert ("Monday", 2.0) == schedule.interval_item.interval
+
+
+def test_get_monthly_by_id(server: TSC.Server) -> None:
+ server.version = "3.8"
+ response_xml = GET_MONTHLY_ID_XML.read_text()
+ with requests_mock.mock() as m:
+ schedule_id = "c9cff7f9-309c-4361-99ff-d4ba8c9f5467"
+ baseurl = f"{server.baseurl}/schedules/{schedule_id}"
+ m.get(baseurl, text=response_xml)
+ schedule = server.schedules.get_by_id(schedule_id)
+ assert schedule is not None
+ assert schedule_id == schedule.id
+ assert "Monthly multiple days" == schedule.name
+ assert "Active" == schedule.state
+ assert ("1", "2") == schedule.interval_item.interval
+
+
+def test_get_monthly_by_id_2(server: TSC.Server) -> None:
+ server.version = "3.15"
+ response_xml = GET_MONTHLY_ID_2_XML.read_text()
+ with requests_mock.mock() as m:
+ schedule_id = "8c5caf33-6223-4724-83c3-ccdc1e730a07"
+ baseurl = f"{server.baseurl}/schedules/{schedule_id}"
+ m.get(baseurl, text=response_xml)
+ schedule = server.schedules.get_by_id(schedule_id)
+ assert schedule is not None
+ assert schedule_id == schedule.id
+ assert "Monthly First Monday!" == schedule.name
+ assert "Active" == schedule.state
+ assert ("Monday", "First") == schedule.interval_item.interval
+
+
+def test_delete(server: TSC.Server) -> None:
+ with requests_mock.mock() as m:
+ m.delete(server.schedules.baseurl + "/c9cff7f9-309c-4361-99ff-d4ba8c9f5467", status_code=204)
+ server.schedules.delete("c9cff7f9-309c-4361-99ff-d4ba8c9f5467")
+
+
+def test_create_hourly(server: TSC.Server) -> None:
+ response_xml = CREATE_HOURLY_XML.read_text()
+ with requests_mock.mock() as m:
+ m.post(server.schedules.baseurl, text=response_xml)
+ hourly_interval = TSC.HourlyInterval(start_time=time(2, 30), end_time=time(23, 0), interval_value=2)
+ new_schedule = TSC.ScheduleItem(
+ "hourly-schedule-1",
+ 50,
+ TSC.ScheduleItem.Type.Extract,
+ TSC.ScheduleItem.ExecutionOrder.Parallel,
+ hourly_interval,
+ )
+ new_schedule = server.schedules.create(new_schedule)
+
+ assert "5f42be25-8a43-47ba-971a-63f2d4e7029c" == new_schedule.id
+ assert "hourly-schedule-1" == new_schedule.name
+ assert "Active" == new_schedule.state
+ assert 50 == new_schedule.priority
+ assert "2016-09-15T20:47:33Z" == format_datetime(new_schedule.created_at)
+ assert "2016-09-15T20:47:33Z" == format_datetime(new_schedule.updated_at)
+ assert TSC.ScheduleItem.Type.Extract == new_schedule.schedule_type
+ assert "2016-09-16T01:30:00Z" == format_datetime(new_schedule.next_run_at)
+ assert TSC.ScheduleItem.ExecutionOrder.Parallel == new_schedule.execution_order
+ assert time(2, 30) == new_schedule.interval_item.start_time
+ assert time(23) == new_schedule.interval_item.end_time # type: ignore[union-attr]
+ assert ("8",) == new_schedule.interval_item.interval # type: ignore[union-attr]
+
+
+def test_create_daily(server: TSC.Server) -> None:
+ response_xml = CREATE_DAILY_XML.read_text()
+ with requests_mock.mock() as m:
+ m.post(server.schedules.baseurl, text=response_xml)
+ daily_interval = TSC.DailyInterval(time(4, 50))
+ new_schedule = TSC.ScheduleItem(
+ "daily-schedule-1",
+ 90,
+ TSC.ScheduleItem.Type.Subscription,
+ TSC.ScheduleItem.ExecutionOrder.Serial,
+ daily_interval,
+ )
+ new_schedule = server.schedules.create(new_schedule)
+
+ assert "907cae38-72fd-417c-892a-95540c4664cd" == new_schedule.id
+ assert "daily-schedule-1" == new_schedule.name
+ assert "Active" == new_schedule.state
+ assert 90 == new_schedule.priority
+ assert "2016-09-15T21:01:09Z" == format_datetime(new_schedule.created_at)
+ assert "2016-09-15T21:01:09Z" == format_datetime(new_schedule.updated_at)
+ assert TSC.ScheduleItem.Type.Subscription == new_schedule.schedule_type
+ assert "2016-09-16T11:45:00Z" == format_datetime(new_schedule.next_run_at)
+ assert TSC.ScheduleItem.ExecutionOrder.Serial == new_schedule.execution_order
+ assert time(4, 45) == new_schedule.interval_item.start_time
+
+
+def test_create_weekly(server: TSC.Server) -> None:
+ response_xml = CREATE_WEEKLY_XML.read_text()
+ with requests_mock.mock() as m:
+ m.post(server.schedules.baseurl, text=response_xml)
+ weekly_interval = TSC.WeeklyInterval(
+ time(9, 15), TSC.IntervalItem.Day.Monday, TSC.IntervalItem.Day.Wednesday, TSC.IntervalItem.Day.Friday
+ )
+ new_schedule = TSC.ScheduleItem(
+ "weekly-schedule-1",
+ 80,
+ TSC.ScheduleItem.Type.Extract,
+ TSC.ScheduleItem.ExecutionOrder.Parallel,
+ weekly_interval,
+ )
+ new_schedule = server.schedules.create(new_schedule)
+
+ assert "1adff386-6be0-4958-9f81-a35e676932bf" == new_schedule.id
+ assert "weekly-schedule-1" == new_schedule.name
+ assert "Active" == new_schedule.state
+ assert 80 == new_schedule.priority
+ assert "2016-09-15T21:12:50Z" == format_datetime(new_schedule.created_at)
+ assert "2016-09-15T21:12:50Z" == format_datetime(new_schedule.updated_at)
+ assert TSC.ScheduleItem.Type.Extract == new_schedule.schedule_type
+ assert "2016-09-16T16:15:00Z" == format_datetime(new_schedule.next_run_at)
+ assert TSC.ScheduleItem.ExecutionOrder.Parallel == new_schedule.execution_order
+ assert time(9, 15) == new_schedule.interval_item.start_time
+ assert ("Monday", "Wednesday", "Friday") == new_schedule.interval_item.interval
+ assert 2 == len(new_schedule.warnings)
+ assert "warning 1" == new_schedule.warnings[0]
+ assert "warning 2" == new_schedule.warnings[1]
+
+
+def test_create_monthly(server: TSC.Server) -> None:
+ response_xml = CREATE_MONTHLY_XML.read_text()
+ with requests_mock.mock() as m:
+ m.post(server.schedules.baseurl, text=response_xml)
+ monthly_interval = TSC.MonthlyInterval(time(7), 12)
+ new_schedule = TSC.ScheduleItem(
+ "monthly-schedule-1",
+ 20,
+ TSC.ScheduleItem.Type.Extract,
+ TSC.ScheduleItem.ExecutionOrder.Serial,
+ monthly_interval,
+ )
+ new_schedule = server.schedules.create(new_schedule)
+
+ assert "e06a7c75-5576-4f68-882d-8909d0219326" == new_schedule.id
+ assert "monthly-schedule-1" == new_schedule.name
+ assert "Active" == new_schedule.state
+ assert 20 == new_schedule.priority
+ assert "2016-09-15T21:16:56Z" == format_datetime(new_schedule.created_at)
+ assert "2016-09-15T21:16:56Z" == format_datetime(new_schedule.updated_at)
+ assert TSC.ScheduleItem.Type.Extract == new_schedule.schedule_type
+ assert "2016-10-12T14:00:00Z" == format_datetime(new_schedule.next_run_at)
+ assert TSC.ScheduleItem.ExecutionOrder.Serial == new_schedule.execution_order
+ assert time(7) == new_schedule.interval_item.start_time
+ assert ("12",) == new_schedule.interval_item.interval # type: ignore[union-attr]
+
+
+def test_update(server: TSC.Server) -> None:
+ response_xml = UPDATE_XML.read_text()
+ with requests_mock.mock() as m:
+ m.put(server.schedules.baseurl + "/7bea1766-1543-4052-9753-9d224bc069b5", text=response_xml)
+ new_interval = TSC.WeeklyInterval(time(7), TSC.IntervalItem.Day.Monday, TSC.IntervalItem.Day.Friday)
+ single_schedule = TSC.ScheduleItem(
+ "weekly-schedule-1",
+ 90,
+ TSC.ScheduleItem.Type.Extract,
+ TSC.ScheduleItem.ExecutionOrder.Parallel,
+ new_interval,
+ )
+ single_schedule._id = "7bea1766-1543-4052-9753-9d224bc069b5"
+ single_schedule.state = TSC.ScheduleItem.State.Suspended
+ single_schedule = server.schedules.update(single_schedule)
+
+ assert "7bea1766-1543-4052-9753-9d224bc069b5" == single_schedule.id
+ assert "weekly-schedule-1" == single_schedule.name
+ assert 90 == single_schedule.priority
+ assert "2016-09-15T23:50:02Z" == format_datetime(single_schedule.updated_at)
+ assert TSC.ScheduleItem.Type.Extract == single_schedule.schedule_type
+ assert "2016-09-16T14:00:00Z" == format_datetime(single_schedule.next_run_at)
+ assert TSC.ScheduleItem.ExecutionOrder.Parallel == single_schedule.execution_order
+ assert time(7) == single_schedule.interval_item.start_time
+ assert ("Monday", "Friday") == single_schedule.interval_item.interval # type: ignore[union-attr]
+ assert TSC.ScheduleItem.State.Suspended == single_schedule.state
+
+
+# Tests calling update with a schedule item returned from the server
+def test_update_after_get(server: TSC.Server) -> None:
+ get_response_xml = GET_XML.read_text()
+ update_response_xml = UPDATE_XML.read_text()
+
+ # Get a schedule
+ with requests_mock.mock() as m:
+ m.get(server.schedules.baseurl, text=get_response_xml)
+ all_schedules, pagination_item = server.schedules.get()
+ schedule_item = all_schedules[0]
+ assert TSC.ScheduleItem.State.Active == schedule_item.state
+ assert "Weekday early mornings" == schedule_item.name
+
+ # Update the schedule
+ with requests_mock.mock() as m:
+ m.put(server.schedules.baseurl + "/c9cff7f9-309c-4361-99ff-d4ba8c9f5467", text=update_response_xml)
+ schedule_item.state = TSC.ScheduleItem.State.Suspended
+ schedule_item.name = "newName"
+ schedule_item = server.schedules.update(schedule_item)
+
+ assert TSC.ScheduleItem.State.Suspended == schedule_item.state
+ assert "weekly-schedule-1" == schedule_item.name
+
+
+def test_add_workbook(server: TSC.Server) -> None:
+ server.version = "2.8"
+ baseurl = f"{server.baseurl}/sites/{server.site_id}/schedules"
+
+ workbook_response = WORKBOOK_GET_BY_ID_XML.read_text()
+ add_workbook_response = ADD_WORKBOOK_TO_SCHEDULE.read_text()
+ with requests_mock.mock() as m:
+ m.get(server.workbooks.baseurl + "/bar", text=workbook_response)
+ m.put(baseurl + "/foo/workbooks", text=add_workbook_response)
+ workbook = server.workbooks.get_by_id("bar")
+ result = server.schedules.add_to_schedule("foo", workbook=workbook)
+ assert 0 == len(result), "Added properly"
+
+
+def test_add_workbook_with_warnings(server: TSC.Server) -> None:
+ server.version = "2.8"
+ baseurl = f"{server.baseurl}/sites/{server.site_id}/schedules"
+
+ workbook_response = WORKBOOK_GET_BY_ID_XML.read_text()
+ add_workbook_response = ADD_WORKBOOK_TO_SCHEDULE_WITH_WARNINGS.read_text()
+ with requests_mock.mock() as m:
+ m.get(server.workbooks.baseurl + "/bar", text=workbook_response)
+ m.put(baseurl + "/foo/workbooks", text=add_workbook_response)
+ workbook = server.workbooks.get_by_id("bar")
+ result = server.schedules.add_to_schedule("foo", workbook=workbook)
+ assert 1 == len(result), "Not added properly"
+ assert 2 == len(result[0].warnings)
+
+
+def test_add_datasource(server: TSC.Server) -> None:
+ server.version = "2.8"
+ baseurl = f"{server.baseurl}/sites/{server.site_id}/schedules"
+
+ datasource_response = DATASOURCE_GET_BY_ID_XML.read_text()
+ add_datasource_response = ADD_DATASOURCE_TO_SCHEDULE.read_text()
+ with requests_mock.mock() as m:
+ m.get(server.datasources.baseurl + "/bar", text=datasource_response)
+ m.put(baseurl + "/foo/datasources", text=add_datasource_response)
+ datasource = server.datasources.get_by_id("bar")
+ result = server.schedules.add_to_schedule("foo", datasource=datasource)
+ assert 0 == len(result), "Added properly"
+
+
+def test_add_flow(server: TSC.Server) -> None:
+ server.version = "3.3"
+ baseurl = f"{server.baseurl}/sites/{server.site_id}/schedules"
+
+ flow_response = FLOW_GET_BY_ID_XML.read_text()
+ add_flow_response = ADD_FLOW_TO_SCHEDULE.read_text()
+ with requests_mock.mock() as m:
+ m.get(server.flows.baseurl + "/bar", text=flow_response)
+ m.put(baseurl + "/foo/flows", text=flow_response)
+ flow = server.flows.get_by_id("bar")
+ result = server.schedules.add_to_schedule("foo", flow=flow)
+ assert 0 == len(result), "Added properly"
+
+
+def test_get_extract_refresh_tasks(server: TSC.Server) -> None:
+ server.version = "2.3"
+
+ response_xml = GET_EXTRACT_TASKS_XML.read_text()
+ with requests_mock.mock() as m:
+ schedule_id = "c9cff7f9-309c-4361-99ff-d4ba8c9f5467"
+ baseurl = f"{server.baseurl}/sites/{server.site_id}/schedules/{schedule_id}/extracts"
+ m.get(baseurl, text=response_xml)
+
+ extracts = server.schedules.get_extract_refresh_tasks(schedule_id)
+
+ assert extracts is not None
+ assert isinstance(extracts[0], list)
+ assert 2 == len(extracts[0])
+ assert "task1" == extracts[0][0].id
+
+
+def test_batch_update_state_items(server: TSC.Server) -> None:
+ server.version = "3.27"
+ hourly_interval = TSC.HourlyInterval(start_time=time(2, 30), end_time=time(23, 0), interval_value=2)
+ args = ("hourly", 50, TSC.ScheduleItem.Type.Extract, TSC.ScheduleItem.ExecutionOrder.Parallel, hourly_interval)
+ new_schedules = [TSC.ScheduleItem(*args), TSC.ScheduleItem(*args), TSC.ScheduleItem(*args)]
+ new_schedules[0]._id = "593d2ebf-0d18-4deb-9d21-b113a4902583"
+ new_schedules[1]._id = "cecbb71e-def0-4030-8068-5ae50f51db1c"
+ new_schedules[2]._id = "f39a6e7d-405e-4c07-8c18-95845f9da80e"
+
+ state = "active"
+ with requests_mock.mock() as m:
+ m.put(f"{server.schedules.baseurl}?state={state}", text=BATCH_UPDATE_STATE.read_text())
+ resp = server.schedules.batch_update_state(new_schedules, state)
+
+ assert len(resp) == 3
+ for sch, r in zip(new_schedules, resp):
+ assert sch.id == r
+
+
+def test_batch_update_state_str(server: TSC.Server) -> None:
+ server.version = "3.27"
+ new_schedules = [
+ "593d2ebf-0d18-4deb-9d21-b113a4902583",
+ "cecbb71e-def0-4030-8068-5ae50f51db1c",
+ "f39a6e7d-405e-4c07-8c18-95845f9da80e",
+ ]
+
+ state = "suspended"
+ with requests_mock.mock() as m:
+ m.put(f"{server.schedules.baseurl}?state={state}", text=BATCH_UPDATE_STATE.read_text())
+ resp = server.schedules.batch_update_state(new_schedules, state)
+
+ assert len(resp) == 3
+ for sch, r in zip(new_schedules, resp):
+ assert sch == r
+
+
+def test_batch_update_state_all(server: TSC.Server) -> None:
+ server.version = "3.27"
+ new_schedules = [
+ "593d2ebf-0d18-4deb-9d21-b113a4902583",
+ "cecbb71e-def0-4030-8068-5ae50f51db1c",
+ "f39a6e7d-405e-4c07-8c18-95845f9da80e",
+ ]
+
+ state = "suspended"
+ with requests_mock.mock() as m:
+ m.put(f"{server.schedules.baseurl}?state={state}&updateAll=true", text=BATCH_UPDATE_STATE.read_text())
+ _ = server.schedules.batch_update_state(new_schedules, state, True)
+
+ history = m.request_history[0]
+
+ assert history.text == ""