5. Testování (Blackbox + Whitebox)

Testování (Blackbox + Whitebox)

Evaluace v BRUTE je spuštěna. Můžete začít nahrávat!

Představte si, že pracujete na projektu, kde je potřeba filtrovat odposlouchané zprávy (sniffer) v textové podobě na základě nějakého kritéria.

Pro zajímavost: analogií v síťových komunikacích může být například nástroj Wireshark.

V rámci dokončení projektu potřebujete otestovat implementaci. V rámci analýzy byly navrhnuty testovací případy, které doimplementujete. Za každou správnou implementaci testovacího případu dostanete příslušné body (dohromady až 7). Pokud se Vám podaří testovacími případy pokrýt celý kód až na pár řádků (testováno pomocí lcov), tak dostanete 3 body.

Testovaná knihovna

Stáhněte si projekt hw5-sniffer.zip a tento projekt rozbalte. Máte k dispozici následující soubory:

  • sniffer.c, sniffer.h - odposlouchávač samotný,
  • sniffer_tests.c - testovací případy, které doimplementujete,
  • sniffer_tests.h - hlavička testovacích případů, využívá se v sniffer_tests_main.c,
  • sniffer_tests_main.c - testovací prostředí, které volá samotné testovací funkce dané rozhraním z sniffer_tests.h.

Funkcionalita snifferu je následující: přijímá všechny zprávy (const char *msg), ale do kruhového bufferu historie ukládá pouze zprávy, které začínají konkrétním řetězcem (hlavičkou), či priorita zprávy je vyšší nebo rovna momentálnímu logging_level odposlouchávače. Každá zpráva v sobě obsahuje časovou značku a prioritu zprávy. Časová značka nemá vliv na pořadí v kruhovém bufferu, jedná se pouze o dodatečnou informaci, do kruhového bufferu se data ukládají v takovém pořadí, v jakém přišly.

Uživatel také může odposlouchávání vypnout, pokud si nepřeje, aby žádná zpráva (i se správnou hlavičkou) nebyla zpracovaná do kruhové fronty.

Struktura zprávy

Zpráva je ve formě const char* a zpracovává se uvnitř metody sniffer_parse_msg. Její struktura je následovná:

LOG_LEVEL (1B) | TIME (4B, Big endian) | Textová zpráva (až 50B)

Předpoklad je, že zpráva v paměti existuje a textová část je ukončena \0. Není potřeba předávat délku.

Testovací případy

Doimplementujte následující testovací případy do souboru sniffer_tests.c:

  • bool sniffer_tests_check_invalid_params(void) (1 bod):

    Otestuje, že veškeré metody vrací false či NULL, když předané parametery nabývají špatných hodnot (NULL, mimo rozsah, atp.). Popis špatných hodnot si přečtěte v docstrings všech metod.

  • bool sniffer_tests_last_msg_bounds(void):

    Otestuje, že metoda sniffer_get_ith_last_message vrátí false mimo rozsah kruhového bufferu. Máte tuto funkci jako příklad, jak používat tuto knihovnu.

  • bool sniffer_message_append_depends_on_stopped(void) (1 bod):

    Otestuje, že zpráva se správnou hlavičkou se přidá, pokud je odposlech aktivní. Také se otestuje, že se zpráva nepřidá, pokud je odposlech deaktivován.

  • bool sniffer_test_message_parser(void) (3.5 bodu):

    Otestuje parser zpráv. Zpráva, která neodpovídá formátu, není zařazena. Nad všemi případy, kdy parser má vrátit true či false, se zamyslete dle specifikace a kódu.

  • bool sniffer_test_check_last_msgs_fifo(void) (1.5 bodu):

    Otestuje, že kruhový buffer se chová správně (odpovídá konceptu FIRST in, FIRST out). Otestuje, že pokud je buffer plný, tak nejstarší zpráva je nahrazena novou.

