TestSauceNaoLimits.setUp()   A
last analyzed

Complexity

Conditions 1

Size

Total Lines 21
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 13
dl 0
loc 21
rs 9.75
c 0
b 0
f 0
cc 1
nop 1
1
#!/usr/bin/python
2
# -*- coding: utf-8 -*-
3
import logging
4
import os
5
import unittest
6
import uuid
7
8
import dotenv
9
from PIL import Image
10
11
from saucenao.saucenao import DailyLimitReachedException
12
from saucenao.saucenao import SauceNao
13
14
dotenv_path = os.path.join(os.path.dirname(__file__), os.path.pardir, os.path.pardir, '.env')
15
dotenv.load_dotenv(dotenv_path)
16
17
SAUCENAO_MIN_WIDTH = 3
18
SAUCENAO_MIN_HEIGHT = 3
19
20
SAUCENAO_IP_LIMIT_UNREGISTERED_USER = 150
21
SAUCENAO_IP_LIMIT_BASIC_USER = 300
22
23
SAUCENAO_API_KEY = os.environ.get('SAUCENAO_API_KEY')
24
25
26
def generate_small_jpg():
27
    """Generate a rather small jpg file to upload faster(631 bytes)
28
29
    :return:
30
    """
31
    file_path = str(uuid.uuid4()) + ".jpg"
32
    im = Image.new("RGB", (SAUCENAO_MIN_WIDTH, SAUCENAO_MIN_HEIGHT))
33
    im.save(os.path.join(os.getcwd(), file_path), "JPEG")
34
    return file_path
35
36
37
class TestSauceNaoLimits(unittest.TestCase):
38
    """
39
    test cases to check the limits for SauceNAO
40
41
    currently not covered is the test case: account limit reached, ip limit not reached
42
    have to add a proxy for this test case to be covered.
43
44
    Test cases covered:
45
     - HTML response type: ip/account limit not reached
46
     - JSON response type: ip/account limit not reached
47
     - HTML response type: ip limit reached
48
     - JSON response type: ip limit reached
49
    """
50
51
    def setUp(self):
52
        """Constructor for the unittest
53
54
        :return:
55
        """
56
        self.test_jpg = generate_small_jpg()
57
58
        self.saucenao_html = SauceNao(os.getcwd(), output_type=SauceNao.API_HTML_TYPE, log_level=logging.DEBUG)
59
        self.saucenao_json = SauceNao(os.getcwd(), output_type=SauceNao.API_JSON_TYPE, log_level=logging.DEBUG)
60
61
        self.NOT_IP_LIMIT_NOT_ACCOUNT_LIMIT = [
62
            {'function': self.check_response_no_api_key, 'expected_success': True},
63
            {'function': self.check_response_api_key, 'expected_success': True}
64
        ]
65
        self.IP_LIMIT_NOT_ACCOUNT_LIMIT = [
66
            {'function': self.check_response_no_api_key, 'expected_success': False},
67
            {'function': self.check_response_api_key, 'expected_success': True}
68
        ]
69
        self.IP_LIMIT_ACCOUNT_LIMIT = [
70
            {'function': self.check_response_no_api_key, 'expected_success': False},
71
            {'function': self.check_response_api_key, 'expected_success': False}
72
        ]
73
74
    def tearDown(self):
75
        """Destructor for the unittest
76
77
        :return:
78
        """
79
        os.remove(self.test_jpg)
80
81
    def run_tests(self, saucenao: SauceNao, tests):
82
        """Run the different tests with the given SauceNao instance
83
84
        :type saucenao: SauceNao
85
        :type tests: list|tuple|Generator
86
        :return:
87
        """
88
        for test in tests:
89
            test_function = test['function']
90
            test_result = test['expected_success']
91
            try:
92
                test_function(saucenao, assert_success=test_result)
93
            except Exception as e:
94
                self.fail("{} failed ({}: {})".format(test, type(e), e))
95
96
    def test_limits(self):
