Exemple #1
0
 def test_canonical_json(self):
     recipe = RecipeFactory(
         action=ActionFactory(name="action"),
         arguments_json='{"foo": 1, "bar": 2}',
         extra_filter_expression="2 + 2 == 4",
         name="canonical",
         filter_object_json=None,
     )
     # Yes, this is really ugly, but we really do need to compare an exact
     # byte sequence, since this is used for hashing and signing
     filter_expression = "2 + 2 == 4"
     expected = (
         "{"
         '"action":"action",'
         '"arguments":{"bar":2,"foo":1},'
         '"filter_expression":"%(filter_expression)s",'
         '"id":%(id)s,'
         '"name":"canonical",'
         '"revision_id":"%(revision_id)s"'
         "}"
     ) % {
         "id": recipe.id,
         "revision_id": recipe.revision_id,
         "filter_expression": filter_expression,
     }
     expected = expected.encode()
     assert recipe.canonical_json() == expected
Exemple #2
0
    def test_signatures_update_correctly_on_enable(self, mocked_autograph):
        recipe = RecipeFactory(signed=False, approver=UserFactory())
        recipe.approved_revision.enable(user=UserFactory())
        recipe.refresh_from_db()

        assert recipe.signature is not None
        assert recipe.signature.signature == fake_sign([recipe.canonical_json()])[0]["signature"]
Exemple #3
0
    def test_delete_pending_approval_request_on_revise(self):
        recipe = RecipeFactory(name="old")
        approval = ApprovalRequestFactory(revision=recipe.latest_revision)
        recipe.revise(name="new")

        with pytest.raises(ApprovalRequest.DoesNotExist):
            ApprovalRequest.objects.get(pk=approval.pk)
Exemple #4
0
    def test_filter_exclude_many(self):
        locale_match1, locale_match2, locale_not = LocaleFactory.create_batch(3)
        recipe = RecipeFactory(locales=[locale_match1, locale_match2])
        client = ClientFactory(locale=locale_not.code)

        assert not recipe.matches(client)
        assert recipe.matches(client, exclude=[get_locales])
Exemple #5
0
 def test_cant_change_signature_and_other_fields(self):
     recipe = RecipeFactory(name='unchanged', signed=False)
     recipe.signature = SignatureFactory()
     recipe.name = 'changed'
     with pytest.raises(ValidationError) as exc_info:
         recipe.save()
     assert exc_info.value.message == 'Signatures must change alone'
Exemple #6
0
    def test_filter_by_sample_rate(self):
        always_match = RecipeFactory(sample_rate=1.0)
        never_match = RecipeFactory(sample_rate=0.0)
        client = ClientFactory()

        assert always_match.matches(client)
        assert not never_match.matches(client)
Exemple #7
0
 def test_enabled_state_carried_over_on_approval(self):
     recipe = RecipeFactory(approver=UserFactory(), enabler=UserFactory())
     carryover_from = recipe.approved_revision.enabled_state
     recipe.revise(name="New name")
     approval_request = recipe.latest_revision.request_approval(UserFactory())
     approval_request.approve(UserFactory(), "r+")
     assert recipe.enabled
     assert recipe.approved_revision.enabled_state.carryover_from == carryover_from
Exemple #8
0
    def test_filter_by_locale_one(self):
        locale1 = LocaleFactory()
        locale2 = LocaleFactory()
        recipe = RecipeFactory(locales=[locale1])
        client1 = ClientFactory(locale=locale1.code)
        client2 = ClientFactory(locale=locale2.code)

        assert recipe.matches(client1)
        assert not recipe.matches(client2)
Exemple #9
0
 def test_can_update_extensions_no_longer_in_use(self, api_client, storage):
     xpi = WebExtensionFileFactory()
     e = ExtensionFactory(xpi__from_func=xpi.open)
     a = ActionFactory(name="opt-out-study")
     r = RecipeFactory(action=a, arguments={"extensionId": e.id})
     r.revise(arguments={"extensionId": 0})
     res = api_client.patch(f"/api/v3/extension/{e.id}/", {"name": "new name"})
     assert res.status_code == 200
     assert res.data["name"] == "new name"
