def delete_config(request, gf_id=None):
    config = GFConfig.objects.get(id=gf_id)

    # Create Grafana class to handle this GF instance
    grafana = Grafana(config)

    try:
        grafana.validate_credentials()
        grafana.delete_all_datasources()
        grafana.delete_all_dashboards()
    except ValueError as error:
        messages.error(request, f"Grafana instance not deleted: {error}")
    else:
        messages.success(request, f"Grafana instance deleted successfully")

    config.delete()

    return redirect("/gfconfig")
Example #2
0
class TestGFConfig(TestCase):
    TESTCODE = "testcode"

    test_sensor_name = "Wind Sensor"
    test_sensor_type = "Dual wind"
    test_sensor_format = {
        "left_gust": {
            "unit": "km/h",
            "format": "float"
        },
        "right_gust": {
            "unit": "km/h",
            "format": "float"
        },
    }
    test_sensor_graph_type = "graph"

    test_event_data = {
        "name": "Sunny Day Test Drive",
        "date": datetime.datetime(2020, 2, 2, 20, 21, 22),
        "description": "A very progressive test run at \
                        Sunnyside Daycare's Butterfly Room.",
        "location": "New York, NY",
    }

    test_venue_data = {
        "name": "Venue 1",
        "description": "foo",
        "latitude": 100,
        "longitude": 200,
    }

    def create_venue_and_event(self, event_name):
        venue = AGVenue.objects.create(
            name=self.test_venue_data["name"],
            description=self.test_venue_data["description"],
            latitude=self.test_venue_data["latitude"],
            longitude=self.test_venue_data["longitude"],
        )
        venue.save()

        event = AGEvent.objects.create(
            name=event_name,
            date=self.test_event_data["date"],
            description=self.test_event_data["description"],
            venue_uuid=venue,
        )
        event.save()

        return event

    def setUp(self):
        # api keys with admin and viewer level permissions
        self.ADMIN = Grafana.create_api_key(HOST, "admin", "Admin")
        self.VIEWER = Grafana.create_api_key(HOST, "viewer", "Viewer")

        self.login_url = "mercury:EventAccess"
        self.sensor_url = "mercury:sensor"
        self.event_url = "mercury:events"
        self.config_url = "mercury:gfconfig"
        self.config_update_url = "mercury:gfconfig_update"
        self.config_delete_url = "mercury:gfconfig_delete"
        self.config_update_dashboard_url = "mercury:gfconfig_update_dashboard"
        self.config_reset_dashboard_url = "mercury:gfconfig_reset_dashboard"
        self.config_delete_dashboard_url = "mercury:gfconfig_delete_dashboard"
        self.config_add_dashboard_url = "mercury:gfconfig_create_dashboard"
        test_code = EventCodeAccess(event_code="testcode", enabled=True)
        test_code.save()
        # Login
        self._get_with_event_code(self.sensor_url, self.TESTCODE)

        self.gfconfig = GFConfig.objects.create(gf_name="Test",
                                                gf_host=HOST,
                                                gf_token=self.ADMIN,
                                                gf_current=True)
        self.gfconfig.save()
        # Create fresh grafana object
        self.grafana = Grafana(self.gfconfig)

        # Create random name to be used for event and datasource
        self.event_name = self.grafana.generate_random_string(10)
        self.datasource_name = self.grafana.generate_random_string(10)

        # Clear existing dashboard and datasource
        self.grafana.delete_all_dashboards()
        self.grafana.delete_all_datasources()

    def tearDown(self):
        # Create fresh grafana instance (in case test invalidated any tokens, etc.)
        self.grafana = Grafana(self.gfconfig)

        # Clear all of the created dashboards
        self.grafana.delete_all_dashboards()
        self.grafana.delete_all_datasources()

    def _get_with_event_code(self, url, event_code):
        self.client.get(reverse(self.login_url))
        self.client.post(reverse(self.login_url),
                         data={"eventcode": event_code})
        response = self.client.get(reverse(url))
        session = self.client.session
        return response, session

    def test_config_view_get_success(self):
        # Login
        self._get_with_event_code(self.sensor_url, self.TESTCODE)

        response = self.client.get(reverse(self.config_url))
        self.assertEqual(200, response.status_code)

    def test_config_view_get_existing_dashboard_displayed(self):
        # Login
        self._get_with_event_code(self.sensor_url, self.TESTCODE)

        venue = AGVenue.objects.create(
            name=self.test_venue_data["name"],
            description=self.test_venue_data["description"],
            latitude=self.test_venue_data["latitude"],
            longitude=self.test_venue_data["longitude"],
        )
        venue.save()

        sensor_type = AGSensorType.objects.create(
            name=self.test_sensor_type,
            processing_formula=0,
            format=self.test_sensor_format,
            graph_type=self.test_sensor_graph_type,
        )
        sensor_type.save()
        sensor = AGSensor.objects.create(name=self.test_sensor_name,
                                         type_id=sensor_type)
        sensor.save()

        # Send a request to create an event (should trigger the creation of a
        # grafana dashboard of the same name)
        self.client.post(
            reverse(self.event_url),
            data={
                "submit-event": "",
                "name": self.event_name,
                "date": self.test_event_data["date"],
                "description": self.test_event_data["description"],
                "venue_uuid": venue.uuid,
            },
        )
        response = self.client.get("/gfconfig/configure/{}".format(
            self.gfconfig.id))
        self.assertContains(response, self.event_name)
        self.assertContains(response, sensor.name)

    def test_config_post_success(self):
        # Delete GFConfig used for the tests (will interfere otherwise)
        self.gfconfig.delete()
        # Login
        self._get_with_event_code(self.sensor_url, self.TESTCODE)

        response = self.client.post(
            reverse(self.config_url),
            data={
                "submit": "",
                "gf_name": "Test Grafana Instance",
                "gf_host": HOST,
                "gf_token": self.ADMIN,
                "gf_username": "******",
                "gf_password": "******",
            },
        )
        self.assertEqual(302, response.status_code)

        # Restore GFConfig instance used for the tests
        self.gfconfig = GFConfig.objects.create(gf_name="Test",
                                                gf_host=HOST,
                                                gf_token=self.ADMIN,
                                                gf_current=True)
        self.gfconfig.save()

        gfconfig = GFConfig.objects.filter(gf_name="Test Grafana Instance")
        self.assertTrue(gfconfig.count() > 0)
        self.assertTrue(gfconfig[0].gf_name == "Test Grafana Instance")
        self.assertTrue(gfconfig[0].gf_host == HOST)
        self.assertTrue(gfconfig[0].gf_token == self.ADMIN)

    def test_config_post_fail_invalid_api_key(self):
        # Login
        self._get_with_event_code(self.sensor_url, self.TESTCODE)

        response = self.client.post(
            reverse(self.config_url),
            data={
                "submit": "",
                "gf_name": "Test Grafana Instance",
                "gf_host": HOST,
                "gf_token": "abcde",
            },
        )
        self.assertEqual(302, response.status_code)

        gfconfig = GFConfig.objects.filter(gf_name="Test Grafana Instance")
        self.assertTrue(gfconfig.count() == 0)

    def test_config_post_fail_insufficient_permissions(self):
        # Login
        self._get_with_event_code(self.sensor_url, self.TESTCODE)

        response = self.client.post(
            reverse(self.config_url),
            data={
                "submit": "",
                "gf_name": "Test Grafana Instance",
                "gf_host": HOST,
                "gf_token": self.VIEWER,
                "gf_username": "******",
                "gf_password": "******",
            },
        )
        self.assertEqual(302, response.status_code)

        gfconfig = GFConfig.objects.filter(gf_name="Test Grafana Instance")
        self.assertTrue(gfconfig.count() == 0)

    def test_delete_config(self):
        # Login
        self._get_with_event_code(self.sensor_url, self.TESTCODE)

        GFConfig.objects.all().delete()

        gfconfig = GFConfig.objects.create(gf_name="Test Grafana Instance",
                                           gf_host=HOST,
                                           gf_token=self.ADMIN)
        gfconfig.save()
        gfconfig = GFConfig.objects.filter(
            gf_name="Test Grafana Instance").first()

        self.client.post(
            os.path.join(
                reverse(self.config_delete_url, kwargs={"gf_id":
                                                        gfconfig.id})),
            data={
                "submit": "",
                "gf_name": "Test Grafana Instance",
                "gf_host": HOST,
                "gf_token": self.ADMIN,
                "gf_username": "******",
                "gf_password": "******",
            },
        )
        gfconfig = GFConfig.objects.filter(gf_name="Test Grafana Instance")
        self.assertTrue(gfconfig.count() == 0)

    # test that GFConfig.gf_current can be set to True using the update view
    def test_update_config(self):
        # Login
        self._get_with_event_code(self.sensor_url, self.TESTCODE)

        GFConfig.objects.all().delete()

        gfconfig = GFConfig.objects.create(
            gf_name="Test Grafana Instance",
            gf_host=HOST,
            gf_token=self.ADMIN,
            gf_current=False,
        )
        gfconfig.save()

        self.client.post(
            os.path.join(
                reverse(self.config_update_url, kwargs={"gf_id":
                                                        gfconfig.id})))

        gfconfig = GFConfig.objects.all().first()
        self.assertEquals(gfconfig.gf_current, True)

    def test_config_post_event_exists_dashboard_created(self):
        # Login
        self._get_with_event_code(self.sensor_url, self.TESTCODE)

        self.create_venue_and_event(self.event_name)

        # Delete GFConfig used for the test (will interfere otherwise)
        self.gfconfig.delete()

        response = self.client.post(
            reverse(self.config_url),
            data={
                "submit": "",
                "gf_name": "Test Grafana Instance",
                "gf_host": HOST,
                "gf_token": self.ADMIN,
                "gf_username": "******",
                "gf_password": "******",
            },
        )
        self.assertEqual(302, response.status_code)

        # Restore GFConfig instance used for the tests
        self.gfconfig = GFConfig.objects.create(gf_name="Test",
                                                gf_host=HOST,
                                                gf_token=self.ADMIN,
                                                gf_current=True)
        self.gfconfig.save()

        # check that dashboard was created with same name as event
        dashboard = self.grafana.get_dashboard_by_name(self.event_name)
        self.assertTrue(dashboard)
        self.assertEquals(dashboard["dashboard"]["title"], self.event_name)

    def test_config_post_event_exists_dashboard_created_with_sensor(self):
        # Login
        self._get_with_event_code(self.sensor_url, self.TESTCODE)

        # Create a sensor type and sensor
        sensor_type = AGSensorType.objects.create(
            name=self.test_sensor_type,
            processing_formula=0,
            format=self.test_sensor_format,
            graph_type=self.test_sensor_graph_type,
        )
        sensor_type.save()
        sensor = AGSensor.objects.create(name=self.test_sensor_name,
                                         type_id=sensor_type)
        sensor.save()

        self.create_venue_and_event(self.event_name)

        # Delete GFConfig used for the test (will interfere otherwise)
        self.gfconfig.delete()

        response = self.client.post(
            reverse(self.config_url),
            data={
                "submit": "",
                "gf_name": "Test Grafana Instance",
                "gf_host": HOST,
                "gf_token": self.ADMIN,
                "gf_username": "******",
                "gf_password": "******",
            },
        )
        self.assertEqual(302, response.status_code)

        # Restore GFConfig instance used for the tests
        self.gfconfig = GFConfig.objects.create(gf_name="Test",
                                                gf_host=HOST,
                                                gf_token=self.ADMIN,
                                                gf_current=True)
        self.gfconfig.save()

        # check that dashboard was created with expected panel
        dashboard = self.grafana.get_dashboard_by_name(self.event_name)
        self.assertTrue(dashboard)
        self.assertEquals(dashboard["dashboard"]["title"], self.event_name)
        # panels should have been created
        # querying like this because the returned dashboard object may have no panels
        # attribute, so trying to retrieve dashboard["panels"] could throw a key error
        panels = dashboard["dashboard"].get("panels", None)
        self.assertTrue(panels)
        self.assertTrue(len(panels) == 1)
        panel = panels[0]
        self.assertEquals(panel["title"], self.test_sensor_name)

    def test_update_dashboard_panels_remove_all_single_gfconfig(self):
        # Login
        self._get_with_event_code(self.sensor_url, self.TESTCODE)

        # Create an event
        event = self.create_venue_and_event(self.event_name)

        # Create a dashboard
        self.grafana.create_dashboard(self.event_name)

        # Add a panel to the dashboard
        #   Create a sensor type and sensor
        sensor_type = AGSensorType.objects.create(
            name=self.test_sensor_type,
            processing_formula=0,
            format=self.test_sensor_format,
            graph_type=self.test_sensor_graph_type,
        )
        sensor_type.save()
        sensor = AGSensor.objects.create(name=self.test_sensor_name,
                                         type_id=sensor_type)
        sensor.save()
        #   Add a sensor panel
        self.grafana.add_panel(sensor, event)

        # Update dashboard with empty list of sensors
        self.client.post(
            reverse(self.config_update_dashboard_url,
                    kwargs={"gf_id": self.gfconfig.id}),
            data={
                "dashboard_name": self.event_name,
                "sensors": []
            },
        )

        # Query dashboard
        dashboard = self.grafana.get_dashboard_by_name(self.event_name)
        self.assertTrue(dashboard)

        # Retrieve current panels
        try:
            panels = dashboard["dashboard"]["panels"]
        except KeyError:
            panels = []

        # Confirm panels were deleted
        self.assertEquals(panels, [])

    def test_update_dashboard_panels_keep_all_panels_single_gfconfig(self):
        # Login
        self._get_with_event_code(self.sensor_url, self.TESTCODE)

        self.create_venue_and_event(self.event_name)

        # create a dashboard
        self.grafana.create_dashboard(self.event_name)

        # add a panel to the dashboard
        # Create a sensor type and sensor
        sensor_type = AGSensorType.objects.create(
            name=self.test_sensor_type,
            processing_formula=0,
            format=self.test_sensor_format,
            graph_type=self.test_sensor_graph_type,
        )
        sensor_type.save()
        sensor = AGSensor.objects.create(name=self.test_sensor_name,
                                         type_id=sensor_type)
        sensor.save()

        sensors = AGSensor.objects.all()
        sensor_ids = []
        for sensor in sensors:
            sensor_ids.append(sensor.uuid)

        self.client.post(
            reverse(self.config_update_dashboard_url,
                    kwargs={"gf_id": self.gfconfig.id}),
            data={
                "dashboard_name": self.event_name,
                "sensors": sensor_ids
            },
        )

        dashboard = self.grafana.get_dashboard_by_name(self.event_name)

        self.assertTrue(dashboard)

        # Retrieve current panels
        try:
            panels = dashboard["dashboard"]["panels"]
        except KeyError:
            panels = []

        self.assertEquals(len(panels), 1)

    def test_update_dashboard_panels_keep_subset_of_panels_single_gfconfig(
            self):
        # Login
        self._get_with_event_code(self.sensor_url, self.TESTCODE)

        self.create_venue_and_event(self.event_name)

        # create a dashboard
        self.grafana.create_dashboard(self.event_name)

        # add a panel to the dashboard
        # Create a sensor type and sensor
        sensor_type = AGSensorType.objects.create(
            name=self.test_sensor_type,
            processing_formula=0,
            format=self.test_sensor_format,
            graph_type=self.test_sensor_graph_type,
        )
        sensor_type.save()

        # Create 5 sensors
        for i in range(5):
            sensor = AGSensor.objects.create(name=self.test_sensor_name + "i",
                                             type_id=sensor_type)
            sensor.save()

        # Retrieve sensor ids for the first 2 sensors
        sensor_ids = []
        sensors = AGSensor.objects.all()
        for i in range(2):
            sensor_ids.append(sensors[i].uuid)

        # Post to update the dashboard with 2 sensor panels
        self.client.post(
            reverse(self.config_update_dashboard_url,
                    kwargs={"gf_id": self.gfconfig.id}),
            data={
                "dashboard_name": self.event_name,
                "sensors": sensor_ids
            },
        )

        dashboard = self.grafana.get_dashboard_by_name(self.event_name)

        self.assertTrue(dashboard)

        # Retrieve current panels
        try:
            panels = dashboard["dashboard"]["panels"]
        except KeyError:
            panels = []

        self.assertEquals(len(panels), 2)
        for i in range(2):
            self.assertEquals(panels[i]["title"], sensors[i].name)

    def test_reset_dashboard_panels_single_gfconfig(self):
        # Login
        self._get_with_event_code(self.sensor_url, self.TESTCODE)

        # update dashboard with a subset of panels, then restore all panels by using
        # reset
        self.create_venue_and_event(self.event_name)

        # create a dashboard
        self.grafana.create_dashboard(self.event_name)

        # add a panel to the dashboard
        # Create a sensor type and sensor
        sensor_type = AGSensorType.objects.create(
            name=self.test_sensor_type,
            processing_formula=0,
            format=self.test_sensor_format,
            graph_type=self.test_sensor_graph_type,
        )
        sensor_type.save()

        # Create 5 sensors
        for i in range(5):
            sensor = AGSensor.objects.create(name=self.test_sensor_name + "i",
                                             type_id=sensor_type)
            sensor.save()

        # Retrieve sensor ids for the first 2 sensors
        sensor_ids_partial = []
        sensors = AGSensor.objects.all()
        for i in range(2):
            sensor_ids_partial.append(sensors[i].uuid)

        # Post to update the dashboard with 2 sensor panels
        self.client.post(
            reverse(self.config_update_dashboard_url,
                    kwargs={"gf_id": self.gfconfig.id}),
            data={
                "dashboard_name": self.event_name,
                "sensors": sensor_ids_partial
            },
        )

        dashboard = self.grafana.get_dashboard_by_name(self.event_name)

        self.assertTrue(dashboard)

        # Retrieve current panels
        try:
            panels = dashboard["dashboard"]["panels"]
        except KeyError:
            panels = []

        self.assertEquals(len(panels), 2)

        sensor_ids = []
        sensors = AGSensor.objects.all()
        for sensor in sensors:
            sensor_ids.append(sensor.uuid)

        # Post to reset the dashboard with all sensor panels
        self.client.post(
            reverse(self.config_reset_dashboard_url,
                    kwargs={"gf_id": self.gfconfig.id}),
            data={"dashboard_name": self.event_name},
        )

        dashboard = self.grafana.get_dashboard_by_name(self.event_name)

        self.assertTrue(dashboard)

        # Retrieve current panels
        try:
            panels = dashboard["dashboard"]["panels"]
        except KeyError:
            panels = []

        self.assertEquals(len(panels), 5)
        for sensor in sensors:
            self.assertEquals(panels[i]["title"], sensor.name)

    def test_delete_dashboard_single_gfconfig(self):
        # Login
        self._get_with_event_code(self.sensor_url, self.TESTCODE)

        # update dashboard with a subset of panels, then restore all panels by using
        # reset
        self.create_venue_and_event(self.event_name)

        # create a dashboard
        self.grafana.create_dashboard(self.event_name)

        # Post to update the dashboard with 2 sensor panels
        self.client.post(
            reverse(self.config_delete_dashboard_url,
                    kwargs={"gf_id": self.gfconfig.id}),
            data={"dashboard_name": self.event_name},
        )

        dashboard = self.grafana.get_dashboard_by_name(self.event_name)

        # No dashboard should exist with this name
        self.assertFalse(dashboard)

    # User can post to a create_dashboard view in GFConfig in order to add an event
    # dashboard to Grafana
    def test_add_event_dashboard_through_gfconfig_view(self):
        # Login
        self._get_with_event_code(self.sensor_url, self.TESTCODE)

        # Create an event
        self.create_venue_and_event(self.event_name)

        # User posts to add_dashboard view
        self.client.post(
            reverse(self.config_add_dashboard_url,
                    kwargs={"gf_id": self.gfconfig.id}),
            data={"selected_event_name": self.event_name},
        )

        # Confirm dashboard added to Grafana
        dashboard = self.grafana.get_dashboard_by_name(self.event_name)
        self.assertTrue(dashboard)

    def test_add_event_dashboard_through_gfconfig_sensor_panels_added(self):
        # Login
        self._get_with_event_code(self.sensor_url, self.TESTCODE)

        # Create an event
        self.create_venue_and_event(self.event_name)

        # Create a sensor type and sensor
        sensor_type = AGSensorType.objects.create(
            name=self.test_sensor_type,
            processing_formula=0,
            format=self.test_sensor_format,
            graph_type=self.test_sensor_graph_type,
        )
        sensor_type.save()
        sensor = AGSensor.objects.create(name=self.test_sensor_name,
                                         type_id=sensor_type)
        sensor.save()

        # User posts to add_dashboard view
        self.client.post(
            reverse(self.config_add_dashboard_url,
                    kwargs={"gf_id": self.gfconfig.id}),
            data={"selected_event_name": self.event_name},
        )

        # Confirm dashboard added with panel for existing sensor
        dashboard = self.grafana.get_dashboard_by_name(self.event_name)
        self.assertTrue(dashboard)

        # Retrieve current panels
        try:
            panels = dashboard["dashboard"]["panels"]
        except KeyError:
            panels = []

        self.assertEquals(len(panels), 1)
        self.assertEquals(panels[0]["title"], sensor.name)
