Пример #1
0
def test_tag(api: Api, resp: RequestsMock) -> None:
    full_url = routes.tag(api.job_type, api.url)

    resp.add(
        responses.GET,
        url=full_url,
        json=[{
            "label": "My Tag",
            "id": 0
        }, {
            "label": "Other Tag",
            "id": 42
        }],
    )

    tags = api.tag()

    assert len(tags) == 2
    assert tags[0].id == 0

    resp.replace(responses.GET, url=full_url, json=[])

    tags = api.tag()

    assert len(tags) == 0
Пример #2
0
def test_profile(api: Api, resp: RequestsMock) -> None:
    full_url = routes.profile(api.job_type, api.url)

    resp.add(
        responses.GET,
        url=full_url,
        json=[
            {
                "name": "HD-1080p",
                "id": 0,
                "cuttoff": 1
            },
            {
                "name": "4K",
                "id": 42
            },
        ],
    )

    profiles = api.profile()

    assert len(profiles) == 2
    assert profiles[0].id == 0

    resp.replace(responses.GET, url=full_url, json=[])

    profiles = api.profile()

    assert len(profiles) == 0
Пример #3
0
def test_radarr_content(resp: RequestsMock, api: Api, file_body: str) -> None:
    url = "http://host/route"
    job_type = JobType.Radarr
    with Api(job_type=job_type, url=url, api_key="aaa") as api:
        full_url = routes.content(api.job_type, api.url)

        resp.add(
            responses.GET,
            url=full_url,
            body=file_body,
            content_type="application/json",
        )

        content_items = api.content()

        assert len(content_items) > 0

        item = content_items[0]

        assert isinstance(item, RadarrContent)

        assert isinstance(item.title, str)
        assert isinstance(item.tmdb_id, int)
        assert isinstance(item.year, int)
        assert len(item.images) > 0
        assert hasattr(item.images[0], "remote_url")
        assert not hasattr(item.images[0], "url")
Пример #4
0
def test_api_post_fail(resp: RequestsMock, api: Api, body: Any, status: Any,
                       expectation: Any) -> None:

    resp.add(responses.POST, url=api.url, body=body, status=status)

    with expectation:
        api.post(api.url, {})
Пример #5
0
def test_api_get_fail(resp: RequestsMock, api: Api, body: Union[str, None],
                      status: int, expectation: Any) -> None:
    url = f"{api.url}test"

    resp.add(responses.GET, url=url, body=body, status=status)

    with expectation:
        api.get(url)
Пример #6
0
def start_sync_job(job: SyncJob, dry_run: bool = False) -> None:
    logger.debug("starting %s job", job.name)

    with Api(
            job_type=job.type,
            url=job.source_url,
            api_key=job.source_key,
            headers=job.source_headers,
    ) as source_api, Api(
            job_type=job.type,
            url=job.dest_url,
            api_key=job.dest_key,
            headers=job.dest_headers,
    ) as dest_api:
        source_status = source_api.status()
        dest_status = dest_api.status()

        if not source_status or not dest_status:
            logger.error("failed %s job", job.name)
            raise Exception("failed to check stauts")

        source_tags = source_api.tag()

        source_profiles = source_api.profile()

        dest_profiles = dest_api.profile()

        dest_metadata_profiles = dest_api.metadata()

        dest_languages = dest_api.language()

        source_content = source_api.content()

        dest_content = dest_api.content()

        content_diff = calculate_content_diff(
            job=job,
            source_content=source_content,
            source_tags=source_tags,
            source_profiles=source_profiles,
            dest_content=dest_content,
        )

        content_payloads = get_content_payloads(
            job=job,
            content=content_diff,
            dest_profiles=dest_profiles,
            dest_metadata_profiles=dest_metadata_profiles,
            dest_languages=dest_languages,
        )

        sync_content(content=content_payloads,
                     dest_api=dest_api,
                     dry_run=dry_run)
