diff --git a/src/auslib/web/admin/views/rules.py b/src/auslib/web/admin/views/rules.py index 754cb104f..07aac57fd 100644 --- a/src/auslib/web/admin/views/rules.py +++ b/src/auslib/web/admin/views/rules.py @@ -260,6 +260,24 @@ def _post(self, transaction, changed_by): if what.get("fallbackMapping") is not None and len(fallback_mapping_values) != 1: return problem(400, "Bad Request", "Invalid fallbackMapping value. No release name found in DB") + alias = what.get("alias", None) + if alias is not None and dbo.rules.getRule(alias): + return problem(400, "Bad Request", "Rule with alias exists") + + if alias is not None: + scheduled_rule_with_alias = ( + dbo.rules.scheduled_changes.t.select() + .where( + dbo.rules.scheduled_changes.base_alias == alias + and dbo.rules.scheduled_changes.complete is False + and (dbo.rules.scheduled_changes.change_type == "insert" or dbo.rules.scheduled_changes.change_type == "update") + ) + .execute() + .fetchall() + ) + if len(scheduled_rule_with_alias) > 0: + return problem(400, "Bad Request", "Rule is scheduled with the given alias") + return super(RuleScheduledChangesView, self)._post(what, transaction, changed_by, change_type) @@ -318,6 +336,24 @@ def _post(self, sc_id, transaction, changed_by): if what.get("fallbackMapping") is not None and len(fallback_mapping_values) != 1: return problem(400, "Bad Request", "Invalid fallbackMapping value. No release name found in DB") + alias = what.get("alias", None) + if alias is not None and dbo.rules.getRule(alias): + return problem(400, "Bad Request", "Rule with alias exists") + + if alias is not None: + scheduled_rule_with_alias = ( + dbo.rules.scheduled_changes.t.select() + .where( + dbo.rules.scheduled_changes.base_alias == alias + and dbo.rules.scheduled_changes.complete is False + and (dbo.rules.scheduled_changes.change_type == "insert" or dbo.rules.scheduled_changes.change_type == "update") + ) + .execute() + .fetchall() + ) + if len(scheduled_rule_with_alias) > 0: + return problem(400, "Bad Request", "Rule is scheduled with the given alias") + return super(RuleScheduledChangeView, self)._post(sc_id, what, transaction, changed_by, connexion.request.get_json().get("sc_data_version", None)) @requirelogin diff --git a/tests/admin/views/test_rules.py b/tests/admin/views/test_rules.py index 838a6692d..8d1deb036 100644 --- a/tests/admin/views/test_rules.py +++ b/tests/admin/views/test_rules.py @@ -2238,6 +2238,146 @@ def testAddScheduledChangeMultipleConditions(self): ret = self._post("scheduled_changes/rules", data=data) self.assertEqual(ret.status_code, 400) + @mock.patch("time.time", mock.MagicMock(return_value=300)) + def testAddScheduledChangesRuleWithDuplicateAliasWithChangeTypeInsert(self): + ret = self._post( + "/rules", + data=dict(backgroundRate=31, mapping="c", priority=33, product="Firefox", update_type="minor", channel="nightly", alias="TestDuplicateAlias1"), + ) + self.assertEqual(ret.status_code, 200, "Status Code: %d, Data: %s" % (ret.status_code, ret.get_data())) + + data1 = { + "rule_id": 10, + "telemetry_product": None, + "telemetry_channel": None, + "telemetry_uptake": None, + "priority": 80, + "buildTarget": "d", + "version": "3.3", + "backgroundRate": 100, + "mapping": "c", + "update_type": "minor", + "data_version": 1, + "change_type": "insert", + "when": 1234567, + "alias": "TestDuplicateAlias1", + } + ret1 = self._post("/scheduled_changes/rules", data=data1) + self.assertEqual(ret1.status_code, 400, ret1.get_data()) + load = ret1.get_json() + self.assertEqual(load["detail"], "Rule with alias exists") + + @mock.patch("time.time", mock.MagicMock(return_value=300)) + def testAddScheduledChangesRuleWithDuplicateAliasWithChangeTypeUpdate(self): + ret = self._post( + "/rules", + data=dict(backgroundRate=31, mapping="c", priority=33, product="Firefox", update_type="minor", channel="nightly", alias="TestDuplicateAlias2"), + ) + self.assertEqual(ret.status_code, 200, "Status Code: %d, Data: %s" % (ret.status_code, ret.get_data())) + + data1 = { + "rule_id": 10, + "telemetry_product": None, + "telemetry_channel": None, + "telemetry_uptake": None, + "priority": 80, + "buildTarget": "d", + "version": "3.3", + "backgroundRate": 100, + "mapping": "c", + "update_type": "minor", + "data_version": 1, + "change_type": "update", + "when": 1234567, + "alias": "TestDuplicateAlias2", + } + ret1 = self._post("/scheduled_changes/rules", data=data1) + self.assertEqual(ret1.status_code, 400, ret1.get_data()) + load = ret1.get_json() + self.assertEqual(load["detail"], "Rule with alias exists") + + @mock.patch("time.time", mock.MagicMock(return_value=300)) + def testAddScheduledChangeWithAliasAlreadyPresentWithChangeTypeInsert(self): + data = { + "rule_id": 5, + "telemetry_product": None, + "telemetry_channel": None, + "telemetry_uptake": None, + "priority": 80, + "buildTarget": "d", + "version": "3.3", + "backgroundRate": 100, + "mapping": "c", + "update_type": "minor", + "data_version": 1, + "change_type": "insert", + "when": 1234567, + "alias": "TestDuplicateAlias3", + "complete": False, + } + ret = self._post("/scheduled_changes/rules", data=data) + self.assertEqual(ret.status_code, 200, ret.get_data()) + + data1 = { + "when": 2000000, + "data_version": 1, + "rule_id": 1, + "priority": 100, + "version": "3.5", + "buildTarget": "d", + "backgroundRate": 100, + "mapping": "c", + "update_type": "minor", + "sc_data_version": 1, + "alias": "TestDuplicateAlias3", + "complete": False, + } + ret1 = self._post("/scheduled_changes/rules/4", data=data1) + self.assertEqual(ret1.status_code, 400, ret1.get_data()) + load = ret1.get_json() + self.assertEqual(load["detail"], "Rule is scheduled with the given alias") + + @mock.patch("time.time", mock.MagicMock(return_value=300)) + def testAddScheduledChangeWithAliasAlreadyPresentWithChangeTypeUpdate(self): + data = { + "rule_id": 5, + "telemetry_product": None, + "telemetry_channel": None, + "telemetry_uptake": None, + "priority": 80, + "buildTarget": "d", + "version": "3.3", + "backgroundRate": 100, + "mapping": "c", + "update_type": "minor", + "data_version": 1, + "change_type": "update", + "when": 1234567, + "alias": "TestDuplicateAlias4", + "complete": False, + } + ret = self._post("/scheduled_changes/rules", data=data) + self.assertEqual(ret.status_code, 200, ret.get_data()) + + data1 = { + "when": 2000000, + "data_version": 1, + "rule_id": 1, + "priority": 100, + "version": "3.5", + "buildTarget": "d", + "backgroundRate": 100, + "mapping": "c", + "update_type": "minor", + "sc_data_version": 1, + "alias": "TestDuplicateAlias4", + "complete": False, + } + ret1 = self._post("/scheduled_changes/rules/4", data=data1) + self.assertEqual(ret1.status_code, 400, ret1.get_data()) + load = ret1.get_json() + self.assertEqual(load["detail"], "Rule is scheduled with the given alias") + def testAddScheduledChangeMissingRequiredTelemetryFields(self): data = {"telemetry_product": "foo", "priority": 120, "backgroundRate": 100, "update_type": "minor", "change_type": "insert"} ret = self._post("scheduled_changes/rules", data=data)