Example #3
0
class TestGrafana(TestCase):
    TESTCODE = "testcode"

    title = "Bar"

    test_sensor_name = "Wind Sensor"
    test_sensor_name_update = "Another Name"
    test_sensor_type = "Dual wind"
    test_sensor_format = {
        "left_gust": {
            "unit": "km/h",
            "format": "float"
        },
        "right_gust": {
            "unit": "km/h",
            "format": "float"
        },
    }
    test_sensor_graph_type = "graph"

    field_name_1 = "test-field-1"
    field_name_2 = "test-field-2"
    data_type_1 = "test-data-type-1"
    data_type_2 = "test-data-type-2"
    unit_1 = "test-unit-1"
    unit_2 = "test-unit-2"

    test_sensor = {
        "name": test_sensor_name,
        "processing formula": 0,
        "field-names": [field_name_1, field_name_2],
        "data-types": [data_type_1, data_type_2],
        "units": [unit_1, unit_2],
    }

    test_sensor_format_update = {
        "fuel reading": {
            "unit": "m",
            "format": "float"
        },
    }

    test_event_data = {
        "name": "Sunny Day Test Drive",
        "date": datetime.datetime(2020, 2, 2, 20, 21, 22),
        "description": "A very progressive test run at \
                    Sunnyside Daycare's Butterfly Room.",
        "location": "New York, NY",
    }

    test_event_data_update = {
        "name": "Another Day Test Drive",
        "date": datetime.datetime(2020, 3, 3, 20, 21, 22),
        "description": "A very modern test run at \
                        my backyard.",
        "location": "Buffalo, NY",
    }

    test_venue_data = {
        "name": "Venue 1",
        "description": "foo",
        "latitude": 100,
        "longitude": 200,
    }

    def create_gfconfig(self):
        config = GFConfig.objects.create(
            gf_host=HOST,
            gf_token=self.ADMIN,
            gf_db_host=DB_HOSTNAME,
            gf_db_name=DB_NAME,
            gf_db_username=DB_USERNAME,
            gf_db_pw=DB_PASSWORD,
            gf_current=True,
        )
        config.save()
        return config

    # Returns event
    def create_venue_and_event(self, event_name):
        venue = AGVenue.objects.create(
            name=self.test_venue_data["name"],
            description=self.test_venue_data["description"],
            latitude=self.test_venue_data["latitude"],
            longitude=self.test_venue_data["longitude"],
        )
        venue.save()

        event = AGEvent.objects.create(
            name=event_name,
            date=self.test_event_data["date"],
            description=self.test_event_data["description"],
            venue_uuid=venue,
        )
        event.save()

        return event

    def setUp(self):
        # api keys with admin and viewer level permissions
        self.ADMIN = Grafana.create_api_key(HOST, "admin", "Admin")
        self.VIEWER = Grafana.create_api_key(HOST, "viewer", "Viewer")

        self.login_url = "mercury:EventAccess"
        self.sensor_url = "mercury:sensor"
        self.event_url = "mercury:events"
        self.event_delete_url = "mercury:delete_event"
        self.event_update_url = "mercury:update_event"
        self.update_sensor_url = "mercury:update_sensor"
        self.delete_sensor_url = "mercury:delete_sensor"
        self.update_sensor_type_url = "mercury:update_type"
        test_code = EventCodeAccess(event_code="testcode", enabled=True)
        test_code.save()
        # Login
        self._get_with_event_code(self.sensor_url, self.TESTCODE)

        # Create fresh grafana object
        self.config = self.create_gfconfig()
        self.grafana = Grafana(self.config)

        # Create random name to be used for event and datasource
        self.event_name = self.grafana.generate_random_string(10)
        self.updated_event_name = self.event_name + " Day Two"
        self.datasource_name = self.grafana.generate_random_string(10)

        # Clear existing dashboard and datasource
        self.grafana.delete_all_dashboards()
        self.grafana.delete_all_datasources()

    def tearDown(self):
        # Create fresh grafana instance (in case test invalidated any tokens, etc.)
        self.grafana = Grafana(self.config)

        # Clear all of the created dashboards
        self.grafana.delete_all_dashboards()
        self.grafana.delete_all_datasources()

    def _get_with_event_code(self, url, event_code):
        self.client.get(reverse(self.login_url))
        self.client.post(reverse(self.login_url),
                         data={"eventcode": event_code})
        response = self.client.get(reverse(url))
        session = self.client.session
        return response, session

    def test_get_dashboard_with_uid_success(self):
        # Should return True if create_dashboard was successful
        dashboard = self.grafana.create_dashboard(self.event_name)
        self.assertTrue(dashboard)

        # Query new dashboard
        uid = dashboard["uid"]
        fetched_dashboard = self.grafana.get_dashboard_with_uid(uid)

        # Confirm params of new dashboard (slug, uid, title)
        self.assertTrue(fetched_dashboard)
        self.assertTrue(fetched_dashboard["meta"])
        self.assertTrue(fetched_dashboard["meta"]["slug"],
                        self.event_name.lower())
        self.assertTrue(fetched_dashboard["dashboard"])
        self.assertTrue(fetched_dashboard["dashboard"]["uid"], uid)
        self.assertTrue(fetched_dashboard["dashboard"]["title"],
                        self.event_name)

    def test_get_dashboard_url_success(self):
        self.grafana.create_dashboard(self.event_name)
        self.assertTrue(self.grafana.get_dashboard_url_by_name(
            self.event_name))

    def test_get_dashboard_url_none(self):
        self.assertIsNone(
            self.grafana.get_dashboard_url_by_name(self.event_name + "foo"))

    def test_get_dashboard_with_uid_fail(self):
        # Create a random UID to search for
        uid = self.grafana.generate_random_string(10)

        # Try and fetch random UID (should return None)
        fetched_dashboard = self.grafana.get_dashboard_with_uid(uid)
        self.assertFalse(fetched_dashboard)

    def test_create_grafana_dashboard_success(self):
        # Should return an object with dashboard credentials
        dashboard = self.grafana.create_dashboard(self.event_name)
        self.assertTrue(dashboard)

    def test_create_grafana_dashboard_verify_new_dashboard_contents(self):
        # Should return an object with dashboard credentials
        dashboard = self.grafana.create_dashboard(self.event_name)

        # Confirm that an object was returned
        self.assertTrue(dashboard)
        # Check for success status message
        self.assertEquals(dashboard["status"], "success")
        # Check that dashboard has correct name
        self.assertEquals(dashboard["slug"], self.event_name.lower())

        # Retrieve UID for new dashboard, use to query new dashboard
        uid = dashboard["uid"]

        # Confirm new dashboard can be queried from the API
        endpoint = os.path.join(self.grafana.endpoints["dashboard_uid"], uid)
        headers = {"Content-Type": "application/json"}
        response = requests.get(url=endpoint,
                                headers=headers,
                                auth=("api_key", self.grafana.api_token))

        # Confirm uid and title are as expected
        self.assertEquals(response.json()["dashboard"]["uid"], uid)
        self.assertEquals(response.json()["dashboard"]["title"],
                          self.event_name)

    def test_create_grafana_dashboard_fail_authorization(self):
        self.grafana.api_token = "abcde"  # invalid API token

        expected_message = "Invalid API key"
        with self.assertRaisesMessage(ValueError, expected_message):
            self.grafana.create_dashboard(self.event_name)

    def test_create_grafana_dashboard_fail_permissions(self):
        self.grafana.api_token = self.VIEWER  # API token with viewer permissions

        expected_message = "Access denied - check API permissions"
        with self.assertRaisesMessage(ValueError, expected_message):
            self.grafana.create_dashboard(self.event_name)

    def test_create_grafana_dashboard_fail_empty_title(self):
        expected_message = "Dashboard title cannot be empty"
        with self.assertRaisesMessage(ValueError, expected_message):
            self.grafana.create_dashboard("")

    def test_validate_credentials_success(self):
        # should return True if credentials are valid
        self.assertTrue(self.grafana.validate_credentials())

    def test_update_dashboard_title_success(self):
        event = self.create_venue_and_event(self.event_name)
        self.grafana.create_dashboard(self.event_name)
        new_name = event.name + " foo"
        self.assertTrue(self.grafana.update_dashboard_title(event, new_name))

    def test_update_dashboard_title_fail_same_name(self):
        event = self.create_venue_and_event(self.event_name)
        self.grafana.create_dashboard(self.event_name)
        self.assertFalse(self.grafana.update_dashboard_title(
            event, event.name))

    def test_update_dashboard_title_fail_no_dashboard(self):
        event = self.create_venue_and_event(self.event_name)
        self.assertFalse(self.grafana.update_dashboard_title(
            event, event.name))

    def test_validate_credentials_fail_authorization(self):
        self.grafana.api_token = "abcde"  # invalid API token

        expected_message = "Grafana API validation failed: Invalid API key"
        with self.assertRaisesMessage(ValueError, expected_message):
            self.grafana.validate_credentials()

    def test_validate_credentials_fail_permissions(self):
        self.grafana.api_token = self.VIEWER  # API token with viewer permissions

        expected_message = ("Grafana API validation failed: Access denied - "
                            "check API permissions")
        with self.assertRaisesMessage(ValueError, expected_message):
            self.grafana.validate_credentials()

    def test_create_grafana_dashboard_fail_duplicate_title(self):
        # Should return a JSON object with a message that the dashboard already exists
        dashboard = self.grafana.create_dashboard(self.event_name)
        self.assertTrue(dashboard)

        expected_message = "Dashboard with the same name already exists"
        with self.assertRaisesMessage(ValueError, expected_message):
            self.grafana.create_dashboard(self.event_name)

    def test_delete_grafana_dashboard(self):
        # Create a dashboard
        dashboard = self.grafana.create_dashboard(self.event_name)
        self.assertTrue(dashboard)

        # Delete the dashboard, should return True if deleted
        deleted_dashboard = self.grafana.delete_dashboard(dashboard["uid"])
        self.assertTrue(deleted_dashboard)

        # Confirm that dashboard was deleted by querying it
        endpoint = os.path.join(self.grafana.endpoints["dashboard_uid"],
                                dashboard["uid"])
        headers = {"Content-Type": "application/json"}
        response = requests.get(url=endpoint,
                                headers=headers,
                                auth=("api_key", self.grafana.api_token))
        self.assertTrue(response.json()["message"])
        self.assertEquals(response.json()["message"], "Dashboard not found")

    def test_delete_grafana_dashboard_fail(self):
        # Generate a random uid
        uid = self.grafana.generate_random_string(10)

        # Attempt to delete dashboard that doesn't exist, should return False
        deleted_dashboard = self.grafana.delete_dashboard(uid)
        self.assertFalse(deleted_dashboard)

    def test_add_panel(self):
        # Create a dashboard, confirm it was created and retrieve its UID
        dashboard = self.grafana.create_dashboard(self.event_name)
        self.assertTrue(dashboard)
        uid = dashboard["uid"]

        # Create an event and venue
        event = self.create_venue_and_event(self.event_name)

        # Create a sensor type and sensor
        sensor_type = AGSensorType.objects.create(
            name=self.test_sensor_type,
            processing_formula=0,
            format=self.test_sensor_format,
            graph_type=self.test_sensor_graph_type,
        )
        sensor_type.save()
        sensor = AGSensor.objects.create(name=self.test_sensor_name,
                                         type_id=sensor_type)
        sensor.save()

        # Add a panel to the dashboard
        self.grafana.add_panel(sensor, event)

        # Retrieve the current dashboard
        dashboard_info = self.grafana.get_dashboard_with_uid(uid)

        # Confirm that a panel was added to the dashboard with the expected title
        self.assertTrue(dashboard_info)
        self.assertTrue(dashboard_info["dashboard"])
        self.assertTrue(dashboard_info["dashboard"]["panels"])
        self.assertTrue(len(dashboard_info["dashboard"]["panels"]) == 1)
        self.assertTrue(
            dashboard_info["dashboard"]["panels"][0]["title"] == sensor.name)

    def test_add_multiple_panels(self):
        # Create a dashboard, confirm it was created and retrieve its UID
        dashboard = self.grafana.create_dashboard(self.event_name)
        self.assertTrue(dashboard)
        uid = dashboard["uid"]

        # Create an event and venue
        event = self.create_venue_and_event(self.event_name)

        # Create a sensor type
        sensor_type = AGSensorType.objects.create(
            name=self.test_sensor_type,
            processing_formula=0,
            format=self.test_sensor_format,
            graph_type=self.test_sensor_graph_type,
        )
        sensor_type.save()

        # Create 10 sensors, invoking add_panel for each new sensor
        for i in range(10):
            sensor = AGSensor.objects.create(name="".join(
                [self.test_sensor_name, str(i)]),
                                             type_id=sensor_type)
            sensor.save()

            self.grafana.add_panel(sensor, event)

        # Query dashboard to confirm 10 panels were added
        dashboard_info = self.grafana.get_dashboard_with_uid(uid)
        self.assertTrue(dashboard_info)
        self.assertTrue(dashboard_info["dashboard"])
        self.assertTrue(dashboard_info["dashboard"]["panels"])
        self.assertTrue(len(dashboard_info["dashboard"]["panels"]) == 10)

        # Confirm correct title for each panel
        for i in range(10):
            name = "".join([self.test_sensor_name, str(i)])
            self.assertTrue(
                dashboard_info["dashboard"]["panels"][i]["title"] == name)

    def test_add_sensor_creates_panel_in_dashboard(self):
        # Create a dashboard, confirm it was created and retrieve its UID
        dashboard = self.grafana.create_dashboard(self.event_name)
        self.assertTrue(dashboard)

        # Create an event
        event = self.create_venue_and_event(self.event_name)

        # Make the event the active event
        AGActiveEvent.objects.create(agevent=event).save()

        # Create a sensor through the UI
        self.client.post(
            reverse(self.sensor_url),
            data={
                "submit_new_sensor": "",
                "sensor-name": self.test_sensor["name"],
                "field-names": self.test_sensor["field-names"],
                "data-types": self.test_sensor["data-types"],
                "units": self.test_sensor["units"],
                "sensor-graph-type": self.test_sensor_graph_type,
            },
        )

        self.assertEquals(AGSensor.objects.count(), 1)

        # Fetch the dashboard again
        dashboard = self.grafana.get_dashboard_by_name(self.event_name)
        self.assertTrue(dashboard)

        # Confirm that a panel was added to the dashboard with the expected title
        self.assertTrue(dashboard)
        self.assertTrue(dashboard["dashboard"])
        self.assertTrue(dashboard["dashboard"]["panels"])
        self.assertTrue(len(dashboard["dashboard"]["panels"]) == 1)

        # Note: converting test_sensor_name to lowercase because currently
        # sensor names are automatically capitalized when they are created
        self.assertEquals(
            dashboard["dashboard"]["panels"][0]["title"],
            self.test_sensor["name"].lower(),
        )

    def test_update_sensor_name_updates_panel_title(self):
        # Create a dashboard
        dashboard = self.grafana.create_dashboard(self.event_name)
        self.assertTrue(dashboard)

        # Create an event, create a sensor
        event = self.create_venue_and_event(self.event_name)

        # Create AGSensorType object for foreign key reference
        sensor_type = AGSensorType.objects.create(
            name=self.test_sensor["name"].lower(),
            processing_formula=0,
            format={
                self.field_name_1: {
                    "data_type": self.data_type_1,
                    "unit": self.unit_1
                },
                self.field_name_2: {
                    "data_type": self.data_type_2,
                    "unit": self.unit_2
                },
            },
            graph_type=self.test_sensor_graph_type,
        )
        sensor_type.save()

        # Create AG Sensor Object
        sensor = AGSensor.objects.create(name=self.test_sensor["name"].lower(),
                                         type_id=sensor_type)
        sensor.save()

        # Add the sensor panel to the dashboard
        self.grafana.add_panel(sensor, event)

        updated_test_sensor_name = "foo"

        # Post Edited Name
        self.client.post(
            reverse(self.sensor_url),
            data={
                "edit_sensor": "",
                "sensor-name": self.test_sensor["name"].lower(),
                "sensor-name-updated": updated_test_sensor_name,
                "field-names": self.test_sensor["field-names"],
                "data-types": self.test_sensor["data-types"],
                "units": self.test_sensor["units"],
                "sensor-graph-type": self.test_sensor_graph_type,
            },
        )

        # Check that AGSensor object has new name
        sensor = AGSensor.objects.all()[0]
        self.assertEqual(sensor.name, updated_test_sensor_name)

        # Check that sensor name was updated
        sensor = AGSensor.objects.all()[0]
        self.assertEquals(sensor.name, updated_test_sensor_name)

        # Confirm that Grafana panel title was updated
        # Confirm that a panel was added to the dashboard with the expected title
        dashboard = self.grafana.get_dashboard_by_name(self.event_name)

        self.assertTrue(dashboard)
        self.assertTrue(dashboard["dashboard"])
        self.assertTrue(dashboard["dashboard"]["panels"])
        self.assertTrue(len(dashboard["dashboard"]["panels"]) == 1)

        self.assertEquals(
            dashboard["dashboard"]["panels"][0]["title"],
            updated_test_sensor_name,
        )

    def test_update_sensor_type_updates_panel_query(self):
        # Create a dashboard, confirm it was created
        dashboard = self.grafana.create_dashboard(self.event_name)
        self.assertTrue(dashboard)

        # Create an event
        event = self.create_venue_and_event(self.event_name)

        # Create sensor and sensor type
        sensor_type = AGSensorType.objects.create(
            name=self.test_sensor_name.lower(),
            processing_formula=0,
            format=self.test_sensor_format,
            graph_type=self.test_sensor_graph_type,
        )
        sensor_type.save()

        sensor = AGSensor.objects.create(name=self.test_sensor_name.lower(),
                                         type_id=sensor_type)
        sensor.save()

        # Create grafana sensor panel
        self.grafana.add_panel(sensor, event)

        # New fields
        field_names_updated = ["foo"]
        data_types_updated = ["float"]
        units_updated = ["km/h"]

        # Post edited sensor type
        self.client.post(
            reverse(self.sensor_url),
            data={
                "edit_sensor": "",
                "sensor-name": self.test_sensor["name"].lower(),
                "sensor-name-updated": self.test_sensor["name"].lower(),
                "field-names": field_names_updated,
                "data-types": data_types_updated,
                "units": units_updated,
                "sensor-graph-type": self.test_sensor_graph_type,
            },
        )

        # Confirm that a new Grafana panel was created with a query containing all of
        # the current field names (not checking the full syntax of the query, just that
        # the new field name is in the query)
        dashboard = self.grafana.get_dashboard_by_name(self.event_name)

        self.assertIn(
            field_names_updated[0],
            dashboard["dashboard"]["panels"][0]["targets"][0]["rawSql"],
        )

    def test_update_sensor_name_and_type_updates_panel_title_and_query(self):
        # Create a dashboard, confirm it was created
        dashboard = self.grafana.create_dashboard(self.event_name)
        self.assertTrue(dashboard)

        # Create an event
        event = self.create_venue_and_event(self.event_name)

        # Create sensor and sensor type
        sensor_type = AGSensorType.objects.create(
            name=self.test_sensor_name.lower(),
            processing_formula=0,
            format=self.test_sensor_format,
            graph_type=self.test_sensor_graph_type,
        )
        sensor_type.save()

        sensor = AGSensor.objects.create(name=self.test_sensor_name.lower(),
                                         type_id=sensor_type)
        sensor.save()

        # Create grafana sensor panel
        self.grafana.add_panel(sensor, event)

        # New fields
        updated_sensor_name = "bar"
        field_names_updated = ["foo"]
        data_types_updated = ["float"]
        units_updated = ["km/h"]

        # Post edited sensor type
        self.client.post(
            reverse(self.sensor_url),
            data={
                "edit_sensor": "",
                "sensor-name": self.test_sensor["name"].lower(),
                "sensor-name-updated": updated_sensor_name,
                "field-names": field_names_updated,
                "data-types": data_types_updated,
                "units": units_updated,
                "sensor-graph-type": self.test_sensor_graph_type,
            },
        )

        dashboard = self.grafana.get_dashboard_by_name(self.event_name)

        # Confirm title and query
        self.assertEquals(
            dashboard["dashboard"]["panels"][0]["title"],
            updated_sensor_name,
        )
        self.assertIn(
            field_names_updated[0],
            dashboard["dashboard"]["panels"][0]["targets"][0]["rawSql"],
        )

    def test_delete_sensor_deletes_panel_in_dashboard(self):
        # Create a dashboard, confirm it was created
        dashboard = self.grafana.create_dashboard(self.event_name)
        self.assertTrue(dashboard)

        # Create an event
        event = self.create_venue_and_event(self.event_name)

        sensor_type = AGSensorType.objects.create(
            name=self.test_sensor_name,
            processing_formula=0,
            format=self.test_sensor_format,
            graph_type=self.test_sensor_graph_type,
        )
        sensor_type.save()

        sensor = AGSensor.objects.create(name=self.test_sensor_name,
                                         type_id=sensor_type)
        sensor.save()

        self.grafana.add_panel(sensor, event)

        # Delete sensor
        self.client.post(
            reverse(self.delete_sensor_url,
                    kwargs={"sensor_name": sensor.name}),
            follow=True,
        )

        # Confirm sensor was deleted
        self.assertEquals(AGSensor.objects.count(), 0)

        # Confirm that sensor was deleted from Grafana
        # Fetch the dashboard again
        dashboard = self.grafana.get_dashboard_by_name(dashboard["slug"])
        self.assertTrue(dashboard)

        # Confirm that a panel was added to the dashboard with the expected title
        self.assertTrue(dashboard)
        self.assertTrue(dashboard["dashboard"])
        self.assertEquals(len(dashboard["dashboard"]["panels"]), 0)

    def test_add_panel_fail_no_dashboard_exists_for_event(self):
        # Create an event
        event = self.create_venue_and_event(self.event_name)

        # Create a sensor type and sensor
        sensor_type = AGSensorType.objects.create(
            name=self.test_sensor_type,
            processing_formula=0,
            format=self.test_sensor_format,
            graph_type=self.test_sensor_graph_type,
        )
        sensor_type.save()
        sensor = AGSensor.objects.create(name=self.test_sensor_name,
                                         type_id=sensor_type)
        sensor.save()

        # Check for expected ValueError and message
        expected_message = "Dashboard not found for this event."
        with self.assertRaisesMessage(ValueError, expected_message):
            self.grafana.add_panel(sensor, event)

    def test_create_postgres_datasource(self):
        # Create datasource
        self.grafana.create_postgres_datasource(self.datasource_name)

        # Query new datasource
        endpoint = os.path.join(self.grafana.endpoints["datasource_name"],
                                self.datasource_name)
        headers = {"Content-Type": "application/json"}
        response = requests.get(url=endpoint,
                                headers=headers,
                                auth=("api_key", self.grafana.api_token))

        # Confirm datasource exists with expected name
        self.assertEquals(response.json()["name"], self.datasource_name)

    def test_create_datasource_fail_authorization(self):
        self.grafana.api_token = "abcde"  # invalid API token

        expected_message = "Invalid API key"
        with self.assertRaisesMessage(ValueError, expected_message):
            self.grafana.create_postgres_datasource(self.datasource_name)

    def test_create_datasource_fail_permissions(self):
        self.grafana.api_token = self.VIEWER  # API token with viewer permissions

        expected_message = "Access denied - check API permissions"
        with self.assertRaisesMessage(ValueError, expected_message):
            self.grafana.create_postgres_datasource(self.datasource_name)

    def test_create_datasource_fail_empty_string(self):
        expected_message = "Response contains no message"
        with self.assertRaisesMessage(ValueError, expected_message):
            self.grafana.create_postgres_datasource("")

    def test_delete_postgres_datasource(self):
        # create the datasource
        self.grafana.create_postgres_datasource(self.datasource_name)

        # deleted should be True if delete_datasource_by_name returns true
        deleted = self.grafana.delete_datasource_by_name(self.datasource_name)
        self.assertTrue(deleted)

        # confirm that the datasource was actually deleted by querying it
        endpoint = os.path.join(self.grafana.endpoints["datasource_name"],
                                self.datasource_name)
        headers = {"Content-Type": "application/json"}
        response = requests.get(url=endpoint,
                                headers=headers,
                                auth=("api_key", self.grafana.api_token))

        self.assertTrue(response.json()["message"])
        self.assertEquals(response.json()["message"], "Data source not found")

    def test_create_event_creates_dashboard_no_panels(self):
        self.grafana.create_postgres_datasource(self.datasource_name)

        # Create a venue
        venue = AGVenue.objects.create(
            name=self.event_name,
            description=self.test_venue_data["description"],
            latitude=self.test_venue_data["latitude"],
            longitude=self.test_venue_data["longitude"],
        )
        venue.save()

        # Send a request to create an event (should trigger the creation of a
        # grafana dashboard of the same name)
        self.client.post(
            reverse(self.event_url),
            data={
                "submit-event": "",
                "name": self.event_name,
                "date": self.test_event_data["date"],
                "description": self.test_event_data["description"],
                "venue_uuid": venue.uuid,
            },
        )

        # If there are spaces in the name, the GF API will replace them with dashes
        # to generate the "slug". A slug can be used to query the API.
        endpoint = os.path.join(
            self.grafana.hostname,
            "api/dashboards/db",
            self.event_name.lower().replace(" ", "-"),
        )

        response = requests.get(url=endpoint,
                                auth=("api_key", self.grafana.api_token))

        # Confirm that a dashboard was created with the expected name
        self.assertEquals(response.status_code, 200)
        self.assertEquals(response.json()["dashboard"]["title"],
                          self.event_name)

    def test_create_event_creates_dashboard_with_panel(self):
        self.grafana.create_postgres_datasource(self.datasource_name)

        # Create a venue
        venue = AGVenue.objects.create(
            name=self.test_venue_data["name"],
            description=self.test_venue_data["description"],
            latitude=self.test_venue_data["latitude"],
            longitude=self.test_venue_data["longitude"],
        )
        venue.save()

        sensor_type = AGSensorType.objects.create(
            name=self.test_sensor_type,
            processing_formula=0,
            format=self.test_sensor_format,
            graph_type=self.test_sensor_graph_type,
        )
        sensor_type.save()
        sensor = AGSensor.objects.create(name=self.test_sensor_name,
                                         type_id=sensor_type)
        sensor.save()

        # Send a request to create an event (should trigger the creation of a
        # grafana dashboard of the same name)
        self.client.post(
            reverse(self.event_url),
            data={
                "submit-event": "",
                "name": self.event_name,
                "date": self.test_event_data["date"],
                "description": self.test_event_data["description"],
                "venue_uuid": venue.uuid,
            },
        )

        # If there are spaces in the name, the GF API will replace them with dashes
        # to generate the "slug". A slug can be used to query the API.
        endpoint = os.path.join(
            self.grafana.hostname,
            "api/dashboards/db",
            self.event_name.lower().replace(" ", "-"),
        )

        response = requests.get(url=endpoint,
                                auth=("api_key", self.grafana.api_token))

        # Confirm that a dashboard was created with the expected name
        self.assertEquals(response.status_code, 200)
        self.assertEquals(response.json()["dashboard"]["title"],
                          self.event_name)

        # Confirm that a the new dashboard can be queried and has panel with expected
        # title
        dashboard_info = self.grafana.get_dashboard_with_uid(
            response.json()["dashboard"]["uid"])
        self.assertTrue(dashboard_info)
        self.assertTrue(dashboard_info["dashboard"])
        self.assertTrue(dashboard_info["dashboard"]["panels"])
        self.assertTrue(len(dashboard_info["dashboard"]["panels"]) == 1)
        self.assertTrue(
            dashboard_info["dashboard"]["panels"][0]["title"] == sensor.name)

    def test_delete_event_deletes_grafana_dashboard(self):
        self.grafana.create_postgres_datasource(self.datasource_name)

        # Create a venue
        venue = AGVenue.objects.create(
            name=self.event_name,
            description=self.test_venue_data["description"],
            latitude=self.test_venue_data["latitude"],
            longitude=self.test_venue_data["longitude"],
        )
        venue.save()

        # Send a request to create an event (should trigger the creation of a
        # grafana dashboard of the same name)
        self.client.post(
            reverse(self.event_url),
            data={
                "submit-event": "",
                "name": self.event_name,
                "date": self.test_event_data["date"],
                "description": self.test_event_data["description"],
                "venue_uuid": venue.uuid,
            },
        )

        dashboard = self.grafana.get_dashboard_by_name(self.event_name)
        self.assertTrue(dashboard)

        # Retrieve event object
        event = AGEvent.objects.all().first()

        # Delete the event by posting to the delete view
        self.client.post(
            reverse(self.event_delete_url, kwargs={"event_uuid": event.uuid}))
        # Try and retrieve the dashboard
        dashboard = self.grafana.get_dashboard_by_name(self.event_name)

        self.assertFalse(dashboard)

    def test_update_event_name_updates_grafana_dashboard_name(self):
        self.grafana.create_postgres_datasource(self.datasource_name)

        event = self.create_venue_and_event(self.event_name)

        updated_event_name = self.updated_event_name

        venue = AGVenue.objects.first()

        # Send a request to create an event (should trigger the creation of a
        # grafana dashboard of the same name)
        self.client.post(
            reverse(self.event_url),
            data={
                "submit-event": "",
                "name": self.event_name,
                "date": self.test_event_data["date"],
                "description": self.test_event_data["description"],
                "venue_uuid": venue.uuid,
            },
        )

        dashboard = self.grafana.get_dashboard_by_name(self.event_name)
        self.assertTrue(dashboard)

        # Update the event name
        self.client.post(
            reverse(self.event_update_url, kwargs={"event_uuid": event.uuid}),
            data={
                "name": updated_event_name,
                "description": self.test_event_data["description"],
                "venue_uuid": venue.uuid,
            },
        )

        # Confirm that a dashboard exists with the new event name
        dashboard = self.grafana.get_dashboard_by_name(updated_event_name)
        self.assertTrue(dashboard)
        self.assertEquals(dashboard["dashboard"]["title"], updated_event_name)