pcie_errors: plugin to read PCIe errors
[collectd.git] / src / pcie_errors_test.c
diff --git a/src/pcie_errors_test.c b/src/pcie_errors_test.c
new file mode 100644 (file)
index 0000000..48b01b1
--- /dev/null
@@ -0,0 +1,581 @@
+/**
+ * collectd - src/pcie_errors.c
+ *
+ * Copyright(c) 2018 Intel Corporation. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *   Kamil Wiatrowski <kamilx.wiatrowski@intel.com>
+ **/
+
+#include "pcie_errors.c" /* sic */
+#include "testing.h"
+
+#define TEST_DOMAIN 1
+#define TEST_BUS 5
+#define TEST_DEVICE 0xc
+#define TEST_FUNCTION 2
+#define TEST_DEVICE_STR "0001:05:0c.2"
+
+#define G_BUFF_LEN 4
+
+static notification_t last_notif;
+static char g_buff[G_BUFF_LEN];
+
+/* mock functions */
+int plugin_dispatch_notification(const notification_t *notif) {
+  last_notif = *notif;
+  return ENOTSUP;
+}
+
+ssize_t pread(__attribute__((unused)) int fd, void *buf, size_t count,
+              __attribute__((unused)) off_t offset) {
+  if (count == 0 || count > G_BUFF_LEN)
+    return -1;
+
+  memcpy(buf, g_buff, count);
+  return count;
+}
+/* end mock functions */
+
+DEF_TEST(clear_dev_list) {
+  pcie_clear_list(NULL);
+
+  llist_t *test_list = llist_create();
+  CHECK_NOT_NULL(test_list);
+
+  pcie_device_t *dev = calloc(1, sizeof(*dev));
+  CHECK_NOT_NULL(dev);
+
+  llentry_t *entry = llentry_create(NULL, dev);
+  CHECK_NOT_NULL(entry);
+
+  llist_append(test_list, entry);
+
+  for (llentry_t *e = llist_head(test_list); e != NULL; e = e->next) {
+    EXPECT_EQ_UINT64(dev, e->value);
+  }
+
+  pcie_clear_list(test_list);
+
+  return 0;
+}
+
+DEF_TEST(add_to_list) {
+  llist_t *test_list = llist_create();
+  CHECK_NOT_NULL(test_list);
+
+  int ret = pcie_add_device(test_list, TEST_DOMAIN, TEST_BUS, TEST_DEVICE,
+                            TEST_FUNCTION);
+  EXPECT_EQ_INT(0, ret);
+
+  llentry_t *e = llist_head(test_list);
+  CHECK_NOT_NULL(e);
+  OK(NULL == e->next);
+
+  pcie_device_t *dev = e->value;
+  CHECK_NOT_NULL(dev);
+  EXPECT_EQ_INT(TEST_DOMAIN, dev->domain);
+  EXPECT_EQ_INT(TEST_BUS, dev->bus);
+  EXPECT_EQ_INT(TEST_DEVICE, dev->device);
+  EXPECT_EQ_INT(TEST_FUNCTION, dev->function);
+  EXPECT_EQ_INT(-1, dev->cap_exp);
+  EXPECT_EQ_INT(-1, dev->ecap_aer);
+
+  pcie_clear_list(test_list);
+
+  return 0;
+}
+
+DEF_TEST(pcie_read) {
+  int ret;
+  pcie_device_t dev = {0};
+  uint32_t val = 0;
+  g_buff[0] = 4;
+  g_buff[1] = 3;
+  g_buff[2] = 2;
+  g_buff[3] = 1;
+
+  ret = pcie_read(&dev, &val, 1, 0);
+  EXPECT_EQ_INT(0, ret);
+  EXPECT_EQ_INT(4, val);
+
+  ret = pcie_read(&dev, &val, 2, 0);
+  EXPECT_EQ_INT(0, ret);
+  EXPECT_EQ_INT(0x304, val);
+
+  ret = pcie_read(&dev, &val, 3, 0);
+  EXPECT_EQ_INT(0, ret);
+  EXPECT_EQ_INT(0x20304, val);
+
+  ret = pcie_read(&dev, &val, 4, 0);
+  EXPECT_EQ_INT(0, ret);
+  EXPECT_EQ_INT(0x1020304, val);
+
+  ret = pcie_read(&dev, &val, G_BUFF_LEN + 1, 0);
+  EXPECT_EQ_INT(-1, ret);
+
+  pcie_fops.read = pcie_read;
+
+  uint8_t val8 = pcie_read8(&dev, 0);
+  EXPECT_EQ_INT(4, val8);
+
+  uint16_t val16 = pcie_read16(&dev, 0);
+  EXPECT_EQ_INT(0x304, val16);
+
+  uint32_t val32 = pcie_read32(&dev, 0);
+  EXPECT_EQ_INT(0x1020304, val32);
+
+  return 0;
+}
+
+DEF_TEST(dispatch_notification) {
+  pcie_device_t dev = {0, TEST_DOMAIN, TEST_BUS, TEST_DEVICE, TEST_FUNCTION,
+                       0, 0,           0,        0,           0};
+  cdtime_t t = cdtime();
+  notification_t n = {
+      .severity = 1, .time = t, .plugin = "pcie_errors_test", .meta = NULL};
+
+  pcie_dispatch_notification(&dev, &n, "test_type", "test_type_instance");
+  EXPECT_EQ_INT(1, last_notif.severity);
+  EXPECT_EQ_UINT64(t, last_notif.time);
+  EXPECT_EQ_STR("pcie_errors_test", last_notif.plugin);
+  OK(NULL == last_notif.meta);
+  EXPECT_EQ_STR(hostname_g, last_notif.host);
+  EXPECT_EQ_STR(TEST_DEVICE_STR, last_notif.plugin_instance);
+  EXPECT_EQ_STR("test_type", last_notif.type);
+  EXPECT_EQ_STR("test_type_instance", last_notif.type_instance);
+
+  return 0;
+}
+
+DEF_TEST(access_config) {
+  pcie_config.use_sysfs = 0;
+  pcie_access_config();
+  EXPECT_EQ_UINT64(pcie_list_devices_proc, pcie_fops.list_devices);
+  EXPECT_EQ_UINT64(pcie_open_proc, pcie_fops.open);
+  EXPECT_EQ_UINT64(pcie_close, pcie_fops.close);
+  EXPECT_EQ_UINT64(pcie_read, pcie_fops.read);
+  EXPECT_EQ_STR(PCIE_DEFAULT_PROCDIR, pcie_config.access_dir);
+
+  sstrncpy(pcie_config.access_dir, "Test", sizeof(pcie_config.access_dir));
+  pcie_access_config();
+  EXPECT_EQ_STR("Test", pcie_config.access_dir);
+
+  pcie_config.use_sysfs = 1;
+  pcie_access_config();
+  EXPECT_EQ_UINT64(pcie_list_devices_sysfs, pcie_fops.list_devices);
+  EXPECT_EQ_UINT64(pcie_open_sysfs, pcie_fops.open);
+  EXPECT_EQ_UINT64(pcie_close, pcie_fops.close);
+  EXPECT_EQ_UINT64(pcie_read, pcie_fops.read);
+  EXPECT_EQ_STR("Test", pcie_config.access_dir);
+
+  pcie_config.access_dir[0] = '\0';
+  pcie_access_config();
+  EXPECT_EQ_STR(PCIE_DEFAULT_SYSFSDIR, pcie_config.access_dir);
+
+  return 0;
+}
+
+DEF_TEST(plugin_config_fail) {
+  oconfig_item_t test_cfg_parent = {"pcie_errors", NULL, 0, NULL, NULL, 0};
+  char value_buff[256] = "procs";
+  char key_buff[256] = "Sources";
+  oconfig_value_t test_cfg_value = {{value_buff}, OCONFIG_TYPE_STRING};
+  oconfig_item_t test_cfg = {
+      key_buff, &test_cfg_value, 1, &test_cfg_parent, NULL, 0};
+
+  test_cfg_parent.children = &test_cfg;
+  test_cfg_parent.children_num = 1;
+
+  int ret = pcie_plugin_config(&test_cfg_parent);
+  EXPECT_EQ_INT(0, ret);
+  EXPECT_EQ_INT(1, pcie_config.config_error);
+  pcie_config.config_error = 0;
+
+  sstrncpy(key_buff, "Source", sizeof(key_buff));
+  ret = pcie_plugin_config(&test_cfg_parent);
+  EXPECT_EQ_INT(0, ret);
+  EXPECT_EQ_INT(1, pcie_config.config_error);
+  pcie_config.config_error = 0;
+
+  sstrncpy(value_buff, "proc", sizeof(value_buff));
+  test_cfg_value.type = OCONFIG_TYPE_NUMBER;
+  ret = pcie_plugin_config(&test_cfg_parent);
+  EXPECT_EQ_INT(0, ret);
+  EXPECT_EQ_INT(1, pcie_config.config_error);
+  pcie_config.config_error = 0;
+
+  sstrncpy(key_buff, "AccessDir", sizeof(key_buff));
+  ret = pcie_plugin_config(&test_cfg_parent);
+  EXPECT_EQ_INT(0, ret);
+  EXPECT_EQ_INT(1, pcie_config.config_error);
+  pcie_config.config_error = 0;
+
+  return 0;
+}
+
+DEF_TEST(plugin_config) {
+  oconfig_item_t test_cfg_parent = {"pcie_errors", NULL, 0, NULL, NULL, 0};
+  char value_buff[256] = "proc";
+  char key_buff[256] = "source";
+  oconfig_value_t test_cfg_value = {{value_buff}, OCONFIG_TYPE_STRING};
+  oconfig_item_t test_cfg = {
+      key_buff, &test_cfg_value, 1, &test_cfg_parent, NULL, 0};
+
+  test_cfg_parent.children = &test_cfg;
+  test_cfg_parent.children_num = 1;
+
+  pcie_config.use_sysfs = 1;
+  int ret = pcie_plugin_config(&test_cfg_parent);
+  EXPECT_EQ_INT(0, ret);
+  EXPECT_EQ_INT(0, pcie_config.config_error);
+  EXPECT_EQ_INT(0, pcie_config.use_sysfs);
+
+  pcie_config.use_sysfs = 1;
+  sstrncpy(value_buff, "sysfs", sizeof(value_buff));
+  ret = pcie_plugin_config(&test_cfg_parent);
+  EXPECT_EQ_INT(0, ret);
+  EXPECT_EQ_INT(0, pcie_config.config_error);
+  EXPECT_EQ_INT(1, pcie_config.use_sysfs);
+
+  sstrncpy(key_buff, "AccessDir", sizeof(key_buff));
+  sstrncpy(value_buff, "some/test/value", sizeof(value_buff));
+  ret = pcie_plugin_config(&test_cfg_parent);
+  EXPECT_EQ_INT(0, ret);
+  EXPECT_EQ_INT(0, pcie_config.config_error);
+  EXPECT_EQ_STR("some/test/value", pcie_config.access_dir);
+
+  memset(&test_cfg_value.value, 0, sizeof(test_cfg_value.value));
+  test_cfg_value.value.boolean = 1;
+  test_cfg_value.type = OCONFIG_TYPE_BOOLEAN;
+  sstrncpy(key_buff, "ReportMasked", sizeof(key_buff));
+  ret = pcie_plugin_config(&test_cfg_parent);
+  EXPECT_EQ_INT(0, ret);
+  EXPECT_EQ_INT(0, pcie_config.config_error);
+  EXPECT_EQ_INT(1, pcie_config.notif_masked);
+
+  sstrncpy(key_buff, "PersistentNotifications", sizeof(key_buff));
+  ret = pcie_plugin_config(&test_cfg_parent);
+  EXPECT_EQ_INT(0, ret);
+  EXPECT_EQ_INT(0, pcie_config.config_error);
+  EXPECT_EQ_INT(1, pcie_config.persistent);
+
+  return 0;
+}
+
+#define BAD_TLP_SET_MSG "Correctable Error set: Bad TLP Status"
+#define BAD_TLP_CLEAR_MSG "Correctable Error cleared: Bad TLP Status"
+
+DEF_TEST(dispatch_correctable_errors) {
+  pcie_device_t dev = {0, TEST_DOMAIN, TEST_BUS, TEST_DEVICE, TEST_FUNCTION,
+                       0, 0,           0,        0,           0};
+  pcie_config.notif_masked = 0;
+  pcie_config.persistent = 0;
+
+  pcie_dispatch_correctable_errors(&dev, PCI_ERR_COR_BAD_TLP,
+                                   ~(PCI_ERR_COR_BAD_TLP));
+  EXPECT_EQ_INT(NOTIF_WARNING, last_notif.severity);
+  EXPECT_EQ_STR(PCIE_ERRORS_PLUGIN, last_notif.plugin);
+  OK(NULL == last_notif.meta);
+  EXPECT_EQ_STR(TEST_DEVICE_STR, last_notif.plugin_instance);
+  EXPECT_EQ_STR(PCIE_ERROR, last_notif.type);
+  EXPECT_EQ_STR(PCIE_SEV_CE, last_notif.type_instance);
+  EXPECT_EQ_STR(BAD_TLP_SET_MSG, last_notif.message);
+
+  memset(&last_notif, 0, sizeof(last_notif));
+  dev.correctable_errors = PCI_ERR_COR_BAD_TLP;
+  pcie_dispatch_correctable_errors(&dev, PCI_ERR_COR_BAD_TLP,
+                                   ~(PCI_ERR_COR_BAD_TLP));
+  EXPECT_EQ_STR("", last_notif.plugin_instance);
+
+  pcie_config.persistent = 1;
+  pcie_dispatch_correctable_errors(&dev, PCI_ERR_COR_BAD_TLP,
+                                   ~(PCI_ERR_COR_BAD_TLP));
+  EXPECT_EQ_INT(NOTIF_WARNING, last_notif.severity);
+  EXPECT_EQ_STR(PCIE_ERRORS_PLUGIN, last_notif.plugin);
+  OK(NULL == last_notif.meta);
+  EXPECT_EQ_STR(TEST_DEVICE_STR, last_notif.plugin_instance);
+  EXPECT_EQ_STR(PCIE_ERROR, last_notif.type);
+  EXPECT_EQ_STR(PCIE_SEV_CE, last_notif.type_instance);
+  EXPECT_EQ_STR(BAD_TLP_SET_MSG, last_notif.message);
+
+  memset(&last_notif, 0, sizeof(last_notif));
+  pcie_dispatch_correctable_errors(&dev, PCI_ERR_COR_BAD_TLP,
+                                   PCI_ERR_COR_BAD_TLP);
+  EXPECT_EQ_STR("", last_notif.plugin_instance);
+
+  pcie_config.notif_masked = 1;
+  pcie_dispatch_correctable_errors(&dev, PCI_ERR_COR_BAD_TLP,
+                                   PCI_ERR_COR_BAD_TLP);
+  EXPECT_EQ_INT(NOTIF_WARNING, last_notif.severity);
+  EXPECT_EQ_STR(PCIE_ERRORS_PLUGIN, last_notif.plugin);
+  OK(NULL == last_notif.meta);
+  EXPECT_EQ_STR(TEST_DEVICE_STR, last_notif.plugin_instance);
+  EXPECT_EQ_STR(PCIE_ERROR, last_notif.type);
+  EXPECT_EQ_STR(PCIE_SEV_CE, last_notif.type_instance);
+  EXPECT_EQ_STR(BAD_TLP_SET_MSG, last_notif.message);
+
+  pcie_config.persistent = 0;
+  memset(&last_notif, 0, sizeof(last_notif));
+  pcie_dispatch_correctable_errors(&dev, PCI_ERR_COR_BAD_TLP,
+                                   PCI_ERR_COR_BAD_TLP);
+  EXPECT_EQ_STR("", last_notif.plugin_instance);
+
+  dev.correctable_errors = 0;
+  pcie_dispatch_correctable_errors(&dev, PCI_ERR_COR_BAD_TLP,
+                                   PCI_ERR_COR_BAD_TLP);
+  EXPECT_EQ_INT(NOTIF_WARNING, last_notif.severity);
+  EXPECT_EQ_STR(PCIE_ERRORS_PLUGIN, last_notif.plugin);
+  OK(NULL == last_notif.meta);
+  EXPECT_EQ_STR(TEST_DEVICE_STR, last_notif.plugin_instance);
+  EXPECT_EQ_STR(PCIE_ERROR, last_notif.type);
+  EXPECT_EQ_STR(PCIE_SEV_CE, last_notif.type_instance);
+  EXPECT_EQ_STR(BAD_TLP_SET_MSG, last_notif.message);
+
+  pcie_dispatch_correctable_errors(&dev, PCI_ERR_COR_BAD_TLP,
+                                   ~(PCI_ERR_COR_BAD_TLP));
+  EXPECT_EQ_INT(NOTIF_WARNING, last_notif.severity);
+  EXPECT_EQ_STR(PCIE_ERRORS_PLUGIN, last_notif.plugin);
+  OK(NULL == last_notif.meta);
+  EXPECT_EQ_STR(TEST_DEVICE_STR, last_notif.plugin_instance);
+  EXPECT_EQ_STR(PCIE_ERROR, last_notif.type);
+  EXPECT_EQ_STR(PCIE_SEV_CE, last_notif.type_instance);
+  EXPECT_EQ_STR(BAD_TLP_SET_MSG, last_notif.message);
+
+  pcie_config.notif_masked = 0;
+  dev.correctable_errors = PCI_ERR_COR_BAD_TLP;
+  pcie_dispatch_correctable_errors(&dev, 0, ~(PCI_ERR_COR_BAD_TLP));
+  EXPECT_EQ_INT(NOTIF_OKAY, last_notif.severity);
+  EXPECT_EQ_STR(PCIE_ERRORS_PLUGIN, last_notif.plugin);
+  OK(NULL == last_notif.meta);
+  EXPECT_EQ_STR(TEST_DEVICE_STR, last_notif.plugin_instance);
+  EXPECT_EQ_STR(PCIE_ERROR, last_notif.type);
+  EXPECT_EQ_STR(PCIE_SEV_CE, last_notif.type_instance);
+  EXPECT_EQ_STR(BAD_TLP_CLEAR_MSG, last_notif.message);
+
+  return 0;
+}
+
+#define FCP_NF_SET_MSG                                                         \
+  "Uncorrectable(non_fatal) Error set: Flow Control Protocol"
+#define FCP_F_SET_MSG "Uncorrectable(fatal) Error set: Flow Control Protocol"
+#define FCP_NF_CLEAR_MSG                                                       \
+  "Uncorrectable(non_fatal) Error cleared: Flow Control Protocol"
+#define FCP_F_CLEAR_MSG                                                        \
+  "Uncorrectable(fatal) Error cleared: Flow Control Protocol"
+
+DEF_TEST(dispatch_uncorrectable_errors) {
+  pcie_device_t dev = {0, TEST_DOMAIN, TEST_BUS, TEST_DEVICE, TEST_FUNCTION,
+                       0, 0,           0,        0,           0};
+  pcie_config.notif_masked = 0;
+  pcie_config.persistent = 0;
+
+  pcie_dispatch_uncorrectable_errors(&dev, PCI_ERR_UNC_FCP, ~(PCI_ERR_UNC_FCP),
+                                     ~(PCI_ERR_UNC_FCP));
+  EXPECT_EQ_INT(NOTIF_WARNING, last_notif.severity);
+  EXPECT_EQ_STR(PCIE_ERRORS_PLUGIN, last_notif.plugin);
+  OK(NULL == last_notif.meta);
+  EXPECT_EQ_STR(TEST_DEVICE_STR, last_notif.plugin_instance);
+  EXPECT_EQ_STR(PCIE_ERROR, last_notif.type);
+  EXPECT_EQ_STR(PCIE_SEV_NOFATAL, last_notif.type_instance);
+  EXPECT_EQ_STR(FCP_NF_SET_MSG, last_notif.message);
+
+  pcie_dispatch_uncorrectable_errors(&dev, PCI_ERR_UNC_FCP, ~(PCI_ERR_UNC_FCP),
+                                     PCI_ERR_UNC_FCP);
+  EXPECT_EQ_INT(NOTIF_FAILURE, last_notif.severity);
+  EXPECT_EQ_STR(PCIE_ERRORS_PLUGIN, last_notif.plugin);
+  OK(NULL == last_notif.meta);
+  EXPECT_EQ_STR(TEST_DEVICE_STR, last_notif.plugin_instance);
+  EXPECT_EQ_STR(PCIE_ERROR, last_notif.type);
+  EXPECT_EQ_STR(PCIE_SEV_FATAL, last_notif.type_instance);
+  EXPECT_EQ_STR(FCP_F_SET_MSG, last_notif.message);
+
+  memset(&last_notif, 0, sizeof(last_notif));
+  dev.uncorrectable_errors = PCI_ERR_UNC_FCP;
+  pcie_dispatch_uncorrectable_errors(&dev, PCI_ERR_UNC_FCP, ~(PCI_ERR_UNC_FCP),
+                                     PCI_ERR_UNC_FCP);
+  EXPECT_EQ_STR("", last_notif.plugin_instance);
+
+  pcie_config.persistent = 1;
+  pcie_dispatch_uncorrectable_errors(&dev, PCI_ERR_UNC_FCP, ~(PCI_ERR_UNC_FCP),
+                                     PCI_ERR_UNC_FCP);
+  EXPECT_EQ_INT(NOTIF_FAILURE, last_notif.severity);
+  EXPECT_EQ_STR(PCIE_ERRORS_PLUGIN, last_notif.plugin);
+  OK(NULL == last_notif.meta);
+  EXPECT_EQ_STR(TEST_DEVICE_STR, last_notif.plugin_instance);
+  EXPECT_EQ_STR(PCIE_ERROR, last_notif.type);
+  EXPECT_EQ_STR(PCIE_SEV_FATAL, last_notif.type_instance);
+  EXPECT_EQ_STR(FCP_F_SET_MSG, last_notif.message);
+
+  memset(&last_notif, 0, sizeof(last_notif));
+  pcie_dispatch_uncorrectable_errors(&dev, PCI_ERR_UNC_FCP, PCI_ERR_UNC_FCP,
+                                     PCI_ERR_UNC_FCP);
+  EXPECT_EQ_STR("", last_notif.plugin_instance);
+
+  pcie_config.notif_masked = 1;
+  pcie_dispatch_uncorrectable_errors(&dev, PCI_ERR_UNC_FCP, PCI_ERR_UNC_FCP,
+                                     PCI_ERR_UNC_FCP);
+  EXPECT_EQ_INT(NOTIF_FAILURE, last_notif.severity);
+  EXPECT_EQ_STR(PCIE_ERRORS_PLUGIN, last_notif.plugin);
+  OK(NULL == last_notif.meta);
+  EXPECT_EQ_STR(TEST_DEVICE_STR, last_notif.plugin_instance);
+  EXPECT_EQ_STR(PCIE_ERROR, last_notif.type);
+  EXPECT_EQ_STR(PCIE_SEV_FATAL, last_notif.type_instance);
+  EXPECT_EQ_STR(FCP_F_SET_MSG, last_notif.message);
+
+  pcie_config.persistent = 0;
+  dev.uncorrectable_errors = 0;
+  memset(&last_notif, 0, sizeof(last_notif));
+  pcie_dispatch_uncorrectable_errors(&dev, PCI_ERR_UNC_FCP, ~(PCI_ERR_UNC_FCP),
+                                     PCI_ERR_UNC_FCP);
+  EXPECT_EQ_INT(NOTIF_FAILURE, last_notif.severity);
+  EXPECT_EQ_STR(PCIE_ERRORS_PLUGIN, last_notif.plugin);
+  OK(NULL == last_notif.meta);
+  EXPECT_EQ_STR(TEST_DEVICE_STR, last_notif.plugin_instance);
+  EXPECT_EQ_STR(PCIE_ERROR, last_notif.type);
+  EXPECT_EQ_STR(PCIE_SEV_FATAL, last_notif.type_instance);
+  EXPECT_EQ_STR(FCP_F_SET_MSG, last_notif.message);
+
+  pcie_config.notif_masked = 0;
+  dev.uncorrectable_errors = PCI_ERR_UNC_FCP;
+  pcie_dispatch_uncorrectable_errors(&dev, 0, ~(PCI_ERR_UNC_FCP),
+                                     ~(PCI_ERR_UNC_FCP));
+  EXPECT_EQ_INT(NOTIF_OKAY, last_notif.severity);
+  EXPECT_EQ_STR(PCIE_ERRORS_PLUGIN, last_notif.plugin);
+  OK(NULL == last_notif.meta);
+  EXPECT_EQ_STR(TEST_DEVICE_STR, last_notif.plugin_instance);
+  EXPECT_EQ_STR(PCIE_ERROR, last_notif.type);
+  EXPECT_EQ_STR(PCIE_SEV_NOFATAL, last_notif.type_instance);
+  EXPECT_EQ_STR(FCP_NF_CLEAR_MSG, last_notif.message);
+
+  memset(&last_notif, 0, sizeof(last_notif));
+  pcie_dispatch_uncorrectable_errors(&dev, 0, ~(PCI_ERR_UNC_FCP),
+                                     PCI_ERR_UNC_FCP);
+  EXPECT_EQ_INT(NOTIF_OKAY, last_notif.severity);
+  EXPECT_EQ_STR(PCIE_ERRORS_PLUGIN, last_notif.plugin);
+  OK(NULL == last_notif.meta);
+  EXPECT_EQ_STR(TEST_DEVICE_STR, last_notif.plugin_instance);
+  EXPECT_EQ_STR(PCIE_ERROR, last_notif.type);
+  EXPECT_EQ_STR(PCIE_SEV_FATAL, last_notif.type_instance);
+  EXPECT_EQ_STR(FCP_F_CLEAR_MSG, last_notif.message);
+
+  return 0;
+}
+
+#define UR_SET_MSG "Device Status Error set: Unsupported Request"
+#define UR_CLEAR_MSG "Device Status Error cleared: Unsupported Request"
+#define FE_SET_MSG "Device Status Error set: Fatal Error"
+#define FE_CLEAR_MSG "Device Status Error cleared: Fatal Error"
+
+DEF_TEST(device_status_errors) {
+  pcie_device_t dev = {0, TEST_DOMAIN, TEST_BUS, TEST_DEVICE, TEST_FUNCTION,
+                       0, 0,           0,        0,           0};
+  pcie_config.persistent = 0;
+  g_buff[0] = (PCI_EXP_DEVSTA_URD & 0xff);
+
+  memset(&last_notif, 0, sizeof(last_notif));
+  pcie_check_dev_status(&dev, 0);
+  EXPECT_EQ_INT(NOTIF_WARNING, last_notif.severity);
+  EXPECT_EQ_STR(PCIE_ERRORS_PLUGIN, last_notif.plugin);
+  OK(NULL == last_notif.meta);
+  EXPECT_EQ_STR(TEST_DEVICE_STR, last_notif.plugin_instance);
+  EXPECT_EQ_STR(PCIE_ERROR, last_notif.type);
+  EXPECT_EQ_STR(PCIE_SEV_NOFATAL, last_notif.type_instance);
+  EXPECT_EQ_STR(UR_SET_MSG, last_notif.message);
+
+  memset(&last_notif, 0, sizeof(last_notif));
+  pcie_check_dev_status(&dev, 0);
+  EXPECT_EQ_STR("", last_notif.plugin_instance);
+
+  pcie_config.persistent = 1;
+  pcie_check_dev_status(&dev, 0);
+  EXPECT_EQ_INT(NOTIF_WARNING, last_notif.severity);
+  EXPECT_EQ_STR(PCIE_ERRORS_PLUGIN, last_notif.plugin);
+  OK(NULL == last_notif.meta);
+  EXPECT_EQ_STR(TEST_DEVICE_STR, last_notif.plugin_instance);
+  EXPECT_EQ_STR(PCIE_ERROR, last_notif.type);
+  EXPECT_EQ_STR(PCIE_SEV_NOFATAL, last_notif.type_instance);
+  EXPECT_EQ_STR(UR_SET_MSG, last_notif.message);
+
+  g_buff[0] = 0;
+  pcie_check_dev_status(&dev, 0);
+  EXPECT_EQ_INT(NOTIF_OKAY, last_notif.severity);
+  EXPECT_EQ_STR(PCIE_ERRORS_PLUGIN, last_notif.plugin);
+  OK(NULL == last_notif.meta);
+  EXPECT_EQ_STR(TEST_DEVICE_STR, last_notif.plugin_instance);
+  EXPECT_EQ_STR(PCIE_ERROR, last_notif.type);
+  EXPECT_EQ_STR(PCIE_SEV_NOFATAL, last_notif.type_instance);
+  EXPECT_EQ_STR(UR_CLEAR_MSG, last_notif.message);
+
+  pcie_config.persistent = 0;
+  dev.device_status = PCI_EXP_DEVSTA_URD;
+  pcie_check_dev_status(&dev, 0);
+  EXPECT_EQ_INT(NOTIF_OKAY, last_notif.severity);
+  EXPECT_EQ_STR(PCIE_ERRORS_PLUGIN, last_notif.plugin);
+  OK(NULL == last_notif.meta);
+  EXPECT_EQ_STR(TEST_DEVICE_STR, last_notif.plugin_instance);
+  EXPECT_EQ_STR(PCIE_ERROR, last_notif.type);
+  EXPECT_EQ_STR(PCIE_SEV_NOFATAL, last_notif.type_instance);
+  EXPECT_EQ_STR(UR_CLEAR_MSG, last_notif.message);
+
+  memset(&last_notif, 0, sizeof(last_notif));
+  pcie_check_dev_status(&dev, 0);
+  EXPECT_EQ_STR("", last_notif.plugin_instance);
+
+  g_buff[0] = (PCI_EXP_DEVSTA_FED & 0xff);
+  pcie_check_dev_status(&dev, 0);
+  EXPECT_EQ_INT(NOTIF_FAILURE, last_notif.severity);
+  EXPECT_EQ_STR(PCIE_ERRORS_PLUGIN, last_notif.plugin);
+  OK(NULL == last_notif.meta);
+  EXPECT_EQ_STR(TEST_DEVICE_STR, last_notif.plugin_instance);
+  EXPECT_EQ_STR(PCIE_ERROR, last_notif.type);
+  EXPECT_EQ_STR(PCIE_SEV_FATAL, last_notif.type_instance);
+  EXPECT_EQ_STR(FE_SET_MSG, last_notif.message);
+
+  g_buff[0] = 0;
+  pcie_check_dev_status(&dev, 0);
+  EXPECT_EQ_INT(NOTIF_OKAY, last_notif.severity);
+  EXPECT_EQ_STR(PCIE_ERRORS_PLUGIN, last_notif.plugin);
+  OK(NULL == last_notif.meta);
+  EXPECT_EQ_STR(TEST_DEVICE_STR, last_notif.plugin_instance);
+  EXPECT_EQ_STR(PCIE_ERROR, last_notif.type);
+  EXPECT_EQ_STR(PCIE_SEV_FATAL, last_notif.type_instance);
+  EXPECT_EQ_STR(FE_CLEAR_MSG, last_notif.message);
+
+  return 0;
+}
+
+int main(void) {
+  RUN_TEST(clear_dev_list);
+  RUN_TEST(add_to_list);
+  RUN_TEST(pcie_read);
+  RUN_TEST(dispatch_notification);
+
+  RUN_TEST(access_config);
+  RUN_TEST(plugin_config_fail);
+  RUN_TEST(plugin_config);
+
+  RUN_TEST(dispatch_correctable_errors);
+  RUN_TEST(dispatch_uncorrectable_errors);
+  RUN_TEST(device_status_errors);
+
+  END_TEST;
+}