97
        """Test the limits of SauceNAO
98
99
        :return:
100
        """
101
        self.saucenao_html.logger.info('running HTML test, ip limit not reached, account limit not reached')
102
        self.run_tests(saucenao=self.saucenao_html, tests=self.NOT_IP_LIMIT_NOT_ACCOUNT_LIMIT)
103
        self.saucenao_html.logger.info('running JSON test, ip limit not reached, account limit not reached')
104
        self.run_tests(saucenao=self.saucenao_json, tests=self.NOT_IP_LIMIT_NOT_ACCOUNT_LIMIT)
105
106
        # now reach the daily limit without API key to reach the IP limit
107
        if self.saucenao_html.api_key:
108
            self.saucenao_html.api_key = None
109
110
        test_files = [self.test_jpg] * (SAUCENAO_IP_LIMIT_UNREGISTERED_USER - 2)
111
        try:
112
            # check_files returns a generator so we have to improvise here a bit
113
            for test_file in test_files:
114
                self.saucenao_html.check_file(test_file)
115
        except DailyLimitReachedException:
116
            pass
117
118
        # we are at 150 searches -> IP limit unregistered user reached, not basic user
119
        self.saucenao_html.logger.info('running HTML test, ip limit reached, account limit not reached')
120
        self.run_tests(saucenao=self.saucenao_html, tests=self.IP_LIMIT_NOT_ACCOUNT_LIMIT)
121
        self.saucenao_html.logger.info('running JSON test, ip limit reached, account limit not reached')
122
        self.run_tests(saucenao=self.saucenao_json, tests=self.IP_LIMIT_NOT_ACCOUNT_LIMIT)
123
124
        # set API key to reach the account limit
125
        self.saucenao_html.api_key = SAUCENAO_API_KEY
126
        test_files = [self.test_jpg] * (SAUCENAO_IP_LIMIT_BASIC_USER - SAUCENAO_IP_LIMIT_UNREGISTERED_USER - 4)
127
        try:
128
            # check_files returns a generator so we have to improvise here a bit
129
            for test_file in test_files:
130
                self.saucenao_html.check_file(test_file)
131
        except DailyLimitReachedException:
132
            pass
133
134
        # we are at 30 searches -> IP limit basic user reached
135
        self.saucenao_html.logger.info('running HTML test, ip limit reached, account limit reached')
136
        self.run_tests(saucenao=self.saucenao_html, tests=self.IP_LIMIT_ACCOUNT_LIMIT)
137
        self.saucenao_html.logger.info('running JSON test, ip limit reached, account limit reached')
138
        self.run_tests(saucenao=self.saucenao_json, tests=self.IP_LIMIT_ACCOUNT_LIMIT)
139
140
    def check_response_no_api_key(self, saucenao: SauceNao, assert_success=True):
141
        """Check the response without an API key
142
        on assert_success=True expect a dictionary, else an exception
143
144
        :type saucenao: SauceNao
145
        :type assert_success: bool
146
        :return:
147
        """
148
        if assert_success:
149
            result = saucenao.check_file(self.test_jpg)
150
            self.assertIsInstance(result, list)
151
        else:
152
            self.assertRaises(DailyLimitReachedException, saucenao.check_file, self.test_jpg)
153
154
    def check_response_api_key(self, saucenao: SauceNao, assert_success=True):
155
        """Check the response with an API key
156
        on assert_success=True expect a dictionary, else an exception
157
158
        :type saucenao: SauceNao
159
        :type assert_success: bool
160
        :return:
161
        """
162
        saucenao.api_key = SAUCENAO_API_KEY
163
        if assert_success:
164
            result = saucenao.check_file(self.test_jpg)
165
            self.assertIsInstance(result, list)
166
        else:
167
            self.assertRaises(DailyLimitReachedException, saucenao.check_file, self.test_jpg)
168
169
170
suite = unittest.TestLoader().loadTestsFromTestCase(TestSauceNaoLimits)
171
unittest.TextTestRunner(verbosity=2).run(suite)
172