Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# (c) Stefan Countryman 2019
3"""
4Unit tests for ``llama.listen.gcn``.
5"""
7import os
8from abc import abstractproperty
9import tempfile
10import logging
11from copy import copy
12from warnings import warn
13from datetime import datetime
14from subprocess import Popen, PIPE
15from time import sleep, time
16from llama.run import Run
17from llama.pipeline import Pipeline
18from llama.listen.gcn import LlamaHandlers, run_on_voevent_file, get_subdir
19from llama.filehandler import FileGraph
20from llama.test.classes import (
21 AbstractFileGenerationComparator,
22 MS181101abMixin,
23 S190425zMixin,
24 S190521gMixin,
25)
26from llama.files.skymap_info import SkymapInfo
27from llama.files.lvc_gcn_xml import LvcGcnXml
28from llama.files.advok import Advok
30LOGGER = logging.getLogger(__name__)
33# pylint: disable=abstract-method
34class AbstractTestLlamaHandlers(AbstractFileGenerationComparator):
35 """
36 Test LlamaHandlers with example GCN Notices to make sure that they are
37 parsed correctly. Implementations of this class must provide an ``EVENTID``
38 class variable specifying the ``eventid`` to use (the ``rundir`` will be a
39 temporary directory and the data source will be in the test data
40 directory).
41 """
43 STARTING_MANIFEST = ()
45 @property
46 def pipeline(self):
47 return Pipeline(
48 SkymapInfo=SkymapInfo,
49 LvcGcnXml=LvcGcnXml,
50 )
52 @property
53 def gcn_archive(self):
54 """A temporary directory for storing GCN archived files."""
55 return getattr(self, '_gcn_archive', None)
57 @gcn_archive.setter
58 def gcn_archive(self, gcn_archive):
59 """Set the gcn_archive value."""
60 setattr(self, '_gcn_archive', gcn_archive)
62 @property
63 def handler(self):
64 """Get a ``LlamaHandlers`` instance for this test class."""
65 return LlamaHandlers(rundir=self.run.rundir,
66 gcn_archive=self.gcn_archive)
68 def execute(self):
69 """Test whether the LLAMA handler properly creates the expected event
70 directory and output files by comparing what is created to the expected
71 output."""
72 filehandler = LvcGcnXml(self.inputevent)
73 run_on_voevent_file(files=filehandler.fullpath, handler=self.handler)
75 def test(self):
76 with tempfile.TemporaryDirectory() as tmpdir:
77 self.gcn_archive = tmpdir
78 # if you run the test at midnight, the files might be different
79 # based on the date switch, so look for files in both places in
80 # case the date switches in the middle of the test
81 start = datetime.utcnow()
82 super().test()
83 end = datetime.utcnow()
84 # might get archived twice if the test received VOEvents before and
85 # after the date change (midnight UTC); check both in that case.
86 for outd in {get_subdir(tmpdir, n) for n in (start, end)}:
87 outfiles = [os.path.join(outd, f) for f in os.listdir(outd)]
88 # test whether files were archived properly
89 assert len(outfiles) == 1, "Expect exactly 1 archived event."
90 archived = outfiles.pop()
91 voe = LvcGcnXml(self.inputevent)
92 if not voe.compare_contents(archived):
93 warn(("{} and {} differ in GCN archive test. Diff:\n"
94 "{}").format(voe.fullpath, archived,
95 voe.diff_contents(archived)))
96 raise AssertionError(("{} and {} differ."
97 "").format(voe.fullpath, archived))
100class GcnInitialMixin(AbstractTestLlamaHandlers):
101 """Specifies that this tests for LVC *Initial* GCN Notices; the proper
102 ``LvcGcnXml``, ``SkymapInfo``, and ``Advok`` files should be generated."""
104 @property
105 def pipeline(self):
106 return super().pipeline + Pipeline(Advok=Advok)
109class AbstractGcndTester(AbstractTestLlamaHandlers):
110 """
111 Test ``gcnd``'s ability to listen for an parse events. ``gcnd`` has to be
112 in your "$PATH" for this to work along with ``pygcn-serve``. Tests the same
113 thing as ``AbstractFileGenerationComparator``, but does so in a more robust
114 way by using the command line interface to test the script's functionality.
115 """
117 SLEEP_INTERVAL = 0.25
118 TIMEOUT = 6
120 def execute(self):
121 """
122 Launch ``gcnd`` and make it listen to a test server set up with
123 ``pygcn-serve``. Let run for 5 seconds before timing out and killing.
124 """
125 env = copy(os.environ)
126 env['PYTEST'] = 'true'
127 server = Popen(['pygcn-serve', LvcGcnXml(self.inputevent).fullpath],
128 stdout=PIPE, stderr=PIPE)
129 listener = Popen(['llama', 'listen', 'gcn', '-r', self.run.rundir,
130 '-g', self.gcn_archive, '-i', '127.0.0.1'],
131 stdout=PIPE, stderr=PIPE, env=env)
132 start = time()
133 # only keep it running till the LLAMA handler and the archive handler
134 # have saved their expected outputs
135 outfiles = self.pipeline.file_handler_instances(self.event)
136 def done():
137 return (all(f.exists() for f in outfiles.values()) and
138 os.listdir(get_subdir(self.gcn_archive,
139 datetime.utcnow())))
140 while time() - start < self.TIMEOUT and not done():
141 sleep(self.SLEEP_INTERVAL)
142 listener.kill()
143 server.kill()
144 print("Server STDOUT:\n%s\nSTDERR:\n%s", *(r.decode() for r in
145 server.communicate()))
146 print("Listener STDOUT:\n%s\nSTDERR:\n%s", *(r.decode() for r in
147 listener.communicate()))
148 # seems there are some race conditions associated with git still
149 # operating on those directories. see if this helps.
150 sleep(0.3)
153class TestLlamaHandlerMS181101ab(MS181101abMixin, GcnInitialMixin):
154 """Test ``LlamaHandlers`` on a sample GCN Initial notice for ER14."""
157class TestLlamaHandlerS190425z(S190425zMixin, GcnInitialMixin):
158 """
159 Test ``LlamaHandlers`` on the GCN Initial notice that came out with
160 the first BNS event of O3 on April 25, 2019
161 """
164class TestLlamaHandlerS190521g(S190521gMixin, AbstractTestLlamaHandlers):
165 """
166 Test ``LlamaHandlers`` parser on the GCN Preliminary notice that came
167 out with an early-O3 BBH event from May 21, 2019.
168 """
171class TestGcndS190425z(S190425zMixin, GcnInitialMixin):
172 """
173 Test the daemon on the GCN Initial notice that came out with the first
174 BNS event of O3 on April 25, 2019.
175 """
178class TestGcndS190521g(S190521gMixin, AbstractGcndTester):
179 """
180 Test the daemon on the GCN Preliminary notice that came out an early-O3
181 BBH event from May 21, 2019.
182 """