Exemple #10
0
    def test_revision_id_increments(self):
        """Ensure that the revision id is incremented on each save"""
        recipe = RecipeFactory()

        # The factory saves a couple times so revision id is not 0
        revision_id = recipe.revision_id

        recipe.save()
        assert recipe.revision_id == revision_id + 1
Exemple #11
0
 def test_can_delete_extensions_no_longer_in_use(self, api_client, storage):
     xpi = WebExtensionFileFactory()
     e = ExtensionFactory(xpi__from_func=xpi.open)
     a = ActionFactory(name="opt-out-study")
     r = RecipeFactory(action=a, arguments={"extensionId": e.id})
     r.revise(arguments={"extensionId": 0})
     res = api_client.delete(f"/api/v3/extension/{e.id}/")
     assert res.status_code == 204
     assert Extension.objects.count() == 0
Exemple #12
0
    def test_recipe_doesnt_revise_when_clean(self):
        recipe = RecipeFactory(name="my name")

        revision_id = recipe.revision_id
        last_updated = recipe.last_updated

        recipe.revise(name="my name")
        assert revision_id == recipe.revision_id
        assert last_updated == recipe.last_updated
Exemple #13
0
    def test_filter_by_country_one(self):
        country1 = CountryFactory()
        country2 = CountryFactory()
        recipe = RecipeFactory(countries=[country1])
        client1 = ClientFactory(country=country1.code)
        client2 = ClientFactory(country=country2.code)

        assert recipe.matches(client1)
        assert not recipe.matches(client2)
Exemple #14
0
    def test_filter_by_channel_one(self):
        beta = ReleaseChannelFactory(slug='beta')
        recipe = RecipeFactory(release_channels=[beta])

        release_client = ClientFactory(release_channel='release')
        beta_client = ClientFactory(release_channel='beta')

        assert not recipe.matches(release_client)
        assert recipe.matches(beta_client)
Exemple #15
0
        def test_history(self, api_client):
            recipe = RecipeFactory(name="version 1")
            recipe.revise(name="version 2")
            recipe.revise(name="version 3")

            res = api_client.get("/api/v1/recipe/%s/history/" % recipe.id)

            assert res.data[0]["recipe"]["name"] == "version 3"
            assert res.data[1]["recipe"]["name"] == "version 2"
            assert res.data[2]["recipe"]["name"] == "version 1"
Exemple #16
0
    def test_signature_is_updated_if_autograph_available(self, mocked_autograph):
        recipe = RecipeFactory(name="unchanged", approver=UserFactory(), enabler=UserFactory())
        original_signature = recipe.signature
        assert original_signature is not None

        recipe.revise(name="changed")

        assert recipe.latest_revision.name == "changed"
        assert recipe.signature is not original_signature
        expected_sig = fake_sign([recipe.canonical_json()])[0]["signature"]
        assert recipe.signature.signature == expected_sig
Exemple #17
0
    def test_signature_is_cleared_if_autograph_unavailable(self, mocker):
        # Mock the Autographer to return an error
        mock_autograph = mocker.patch("normandy.recipes.models.Autographer")
        mock_autograph.side_effect = ImproperlyConfigured

        recipe = RecipeFactory(name="unchanged", signed=True)
        original_signature = recipe.signature
        recipe.revise(name="changed")
        assert recipe.name == "changed"
        assert recipe.signature is not original_signature
        assert recipe.signature is None
Exemple #18
0
        def test_unique_name_update_collision(self):
            action = ActionFactory(name="opt-out-study")
            arguments_a = {"name": "foo"}
            arguments_b = {"name": "bar"}
            RecipeFactory(action=action, arguments=arguments_a)
            recipe = RecipeFactory(action=action, arguments=arguments_b)

            with pytest.raises(serializers.ValidationError) as exc_info1:
                recipe.revise(arguments=arguments_a)
            error = action.errors["duplicate_study_name"]
            assert exc_info1.value.detail == {"arguments": {"name": error}}
Exemple #19
0
    def test_recipe_is_approved(self):
        recipe = RecipeFactory(name="old")
        assert not recipe.is_approved

        approval = ApprovalRequestFactory(revision=recipe.latest_revision)
        approval.approve(UserFactory(), "r+")
        assert recipe.is_approved
        assert recipe.approved_revision == recipe.latest_revision

        recipe.revise(name="new")
        assert recipe.is_approved
        assert recipe.approved_revision != recipe.latest_revision
