def test_sync_jcmt_allocation(self): """ Test JCMT allocation sync operation including unique constraint avoidance. """ proposal_id = self._create_test_proposal() records = JCMTRequestCollection() records[0] = JCMTRequest( None, None, JCMTInstrument.SCUBA2, JCMTAncillary.NONE, JCMTWeather.BAND1, 10.0) records[1] = JCMTRequest( None, None, JCMTInstrument.SCUBA2, JCMTAncillary.NONE, JCMTWeather.BAND2, 20.0) records[2] = JCMTRequest( None, None, JCMTInstrument.SCUBA2, JCMTAncillary.NONE, JCMTWeather.BAND3, 30.0) n = self.db.sync_jcmt_proposal_allocation(proposal_id, records) self.assertEqual(n, (3, 0, 0)) records = self.db.search_jcmt_allocation(proposal_id=proposal_id) self.assertEqual(len(records), 3) id1 = list(records.keys()) records[id1[0]] = records[id1[0]]._replace(weather=JCMTWeather.BAND2) records[id1[1]] = records[id1[1]]._replace(weather=JCMTWeather.BAND3) records[id1[2]] = records[id1[2]]._replace(weather=JCMTWeather.BAND4) n = self.db.sync_jcmt_proposal_allocation(proposal_id, records) self.assertEqual(n, (0, 3, 0)) records = self.db.search_jcmt_allocation(proposal_id=proposal_id) id2 = list(records.keys()) # There was no circular update loop so the identifiers should be # unchanged. self.assertEqual(id1, id2) for (record, id_, weather, time) in zip( records.values(), id2, [JCMTWeather.BAND2, JCMTWeather.BAND3, JCMTWeather.BAND4], [10.0, 20.0, 30.0]): self.assertEqual(record.id, id_) self.assertEqual(record.weather, weather) self.assertEqual(record.time, time) self.assertEqual(record.instrument, JCMTInstrument.SCUBA2)
def test_feedback_extra(self): # Set up test proposal with a JCMT allocation. types = self.view.get_call_types() proposal_id = self._create_test_proposal('20A', 'P', types.STANDARD) proposal = self.db.get_proposal( facility_id=None, proposal_id=proposal_id) rc = JCMTRequestCollection() rc[1] = null_tuple(JCMTRequest)._replace( instrument=JCMTInstrument.HARP, ancillary=JCMTAncillary.NONE, weather=JCMTWeather.BAND5, time=4.5) self.db.sync_jcmt_proposal_allocation(proposal_id, rc) # Test the get_feedback_extra method. extra = self.view.get_feedback_extra(self.db, proposal) self.assertIsInstance(extra, dict) self.assertEqual(set(extra.keys()), set(('jcmt_allocation',))) alloc = extra['jcmt_allocation'] self.assertIsInstance(alloc, list) self.assertEqual(len(alloc), 1) a = alloc[0] self.assertEqual(a.instrument, 'HARP') self.assertEqual(a.weather, 'Band 5') self.assertEqual(a.time, 4.5) self.assertIsNone(a.ancillary)
def test_sync_jcmt_allocation(self): """ Test JCMT allocation sync operation including unique constraint avoidance. """ proposal_id = self._create_test_proposal() records = JCMTRequestCollection() records[0] = JCMTRequest(None, None, JCMTInstrument.SCUBA2, JCMTAncillary.NONE, JCMTWeather.BAND1, 10.0) records[1] = JCMTRequest(None, None, JCMTInstrument.SCUBA2, JCMTAncillary.NONE, JCMTWeather.BAND2, 20.0) records[2] = JCMTRequest(None, None, JCMTInstrument.SCUBA2, JCMTAncillary.NONE, JCMTWeather.BAND3, 30.0) n = self.db.sync_jcmt_proposal_allocation(proposal_id, records) self.assertEqual(n, (3, 0, 0)) records = self.db.search_jcmt_allocation(proposal_id=proposal_id) self.assertEqual(len(records), 3) id1 = list(records.keys()) records[id1[0]] = records[id1[0]]._replace(weather=JCMTWeather.BAND2) records[id1[1]] = records[id1[1]]._replace(weather=JCMTWeather.BAND3) records[id1[2]] = records[id1[2]]._replace(weather=JCMTWeather.BAND4) n = self.db.sync_jcmt_proposal_allocation(proposal_id, records) self.assertEqual(n, (0, 3, 0)) records = self.db.search_jcmt_allocation(proposal_id=proposal_id) id2 = list(records.keys()) # There was no circular update loop so the identifiers should be # unchanged. self.assertEqual(id1, id2) for (record, id_, weather, time) in zip( records.values(), id2, [JCMTWeather.BAND2, JCMTWeather.BAND3, JCMTWeather.BAND4], [10.0, 20.0, 30.0]): self.assertEqual(record.id, id_) self.assertEqual(record.weather, weather) self.assertEqual(record.time, time) self.assertEqual(record.instrument, JCMTInstrument.SCUBA2)
def test_sync_jcmt_request(self): """ Test a JCMT request sync operation which encounters uniqueness constraints. """ proposal_id = self._create_test_proposal() records = JCMTRequestCollection() records[0] = JCMTRequest( None, None, JCMTInstrument.HARP, JCMTAncillary.NONE, JCMTWeather.BAND1, 10.0) records[1] = JCMTRequest( None, None, JCMTInstrument.HARP, JCMTAncillary.NONE, JCMTWeather.BAND5, 20.0) n = self.db.sync_jcmt_proposal_request(proposal_id, records) self.assertEqual(n, (2, 0, 0)) records = self.db.search_jcmt_request(proposal_id) id1 = list(records.keys()) self.assertEqual(records[id1[0]].weather, JCMTWeather.BAND1) self.assertEqual(records[id1[0]].time, 10.0) self.assertEqual(records[id1[1]].weather, JCMTWeather.BAND5) self.assertEqual(records[id1[1]].time, 20.0) # Swap the weather bands. records[id1[0]] = records[id1[0]]._replace(weather=JCMTWeather.BAND5) records[id1[1]] = records[id1[1]]._replace(weather=JCMTWeather.BAND1) n = self.db.sync_jcmt_proposal_request(proposal_id, records) self.assertEqual(n, (0, 2, 0)) records = self.db.search_jcmt_request(proposal_id) id2 = list(records.keys()) # Expect the first entry to have been re-inserted since we made a # circular update. self.assertEqual(id1[1], id2[0]) self.assertNotEqual(id1[0], id2[1]) self.assertEqual(records[id2[0]].weather, JCMTWeather.BAND1) self.assertEqual(records[id2[0]].time, 20.0) self.assertEqual(records[id2[1]].weather, JCMTWeather.BAND5) self.assertEqual(records[id2[1]].time, 10.0)
def test_sync_jcmt_request(self): """ Test a JCMT request sync operation which encounters uniqueness constraints. """ proposal_id = self._create_test_proposal() records = JCMTRequestCollection() records[0] = JCMTRequest(None, None, JCMTInstrument.HARP, JCMTAncillary.NONE, JCMTWeather.BAND1, 10.0) records[1] = JCMTRequest(None, None, JCMTInstrument.HARP, JCMTAncillary.NONE, JCMTWeather.BAND5, 20.0) n = self.db.sync_jcmt_proposal_request(proposal_id, records) self.assertEqual(n, (2, 0, 0)) records = self.db.search_jcmt_request(proposal_id) id1 = list(records.keys()) self.assertEqual(records[id1[0]].weather, JCMTWeather.BAND1) self.assertEqual(records[id1[0]].time, 10.0) self.assertEqual(records[id1[1]].weather, JCMTWeather.BAND5) self.assertEqual(records[id1[1]].time, 20.0) # Swap the weather bands. records[id1[0]] = records[id1[0]]._replace(weather=JCMTWeather.BAND5) records[id1[1]] = records[id1[1]]._replace(weather=JCMTWeather.BAND1) n = self.db.sync_jcmt_proposal_request(proposal_id, records) self.assertEqual(n, (0, 2, 0)) records = self.db.search_jcmt_request(proposal_id) id2 = list(records.keys()) # Expect the first entry to have been re-inserted since we made a # circular update. self.assertEqual(id1[1], id2[0]) self.assertNotEqual(id1[0], id2[1]) self.assertEqual(records[id2[0]].weather, JCMTWeather.BAND1) self.assertEqual(records[id2[0]].time, 20.0) self.assertEqual(records[id2[1]].weather, JCMTWeather.BAND5) self.assertEqual(records[id2[1]].time, 10.0)
def test_jcmt_request(self): proposal_id = self._create_test_proposal() request = self.db.search_jcmt_request(proposal_id) self.assertIsInstance(request, JCMTRequestCollection) self.assertEqual(len(request), 0) records = JCMTRequestCollection() records[1] = JCMTRequest(None, None, JCMTInstrument.HARP, JCMTAncillary.NONE, JCMTWeather.BAND4, 5.0) records[2] = JCMTRequest(None, None, JCMTInstrument.SCUBA2, JCMTAncillary.NONE, JCMTWeather.BAND2, 10.0) self.db.sync_jcmt_proposal_request(proposal_id, records) request = self.db.search_jcmt_request(proposal_id) self.assertEqual(len(request), 2) request_id = list(request.keys()) request = list(request.values()) self.assertIsInstance(request[0], JCMTRequest) self.assertIsInstance(request[0].id, int) self.assertEqual(request[0].id, request_id[0]) self.assertEqual(request[0].proposal_id, proposal_id) self.assertEqual(request[0].instrument, JCMTInstrument.HARP) self.assertEqual(request[0].ancillary, JCMTAncillary.NONE) self.assertEqual(request[0].weather, JCMTWeather.BAND4) self.assertEqual(request[0].time, 5.0) self.assertIsInstance(request[1], JCMTRequest) self.assertIsInstance(request[1].id, int) self.assertEqual(request[1].id, request_id[1]) self.assertEqual(request[1].proposal_id, proposal_id) self.assertEqual(request[1].instrument, JCMTInstrument.SCUBA2) self.assertEqual(request[1].ancillary, JCMTAncillary.NONE) self.assertEqual(request[1].weather, JCMTWeather.BAND2) self.assertEqual(request[1].time, 10.0)
def test_jcmt_allocation(self): proposal_id = self._create_test_proposal() allocation = self.db.search_jcmt_allocation(proposal_id) self.assertIsInstance(allocation, JCMTRequestCollection) self.assertEqual(len(allocation), 0) records = JCMTRequestCollection() records[0] = JCMTRequest(None, None, JCMTInstrument.HARP, JCMTAncillary.NONE, JCMTWeather.BAND2, 25.0) records[1] = JCMTRequest(None, None, JCMTInstrument.HARP, JCMTAncillary.NONE, JCMTWeather.BAND5, 75.0) self.db.sync_jcmt_proposal_allocation(proposal_id, records) allocation = self.db.search_jcmt_allocation(proposal_id) self.assertIsInstance(allocation, JCMTRequestCollection) self.assertEqual(len(allocation), 2) allocation_id = list(allocation.keys()) allocation = list(allocation.values()) self.assertIsInstance(allocation[0], JCMTRequest) self.assertIsInstance(allocation[0].id, int) self.assertEqual(allocation[0].id, allocation_id[0]) self.assertEqual(allocation[0].proposal_id, proposal_id) self.assertEqual(allocation[0].instrument, JCMTInstrument.HARP) self.assertEqual(allocation[0].ancillary, JCMTAncillary.NONE) self.assertEqual(allocation[0].weather, JCMTWeather.BAND2) self.assertEqual(allocation[0].time, 25.0) self.assertIsInstance(allocation[1], JCMTRequest) self.assertIsInstance(allocation[1].id, int) self.assertEqual(allocation[1].id, allocation_id[1]) self.assertEqual(allocation[1].proposal_id, proposal_id) self.assertEqual(allocation[1].instrument, JCMTInstrument.HARP) self.assertEqual(allocation[1].ancillary, JCMTAncillary.NONE) self.assertEqual(allocation[1].weather, JCMTWeather.BAND5) self.assertEqual(allocation[1].time, 75.0)
def test_request_collection(self): c = JCMTRequestCollection() self.assertIsInstance(c, OrderedDict) # An empty table should have a table attribute which is false. t = c.to_table() self.assertIsInstance(t, ResultTable) self.assertFalse(t.table) total = c.get_total() self.assertIsInstance(total, JCMTRequestTotal) self.assertEqual(total.total, 0.0) self.assertEqual(total.instrument, {}) self.assertEqual(total.instrument_grouped, {}) self.assertEqual(total.weather, {}) self.assertEqual(total.total_non_free, 0.0) # Add some rows. c[1] = JCMTRequest(1, 0, instrument=1, ancillary=0, weather=1, time=10.0) c[2] = JCMTRequest(2, 0, instrument=1, ancillary=0, weather=1, time=20.0) c[3] = JCMTRequest(3, 0, instrument=1, ancillary=0, weather=2, time=100.0) # The table's table attribute is now true. t = c.to_table() self.assertIsInstance(t, ResultTable) self.assertTrue(t.table) # We should have the instrument, but no totals as there is only one. self.assertIn((1, 0), t.table) self.assertNotIn(0, t.table) # Check the weather band times have been added up as expected. self.assertEqual(t.table[(1, 0)], {1: 30.0, 2: 100.0, None: 130.0}) # And we should have sensible rows and columns dictionaries. self.assertIsInstance(t.rows, OrderedDict) self.assertEqual(list(t.rows.keys()), [(1, 0)]) self.assertIsInstance(t.columns, OrderedDict) self.assertEqual(list(t.columns.keys()), list(JCMTWeather.get_available().keys())) # Add data for more instruments. c[4] = JCMTRequest(4, 0, instrument=2, ancillary=0, weather=2, time=200.0) c[5] = JCMTRequest(5, 0, instrument=4, ancillary=0, weather=5, time=1000.0) t = c.to_table() # Check the rows. self.assertEqual( set(t.table.keys()), set((None, (1, 0), (2, 0), (4, 0)))) self.assertEqual( set(t.rows.keys()), set(((1, 0), (2, 0), (4, 0)))) # And check the combined times. self.assertEqual( t.table[(1, 0)], {1: 30.0, 2: 100.0, None: 130.0}) self.assertEqual( t.table[(2, 0)], {2: 200.0, None: 200.0}) self.assertEqual( t.table[(4, 0)], {5: 1000.0, None: 1000.0}) self.assertEqual( t.table[None], {1: 30.0, 2: 300.0, 5: 1000.0, None: 1330.0}) total = c.get_total() self.assertIsInstance(total, JCMTRequestTotal) self.assertEqual(total.total, 1330.0) self.assertEqual( total.instrument, {(1, 0): 130.0, (2, 0): 200.0, (4, 0): 1000.0}) self.assertEqual( total.instrument_total, {1: 130.0, 2: 200.0, 4: 1000.0}) self.assertEqual( total.instrument_grouped, {1: {0: 130.0}, 2: {0: 200.0}, 4: {0: 1000.0}}) self.assertEqual(total.weather, {1: 30.0, 2: 300.0, 5: 1000.0}) self.assertEqual(total.total_non_free, 330.0) # Check conversion to sorted list. c[6] = JCMTRequest(6, 0, instrument=2, ancillary=0, weather=1, time=500.0) sorted_list = c.to_sorted_list() self.assertIsInstance(sorted_list, list) self.assertEqual(len(sorted_list), 6) self.assertEqual(sorted_list[0].id, 1) self.assertEqual(sorted_list[1].id, 2) self.assertEqual(sorted_list[2].id, 3) self.assertEqual(sorted_list[3].id, 6) self.assertEqual(sorted_list[4].id, 4) self.assertEqual(sorted_list[5].id, 5) self.assertEqual(sorted_list[0].instrument, 'SCUBA-2') self.assertEqual(sorted_list[1].instrument, 'SCUBA-2') self.assertEqual(sorted_list[2].instrument, 'SCUBA-2') self.assertEqual(sorted_list[3].instrument, 'HARP') self.assertEqual(sorted_list[4].instrument, 'HARP') self.assertEqual(sorted_list[5].instrument, 'RxA3m') self.assertEqual(sorted_list[0].weather, 'Band 1') self.assertEqual(sorted_list[1].weather, 'Band 1') self.assertEqual(sorted_list[2].weather, 'Band 2') self.assertEqual(sorted_list[3].weather, 'Band 1') self.assertEqual(sorted_list[4].weather, 'Band 2') self.assertEqual(sorted_list[5].weather, 'Band 5') self.assertEqual(sorted_list[0].time, 10.0) self.assertEqual(sorted_list[1].time, 20.0) self.assertEqual(sorted_list[2].time, 100.0) self.assertEqual(sorted_list[3].time, 500.0) self.assertEqual(sorted_list[4].time, 200.0) self.assertEqual(sorted_list[5].time, 1000.0) # This result collection isn't valid because instrument=1, weather=1 # is repeated. with self.assertRaisesRegexp(UserError, 'multiple entries'): c.validate() # Validation should succeed if we remove the offending entry. del c[1] c.validate() # Check the other validation constraints. c[1] = JCMTRequest(1, 0, instrument=1, ancillary=0, weather=1, time='') with self.assertRaisesRegexp(UserError, 'valid number'): c.validate() c[1] = JCMTRequest(1, 0, instrument=0, ancillary=0, weather=1, time=1.0) with self.assertRaisesRegexp(UserError, 'Instrument not recognised'): c.validate() c[1] = JCMTRequest(1, 0, instrument=1, ancillary=999, weather=1, time=1.0) with self.assertRaisesRegexp( UserError, 'Ancillary instrument not recognised'): c.validate() c[1] = JCMTRequest(1, 0, instrument=1, ancillary=1, weather=1, time=1.0) with self.assertRaisesRegexp( UserError, 'Ancillary not permitted for this instrument'): c.validate() c[1] = JCMTRequest(1, 0, instrument=1, ancillary=0, weather=0, time=1.0) with self.assertRaisesRegexp(UserError, 'Weather band not recognised'): c.validate()