Task2 - adamk90/training-project-lab GitHub Wiki

Task 2 - A pillow webszerver tesztelése

A pillow webszerver

A pillow egy kisméretű http szerver könyvtár, Qt alapokon.

Fordítás

Mac OS X El Captain 10.11.6-on próbáltam fordítani és több problémába is ütköztem, de végül sikerült megoldanom, ennek menete a következő volt:

A README.MD-ben jelzik, hogy unix alapú operációs rendszeren GCC 4.8-cal és Qt 5.5.1-gyel tesztelték. Mivel nekem Qt 5.9 (és GCC 7.2) van a gépen, ezért a biztonság kedvéért telepítettem egy 5.5.1-et:

brew install [email protected]

Az OS X-en a qmake alapból a clang-ot preferálja, ezért egy kapcsolóval rá kellett venni, hogy gondolja meg magát:

/usr/local/Cellar/[email protected]/5.5.1_1/bin/qmake -spec macx-g++

Ez még nem volt elég, mert a std névtérben nem talált pár dolgot, mint utólag kiderült, az elavult libstdc++-t használta libc++ helyett, ezért a config.pri-hez az alábbi sort hozzáfűztem:

QMAKE_CXXFLAGS += --stdlib=libc++

majd töröltem a .qmake.stash-t és a Makefile-t és újrafuttattam a qmake-et.

Ezután a make még mindig nem futott le, azt írta, hogy a libpillowcore.so-hoz nincs megadva, hogy hogy kell elkészíteni (mivel nincs megadva, ezért biztos nem is kell elkészíteni..). A lib mappában bent volt a keresett fájl, csak .dylib kiterjesztéssel, úgyhogy lemásoltam, hogy legyen .so is. Végül lefutott a make sikeresen.

Majd jött a tests futtatható állomány indítása, aminél panaszkodott, hogy nincs betöltve a libpillowcore.1.dylib. A rövid megoldás, ha mellé másoljuk a lib könyvtárból, amit keres, vagy javítjuk az elérését (otool -L tests megmutatja, hogy maga mellett keresi):

install_name_tool -change libpillowcore.1.dylib ../lib/libpillowcore.1.dylib tests

Így a tesztek futása is megkezdődött.

Tesztek futtatása

Az összes teszt sikeresen lefutott, kivéve egyet: (és kettőt, ami skippelve lett, mert a Zlib támogatás nincs bekapcsolva -> a config.pri-ben ki kellene venni a kommentet, hogy belefordítsa a Zlib támogatást a pillow-ba, akkor ki lehetne értékelni ezeket az eseteket is) egy helyen a header-öknek meg kellett volna egyezniük, de nem egyeztek meg (a dátum nem stimmelt, csúszott 6 órát):

