* Get rid of installation token (for OSS installations) This is done by being required to supply the grafana API URL as an environment variable on the backend. Additionally, optionally an OnCall API URL environment variable can be passed in to the frontend (this basically allows completely skipping the need to configure anything). - deduplicated a lot of the sync logic on the frontend + made error message more useful and consistent - Split PluginConfigPage component into several subcomponents (making it easier to test each individual component) - Moved RootWithLoader (from plugin/GrafanaPluginRootPage) into its own subcomponent (making it easier to test) - Added tests for pre-existing components that were touched: - PluginConfigPage component (and its new subcomponents) - state/plugin and state/rootBaseStore functions - apps.grafana_plugin django app Helm changes: - add GRAFANA_API_URL to oncall.env - some yaml autoformatting changes - remove reference to python manage.py issue_invite_for_the_frontend --override Co-authored-by: Joey Orlando <joseph.t.orlando@gmail.com>
162 lines
6.6 KiB
Python
162 lines
6.6 KiB
Python
import json
|
|
from unittest.mock import patch
|
|
|
|
import pytest
|
|
from django.apps import apps
|
|
from django.conf import settings
|
|
from django.test import override_settings
|
|
from django.urls import reverse
|
|
from rest_framework import status
|
|
from rest_framework.test import APIClient
|
|
|
|
GRAFANA_TOKEN = "TEST_TOKEN"
|
|
STACK_ID = 1
|
|
ORG_ID = 5
|
|
GRAFANA_API_URL = "hello.com"
|
|
LICENSE = "OpenSource"
|
|
STACK_SLUG = "asdfasdf"
|
|
ORG_SLUG = "hellooo"
|
|
ORG_TITLE = "nmvcnmvnmvc"
|
|
REGION_SLUG = "nmcvnmcvnmcvnmcv"
|
|
SELF_HOSTED_SETTINGS = {
|
|
"GRAFANA_API_URL": GRAFANA_API_URL,
|
|
"STACK_ID": STACK_ID,
|
|
"ORG_ID": ORG_ID,
|
|
"LICENSE": LICENSE,
|
|
"STACK_SLUG": STACK_SLUG,
|
|
"ORG_SLUG": ORG_SLUG,
|
|
"ORG_TITLE": ORG_TITLE,
|
|
"REGION_SLUG": REGION_SLUG,
|
|
}
|
|
|
|
UNABLE_TO_FIND_GRAFANA_ERROR_MSG = f"Unable to connect to the specified Grafana API - {GRAFANA_API_URL}"
|
|
UNAUTHED_GRAFANA_API_ERROR_MSG = (
|
|
f"You are not authorized to communicate with the specified Grafana API - {GRAFANA_API_URL}"
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def make_self_hosted_install_header():
|
|
def _make_instance_context_header(token):
|
|
return {
|
|
"HTTP_X-Instance-Context": json.dumps({"grafana_token": token}),
|
|
}
|
|
|
|
return _make_instance_context_header
|
|
|
|
|
|
@override_settings(LICENSE=settings.CLOUD_LICENSE_NAME)
|
|
def test_a_cloud_license_gets_an_unauthorized_error(make_self_hosted_install_header):
|
|
client = APIClient()
|
|
url = reverse("grafana-plugin:self-hosted-install")
|
|
response = client.post(url, format="json", **make_self_hosted_install_header(GRAFANA_TOKEN))
|
|
|
|
assert response.status_code == status.HTTP_403_FORBIDDEN
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"grafana_api_status_code,expected_error_msg",
|
|
[
|
|
(status.HTTP_404_NOT_FOUND, UNABLE_TO_FIND_GRAFANA_ERROR_MSG),
|
|
(status.HTTP_401_UNAUTHORIZED, UNAUTHED_GRAFANA_API_ERROR_MSG),
|
|
(status.HTTP_401_UNAUTHORIZED, UNAUTHED_GRAFANA_API_ERROR_MSG),
|
|
],
|
|
)
|
|
@override_settings(SELF_HOSTED_SETTINGS=SELF_HOSTED_SETTINGS)
|
|
@patch("apps.grafana_plugin.views.self_hosted_install.GrafanaAPIClient")
|
|
def test_it_properly_handles_errors_from_the_grafana_api(
|
|
mocked_grafana_api_client, make_self_hosted_install_header, grafana_api_status_code, expected_error_msg
|
|
):
|
|
mocked_grafana_api_client.return_value.check_token.return_value = (None, {"status_code": grafana_api_status_code})
|
|
|
|
client = APIClient()
|
|
url = reverse("grafana-plugin:self-hosted-install")
|
|
response = client.post(url, format="json", **make_self_hosted_install_header(GRAFANA_TOKEN))
|
|
|
|
assert mocked_grafana_api_client.called_once_with(api_url=GRAFANA_API_URL, api_token=GRAFANA_TOKEN)
|
|
assert mocked_grafana_api_client.return_value.check_token.called_once_with()
|
|
|
|
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
|
assert response.data["error"] == expected_error_msg
|
|
|
|
|
|
@override_settings(SELF_HOSTED_SETTINGS=SELF_HOSTED_SETTINGS)
|
|
@pytest.mark.django_db
|
|
@patch("apps.grafana_plugin.views.self_hosted_install.GrafanaAPIClient")
|
|
@patch("apps.grafana_plugin.views.self_hosted_install.sync_organization")
|
|
@patch("apps.grafana_plugin.views.self_hosted_install.Organization.provision_plugin")
|
|
@patch("apps.grafana_plugin.views.self_hosted_install.Organization.revoke_plugin")
|
|
def test_if_organization_exists_it_is_updated(
|
|
mocked_revoke_plugin,
|
|
mocked_provision_plugin,
|
|
mocked_sync_organization,
|
|
mocked_grafana_api_client,
|
|
make_self_hosted_install_header,
|
|
make_organization,
|
|
):
|
|
organization = make_organization(stack_id=STACK_ID, org_id=ORG_ID)
|
|
provision_plugin_response = {"stackId": STACK_ID, "orgId": ORG_ID, "onCallToken": "HELLOOO", "license": LICENSE}
|
|
|
|
mocked_provision_plugin.return_value = provision_plugin_response
|
|
mocked_grafana_api_client.return_value.check_token.return_value = (None, {"status_code": status.HTTP_200_OK})
|
|
|
|
client = APIClient()
|
|
url = reverse("grafana-plugin:self-hosted-install")
|
|
response = client.post(url, format="json", **make_self_hosted_install_header(GRAFANA_TOKEN))
|
|
|
|
assert mocked_grafana_api_client.called_once_with(api_url=GRAFANA_API_URL, api_token=GRAFANA_TOKEN)
|
|
assert mocked_grafana_api_client.return_value.check_token.called_once_with()
|
|
assert mocked_sync_organization.called_once_with(organization)
|
|
assert mocked_provision_plugin.called_once_with()
|
|
assert mocked_revoke_plugin.called_once_with()
|
|
|
|
assert response.status_code == status.HTTP_201_CREATED
|
|
assert response.data == {"error": None, **provision_plugin_response}
|
|
|
|
organization.refresh_from_db()
|
|
|
|
assert organization.grafana_url == GRAFANA_API_URL
|
|
assert organization.api_token == GRAFANA_TOKEN
|
|
|
|
|
|
@override_settings(SELF_HOSTED_SETTINGS=SELF_HOSTED_SETTINGS)
|
|
@pytest.mark.django_db
|
|
@patch("apps.grafana_plugin.views.self_hosted_install.GrafanaAPIClient")
|
|
@patch("apps.grafana_plugin.views.self_hosted_install.sync_organization")
|
|
@patch("apps.grafana_plugin.views.self_hosted_install.Organization.provision_plugin")
|
|
@patch("apps.grafana_plugin.views.self_hosted_install.Organization.revoke_plugin")
|
|
def test_if_organization_does_not_exist_it_is_created(
|
|
mocked_revoke_plugin,
|
|
mocked_provision_plugin,
|
|
mocked_sync_organization,
|
|
mocked_grafana_api_client,
|
|
make_self_hosted_install_header,
|
|
):
|
|
provision_plugin_response = {"stackId": STACK_ID, "orgId": ORG_ID, "onCallToken": "HELLOOO", "license": LICENSE}
|
|
|
|
mocked_provision_plugin.return_value = provision_plugin_response
|
|
mocked_grafana_api_client.return_value.check_token.return_value = (None, {"status_code": status.HTTP_200_OK})
|
|
|
|
client = APIClient()
|
|
url = reverse("grafana-plugin:self-hosted-install")
|
|
response = client.post(url, format="json", **make_self_hosted_install_header(GRAFANA_TOKEN))
|
|
|
|
Organization = apps.get_model("user_management", "Organization")
|
|
organization = Organization.objects.filter(stack_id=STACK_ID, org_id=ORG_ID).first()
|
|
|
|
assert mocked_grafana_api_client.called_once_with(api_url=GRAFANA_API_URL, api_token=GRAFANA_TOKEN)
|
|
assert mocked_grafana_api_client.return_value.check_token.called_once_with()
|
|
assert mocked_sync_organization.called_once_with(organization)
|
|
assert mocked_provision_plugin.called_once_with()
|
|
assert not mocked_revoke_plugin.called
|
|
|
|
assert response.status_code == status.HTTP_201_CREATED
|
|
assert response.data == {"error": None, **provision_plugin_response}
|
|
|
|
assert organization.stack_id == STACK_ID
|
|
assert organization.stack_slug == STACK_SLUG
|
|
assert organization.org_slug == ORG_SLUG
|
|
assert organization.org_title == ORG_TITLE
|
|
assert organization.region_slug == REGION_SLUG
|
|
assert organization.grafana_url == GRAFANA_API_URL
|
|
assert organization.api_token == GRAFANA_TOKEN
|