Mercurial > personal > weather-server
comparison weather_server/logfile_test.py @ 24:20c8ec56e447
logfile: Pull logfile thread out of Logger.
This enables automatic garbage collection of Logger instances,
since a running thread no longer has a reference to a Logger's self.
It separates exclusive management of logfile state into the
_writer_thread function, which now opens the file and writes it until
it is told to stop by receiving the poison pill.
| author | Paul Fisher <paul@pfish.zone> |
|---|---|
| date | Sun, 10 Nov 2019 23:07:11 -0500 |
| parents | beb42c835c52 |
| children | 9bc3687e1e5e |
comparison
equal
deleted
inserted
replaced
| 23:88249e451566 | 24:20c8ec56e447 |
|---|---|
| 1 import contextlib | 1 import contextlib |
| 2 import datetime | 2 import datetime |
| 3 import os.path | |
| 3 import pathlib | 4 import pathlib |
| 4 import tempfile | 5 import tempfile |
| 6 import threading | |
| 5 import unittest | 7 import unittest |
| 6 | 8 |
| 7 import bson | 9 import bson |
| 8 import pytz | 10 import pytz |
| 9 | 11 |
| 10 from . import common | 12 from . import common |
| 11 from . import logfile | 13 from . import logfile |
| 12 from . import types | |
| 13 | 14 |
| 14 | 15 |
| 15 def ts(n): | 16 def ts(n): |
| 16 return datetime.datetime.utcfromtimestamp(n).replace(tzinfo=pytz.UTC) | 17 return datetime.datetime.utcfromtimestamp(n).replace(tzinfo=pytz.UTC) |
| 17 | 18 |
| 32 def test_empty(self): | 33 def test_empty(self): |
| 33 lg = logfile.Logger( | 34 lg = logfile.Logger( |
| 34 str(self.log_path), sample_field='x') | 35 str(self.log_path), sample_field='x') |
| 35 with contextlib.closing(lg) as logger: | 36 with contextlib.closing(lg) as logger: |
| 36 self.assertEqual(logger.data, ()) | 37 self.assertEqual(logger.data, ()) |
| 38 | |
| 39 def test_fails_to_open(self): | |
| 40 with self.assertRaises(OSError): | |
| 41 logfile.Logger( | |
| 42 os.path.join( | |
| 43 self.temp_dir.name, | |
| 44 'nonexistent-directory', | |
| 45 'bogus-filename'), | |
| 46 sample_field='unimportant') | |
| 47 | |
| 48 def test_del(self): | |
| 49 lg = logfile.Logger( | |
| 50 str(self.log_path), sample_field='x') | |
| 51 del lg | |
| 37 | 52 |
| 38 def test_loading(self): | 53 def test_loading(self): |
| 39 with self.log_path.open('wb') as outfile: | 54 with self.log_path.open('wb') as outfile: |
| 40 outfile.write(common.bson_encode(dict( | 55 outfile.write(common.bson_encode(dict( |
| 41 sample_time=ts(123), | 56 sample_time=ts(123), |
| 70 str(self.log_path), | 85 str(self.log_path), |
| 71 sample_field='sample_time', | 86 sample_field='sample_time', |
| 72 )) as logger: | 87 )) as logger: |
| 73 logger.write_rows([ | 88 logger.write_rows([ |
| 74 # Ignored, since it's older than the newest entry. | 89 # Ignored, since it's older than the newest entry. |
| 75 types.Reading(ts(100), 999, 666, ts(101)).as_dict(), | 90 dict( |
| 76 types.Reading(ts(125), 333, 777, ts(200)).as_dict(), | 91 sample_time=ts(100), |
| 92 temp_c=999, | |
| 93 rh_pct=666, | |
| 94 ingest_time=ts(101), | |
| 95 ), | |
| 96 dict( | |
| 97 sample_time=ts(125), | |
| 98 temp_c=333, | |
| 99 rh_pct=777, | |
| 100 ingest_time=ts(200), | |
| 101 ), | |
| 77 ]) | 102 ]) |
| 78 self.assertEqual( | 103 self.assertEqual( |
| 79 logger.data, | 104 logger.data, |
| 80 ( | 105 ( |
| 81 types.Reading(ts(123), 420, 69, ts(125)).as_dict(), | 106 dict( |
| 82 types.Reading(ts(125), 333, 777, ts(200)).as_dict(), | 107 sample_time=ts(123), |
| 108 temp_c=420, | |
| 109 rh_pct=69, | |
| 110 ingest_time=ts(125), | |
| 111 ), | |
| 112 dict( | |
| 113 sample_time=ts(125), | |
| 114 temp_c=333, | |
| 115 rh_pct=777, | |
| 116 ingest_time=ts(200), | |
| 117 ), | |
| 83 ) | 118 ) |
| 84 ) | 119 ) |
| 85 | 120 |
| 86 self.assertEqual(self.read_bsons(), [ | 121 self.assertEqual(self.read_bsons(), [ |
| 87 dict( | 122 dict( |
| 102 with contextlib.closing(logfile.Logger( | 137 with contextlib.closing(logfile.Logger( |
| 103 str(self.log_path), | 138 str(self.log_path), |
| 104 sample_field='sample_time', | 139 sample_field='sample_time', |
| 105 )) as logger: | 140 )) as logger: |
| 106 logger.write_rows([ | 141 logger.write_rows([ |
| 107 types.Reading(ts(100), 999, 666, ts(101)).as_dict(), | 142 dict( |
| 108 types.Reading(ts(125), 333, 777, ts(200)).as_dict(), | 143 sample_time=ts(100), |
| 144 temp_c=999, | |
| 145 rh_pct=666, | |
| 146 ingest_time=ts(101), | |
| 147 ), | |
| 148 dict( | |
| 149 sample_time=ts(125), | |
| 150 temp_c=333, | |
| 151 rh_pct=777, | |
| 152 ingest_time=ts(200), | |
| 153 ), | |
| 109 ]) | 154 ]) |
| 110 with self.log_path.open('ab') as outfile: | 155 with self.log_path.open('ab') as outfile: |
| 111 outfile.write(common.bson_encode(dict( | 156 outfile.write(common.bson_encode(dict( |
| 112 sample_time=ts(1024), | 157 sample_time=ts(1024), |
| 113 temp_c=256, | 158 temp_c=256, |
| 114 rh_pct=128, | 159 rh_pct=128, |
| 115 ingest_time=ts(4096), | 160 ingest_time=ts(4096), |
| 116 ))) | 161 ))) |
| 117 outfile.flush() | 162 outfile.flush() |
| 118 self.assertEqual(logger.data, ( | 163 self.assertEqual(logger.data, ( |
| 119 types.Reading(ts(100), 999, 666, ts(101)).as_dict(), | 164 dict( |
| 120 types.Reading(ts(125), 333, 777, ts(200)).as_dict(), | 165 sample_time=ts(100), |
| 121 types.Reading(ts(1024), 256, 128, ts(4096)).as_dict(), | 166 temp_c=999, |
| 167 rh_pct=666, | |
| 168 ingest_time=ts(101), | |
| 169 ), | |
| 170 dict( | |
| 171 sample_time=ts(125), | |
| 172 temp_c=333, | |
| 173 rh_pct=777, | |
| 174 ingest_time=ts(200), | |
| 175 ), | |
| 176 dict( | |
| 177 sample_time=ts(1024), | |
| 178 temp_c=256, | |
| 179 rh_pct=128, | |
| 180 ingest_time=ts(4096), | |
| 181 ), | |
| 122 )) | 182 )) |
| 123 | 183 |
| 124 def read_bsons(self): | 184 def read_bsons(self): |
| 125 with self.log_path.open('rb') as infile: | 185 with self.log_path.open('rb') as infile: |
| 126 return bson.decode_all( | 186 return bson.decode_all( |
