From: Christian Heller Date: Tue, 26 Mar 2024 00:25:27 +0000 (+0100) Subject: Add Processes module tests, re-organize/re-factor unit tests. X-Git-Url: https://plomlompom.com/repos/%22https:/validator.w3.org/%7B%7Bdb.prefix%7D%7D/%27%29;%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20chunks.push%28escapeHTML%28span%5B2%5D%29%29;%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20chunks.push%28%27?a=commitdiff_plain;h=f20d686a4972db5e6bc10bdbd48d27d4b035a716;p=plomtask Add Processes module tests, re-organize/re-factor unit tests. --- diff --git a/tests/days.py b/tests/days.py new file mode 100644 index 0000000..5ff6459 --- /dev/null +++ b/tests/days.py @@ -0,0 +1,116 @@ +"""Test Days module.""" +from unittest import TestCase +from http.client import HTTPConnection +from datetime import datetime +from tests.utils import TestCaseWithDB, TestCaseWithServer +from plomtask.days import Day, todays_date +from plomtask.misc import HandledException + + +class TestsSansDB(TestCase): + """Days module tests not requiring DB setup.""" + + def test_Day_dates(self): + """Test Day's date format.""" + with self.assertRaises(HandledException): + Day('foo') + with self.assertRaises(HandledException): + Day(None) + with self.assertRaises(HandledException): + Day(3) + with self.assertRaises(HandledException): + Day('2024-02-30') + with self.assertRaises(HandledException): + Day('2024-02-01 23:00:00') + self.assertEqual(datetime(2024, 1, 1), Day('2024-01-01').datetime) + + def test_Day_sorting(self): + """Test Day.__lt__.""" + day1 = Day('2024-01-01') + day2 = Day('2024-01-02') + day3 = Day('2024-01-03') + days = [day3, day1, day2] + self.assertEqual(sorted(days), [day1, day2, day3]) + + def test_Day_weekday(self): + """Test Day.weekday.""" + self.assertEqual(Day('2024-03-17').weekday, 'Sunday') + + +class TestsWithDB(TestCaseWithDB): + """Days module tests not requiring DB setup.""" + + def test_Day_by_date(self): + """Test Day.by_date().""" + self.assertEqual(None, Day.by_date(self.db_conn, '2024-01-01')) + Day('2024-01-01').save(self.db_conn) + self.assertEqual(Day('2024-01-01'), + Day.by_date(self.db_conn, '2024-01-01')) + self.assertEqual(None, + Day.by_date(self.db_conn, '2024-01-02')) + self.assertEqual(Day('2024-01-02'), + Day.by_date(self.db_conn, '2024-01-02', create=True)) + + def test_Day_all(self): + """Test Day.all(), especially in regards to date range filtering.""" + day1 = Day('2024-01-01') + day2 = Day('2024-01-02') + day3 = Day('2024-01-03') + day1.save(self.db_conn) + day2.save(self.db_conn) + day3.save(self.db_conn) + self.assertEqual(Day.all(self.db_conn), + [day1, day2, day3]) + self.assertEqual(Day.all(self.db_conn, ('', '')), + [day1, day2, day3]) + self.assertEqual(Day.all(self.db_conn, ('2024-01-01', '2024-01-03')), + [day1, day2, day3]) + self.assertEqual(Day.all(self.db_conn, ('2024-01-02', '2024-01-03')), + [day2, day3]) + self.assertEqual(Day.all(self.db_conn, ('2024-01-03', '')), + [day3]) + self.assertEqual(Day.all(self.db_conn, ('2024-01-01', '')), + [day1, day2, day3]) + self.assertEqual(Day.all(self.db_conn, ('', '2024-01-02')), + [day1, day2]) + self.assertEqual(Day.all(self.db_conn, ('2024-01-03', '2024-01-01')), + []) + day4 = Day('2024-01-04') + day5 = Day('2024-01-05') + day6 = Day('2024-01-06') + day6.save(self.db_conn) + self.assertEqual(Day.all(self.db_conn, ('2024-01-02', '2024-01-07'), + fill_gaps=True), + [day2, day3, day4, day5, day6]) + today = Day(todays_date()) + today.save(self.db_conn) + self.assertEqual(Day.all(self.db_conn, ('today', 'today')), [today]) + + def test_Day_neighbor_dates(self): + """Test Day.prev_date and Day.next_date.""" + self.assertEqual(Day('2024-01-01').prev_date, '2023-12-31') + self.assertEqual(Day('2023-02-28').next_date, '2023-03-01') + + +class TestsWithServer(TestCaseWithServer): + """Tests against our HTTP server/handler (and database).""" + + def test_do_GET(self): + """Test /day and /calendar response codes.""" + http_conn = HTTPConnection(*self.httpd.server_address) + http_conn.request('GET', '/day') + self.assertEqual(http_conn.getresponse().status, 200) + http_conn.request('GET', '/day?date=3000-01-01') + self.assertEqual(http_conn.getresponse().status, 200) + http_conn.request('GET', '/day?date=FOO') + self.assertEqual(http_conn.getresponse().status, 400) + http_conn.request('GET', '/calendar') + self.assertEqual(http_conn.getresponse().status, 200) + http_conn.request('GET', '/calendar?start=&end=') + self.assertEqual(http_conn.getresponse().status, 200) + http_conn.request('GET', '/calendar?start=today&end=today') + self.assertEqual(http_conn.getresponse().status, 200) + http_conn.request('GET', '/calendar?start=2024-01-01&end=2025-01-01') + self.assertEqual(http_conn.getresponse().status, 200) + http_conn.request('GET', '/calendar?start=foo') + self.assertEqual(http_conn.getresponse().status, 400) diff --git a/tests/processes.py b/tests/processes.py new file mode 100644 index 0000000..271289b --- /dev/null +++ b/tests/processes.py @@ -0,0 +1,105 @@ +"""Test Processes module.""" +from unittest import TestCase +from http.client import HTTPConnection +from urllib.parse import urlencode +from tests.utils import TestCaseWithDB, TestCaseWithServer +from plomtask.processes import Process + + +class TestsSansDB(TestCase): + """Module tests not requiring DB setup.""" + + def test_Process_versioned_defaults(self): + """Test defaults of Process' VersionedAttributes.""" + self.assertEqual(Process(None).title.newest, 'UNNAMED') + self.assertEqual(Process(None).description.newest, '') + self.assertEqual(Process(None).effort.newest, 1.0) + + +class TestsWithDB(TestCaseWithDB): + """Mdule tests not requiring DB setup.""" + + def test_Process_save(self): + """Test Process.save().""" + p_saved = Process(None) + p_saved.save(self.db_conn) + self.assertEqual(p_saved.id_, + Process.by_id(self.db_conn, 1, create=False).id_) + p_saved = Process(0) + p_saved.save(self.db_conn) + self.assertEqual(p_saved.id_, + Process.by_id(self.db_conn, 2, create=False).id_) + p_saved = Process(5) + p_saved.save(self.db_conn) + self.assertEqual(p_saved.id_, + Process.by_id(self.db_conn, 5, create=False).id_) + p_saved.title.set('named') + p_loaded = Process.by_id(self.db_conn, p_saved.id_) + self.assertNotEqual(p_saved.title.history, p_loaded.title.history) + p_saved.save(self.db_conn) + p_loaded = Process.by_id(self.db_conn, p_saved.id_) + self.assertEqual(p_saved.title.history, p_loaded.title.history) + + def test_Process_by_id(self): + """Test Process.by_id().""" + self.assertEqual(None, Process.by_id(self.db_conn, None, create=False)) + self.assertEqual(None, Process.by_id(self.db_conn, 0, create=False)) + self.assertEqual(None, Process.by_id(self.db_conn, 1, create=False)) + self.assertNotEqual(Process(1).id_, + Process.by_id(self.db_conn, None, create=True).id_) + self.assertNotEqual(Process(1).id_, + Process.by_id(self.db_conn, 0, create=True).id_) + self.assertEqual(Process(1).id_, + Process.by_id(self.db_conn, 1, create=True).id_) + self.assertEqual(Process(2).id_, + Process.by_id(self.db_conn, 2, create=True).id_) + + def test_Process_all(self): + """Test Process.all().""" + p_1 = Process(None) + p_1.save(self.db_conn) + p_2 = Process(None) + p_2.save(self.db_conn) + self.assertEqual({p_1.id_, p_2.id_}, + set(p.id_ for p in Process.all(self.db_conn))) + + +class TestsWithServer(TestCaseWithServer): + """Module tests against our HTTP server/handler (and database).""" + + def test_do_POST_process(self): + """Test POST /process and its effect on the database.""" + def post_data_to_expect(form_data: dict, to_: str, expect: int): + encoded_form_data = urlencode(form_data).encode('utf-8') + headers = {'Content-Type': 'application/x-www-form-urlencoded', + 'Content-Length': str(len(encoded_form_data))} + http_conn.request('POST', to_, + body=encoded_form_data, headers=headers) + self.assertEqual(http_conn.getresponse().status, expect) + http_conn = HTTPConnection(*self.httpd.server_address) + form_data = {'title': 'foo', 'description': 'foo', 'effort': 1.0} + post_data_to_expect(form_data, '/process?id=FOO', 400) + form_data['effort'] = 'foo' + post_data_to_expect(form_data, '/process?id=', 400) + form_data['effort'] = None + post_data_to_expect(form_data, '/process?id=', 400) + form_data = {'title': None, 'description': 1, 'effort': 1.0} + post_data_to_expect(form_data, '/process?id=', 302) + retrieved = Process.by_id(self.db_conn, 1) + self.assertEqual(retrieved.title.newest, 'None') + self.assertEqual([p.id_ for p in Process.all(self.db_conn)], + [retrieved.id_]) + + def test_do_GET(self): + """Test /process and /processes response codes.""" + http_conn = HTTPConnection(*self.httpd.server_address) + http_conn.request('GET', '/process') + self.assertEqual(http_conn.getresponse().status, 200) + http_conn.request('GET', '/process?id=') + self.assertEqual(http_conn.getresponse().status, 200) + http_conn.request('GET', '/process?id=0') + self.assertEqual(http_conn.getresponse().status, 200) + http_conn.request('GET', '/process?id=FOO') + self.assertEqual(http_conn.getresponse().status, 400) + http_conn.request('GET', '/processes') + self.assertEqual(http_conn.getresponse().status, 200) diff --git a/tests/test_days.py b/tests/test_days.py deleted file mode 100644 index bc2e82d..0000000 --- a/tests/test_days.py +++ /dev/null @@ -1,161 +0,0 @@ -"""Test days module.""" -from unittest import TestCase -from threading import Thread -from http.client import HTTPConnection -from urllib.parse import urlencode -from datetime import datetime -from os import remove as remove_file -from plomtask.http import TaskHandler, TaskServer -from plomtask.days import Day, todays_date -from plomtask.misc import HandledException -from plomtask.db import DatabaseFile, DatabaseConnection - - -class TestsSansDB(TestCase): - """Days module tests not requiring DB setup.""" - - def test_Day_dates(self): - """Test Day's date format.""" - with self.assertRaises(HandledException): - Day('foo') - with self.assertRaises(HandledException): - Day(None) - with self.assertRaises(HandledException): - Day(3) - with self.assertRaises(HandledException): - Day('2024-02-30') - with self.assertRaises(HandledException): - Day('2024-02-01 23:00:00') - self.assertEqual(datetime(2024, 1, 1), Day('2024-01-01').datetime) - - def test_Day_sorting(self): - """Test Day.__lt__.""" - day1 = Day('2024-01-01') - day2 = Day('2024-01-02') - day3 = Day('2024-01-03') - days = [day3, day1, day2] - self.assertEqual(sorted(days), [day1, day2, day3]) - - def test_Day_weekday(self): - """Test Day.weekday.""" - self.assertEqual(Day('2024-03-17').weekday, 'Sunday') - - -class TestsWithDB(TestCase): - """Days module tests not requiring DB setup.""" - - def setUp(self): - timestamp = datetime.now().timestamp() - self.db_file = DatabaseFile(f'test_db:{timestamp}') - self.db_file.remake() - self.db_conn = DatabaseConnection(self.db_file) - - def tearDown(self): - self.db_conn.close() - remove_file(self.db_file.path) - - def test_Day_by_date(self): - """Test Day.by_date().""" - self.assertEqual(None, Day.by_date(self.db_conn, '2024-01-01')) - Day('2024-01-01').save(self.db_conn) - self.assertEqual(Day('2024-01-01'), - Day.by_date(self.db_conn, '2024-01-01')) - self.assertEqual(None, - Day.by_date(self.db_conn, '2024-01-02')) - self.assertEqual(Day('2024-01-02'), - Day.by_date(self.db_conn, '2024-01-02', create=True)) - - def test_Day_all(self): - """Test Day.all(), especially in regards to date range filtering.""" - day1 = Day('2024-01-01') - day2 = Day('2024-01-02') - day3 = Day('2024-01-03') - day1.save(self.db_conn) - day2.save(self.db_conn) - day3.save(self.db_conn) - self.assertEqual(Day.all(self.db_conn), - [day1, day2, day3]) - self.assertEqual(Day.all(self.db_conn, ('', '')), - [day1, day2, day3]) - self.assertEqual(Day.all(self.db_conn, ('2024-01-01', '2024-01-03')), - [day1, day2, day3]) - self.assertEqual(Day.all(self.db_conn, ('2024-01-02', '2024-01-03')), - [day2, day3]) - self.assertEqual(Day.all(self.db_conn, ('2024-01-03', '')), - [day3]) - self.assertEqual(Day.all(self.db_conn, ('2024-01-01', '')), - [day1, day2, day3]) - self.assertEqual(Day.all(self.db_conn, ('', '2024-01-02')), - [day1, day2]) - self.assertEqual(Day.all(self.db_conn, ('2024-01-03', '2024-01-01')), - []) - day4 = Day('2024-01-04') - day5 = Day('2024-01-05') - day6 = Day('2024-01-06') - day6.save(self.db_conn) - self.assertEqual(Day.all(self.db_conn, ('2024-01-02', '2024-01-07'), - fill_gaps=True), - [day2, day3, day4, day5, day6]) - today = Day(todays_date()) - today.save(self.db_conn) - self.assertEqual(Day.all(self.db_conn, ('today', 'today')), [today]) - - def test_Day_neighbor_dates(self): - """Test Day.prev_date and Day.next_date.""" - self.assertEqual(Day('2024-01-01').prev_date, '2023-12-31') - self.assertEqual(Day('2023-02-28').next_date, '2023-03-01') - - -class TestsWithServer(TestsWithDB): - """Tests against our HTTP server/handler (and database).""" - - def setUp(self): - super().setUp() - self.httpd = TaskServer(self.db_file, ('localhost', 0), TaskHandler) - self.server_thread = Thread(target=self.httpd.serve_forever) - self.server_thread.daemon = True - self.server_thread.start() - - def test_do_POST_day(self): - """Test POST /day and its effect on the database.""" - http_conn = HTTPConnection(*self.httpd.server_address) - form_data = {'comment': 'foo'} - encoded_form_data = urlencode(form_data).encode('utf-8') - headers = {'Content-Type': 'application/x-www-form-urlencoded', - 'Content-Length': str(len(encoded_form_data))} - http_conn.request('POST', '/day?date=FOO', - body=encoded_form_data, headers=headers) - self.assertEqual(http_conn.getresponse().status, 400) - self.assertEqual(Day.all(self.db_conn), []) - http_conn.request('POST', '/day?date=2024-01-01', - body=encoded_form_data, headers=headers) - self.assertEqual(http_conn.getresponse().status, 302) - retrieved = Day.by_date(self.db_conn, '2024-01-01') - self.assertEqual(retrieved.comment, 'foo') - self.assertEqual(Day.all(self.db_conn), [retrieved]) - - def test_do_GET(self): - """Test /day and /calendar response codes.""" - http_conn = HTTPConnection(*self.httpd.server_address) - http_conn.request('GET', '/day') - self.assertEqual(http_conn.getresponse().status, 200) - http_conn.request('GET', '/day?date=3000-01-01') - self.assertEqual(http_conn.getresponse().status, 200) - http_conn.request('GET', '/day?date=FOO') - self.assertEqual(http_conn.getresponse().status, 400) - http_conn.request('GET', '/calendar') - self.assertEqual(http_conn.getresponse().status, 200) - http_conn.request('GET', '/calendar?start=&end=') - self.assertEqual(http_conn.getresponse().status, 200) - http_conn.request('GET', '/calendar?start=today&end=today') - self.assertEqual(http_conn.getresponse().status, 200) - http_conn.request('GET', '/calendar?start=2024-01-01&end=2025-01-01') - self.assertEqual(http_conn.getresponse().status, 200) - http_conn.request('GET', '/calendar?start=foo') - self.assertEqual(http_conn.getresponse().status, 400) - - def tearDown(self): - self.httpd.shutdown() - self.httpd.server_close() - self.server_thread.join() - super().tearDown() diff --git a/tests/utils.py b/tests/utils.py new file mode 100644 index 0000000..cd0c457 --- /dev/null +++ b/tests/utils.py @@ -0,0 +1,38 @@ +"""Shared test utilities.""" +from unittest import TestCase +from threading import Thread +from datetime import datetime +from os import remove as remove_file +from plomtask.db import DatabaseFile, DatabaseConnection +from plomtask.http import TaskHandler, TaskServer + + +class TestCaseWithDB(TestCase): + """Module tests not requiring DB setup.""" + + def setUp(self): + timestamp = datetime.now().timestamp() + self.db_file = DatabaseFile(f'test_db:{timestamp}') + self.db_file.remake() + self.db_conn = DatabaseConnection(self.db_file) + + def tearDown(self): + self.db_conn.close() + remove_file(self.db_file.path) + + +class TestCaseWithServer(TestCaseWithDB): + """Module tests against our HTTP server/handler (and database).""" + + def setUp(self): + super().setUp() + self.httpd = TaskServer(self.db_file, ('localhost', 0), TaskHandler) + self.server_thread = Thread(target=self.httpd.serve_forever) + self.server_thread.daemon = True + self.server_thread.start() + + def tearDown(self): + self.httpd.shutdown() + self.httpd.server_close() + self.server_thread.join() + super().tearDown()