Пример #7
0
def test_metadata_profile(resp: RequestsMock) -> None:
    with Api(job_type=JobType.Sonarr, url="http://host/",
             api_key="aaa") as api:
        assert len(api.metadata()) == 0

    with Api(job_type=JobType.Radarr, url="http://host/",
             api_key="aaa") as api:
        assert len(api.metadata()) == 0

    with Api(job_type=JobType.Lidarr, url="http://host/",
             api_key="aaa") as api:

        full_url = routes.metadata(api.job_type, api.url)

        resp.add(
            responses.GET,
            url=full_url,
            json=[
                {
                    "name":
                    "One",
                    "id":
                    0,
                    "releaseStatuses": [{
                        "allowed": True,
                        "releaseStatus": {
                            "id": 0,
                            "name": "Unknown"
                        }
                    }],
                },
                {
                    "name": "Two",
                    "id": 42
                },
            ],
        )

        metadata = api.metadata()

        assert len(metadata) == 2
        assert metadata[1].id == 42
        assert not hasattr(metadata[0], "releaseStatuses")

        resp.replace(responses.GET, url=full_url, json=[])

        metadata = api.metadata()

        assert len(metadata) == 0
Пример #8
0
def test_language(resp: RequestsMock) -> None:
    with Api(job_type=JobType.Lidarr, url="http://host/",
             api_key="aaa") as api:
        assert len(api.language()) == 0

    with Api(job_type=JobType.Radarr, url="http://host/",
             api_key="aaa") as api:
        assert len(api.language()) == 0

    with Api(job_type=JobType.Sonarr, url="http://host/",
             api_key="aaa") as api:

        full_url = routes.language(api.job_type, api.url)

        resp.add(
            responses.GET,
            url=full_url,
            json=[
                {
                    "name":
                    "English",
                    "id":
                    0,
                    "languages": [{
                        "allowed": True,
                        "language": {
                            "id": 0,
                            "name": "Unknown"
                        }
                    }],
                },
                {
                    "name": "Forign",
                    "id": 42
                },
            ],
        )

        languages = api.language()

        assert len(languages) == 2
        assert languages[1].id == 42
        assert not hasattr(languages[0], "languages")

        resp.replace(responses.GET, url=full_url, json=[])

        languages = api.language()

        assert len(languages) == 0
Пример #9
0
def test_lidarr_content(resp: RequestsMock, file_body: str) -> None:
    url = "http://host/route"
    job_type = JobType.Lidarr
    with Api(job_type=job_type, url=url, api_key="aaa") as api:
        full_url = routes.content(api.job_type, api.url)

        resp.add(
            responses.GET,
            url=full_url,
            body=file_body,
            content_type="application/json",
        )

        content_items = api.content()

        assert len(content_items) > 0

        item = content_items[0]

        assert isinstance(item, LidarrContent)

        assert isinstance(item.artist_name, str)
        assert isinstance(item.foreign_artist_id, str)
        assert len(item.images) > 0
        assert hasattr(item.images[0], "url")
Пример #10
0
def test_api_attaches_headers() -> None:
    with Api(
            job_type=JobType.Sonarr,
            url="http://host",
            api_key="aaa",
            headers={"X-My-Header": "yes"},
    ) as api:
        assert api.session.headers.get("X-My-Other-Header") is None
        assert api.session.headers.get("X-My-Header") == "yes"
Пример #11
0
def test_status(api: Api, resp: RequestsMock) -> None:
    full_url = routes.status(api.job_type, api.url)

    resp.add(responses.GET,
             url=full_url,
             json={
                 "version": "3",
                 "ignore": True
             })

    status = api.status()

    assert status.version == "3"
    assert not hasattr(status, "ignore")

    resp.replace(responses.GET, url=full_url, json={})

    with pytest.raises(ValidationError):
        api.status()
