hass-core/tests/components/sensor/test_sonarr.py
Harris Borawski 85d6970df8 Add Sensor for Sonarr (#4496)
* Add sonarr sensor and tests for sensor

* Fixed some linting errors and removed unused import

* Add SSL option for those who use SSL from within Sonarr

* Add requirements to all requirements, and sensor to coveragerc

* remove unused variable

* move methods to functions, and other lint fixes

* linting fixes

* linting is clean now

* Remove double requirement

* fix linting for docstrings, this should probably be a part of the script/lint and not just travis
2016-11-22 22:32:45 -08:00

811 lines
31 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""The tests for the sonarr platform."""
import unittest
import time
from datetime import datetime
from homeassistant.components.sensor import sonarr
from tests.common import get_test_home_assistant
def mocked_requests_get(*args, **kwargs):
"""Mock requests.get invocations."""
class MockResponse:
"""Class to represent a mocked response."""
def __init__(self, json_data, status_code):
"""Initialize the mock response class."""
self.json_data = json_data
self.status_code = status_code
def json(self):
"""Return the json of the response."""
return self.json_data
today = datetime.date(datetime.fromtimestamp(time.time()))
url = str(args[0])
if 'api/calendar' in url:
return MockResponse([
{
"seriesId": 3,
"episodeFileId": 0,
"seasonNumber": 4,
"episodeNumber": 11,
"title": "Easy Com-mercial, Easy Go-mercial",
"airDate": str(today),
"airDateUtc": "2014-01-27T01:30:00Z",
"overview": "To compete with fellow “restaurateur,” Ji...",
"hasFile": "false",
"monitored": "true",
"sceneEpisodeNumber": 0,
"sceneSeasonNumber": 0,
"tvDbEpisodeId": 0,
"series": {
"tvdbId": 194031,
"tvRageId": 24607,
"imdbId": "tt1561755",
"title": "Bob's Burgers",
"cleanTitle": "bobsburgers",
"status": "continuing",
"overview": "Bob's Burgers follows a third-generation ...",
"airTime": "5:30pm",
"monitored": "true",
"qualityProfileId": 1,
"seasonFolder": "true",
"lastInfoSync": "2014-01-26T19:25:55.4555946Z",
"runtime": 30,
"images": [
{
"coverType": "banner",
"url": "http://slurm.trakt.us/images/bann.jpg"
},
{
"coverType": "poster",
"url": "http://slurm.trakt.us/images/poster00.jpg"
},
{
"coverType": "fanart",
"url": "http://slurm.trakt.us/images/fan6.jpg"
}
],
"seriesType": "standard",
"network": "FOX",
"useSceneNumbering": "false",
"titleSlug": "bobs-burgers",
"path": "T:\\Bob's Burgers",
"year": 0,
"firstAired": "2011-01-10T01:30:00Z",
"qualityProfile": {
"value": {
"name": "SD",
"allowed": [
{
"id": 1,
"name": "SDTV",
"weight": 1
},
{
"id": 8,
"name": "WEBDL-480p",
"weight": 2
},
{
"id": 2,
"name": "DVD",
"weight": 3
}
],
"cutoff": {
"id": 1,
"name": "SDTV",
"weight": 1
},
"id": 1
},
"isLoaded": "true"
},
"seasons": [
{
"seasonNumber": 4,
"monitored": "true"
},
{
"seasonNumber": 3,
"monitored": "true"
},
{
"seasonNumber": 2,
"monitored": "true"
},
{
"seasonNumber": 1,
"monitored": "true"
},
{
"seasonNumber": 0,
"monitored": "false"
}
],
"id": 66
},
"downloading": "false",
"id": 14402
}
], 200)
elif 'api/command' in url:
return MockResponse([
{
"name": "RescanSeries",
"startedOn": "0001-01-01T00:00:00Z",
"stateChangeTime": "2014-02-05T05:09:09.2366139Z",
"sendUpdatesToClient": "true",
"state": "pending",
"id": 24
}
], 200)
elif 'api/wanted/missing' in url or 'totalRecords' in url:
return MockResponse(
{
"page": 1,
"pageSize": 15,
"sortKey": "airDateUtc",
"sortDirection": "descending",
"totalRecords": 1,
"records": [
{
"seriesId": 1,
"episodeFileId": 0,
"seasonNumber": 5,
"episodeNumber": 4,
"title": "Archer Vice: House Call",
"airDate": "2014-02-03",
"airDateUtc": "2014-02-04T03:00:00Z",
"overview": "Archer has to stage an that ... ",
"hasFile": "false",
"monitored": "true",
"sceneEpisodeNumber": 0,
"sceneSeasonNumber": 0,
"tvDbEpisodeId": 0,
"absoluteEpisodeNumber": 50,
"series": {
"tvdbId": 110381,
"tvRageId": 23354,
"imdbId": "tt1486217",
"title": "Archer (2009)",
"cleanTitle": "archer2009",
"status": "continuing",
"overview": "At ISIS, an international spy ...",
"airTime": "7:00pm",
"monitored": "true",
"qualityProfileId": 1,
"seasonFolder": "true",
"lastInfoSync": "2014-02-05T04:39:28.550495Z",
"runtime": 30,
"images": [
{
"coverType": "banner",
"url": "http://slurm.trakt.us//57.12.jpg"
},
{
"coverType": "poster",
"url": "http://slurm.trakt.u/57.12-300.jpg"
},
{
"coverType": "fanart",
"url": "http://slurm.trakt.us/image.12.jpg"
}
],
"seriesType": "standard",
"network": "FX",
"useSceneNumbering": "false",
"titleSlug": "archer-2009",
"path": "E:\\Test\\TV\\Archer (2009)",
"year": 2009,
"firstAired": "2009-09-18T02:00:00Z",
"qualityProfile": {
"value": {
"name": "SD",
"cutoff": {
"id": 1,
"name": "SDTV"
},
"items": [
{
"quality": {
"id": 1,
"name": "SDTV"
},
"allowed": "true"
},
{
"quality": {
"id": 8,
"name": "WEBDL-480p"
},
"allowed": "true"
},
{
"quality": {
"id": 2,
"name": "DVD"
},
"allowed": "true"
},
{
"quality": {
"id": 4,
"name": "HDTV-720p"
},
"allowed": "false"
},
{
"quality": {
"id": 9,
"name": "HDTV-1080p"
},
"allowed": "false"
},
{
"quality": {
"id": 10,
"name": "Raw-HD"
},
"allowed": "false"
},
{
"quality": {
"id": 5,
"name": "WEBDL-720p"
},
"allowed": "false"
},
{
"quality": {
"id": 6,
"name": "Bluray-720p"
},
"allowed": "false"
},
{
"quality": {
"id": 3,
"name": "WEBDL-1080p"
},
"allowed": "false"
},
{
"quality": {
"id": 7,
"name": "Bluray-1080p"
},
"allowed": "false"
}
],
"id": 1
},
"isLoaded": "true"
},
"seasons": [
{
"seasonNumber": 5,
"monitored": "true"
},
{
"seasonNumber": 4,
"monitored": "true"
},
{
"seasonNumber": 3,
"monitored": "true"
},
{
"seasonNumber": 2,
"monitored": "true"
},
{
"seasonNumber": 1,
"monitored": "true"
},
{
"seasonNumber": 0,
"monitored": "false"
}
],
"id": 1
},
"downloading": "false",
"id": 55
}
]
}, 200)
elif 'api/queue' in url:
return MockResponse([
{
"series": {
"title": "Game of Thrones",
"sortTitle": "game thrones",
"seasonCount": 6,
"status": "continuing",
"overview": "Seven noble families fight for land ...",
"network": "HBO",
"airTime": "21:00",
"images": [
{
"coverType": "fanart",
"url": "http://thetvdb.com/banners/fanart/-83.jpg"
},
{
"coverType": "banner",
"url": "http://thetvdb.com/banners/-g19.jpg"
},
{
"coverType": "poster",
"url": "http://thetvdb.com/banners/posters-34.jpg"
}
],
"seasons": [
{
"seasonNumber": 0,
"monitored": "false"
},
{
"seasonNumber": 1,
"monitored": "false"
},
{
"seasonNumber": 2,
"monitored": "true"
},
{
"seasonNumber": 3,
"monitored": "false"
},
{
"seasonNumber": 4,
"monitored": "false"
},
{
"seasonNumber": 5,
"monitored": "true"
},
{
"seasonNumber": 6,
"monitored": "true"
}
],
"year": 2011,
"path": "/Volumes/Media/Shows/Game of Thrones",
"profileId": 5,
"seasonFolder": "true",
"monitored": "true",
"useSceneNumbering": "false",
"runtime": 60,
"tvdbId": 121361,
"tvRageId": 24493,
"tvMazeId": 82,
"firstAired": "2011-04-16T23:00:00Z",
"lastInfoSync": "2016-02-05T16:40:11.614176Z",
"seriesType": "standard",
"cleanTitle": "gamethrones",
"imdbId": "tt0944947",
"titleSlug": "game-of-thrones",
"certification": "TV-MA",
"genres": [
"Adventure",
"Drama",
"Fantasy"
],
"tags": [],
"added": "2015-12-28T13:44:24.204583Z",
"ratings": {
"votes": 1128,
"value": 9.4
},
"qualityProfileId": 5,
"id": 17
},
"episode": {
"seriesId": 17,
"episodeFileId": 0,
"seasonNumber": 3,
"episodeNumber": 8,
"title": "Second Sons",
"airDate": "2013-05-19",
"airDateUtc": "2013-05-20T01:00:00Z",
"overview": "Kings Landing hosts a wedding, and ...",
"hasFile": "false",
"monitored": "false",
"absoluteEpisodeNumber": 28,
"unverifiedSceneNumbering": "false",
"id": 889
},
"quality": {
"quality": {
"id": 7,
"name": "Bluray-1080p"
},
"revision": {
"version": 1,
"real": 0
}
},
"size": 4472186820,
"title": "Game.of.Thrones.S03E08.Second.Sons.2013.1080p.",
"sizeleft": 0,
"timeleft": "00:00:00",
"estimatedCompletionTime": "2016-02-05T22:46:52.440104Z",
"status": "Downloading",
"trackedDownloadStatus": "Ok",
"statusMessages": [],
"downloadId": "SABnzbd_nzo_Mq2f_b",
"protocol": "usenet",
"id": 1503378561
}
], 200)
elif 'api/series' in url:
return MockResponse([
{
"title": "Marvel's Daredevil",
"alternateTitles": [{
"title": "Daredevil",
"seasonNumber": -1
}],
"sortTitle": "marvels daredevil",
"seasonCount": 2,
"totalEpisodeCount": 26,
"episodeCount": 26,
"episodeFileCount": 26,
"sizeOnDisk": 79282273693,
"status": "continuing",
"overview": "Matt Murdock was blinded in a tragic accident...",
"previousAiring": "2016-03-18T04:01:00Z",
"network": "Netflix",
"airTime": "00:01",
"images": [
{
"coverType": "fanart",
"url": "/sonarr/MediaCover/7/fanart.jpg?lastWrite="
},
{
"coverType": "banner",
"url": "/sonarr/MediaCover/7/banner.jpg?lastWrite="
},
{
"coverType": "poster",
"url": "/sonarr/MediaCover/7/poster.jpg?lastWrite="
}
],
"seasons": [
{
"seasonNumber": 1,
"monitored": "false",
"statistics": {
"previousAiring": "2015-04-10T04:01:00Z",
"episodeFileCount": 13,
"episodeCount": 13,
"totalEpisodeCount": 13,
"sizeOnDisk": 22738179333,
"percentOfEpisodes": 100
}
},
{
"seasonNumber": 2,
"monitored": "false",
"statistics": {
"previousAiring": "2016-03-18T04:01:00Z",
"episodeFileCount": 13,
"episodeCount": 13,
"totalEpisodeCount": 13,
"sizeOnDisk": 56544094360,
"percentOfEpisodes": 100
}
}
],
"year": 2015,
"path": "F:\\TV_Shows\\Marvels Daredevil",
"profileId": 6,
"seasonFolder": "true",
"monitored": "true",
"useSceneNumbering": "false",
"runtime": 55,
"tvdbId": 281662,
"tvRageId": 38796,
"tvMazeId": 1369,
"firstAired": "2015-04-10T04:00:00Z",
"lastInfoSync": "2016-09-09T09:02:49.4402575Z",
"seriesType": "standard",
"cleanTitle": "marvelsdaredevil",
"imdbId": "tt3322312",
"titleSlug": "marvels-daredevil",
"certification": "TV-MA",
"genres": [
"Action",
"Crime",
"Drama"
],
"tags": [],
"added": "2015-05-15T00:20:32.7892744Z",
"ratings": {
"votes": 461,
"value": 8.9
},
"qualityProfileId": 6,
"id": 7
}
], 200)
elif 'api/diskspace' in url:
return MockResponse([
{
"path": "/data",
"label": "",
"freeSpace": 282500067328,
"totalSpace": 499738734592
}
], 200)
else:
return MockResponse({
"error": "Unauthorized"
}, 401)
class TestSonarrSetup(unittest.TestCase):
"""Test the Sonarr platform."""
# pylint: disable=invalid-name
DEVICES = []
def add_devices(self, devices):
"""Mock add devices."""
for device in devices:
self.DEVICES.append(device)
def setUp(self):
"""Initialize values for this testcase class."""
self.DEVICES = []
self.hass = get_test_home_assistant()
self.hass.config.time_zone = 'America/Los_Angeles'
@unittest.mock.patch('requests.get', side_effect=mocked_requests_get)
def test_diskspace_no_paths(self, req_mock):
"""Tests getting all disk space"""
config = {
'platform': 'sonarr',
'api_key': 'foo',
'days': '2',
'unit': 'GB',
"include_paths": [],
'monitored_conditions': [
'diskspace'
]
}
sonarr.setup_platform(self.hass, config, self.add_devices, None)
for device in self.DEVICES:
device.update()
self.assertEqual('263.10', device.state)
self.assertEqual('mdi:harddisk', device.icon)
self.assertEqual('GB', device.unit_of_measurement)
self.assertEqual('Sonarr Disk Space', device.name)
self.assertEqual(
'263.10/465.42GB (56.53%)',
device.device_state_attributes["/data"]
)
@unittest.mock.patch('requests.get', side_effect=mocked_requests_get)
def test_diskspace_paths(self, req_mock):
"""Tests getting diskspace for included paths"""
config = {
'platform': 'sonarr',
'api_key': 'foo',
'days': '2',
'unit': 'GB',
"include_paths": [
'/data'
],
'monitored_conditions': [
'diskspace'
]
}
sonarr.setup_platform(self.hass, config, self.add_devices, None)
for device in self.DEVICES:
device.update()
self.assertEqual('263.10', device.state)
self.assertEqual('mdi:harddisk', device.icon)
self.assertEqual('GB', device.unit_of_measurement)
self.assertEqual('Sonarr Disk Space', device.name)
self.assertEqual(
'263.10/465.42GB (56.53%)',
device.device_state_attributes["/data"]
)
@unittest.mock.patch('requests.get', side_effect=mocked_requests_get)
def test_commands(self, req_mock):
"""Tests getting running commands"""
config = {
'platform': 'sonarr',
'api_key': 'foo',
'days': '2',
'unit': 'GB',
"include_paths": [
'/data'
],
'monitored_conditions': [
'commands'
]
}
sonarr.setup_platform(self.hass, config, self.add_devices, None)
for device in self.DEVICES:
device.update()
self.assertEqual(1, device.state)
self.assertEqual('mdi:code-braces', device.icon)
self.assertEqual('Commands', device.unit_of_measurement)
self.assertEqual('Sonarr Commands', device.name)
self.assertEqual(
'pending',
device.device_state_attributes["RescanSeries"]
)
@unittest.mock.patch('requests.get', side_effect=mocked_requests_get)
def test_queue(self, req_mock):
"""Tests getting downloads in the queue"""
config = {
'platform': 'sonarr',
'api_key': 'foo',
'days': '2',
'unit': 'GB',
"include_paths": [
'/data'
],
'monitored_conditions': [
'queue'
]
}
sonarr.setup_platform(self.hass, config, self.add_devices, None)
for device in self.DEVICES:
device.update()
self.assertEqual(1, device.state)
self.assertEqual('mdi:download', device.icon)
self.assertEqual('Episodes', device.unit_of_measurement)
self.assertEqual('Sonarr Queue', device.name)
self.assertEqual(
'100.00%',
device.device_state_attributes["Game of Thrones S03E08"]
)
@unittest.mock.patch('requests.get', side_effect=mocked_requests_get)
def test_series(self, req_mock):
"""Tests getting the number of series"""
config = {
'platform': 'sonarr',
'api_key': 'foo',
'days': '2',
'unit': 'GB',
"include_paths": [
'/data'
],
'monitored_conditions': [
'series'
]
}
sonarr.setup_platform(self.hass, config, self.add_devices, None)
for device in self.DEVICES:
device.update()
self.assertEqual(1, device.state)
self.assertEqual('mdi:television', device.icon)
self.assertEqual('Shows', device.unit_of_measurement)
self.assertEqual('Sonarr Series', device.name)
self.assertEqual(
'26/26 Episodes',
device.device_state_attributes["Marvel's Daredevil"]
)
@unittest.mock.patch('requests.get', side_effect=mocked_requests_get)
def test_wanted(self, req_mock):
"""Tests getting wanted episodes"""
config = {
'platform': 'sonarr',
'api_key': 'foo',
'days': '2',
'unit': 'GB',
"include_paths": [
'/data'
],
'monitored_conditions': [
'wanted'
]
}
sonarr.setup_platform(self.hass, config, self.add_devices, None)
for device in self.DEVICES:
device.update()
self.assertEqual(1, device.state)
self.assertEqual('mdi:television', device.icon)
self.assertEqual('Episodes', device.unit_of_measurement)
self.assertEqual('Sonarr Wanted', device.name)
self.assertEqual(
'2014-02-03',
device.device_state_attributes["Archer (2009) S05E04"]
)
@unittest.mock.patch('requests.get', side_effect=mocked_requests_get)
def test_upcoming_multiple_days(self, req_mock):
"""Tests upcoming episodes for multiple days"""
config = {
'platform': 'sonarr',
'api_key': 'foo',
'days': '2',
'unit': 'GB',
"include_paths": [
'/data'
],
'monitored_conditions': [
'upcoming'
]
}
sonarr.setup_platform(self.hass, config, self.add_devices, None)
for device in self.DEVICES:
device.update()
self.assertEqual(1, device.state)
self.assertEqual('mdi:television', device.icon)
self.assertEqual('Episodes', device.unit_of_measurement)
self.assertEqual('Sonarr Upcoming', device.name)
self.assertEqual(
'S04E11',
device.device_state_attributes["Bob's Burgers"]
)
@unittest.mock.patch('requests.get', side_effect=mocked_requests_get)
def test_upcoming_today(self, req_mock):
"""
Tests filtering for a single day.
Sonarr needs to respond with at least 2 days
"""
config = {
'platform': 'sonarr',
'api_key': 'foo',
'days': '1',
'unit': 'GB',
"include_paths": [
'/data'
],
'monitored_conditions': [
'upcoming'
]
}
sonarr.setup_platform(self.hass, config, self.add_devices, None)
for device in self.DEVICES:
device.update()
self.assertEqual(1, device.state)
self.assertEqual('mdi:television', device.icon)
self.assertEqual('Episodes', device.unit_of_measurement)
self.assertEqual('Sonarr Upcoming', device.name)
self.assertEqual(
'S04E11',
device.device_state_attributes["Bob's Burgers"]
)
@unittest.mock.patch('requests.get', side_effect=mocked_requests_get)
def test_ssl(self, req_mock):
"""Tests SSL being enabled"""
config = {
'platform': 'sonarr',
'api_key': 'foo',
'days': '1',
'unit': 'GB',
"include_paths": [
'/data'
],
'monitored_conditions': [
'upcoming'
],
"ssl": "true"
}
sonarr.setup_platform(self.hass, config, self.add_devices, None)
for device in self.DEVICES:
device.update()
self.assertEqual(1, device.state)
self.assertEqual('s', device.ssl)
self.assertEqual('mdi:television', device.icon)
self.assertEqual('Episodes', device.unit_of_measurement)
self.assertEqual('Sonarr Upcoming', device.name)
self.assertEqual(
'S04E11',
device.device_state_attributes["Bob's Burgers"]
)