Exemple #20
0
    def test_revision_id_doesnt_increment_if_no_changes(self):
        """
        revision_id should not increment if a recipe is saved with no
        changes.
        """
        recipe = RecipeFactory()

        # The factory saves a couple times so revision id is not 0
        revision_id = recipe.revision_id

        recipe.save()
        assert recipe.revision_id == revision_id
Exemple #21
0
    def test_update_signature(self, mocker):
        # Mock the Autographer
        mock_autograph = mocker.patch('normandy.recipes.models.Autographer')
        mock_autograph.return_value.sign_data.return_value = [
            {'signature': 'fake signature'},
        ]

        recipe = RecipeFactory(signed=False)
        recipe.update_signature()
        recipe.save()
        assert recipe.signature is not None
        assert recipe.signature.signature == 'fake signature'
Exemple #22
0
 def test_update_signature(self, mock_logger, mocked_autograph):
     recipe = RecipeFactory(enabler=UserFactory(), approver=UserFactory())
     recipe.signature = None
     recipe.update_signature()
     mock_logger.info.assert_called_with(
         Whatever.contains(str(recipe.id)),
         extra={"code": INFO_REQUESTING_RECIPE_SIGNATURES, "recipe_ids": [recipe.id]},
     )
     mocked_autograph.return_value.sign_data.assert_called_with(
         [Whatever(lambda s: json.loads(s)["id"] == recipe.id)]
     )
     assert recipe.signature is not None
Exemple #23
0
    def test_signature_is_cleared_if_autograph_unavailable(self, mocker):
        # Mock the Autographer
        mock_autograph = mocker.patch('normandy.recipes.models.Autographer')
        mock_autograph.return_value.sign_data.side_effect = ImproperlyConfigured

        recipe = RecipeFactory(name='unchanged', signed=True)
        original_signature = recipe.signature
        recipe.name = 'changed'
        recipe.save()
        assert recipe.name == 'changed'
        assert recipe.signature is not original_signature
        assert recipe.signature is None
Exemple #24
0
    def test_it_doesnt_disable_recipes(self, mock_action):
        recipe = RecipeFactory(
            action__name='test-action',
            action__implementation='old',
            enabled=True
        )
        action = recipe.action
        mock_action(action.name, 'impl', action.arguments_schema)

        call_command('update_actions')
        recipe.refresh_from_db()
        assert recipe.enabled
Exemple #25
0
    def test_filter_by_channel_many(self):
        release = ReleaseChannelFactory(slug='release')
        beta = ReleaseChannelFactory(slug='beta')
        recipe = RecipeFactory(release_channels=[release, beta])

        release_client = ClientFactory(release_channel='release')
        beta_client = ClientFactory(release_channel='beta')
        aurora_client = ClientFactory(release_channel='aurora')

        assert recipe.matches(release_client)
        assert recipe.matches(beta_client)
        assert not recipe.matches(aurora_client)
Exemple #26
0
    def test_signature_is_updated_if_autograph_available(self, mocked_autograph):
        recipe = RecipeFactory(name='unchanged')
        original_signature = recipe.signature
        assert original_signature is not None

        recipe.name = 'changed'
        recipe.save()

        assert recipe.name == 'changed'
        assert recipe.signature is not original_signature
        expected_sig = hashlib.sha256(recipe.canonical_json()).hexdigest()
        assert recipe.signature.signature == expected_sig
Exemple #27
0
        def test_unique_experiment_slug_update_collision(self):
            action = ActionFactory(name="preference-experiment")
            arguments_a = {"slug": "a", "branches": []}
            arguments_b = {"slug": "b", "branches": []}
            # Does not throw when saving revisions
            RecipeFactory(action=action, arguments=arguments_a)
            recipe = RecipeFactory(action=action, arguments=arguments_b)

            with pytest.raises(serializers.ValidationError) as exc_info1:
                recipe.revise(arguments=arguments_a)
            error = action.errors["duplicate_experiment_slug"]
            assert exc_info1.value.detail == {"arguments": {"slug": error}}