QWARN  : NetworkAccessManagerTest::should_set_cooked_headers_from_received_headers() Headers do not match
QWARN  : NetworkAccessManagerTest::should_set_cooked_headers_from_received_headers()   Actual: 5
QWARN  : NetworkAccessManagerTest::should_set_cooked_headers_from_received_headers()      "Location" : "http://example.org"
QWARN  : NetworkAccessManagerTest::should_set_cooked_headers_from_received_headers()      "Last-Modified" : "Mon, 30 Apr 2012 06:09:00 GMT"
QWARN  : NetworkAccessManagerTest::should_set_cooked_headers_from_received_headers()      "Content-Length" : "6"
QWARN  : NetworkAccessManagerTest::should_set_cooked_headers_from_received_headers()      "Content-Type" : "some/type"
QWARN  : NetworkAccessManagerTest::should_set_cooked_headers_from_received_headers()      "Set-Cookie" : "ChocolateCookie=Very Delicious"
QWARN  : NetworkAccessManagerTest::should_set_cooked_headers_from_received_headers()   Expected: 5
QWARN  : NetworkAccessManagerTest::should_set_cooked_headers_from_received_headers()      "Location" : "http://example.org"
QWARN  : NetworkAccessManagerTest::should_set_cooked_headers_from_received_headers()      "Last-Modified" : "Mon, 30 Apr 2012 12:09:00 GMT"
QWARN  : NetworkAccessManagerTest::should_set_cooked_headers_from_received_headers()      "Content-Length" : "6"
QWARN  : NetworkAccessManagerTest::should_set_cooked_headers_from_received_headers()      "Content-Type" : "some/type"
QWARN  : NetworkAccessManagerTest::should_set_cooked_headers_from_received_headers()      "Set-Cookie": "ChocolateCookie=Very Delicious"
FAIL!  : NetworkAccessManagerTest::should_set_cooked_headers_from_received_headers() Compared values are not the same`

Ami az érdekes ezzel a hibával kapcsolatban, hogy a kód így néz ki:

server.receivedConnections.last()->writeResponse(
    				302,
    				Pillow::HttpHeaderCollection()
    				<< Pillow::HttpHeader("Location", "http://example.org")
    				<< Pillow::HttpHeader("Content-Type", "some/type")
    				<< Pillow::HttpHeader("Last-Modified", 
Pillow::HttpProtocol::Dates::getHttpDate(QDateTime(QDate(2012, 4, 30), QTime(8, 9, 0))))
    				<< Pillow::HttpHeader("Set-Cookie", "ChocolateCookie=Very Delicious")
    				, "Hello!");

    	QVERIFY(waitForSignal(r, SIGNAL(finished())));
    	QCOMPARE(r->readAll(), QByteArray("Hello!"));
    	QCOMPARE(r->rawHeaderPairs(), Pillow::HttpHeaderCollection()
    			 << Pillow::HttpHeader("Location", "http://example.org")
    			 << Pillow::HttpHeader("Last-Modified", "Mon, 30 Apr 2012 12:09:00 GMT")
    			 << Pillow::HttpHeader("Content-Length", "6")
    			 << Pillow::HttpHeader("Content-Type", "some/type")
    			 << Pillow::HttpHeader("Set-Cookie", "ChocolateCookie=Very Delicious")
    			 );

    	QCOMPARE(r->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(), QUrl("http://example.org"));
    	QCOMPARE(r->header(QNetworkRequest::ContentTypeHeader).toByteArray(), QByteArray("some/type"));
    	QCOMPARE(r->header(QNetworkRequest::ContentLengthHeader).toInt(), 6);
    	QCOMPARE(r->header(QNetworkRequest::LastModifiedHeader).toDateTime(), QDateTime(QDate(2012, 4, 30), QTime(8, 9, 0)));

A QDateTime specifikációja szerint, ha nem ad meg harmadik paramétert a konstruktorban, akkor alapból LocalTime-ra állítódik a QTimeZone -> már eleve 8 óra 9 perccel állítja be és arra is ellenőriz, de ellenpárnak be van égetve a 12 óra. Ha a fölötte lévő módszerrel beleszámítjuk az ellenőrzésbe a LocalTime szerintit, így: Pillow::HttpProtocol::Dates::getHttpDate(QDateTime(QDate(2012, 4, 30), QTime(8, 9, 0)))) akkor újrafordítva a tesztet, már nem hibás. Így elmondható, hogy nem a program hibás, hanem a teszt (ezt nevezhetjük test smell-nek?).

Végül belefordítottam a Zlib támogatást is, így a két skippelt teszteset is sikeresen lefutott.

A tesztekhez a Qt Qtest keretrendszerét használja.

A tesztek több nagyobb csoportra oszthatóak:

  • A HTTP csatlakozás tesztelése
    • Különböző típusú socket-ek ellenőrzése (Tcp, Ssl, Local)
    • Buffer ellenőrzése
  • A HTTP, HTTPS és Local szerver ellenőrzése
  • A HTTP kérés-kezelők ellenőrzése
  • Teszteli, hogy a HTTP kéréseket helyesen készíti-e el és, hogy a válaszokat helyesen értelmezi-e
  • Teszteli a HTTP klienst (ez a legtöbb tesztesetből álló teszt)
  • és még néhány egyebet:)

Vélemények

Összességében elég sokrétűnek és kimerítőnek tűnik a tesztelés, viszont épp ezért, mert a tesztek is többezer sorosak, jó lenne, ha jobban dokumentálnák, hogy mi az egyes tesztesetek célja, hogyan működik, stb. (jelenleg egyáltalán nincs dokumentálva, ami van komment, az nem igazán segít semmit). A teszt lefutása során jó lenne egy összesítő a végére, hogy hány tesztből hány sikerült, külön felsorolni azokat, amik nem sikerültek... (kézzel scrollozgatni és nézegetni nem túl kellemes és könnyen át is lehet siklani valami felett). Ami a mintákat illeti:

  • A HTTP kérés-kezelőknél mock handler-öket használ, hogy a közös tesztekhez (van külön Fixed handler, 404 handler, stb.) ne kelljen minden leszármazott típushoz tesztesetet írni (hogy ez így mennyire megbízható, azt nem tudom).
  • A tesztek nagyrészt Four-Phase-szerű, mert az Exercise és a Verify rész néhol összemosódik, de a Qtest keretrendszer miatt van init rész (sokszor az init-ben is ellenőriz, de csak azért, hogy "tisztán" indul-e az új teszteset) és cleanup is.
  • A Qtest framework asszercióit használja ellenőrzésre (Test Assertion)
  • Assertion Message -> ez csak részben teljesül, a Qtest a meghívott metódusok nevét írja ki, azok eléggé bőbeszédűen vannak elnevezve
  • Test Method -> a Qtest framework így működik (ahogy eddig látom)