Coverage for tests/test_generic_workflow.py: 15%
173 statements
« prev ^ index » next coverage.py v7.5.0, created at 2024-04-26 02:57 -0700
« prev ^ index » next coverage.py v7.5.0, created at 2024-04-26 02:57 -0700
1# This file is part of ctrl_bps.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (https://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# This software is dual licensed under the GNU General Public License and also
10# under a 3-clause BSD license. Recipients may choose which of these licenses
11# to use; please see the files gpl-3.0.txt and/or bsd_license.txt,
12# respectively. If you choose the GPL option then the following text applies
13# (but note that there is still no warranty even if you opt for BSD instead):
14#
15# This program is free software: you can redistribute it and/or modify
16# it under the terms of the GNU General Public License as published by
17# the Free Software Foundation, either version 3 of the License, or
18# (at your option) any later version.
19#
20# This program is distributed in the hope that it will be useful,
21# but WITHOUT ANY WARRANTY; without even the implied warranty of
22# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23# GNU General Public License for more details.
24#
25# You should have received a copy of the GNU General Public License
26# along with this program. If not, see <https://www.gnu.org/licenses/>.
27import io
28import unittest
29from collections import Counter
31import lsst.ctrl.bps.generic_workflow as gw
32import networkx
33import networkx.algorithms.isomorphism as iso
36class TestGenericWorkflowJob(unittest.TestCase):
37 """Test of generic workflow jobs."""
39 def testEquality(self):
40 job1 = gw.GenericWorkflowJob("job1")
41 job2 = gw.GenericWorkflowJob("job1")
42 self.assertEqual(job1, job2)
45class TestGenericWorkflow(unittest.TestCase):
46 """Test generic workflow."""
48 def setUp(self):
49 self.exec1 = gw.GenericWorkflowExec(
50 name="test1.py", src_uri="${CTRL_BPS_DIR}/bin/test1.py", transfer_executable=False
51 )
52 self.job1 = gw.GenericWorkflowJob("job1", label="label1")
53 self.job1.quanta_counts = Counter({"pt1": 1, "pt2": 2})
54 self.job1.executable = self.exec1
56 self.job2 = gw.GenericWorkflowJob("job2", label="label2")
57 self.job2.quanta_counts = Counter({"pt1": 1, "pt2": 2})
58 self.job2.executable = self.exec1
60 def testAddJobDuplicate(self):
61 gwf = gw.GenericWorkflow("mytest")
62 gwf.add_job(self.job1)
63 with self.assertRaises(RuntimeError):
64 gwf.add_job(self.job1)
66 def testAddJobValid(self):
67 gwf = gw.GenericWorkflow("mytest")
68 gwf.add_job(self.job1)
69 self.assertEqual(1, gwf.number_of_nodes())
70 self.assertListEqual(["job1"], list(gwf))
71 getjob = gwf.get_job("job1")
72 self.assertEqual(self.job1, getjob)
74 def testAddJobRelationshipsSingle(self):
75 gwf = gw.GenericWorkflow("mytest")
76 gwf.add_job(self.job1)
77 gwf.add_job(self.job2)
78 gwf.add_job_relationships("job1", "job2")
79 self.assertListEqual([("job1", "job2")], list(gwf.edges()))
81 def testAddJobRelationshipsMultiChild(self):
82 job3 = gw.GenericWorkflowJob("job3")
83 job3.label = "label2"
84 job3.quanta_counts = Counter({"pt1": 1, "pt2": 2})
85 job3.executable = self.exec1
87 gwf = gw.GenericWorkflow("mytest")
88 gwf.add_job(self.job1)
89 gwf.add_job(self.job2)
90 gwf.add_job(job3)
91 gwf.add_job_relationships("job1", ["job2", "job3"])
92 self.assertListEqual([("job1", "job2"), ("job1", "job3")], list(gwf.edges()))
94 def testAddJobRelationshipsMultiParents(self):
95 job3 = gw.GenericWorkflowJob("job3")
96 job3.label = "label2"
97 job3.quanta_counts = Counter({"pt1": 1, "pt2": 2})
98 job3.executable = self.exec1
99 gwf = gw.GenericWorkflow("mytest")
100 gwf.add_job(self.job1)
101 gwf.add_job(self.job2)
102 gwf.add_job(job3)
103 gwf.add_job_relationships(["job1", "job2"], "job3")
104 self.assertListEqual([("job1", "job3"), ("job2", "job3")], list(gwf.edges()))
106 def testAddJobRelationshipsNone(self):
107 gwf = gw.GenericWorkflow("mytest")
108 gwf.add_job(self.job1)
109 gwf.add_job_relationships(None, "job1")
110 self.assertListEqual([], list(gwf.edges()))
111 gwf.add_job_relationships("job1", None)
112 self.assertListEqual([], list(gwf.edges()))
114 def testGetJobExists(self):
115 gwf = gw.GenericWorkflow("mytest")
116 gwf.add_job(self.job1)
117 get_job = gwf.get_job("job1")
118 self.assertIs(self.job1, get_job)
120 def testGetJobError(self):
121 gwf = gw.GenericWorkflow("mytest")
122 gwf.add_job(self.job1)
123 with self.assertRaises(KeyError):
124 _ = gwf.get_job("job_not_there")
126 def testSaveInvalidFormat(self):
127 gwf = gw.GenericWorkflow("mytest")
128 stream = io.BytesIO()
129 with self.assertRaises(RuntimeError):
130 gwf.save(stream, "badformat")
132 def testSavePickle(self):
133 gwf = gw.GenericWorkflow("mytest")
134 gwf.add_job(self.job1)
135 gwf.add_job(self.job2)
136 gwf.add_job_relationships("job1", "job2")
137 stream = io.BytesIO()
138 gwf.save(stream, "pickle")
139 stream.seek(0)
140 gwf2 = gw.GenericWorkflow.load(stream, "pickle")
141 self.assertTrue(
142 networkx.is_isomorphic(gwf, gwf2, node_match=iso.categorical_node_match("data", None))
143 )
145 def testLabels(self):
146 job3 = gw.GenericWorkflowJob("job3")
147 job3.label = "label2"
148 gwf = gw.GenericWorkflow("mytest")
149 gwf.add_job(self.job1)
150 gwf.add_job(self.job2)
151 gwf.add_job(job3)
152 gwf.add_job_relationships(["job1", "job2"], "job3")
153 self.assertListEqual(["label1", "label2"], gwf.labels)
155 def testRegenerateLabels(self):
156 job3 = gw.GenericWorkflowJob("job3", label="label2")
157 gwf = gw.GenericWorkflow("mytest")
158 gwf.add_job(self.job1)
159 gwf.add_job(self.job2)
160 gwf.add_job(job3)
161 gwf.add_job_relationships(["job1", "job2"], "job3")
162 self.job1.label = "label1b"
163 self.job2.label = "label1b"
164 job3.label = "label2b"
165 gwf.regenerate_labels()
166 self.assertListEqual(["label1b", "label2b"], gwf.labels)
168 def testJobCounts(self):
169 job3 = gw.GenericWorkflowJob("job3", label="label2")
170 gwf = gw.GenericWorkflow("mytest")
171 gwf.add_job(self.job1)
172 gwf.add_job(self.job2)
173 gwf.add_job(job3)
174 gwf.add_job_relationships(["job1", "job2"], "job3")
175 self.assertEqual(Counter({"label1": 1, "label2": 2}), gwf.job_counts)
177 def testDelJob(self):
178 job3 = gw.GenericWorkflowJob("job3", label="label2")
179 gwf = gw.GenericWorkflow("mytest")
180 gwf.add_job(self.job1)
181 gwf.add_job(self.job2)
182 gwf.add_job(job3)
183 gwf.add_job_relationships(["job1", "job2"], "job3")
185 gwf.del_job("job2")
187 self.assertListEqual([("job1", "job3")], list(gwf.edges()))
188 self.assertEqual(Counter({"label1": 1, "label2": 1}), gwf.job_counts)
190 def testAddWorkflowSource(self):
191 job3 = gw.GenericWorkflowJob("job3")
192 job3.label = "label2"
193 gwf = gw.GenericWorkflow("mytest")
194 gwf.add_job(self.job1)
195 gwf.add_job(self.job2)
196 gwf.add_job(job3)
197 gwf.add_job_relationships(["job1", "job2"], "job3")
199 srcjob1 = gw.GenericWorkflowJob("srcjob1")
200 srcjob1.label = "srclabel1"
201 srcjob1.executable = self.exec1
202 srcjob2 = gw.GenericWorkflowJob("srcjob2")
203 srcjob2.label = "srclabel1"
204 srcjob2.executable = self.exec1
205 srcjob3 = gw.GenericWorkflowJob("srcjob3")
206 srcjob3.label = "srclabel2"
207 srcjob3.executable = self.exec1
208 srcjob4 = gw.GenericWorkflowJob("srcjob4")
209 srcjob4.label = "srclabel2"
210 srcjob4.executable = self.exec1
211 gwf2 = gw.GenericWorkflow("mytest2")
212 gwf2.add_job(srcjob1)
213 gwf2.add_job(srcjob2)
214 gwf2.add_job(srcjob3)
215 gwf2.add_job(srcjob4)
216 gwf2.add_job_relationships("srcjob1", "srcjob3")
217 gwf2.add_job_relationships("srcjob2", "srcjob4")
219 gwf.add_workflow_source(gwf2)
221 self.assertEqual(Counter({"srclabel1": 2, "srclabel2": 2, "label1": 1, "label2": 2}), gwf.job_counts)
222 self.assertListEqual(["srclabel1", "srclabel2", "label1", "label2"], gwf.labels)
223 self.assertListEqual(
224 sorted(
225 [
226 ("srcjob1", "srcjob3"),
227 ("srcjob2", "srcjob4"),
228 ("srcjob3", "job1"),
229 ("srcjob3", "job2"),
230 ("srcjob4", "job1"),
231 ("srcjob4", "job2"),
232 ("job1", "job3"),
233 ("job2", "job3"),
234 ]
235 ),
236 sorted(gwf.edges()),
237 )
239 def testGetJobsByLabel(self):
240 job3 = gw.GenericWorkflowJob("job3")
241 job3.label = "label3"
242 gwf = gw.GenericWorkflow("mytest")
243 gwf.add_job(self.job1)
244 gwf.add_job(self.job2)
245 gwf.add_job(job3)
246 gwf.add_job_relationships(["job1", "job2"], "job3")
248 self.assertListEqual([job3], gwf.get_jobs_by_label("label3"))
251if __name__ == "__main__": 251 ↛ 252line 251 didn't jump to line 252, because the condition on line 251 was never true
252 unittest.main()