Exemple #28
0
    def test_it_publishes_new_revisions_if_enabled(self, mocked_remotesettings):
        recipe = RecipeFactory(name="Test", approver=UserFactory(), enabler=UserFactory())
        assert mocked_remotesettings.return_value.publish.call_count == 1

        recipe.revise(name="Modified")
        approval_request = recipe.latest_revision.request_approval(creator=UserFactory())
        approval_request.approve(approver=UserFactory(), comment="r+")

        assert mocked_remotesettings.return_value.publish.call_count == 2
        second_call_args, _ = mocked_remotesettings.return_value.publish.call_args_list[1]
        modified_recipe, = second_call_args
        assert modified_recipe.name == "Modified"
Exemple #29
0
    def test_enabled_updates_signatures(self, mocked_autograph):
        recipe = RecipeFactory(name="first")
        ar = recipe.latest_revision.request_approval(UserFactory())
        ar.approve(approver=UserFactory(), comment="r+")
        recipe = Recipe.objects.get()
        recipe.approved_revision.enable(UserFactory())

        recipe.refresh_from_db()
        data_to_sign = recipe.canonical_json()
        signature_of_data = fake_sign([data_to_sign])[0]["signature"]
        signature_in_db = recipe.signature.signature
        assert signature_of_data == signature_in_db
Exemple #30
0
    def test_approval_request_property(self):
        # Make sure it works when there is no approval request
        recipe = RecipeFactory(name="old")
        assert recipe.approval_request is None

        # Make sure it returns an approval request if it exists
        approval = ApprovalRequestFactory(revision=recipe.latest_revision)
        assert recipe.approval_request == approval

        # Check the edge case where there is no latest_revision
        recipe.latest_revision.delete()
        recipe.refresh_from_db()
        assert recipe.approval_request is None
Exemple #31
0
    def test_cannot_enable_unapproved_recipes(self, api_client):
        recipe = RecipeFactory(enabled=False)

        res = api_client.post('/api/v2/recipe/%s/enable/' % recipe.id)
        assert res.status_code == 409
        assert res.data[
            'enabled'] == 'Cannot enable a recipe that is not approved.'
Exemple #32
0
    def test_recipe_as_remotesettings_record(self, mocked_autograph):
        """Test that recipes are serialized as expected by our clients."""

        recipe = RecipeFactory(name="Test",
                               approver=UserFactory(),
                               enabler=UserFactory(),
                               signed=True)

        record = exports.recipe_as_record(recipe)
        assert record == {
            "id": str(recipe.id),
            "recipe": {
                "action":
                recipe.action.name,
                "arguments":
                recipe.arguments,
                "filter_expression":
                recipe.filter_expression,
                "id":
                recipe.id,
                "name":
                recipe.name,
                "revision_id":
                str(recipe.revision_id),
                "capabilities":
                Whatever(lambda caps: set(caps) == recipe.capabilities),
            },
            "signature": {
                "public_key": Whatever.regex(r"[a-zA-Z0-9/+]{160}"),
                "signature": Whatever.regex(r"[a-f0-9]{40}"),
                "timestamp": Whatever.iso8601(),
                "x5u": Whatever.startswith("https://"),
            },
        }
Exemple #33
0
    def test_it_works(self, rf):
        recipe = RecipeFactory(arguments={"foo": "bar"})
        approval = ApprovalRequestFactory(revision=recipe.latest_revision)
        action = recipe.action
        serializer = RecipeSerializer(recipe, context={"request": rf.get("/")})

        assert serializer.data == {
            "name": recipe.name,
            "id": recipe.id,
            "last_updated": Whatever(),
            "enabled": recipe.enabled,
            "extra_filter_expression": recipe.extra_filter_expression,
            "filter_expression": recipe.filter_expression,
            "revision_id": recipe.revision_id,
            "action": action.name,
            "arguments": {
                "foo": "bar"
            },
            "is_approved": False,
            "latest_revision_id": recipe.latest_revision.id,
            "approved_revision_id": None,
            "approval_request": {
                "id": approval.id,
                "created": Whatever(),
                "creator": Whatever(),
                "approved": None,
                "approver": None,
                "comment": None,
            },
            "identicon_seed": Whatever.startswith("v1:"),
        }