Soubory sniffer.c, sniffer.h, sniffer_tests_main.c a sniffer_tests_main.h neměňte. Implementuje pouze testovací případy v sniffer_tests.c.

Hodnocení

Za každý správný testovací případ dostanete příslušné body. Vaše testovací případy budou puštěny vůči správné referenční implementaci se stejným překladem jako máte u Vás a také vůči několika špatným, kde budou špatně implementované funkce.

Úkol by Vás měl naučit navrhnout testovací případy podle specifikace zadání. I když klasické blackbox testování se týká jen specifikace kódu, Vašim úkolem je také zanalyzovat kód "whitebox způsobem" tak, aby Váš napsaný testovací případ byl dostatečně robustní. Při psaní testovacích případů se vždy koukněte na danou funkci, kterou testujete, a zamyslete se, v jakých částech by mohlo ve vadných implementacích dojít k chybě.

Abyste dostali aspoň jeden bod, musí Vám projít testy na referenční implementaci sniffer.c.

Za úspěšné pokrytí všech řádek pomocí vašich testů ve funkcích

  • sniffer_change_sniffing,
  • sniffer_get_ith_last_msg,
  • sniffer_parse_msg,
  • sniffer_enplace_into_buffers,
  • sniffer_set_log_level

v referenčním implementaci sniffer.c dostanete až 3 body. Všechny řádky v sniffer_new a sniffer_dispose pokrývat nemusíte. Dalších 7 bodů získáte za výše uvedené testovací případy pro blackbox testování. Bodové zisky za blackbox testy jsou uvedeny u názvů testovacích funkcí v závorce.

K odevzdání použijte přiložený Makefile a pravidlo zip - odevzdává se pouze sniffer_tests.c.

Překlad projektu

Použijte přiložený Makefile. Pravidlo run-tests přeloží testovací prostředí a uvidíte, zda-li testovací případy vůči lokálnímu referenčnímu sniffer.c prošly. Pravidlo gen-cov vygeneruje lcov coverage report. Po spuštění gen-cov se vždy smažou sourbory *.gcda a *.gcno, aby jste viděli vždy pokrytí při posledním puštění.

Nápověda

Při implementaci testovacích případů je potřeba si zaalokovat strukturu snifferu přes metodu sniffer_new a poté na této struktuře volat metody. Při dokončení testovacího případu je potřeba strukturu odposlouchávače uvolnit pomocí sniffer_dispose.

Příklad zkonstruování validní zprávy (pokud ji budete v testu potřebovat) a její použití, včetně alokace odposlouchávače.

bool test_case_123(void)
{
    const char *msg_valid_text = "syslog: ID=0xDEADBEEF, Temp=47C";
    size_t msg_len = strlen(msg_valid_text);
    struct psy_sniffer *sniffer = sniffer_new("syslog");

    char msg[100];
    msg[0] = OK;                   /* Priority */
    msg[1] = msg[2] = msg[3] = 0;  /* Time */
    msg[4] = 20;                   /* Time */
    /* Data */
    strncpy(msg + 5, msg_valid_text, MAX_DATA_MSG_LEN);
    if (msg_len > MAX_DATA_MSG_LEN) {
        msg[5 + MAX_DATA_MSG_LEN] = '\0';
    } else {
        msg[5 + msg_len] = '\0';
    }
    /* ..... Test begins here .....
     * Call the methods from sniffer.h in the right order to test
     * the right feature.
     * If anything fails according to specification, call:
     * sniffer_dispose(sniffer); return false;
     * .....  Test ends here  ..... */
    sniffer_dispose(sniffer);
    return true;
}

Odevzdání

Povinné zadání
Název v BRUTE05-testing
Odevzdávané souborysniffer_tests.c
Argumenty při spuštěnížádné
Kompilace ref. řešeníclang -Wall -pedantic -MMD -MP -fprofile-arcs -ftest-coverage
Kompilace špatných případůclang -Wall -pedantic