Пример #12
0
def test_api_get_success(resp: RequestsMock, api: Api, body: str) -> None:
    url = f"{api.url}test"

    resp.add(
        responses.GET,
        url=url,
        body=body,
        content_type="application/json",
        status=200,
    )

    assert api.get(url) == json.loads(body)
Пример #13
0
def test_save_content(resp: RequestsMock, job_type: JobType, url: str,
                      item: ContentItem) -> None:
    with Api(job_type=job_type, url=url, api_key="aaa") as api:
        full_url = routes.content(job_type=job_type, url=api.url)
        resp.add(
            responses.POST,
            url=full_url,
            json=item.dict(),
            match=[responses.json_params_matcher(item.dict(by_alias=True))],
            status=200,
        )
        api.save(item)
Пример #14
0
def test_api_post_success(resp: RequestsMock, api: Api,
                          json_dict: Any) -> None:
    url = f"{api.url}test"

    resp.add(
        responses.POST,
        url=url,
        json=json_dict,
        match=[responses.json_params_matcher(json_dict)],
        status=200,
    )

    assert api.post(url, json_dict) == json_dict
Пример #15
0
def sync_content(content: ContentItems,
                 dest_api: Api,
                 dry_run: bool = False) -> None:
    for item in content:
        post_json = None
        if not dry_run:
            post_json = dest_api.save(content_item=item)

        if not post_json and not dry_run:
            logger.error("failed to sync %s", get_debug_title(item))
            raise Exception(f"Failed to create {get_debug_title(item)}")
        else:
            logger.info("synced %s%s", get_debug_title(item),
                        " (dry-run)" if dry_run else "")
Пример #16
0
def test_unknown_content(mocker: MockerFixture, resp: RequestsMock) -> None:
    mock_route = mocker.patch("arrsync.api.routes")
    url = "http://host"
    route = "v3/new/path"
    mock_route.content.return_value = f"{url}/{route}"
    unknown_job_type = cast(JobType, "unknown")

    with Api(job_type=unknown_job_type, url=url, api_key="aaa") as api:
        resp.add(
            responses.GET,
            json={},
            url=f"{api.url}{route}",
        )
        with pytest.raises(Exception):
            api.content()
Пример #17
0
def test_sync_content_dry_run(
    mocker: MockerFixture,
    job_type: JobType,
    create_content_item: CreateContentItem,
) -> None:
    item_one = create_content_item(job_type)

    content: ContentItems = [item_one]

    with Api(job_type=job_type, url="http://host", api_key="aaa") as api:
        dest_api = mocker.patch.object(target=api, attribute="save")
        dest_api.save.return_value = content[0].dict()

        sync_content(content=content, dest_api=dest_api, dry_run=True)

        dest_api.save.assert_not_called()
Пример #18
0
def test_sync_content(
    mocker: MockerFixture,
    job_type: JobType,
    create_content_item: CreateContentItem,
) -> None:
    item_one = create_content_item(job_type)

    content: ContentItems = [item_one]

    with Api(job_type=job_type, url="http://host", api_key="aaa") as api:
        dest_api = mocker.patch.object(target=api, attribute="save")
        dest_api.save.return_value = content[0].dict()

        sync_content(content=content, dest_api=dest_api)

        dest_api.save.assert_called_once_with(content_item=content[0])

        dest_api.save.return_value = None

        with pytest.raises(Exception):
            sync_content(content=content, dest_api=dest_api)
Пример #19
0
def api(request: SubRequest) -> Iterator[Api]:
    url, job_type = request.param
    with Api(job_type=job_type, url=url, api_key="aaa") as api:
        yield api
Пример #20
0
def test_api_attaches_key() -> None:
    with Api(job_type=JobType.Sonarr, url="http://host", api_key="aaa") as api:
        assert api.session.headers.get("X-API-Key") == "aaa"
Пример #21
0
def tets_api_normalize_url(url: str) -> None:
    with Api(job_type=JobType.Sonarr, url=url, api_key="aaa") as api:
        assert api.url.endswith("/")