Exemple #34
0
    def test_disable(self):
        recipe = RecipeFactory(name="Test",
                               approver=UserFactory(),
                               enabler=UserFactory())
        assert recipe.enabled

        recipe.approved_revision.disable(user=UserFactory())
        assert not recipe.enabled

        with pytest.raises(EnabledState.NotActionable):
            recipe.approved_revision.disable(user=UserFactory())

        recipe.revise(name="New name")

        with pytest.raises(EnabledState.NotActionable):
            recipe.latest_revision.disable(user=UserFactory())
Exemple #35
0
 def test_slug_must_match_a_rollout(self):
     rollback_action = ActionFactory(name="preference-rollback")
     arguments = {"rolloutSlug": "does-not-exist"}
     with pytest.raises(serializers.ValidationError) as exc_info:
         RecipeFactory(action=rollback_action, arguments=arguments)
     error = rollback_action.errors["rollout_slug_not_found"]
     assert exc_info.value.detail == {"arguments": {"slug": error}}
Exemple #36
0
    def test_it_passes_expire_early_setting(self, mocker, settings):
        settings.CERTIFICATES_EXPIRE_EARLY_DAYS = 7
        recipe = RecipeFactory(signed=True)
        mock_verify_x5u = mocker.patch('normandy.recipes.checks.signing.verify_x5u')

        errors = checks.signatures_use_good_certificates(None)
        mock_verify_x5u.assert_called_once_with(recipe.signature.x5u, timedelta(7))
        assert errors == []
Exemple #37
0
 def test_it_ignores_signatures_without_x5u(self):
     recipe = RecipeFactory(signed=True)
     recipe.signature.x5u = None
     recipe.signature.save()
     actions = ActionFactory(signed=True)
     actions.signature.x5u = None
     actions.signature.save()
     assert checks.signatures_use_good_certificates(None) == []
Exemple #38
0
        def test_it_publishes_several_times_when_reenabled(self, mocked_remotesettings):
            recipe = RecipeFactory(name="Test", approver=UserFactory(), enabler=UserFactory())

            recipe.approved_revision.disable(user=UserFactory())
            recipe.approved_revision.enable(user=UserFactory())

            assert mocked_remotesettings.return_value.unpublish.call_count == 1
            assert mocked_remotesettings.return_value.publish.call_count == 2
Exemple #39
0
 def test_signed_listing_works(self, api_client):
     r1 = RecipeFactory(signed=True)
     res = api_client.get('/api/v1/recipe/signed/')
     assert res.status_code == 200
     assert len(res.data) == 1
     assert res.data[0]['recipe']['id'] == r1.id
     assert res.data[0]['signature'][
         'signature'] == r1.signature.signature
Exemple #40
0
    def test_classify_no_sample(self, admin_client):
        """The classify view should ignore sampling."""
        locale = LocaleFactory()
        country = CountryFactory()
        release_channel = ReleaseChannelFactory()

        recipe = RecipeFactory(sample_rate=0)
        response = admin_client.get(
            '/admin/classifier_preview', {
                'locale': locale.code,
                'release_channel': release_channel.slug,
                'country': country.code
            })

        assert response.status_code == 200
        assert not recipe.matches(response.context['client'])
        assert list(response.context['bundle']) == [recipe]
Exemple #41
0
    def test_it_can_disable_recipes(self, api_client):
        recipe = RecipeFactory(enabled=True)

        res = api_client.post('/api/v1/recipe/%s/disable/' % recipe.id)
        assert res.status_code == 204

        recipe = Recipe.objects.all()[0]
        assert not recipe.enabled
Exemple #42
0
    def test_it_can_delete_recipes(self, api_client):
        recipe = RecipeFactory()

        res = api_client.delete('/api/v1/recipe/%s/' % recipe.id)
        assert res.status_code == 204

        recipes = Recipe.objects.all()
        assert recipes.count() == 0
Exemple #43
0
 def test_signed_listing_works(self, api_client):
     r1 = RecipeFactory(signed=True)
     res = api_client.get("/api/v1/recipe/signed/")
     assert res.status_code == 200
     assert len(res.data) == 1
     assert res.data[0]["recipe"]["id"] == r1.id
     assert res.data[0]["signature"][
         "signature"] == r1.signature.signature
Exemple #44
0
        def test_it_serves_recipes(self, api_client, settings):
            recipe = RecipeFactory()
            settings.BASELINE_CAPABILITIES |= recipe.latest_revision.capabilities

            res = api_client.get("/api/v1/recipe/")
            assert res.status_code == 200
            assert len(res.data) == 1
            assert res.data[0]["name"] == recipe.latest_revision.name
Exemple #45
0
    def test_it_publishes_new_revisions_if_enabled(self,
                                                   mocked_remotesettings):
        recipe = RecipeFactory(name="Test",
                               approver=UserFactory(),
                               enabler=UserFactory())
        assert mocked_remotesettings.return_value.publish.call_count == 1

        recipe.revise(name="Modified")
        approval_request = recipe.latest_revision.request_approval(
            creator=UserFactory())
        approval_request.approve(approver=UserFactory(), comment="r+")

        assert mocked_remotesettings.return_value.publish.call_count == 2
        second_call_args, _ = mocked_remotesettings.return_value.publish.call_args_list[
            1]
        modified_recipe, = second_call_args
        assert modified_recipe.name == "Modified"
Exemple #46
0
 def test_setting_signature_doesnt_change_canonical_json(self):
     recipe = RecipeFactory(name="unchanged", signed=False)
     serialized = recipe.canonical_json()
     recipe.signature = SignatureFactory()
     recipe.save()
     assert recipe.signature is not None
     assert recipe.canonical_json() == serialized
Exemple #47
0
        def test_no_errors(self):
            action = ActionFactory(name="opt-out-study")
            recipe = RecipeFactory(action=action)

            # Approve and enable the revision
            rev = recipe.latest_revision
            approval_request = rev.request_approval(UserFactory())
            approval_request.approve(UserFactory(), "r+")
            rev.enable(UserFactory())
 def test_cannot_delete_in_use_extension(self, api_client, storage):
     xpi = WebExtensionFileFactory()
     e = ExtensionFactory(xpi__from_func=xpi.open)
     a = ActionFactory(name="opt-out-study")
     RecipeFactory(action=a, arguments={"extensionId": e.id})
     res = api_client.delete(f"/api/v3/extension/{e.id}/")
     assert res.status_code == 400
     assert res.data == ["Extension cannot be updated while in use by a recipe."]
     assert Extension.objects.count() == 1
Exemple #49
0
    def test_it_can_edit_actions_in_use_with_setting(self, api_client, settings):
        RecipeFactory(action__name='active', enabled=True)
        settings.CAN_EDIT_ACTIONS_IN_USE = True

        res = api_client.patch('/api/v1/action/active/', {'implementation': 'foobar'})
        assert res.status_code == 200

        res = api_client.delete('/api/v1/action/active/')
        assert res.status_code == 204
Exemple #50
0
def test_action_admin_form_not_in_use():
    """Actions that are not in-use can be edited."""
    action = RecipeFactory(enabled=False).action

    FormClass = modelform_factory(Action,
                                  form=ActionAdminForm,
                                  fields=['name'])
    form = FormClass({'name': 'foo'}, instance=action)
    assert form.is_valid()
Exemple #51
0
 def test_signed_listing_works(self, api_client, settings):
     r1 = RecipeFactory(approver=UserFactory(), signed=True)
     settings.BASELINE_CAPABILITIES |= r1.latest_revision.capabilities
     res = api_client.get("/api/v1/recipe/signed/")
     assert res.status_code == 200
     assert len(res.data) == 1
     assert res.data[0]["recipe"]["id"] == r1.id
     assert res.data[0]["signature"][
         "signature"] == r1.signature.signature
Exemple #52
0
    def test_it_works_for_multiple_extensions(self, storage):
        extension1 = ExtensionFactory(name="1.xpi")
        extension2 = ExtensionFactory(name="2.xpi")

        fake_old_url1 = extension1.xpi.url.replace("/media/", "/media-old/")
        fake_old_url2 = extension2.xpi.url.replace("/media/", "/media-old/")

        action = ActionFactory(name="opt-out-study")
        recipe1 = RecipeFactory(action=action, arguments={"name": "1", addonUrl: fake_old_url1})
        recipe2 = RecipeFactory(action=action, arguments={"name": "2", addonUrl: fake_old_url2})
        call_command("update_addon_urls")

        # For reasons that I don't understand, recipe.update_from_db() doesn't work here.
        recipe1 = Recipe.objects.get(id=recipe1.id)
        recipe2 = Recipe.objects.get(id=recipe2.id)

        assert recipe1.latest_revision.arguments[addonUrl] == extension1.xpi.url
        assert recipe2.latest_revision.arguments[addonUrl] == extension2.xpi.url
Exemple #53
0
 def test_it_warns_if_a_field_isnt_available(self, mocker):
     """This is to allow for un-applied to migrations to not break running migrations."""
     RecipeFactory(approver=UserFactory(), signed=True)
     mock_canonical_json = mocker.patch(
         "normandy.recipes.models.Recipe.canonical_json")
     mock_canonical_json.side_effect = ProgrammingError("error for testing")
     errors = checks.recipe_signatures_are_correct(None)
     assert len(errors) == 1
     assert errors[0].id == checks.WARNING_COULD_NOT_CHECK_SIGNATURES
Exemple #54
0
 def test_it_reports_x5u_network_errors(self, mocker):
     RecipeFactory(signed=True)
     mock_verify_x5u = mocker.patch(
         "normandy.recipes.checks.signing.verify_x5u")
     mock_verify_x5u.side_effect = requests.exceptions.ConnectionError
     errors = checks.signatures_use_good_certificates(None)
     mock_verify_x5u.assert_called_once()
     assert len(errors) == 1
     assert errors[0].id == checks.ERROR_COULD_NOT_VERIFY_CERTIFICATE
Exemple #55
0
    def test_it_can_enable_recipes(self, api_client):
        recipe = RecipeFactory(enabled=False, approver=UserFactory())

        res = api_client.post('/api/v1/recipe/%s/enable/' % recipe.id)
        assert res.status_code == 200
        assert res.data['enabled'] is True

        recipe = Recipe.objects.all()[0]
        assert recipe.enabled
Exemple #56
0
    def test_it_sends_metrics(self, settings, mocked_autograph):
        # 3 to sign
        RecipeFactory.create_batch(3,
                                   approver=UserFactory(),
                                   enabler=UserFactory(),
                                   signed=False)
        # and 1 to unsign
        RecipeFactory(signed=True, enabled=False)

        with MetricsMock() as mm:
            call_command("update_recipe_signatures")
            mm.print_records()
            assert mm.has_record(GAUGE,
                                 stat="normandy.signing.recipes.signed",
                                 value=3)
            assert mm.has_record(GAUGE,
                                 stat="normandy.signing.recipes.unsigned",
                                 value=1)
Exemple #57
0
    def test_it_does_not_publish_when_approved_if_not_enabled(
            self, mocked_remotesettings):
        recipe = RecipeFactory(name="Test")

        approval_request = recipe.latest_revision.request_approval(
            creator=UserFactory())
        approval_request.approve(approver=UserFactory(), comment="r+")

        assert not mocked_remotesettings.return_value.publish.called
Exemple #58
0
    def test_close(self, api_client):
        r = RecipeFactory()
        a = ApprovalRequestFactory(revision=r.latest_revision)
        res = api_client.post('/api/v1/approval_request/{}/close/'.format(
            a.id))
        assert res.status_code == 204

        with pytest.raises(ApprovalRequest.DoesNotExist):
            ApprovalRequest.objects.get(pk=a.pk)
Exemple #59
0
    def test_disabling_recipe_removes_approval(self):
        recipe = RecipeFactory(approver=UserFactory(), enabled=True)
        assert recipe.is_approved

        recipe.enabled = False
        recipe.save()
        recipe.refresh_from_db()
        assert not recipe.is_approved
Exemple #60
0
    def test_it_can_disable_recipes(self, api_client):
        recipe = RecipeFactory(approver=UserFactory(), enabled=True)

        res = api_client.post('/api/v1/recipe/%s/disable/' % recipe.id)
        assert res.status_code == 200
        assert res.data['enabled'] is False

        recipe = Recipe.objects.all()[0]
        assert not recipe.is_approved
        assert not recipe.enabled