Zum Inhalt springen

Wie wir Raima Database Manager testen

Vor der Veröffentlichung von RDM wurden viele Tests und Methoden entwickelt, um ein robustes und verwendbares Produkt sicherzustellen. Dies liegt daran, dass die Stabilitäts- und Robustheitsanforderungen für eine Datenbank viel strenger sind als für viele andere Arten von Anwendungen.

Zum Beispiel ist die Haltbarkeit von äußerster Wichtigkeit. Ein Benutzer möchte niemals seine Daten verlieren, nur weil seine Anwendung aufgrund eines Softwarefehlers oder eines Hardwarefehlers abgestürzt ist. Raima tut alles in seiner Macht stehende, um die Daten zu schützen.

Auf dieser Seite erhalten Sie einen Einblick in einige der Verfahren und Methoden, die Raima befolgt, um ein robustes und gut getestetes Produkt zu erstellen.

Raima Bug Testing

Datenbankinvariante Tests

Das bei Raima entwickelte C / C ++ - QA-Framework bietet integrierte Unterstützung für invariante Tests. Ein invarianter Test ist eine spezielle Art von Test, bei dem eine festgelegte Bedingung über "einige Zeit" wahr sein sollte. Diese Bedingung wird als Invariante bezeichnet. Was "einige Zeit" bedeutet, wird später weiter erläutert. Bei einer Datenbank ist die Invariante normalerweise Informationen zu den in der Datenbank gespeicherten Daten. Die Invariante kann sehr entspannt oder sehr streng sein. Ein Beispiel für eine entspannte Invariante ist "Die Datenbank existiert". Ein Beispiel für eine strengere Invariante lautet: "Die Berechnung einer Art Hash aus allen Daten in der Datenbank sollte einen bestimmten Wert ergeben."

Die QA-Frameworks bieten spezielle Unterstützung zum Erstellen, Ausführen und Zerstören einer Datenbankinvariante. Ein Erstellungsfall für eine Datenbankinvariante erstellt die Datenbank mit einem bestimmten Schema und fügt normalerweise einige Daten ein, um eine Datenbankinvariante zu erstellen. Dieser Sonderfall wird immer vor dem oder den normalen Ausführungsfällen ausgeführt. Die normalen Lauffälle werden geschrieben, um die Invariante zu "pflegen". Was wir unter "pflegen" verstehen, wird später angegeben. Nachdem die normalen Fälle ausgeführt wurden, wird der Zerstörungsfall ausgeführt und die Invariante wird nicht mehr beibehalten. Die Zeit von der Rückkehr des Erstellungsfalls bis zum Aufruf des Zerstörungsfalls ist die "einige Zeit", in der die Invariante beibehalten wird.

Standardlauf

Bei einem Standardlauf eines invarianten QA Framework-Tests wird der Zerstörungsfall, dann der Erstellungsfall, gefolgt von den normalen Ausführungsfällen und zuletzt der Zerstörungsfall ausgeführt.

Mehrere Threads

Das QA-Framework kann angewiesen werden, die normalen Ausführungsfälle von mehreren Threads aus auszuführen. Das QA-Framework instanziiert die Threads und führt die Normalfälle parallel aus. Ein korrekt geschriebener invarianter Test und ein robustes Produkt sollten damit umgehen können.

Prozesse

Ein anderes Szenario besteht darin, den Test einmal auszuführen und das QA-Framework anzuweisen, den Zerstörungsfall am Ende nicht auszuführen. Dadurch bleibt die Datenbankinvariante intakt. Dann können wir den Test in mehreren Prozessen ausführen, in denen nur die normalen Ausführungsfälle ausgeführt werden. Ein korrekt geschriebener invarianter Test und ein robustes Produkt sollten ebenfalls in der Lage sein, damit umzugehen.

Plattformunabhängig

Ein anderes Szenario besteht darin, den Test einmal auszuführen und das QA-Framework anzuweisen, den Zerstörungsfall am Ende zu überspringen, das Datenbankabbild auf eine andere Architektur oder ein anderes Betriebssystem zu kopieren und die normalen Fälle erneut auszuführen. Ein korrekt geschriebener invarianter Test, ein robustes Produkt und ein tragbares Produkt sollten auch in der Lage sein, mit dieser Situation umzugehen.

Bildkompatibilität zwischen RDM-Versionen

Ein anderes Szenario besteht darin, den Test einmal auszuführen, das QA-Framework anzuweisen, den Zerstörungsfall am Ende zu überspringen und das Datenbank-Image für spätere Versionen zu speichern. Vor diesen späteren Versionen stellen wir die Datenbankabbilder wieder her und führen die Tests nur in den normalen Fällen erneut aus. Ein korrekt geschriebener invarianter Test, ein robustes Produkt und ein gut gewartetes Produkt sollten in der Lage sein, mit dieser Situation umzugehen.

Crashtests

Ein datenbankinvarianter Test kann verwendet werden, um sicherzustellen, dass die Datenbankwiederherstellung ordnungsgemäß funktioniert.

Es ist unpraktisch, eine Maschine aus- und wieder einzuschalten (obwohl wir das in der Vergangenheit getan haben). Stattdessen simulieren wir jetzt einen Systemabsturz, indem wir zwischen RDM und dem Betriebssystem einbinden. Dies kann durch Vorladen unter Linux erfolgen. Auf diese Weise können wir einen Systemabsturz mit verlorenen Schreibvorgängen simulieren. Das erneute Ausführen eines datenbankinvarianten Tests mit nur den normalen Testfällen sollte für einen korrekt geschriebenen Test und ein dauerhaftes Produkt erfolgreich sein.

Beschädigte Bildtests

Ein datenbankinvarianter Test kann auch verwendet werden, um zu überprüfen, ob der Test und das RDM gegenüber einer Beschädigung des Datenbankabbilds robust sind.

Verwenden Sie erneut einen datenbankinvarianten Test und führen Sie zufällige Schreibvorgänge in eine oder mehrere der Datenbankdateien durch gleichzeitig kann zu einem Fehler führen. Ein solcher Fehler ist akzeptabel. In diesem Fall muss RDM oder der Test für einen korrekt geschriebenen Test und ein robustes Produkt nicht abstürzen.

Remote-TFS gegen lokales TFS

Ein Test mit dem C / C ++ QA Framework kann auf viele Arten eine Verbindung zum Transactional File Server (TFS) herstellen. Beispielsweise kann das TFS in einen datenbankinvarianten Test eingebettet sein, der ausgeführt wird, und gleichzeitig kann eine andere Instanz desselben datenbankinvarianten Tests remote mit der ersten Instanz verbunden werden. Die zweite Instanz wird möglicherweise lokal auf demselben Computer wie die erste Instanz oder remote auf einem zweiten Computer ausgeführt. Die zweite Maschine kann dieselbe Architektur und / oder dasselbe Betriebssystem wie die erste haben oder sie kann unterschiedlich sein. Hier stehen viele Kombinationen zur Verfügung.

Überprüfen Sie die Tests

Wir haben einige Tests, die nicht ausschließlich ein datenbankinvarianter Test sind. Zu diesen Fällen gehören Tests, bei denen der Normalfall oder die Normalfälle nur einmal ausgeführt werden können. Wenn wir die normalen Fälle erneut ausführen, muss das QA-Framework angewiesen werden, nur eine "Überprüfung" durchzuführen. Eine "Überprüfung" ändert die Datenbank in keiner Weise; Es wird nur die Datenbankinvariante überprüft. Wenn das QA-Framework angewiesen wird, die Normalfälle für einen Überprüfungstest von mehreren Threads parallel auszuführen, wird eine solche Anweisung ignoriert. Es wird immer nur von einem Thread ausgeführt.

Sequenztests

Die letzte Art von datenbankinvarianten Tests sind Sequenztests. Sie sind wie datenbankinvariante Tests, außer dass die normalen Fälle nicht parallel ausgeführt werden können. Die Datenbankinvariante ist erst nach einem erfolgreichen Durchlauf aller Normalfälle gültig. Es gibt kein Versprechen, dass die Datenbankinvariante im Normalfall gültig ist werden ausgeführt.

Fuzzy-Tests

Wir führen eine Reihe von datenbankinvarianten Tests durch, wie oben beschrieben. Einer unserer wichtigsten datenbankinvarianten Tests führt viele zufällige Operationen aus. Jedes Mal, wenn die Summe von etwas festgeschrieben wird, wird die Summe auf 0 gehalten. Dieser Test kombiniert verschiedene Arten des Einfügens, Aktualisierens und Löschens mit Überprüfungsteilen. Der Test verwendet verschachtelte Startaktualisierungen und Startlesevorgänge, bei denen zufällig ein vorheriger Status wiederhergestellt wird. Zur Überprüfung werden sowohl Start-Read als auch Star-Snapshot verwendet. Dieser Test wurde nicht für den Durchsatz geschrieben, sondern um unsere Transaktions-Engine zu belasten und sicherzustellen, dass wir vollständig SÄURE sind.

Testen von Daten mit hohem Datenvolumen

Ein weiterer datenbankinvarianter Test wurde für einen hohen Durchsatz geschrieben. Der Hauptzweck besteht darin, einige Einfügungen vorzunehmen, zu überprüfen, ob die Daten vorhanden sind, und dann die eingefügten Daten zu löschen. Die Daten werden basierend auf Pseudozufallszahlen eingefügt. Das für diese Einsätze verwendete Saatgut wird ebenfalls eingefügt. Die Invariante ist, dass Daten, die diesen Samen entsprechen, existieren sollten. Der Hauptzweck dieses Tests besteht darin, einfach viele Daten zu erstellen und unsere Engine mit der Erstellung neuer Datenbankdateien zu belasten. Durch Ausführen dieses Tests auf ähnliche Weise wie bei unseren anderen Tests wird sichergestellt, dass das Rollover auf eine neue Datenbankdatei auch in Fällen funktioniert, in denen eine Wiederherstellung erforderlich ist.

Replikationstests

Datenbankinvariante Tests, einschließlich Verifikationstests und Sequenztests, können zum Testen der Einwegreplikation verwendet werden. Dies wird in Kürze zu der Testmatrix hinzugefügt, die wir vor einer Veröffentlichung ausführen.

Fazit

Datenbankinvariante Tests sind für Tests bei Raima von entscheidender Bedeutung. Ein Teil der Komplexität wird vom QS-Framework und einer Datenbankinvariante übernommen.

Sperrtest

Diese Testsuite wurde speziell für unseren Schlossmanager entwickelt. Einige Tests wurden speziell für allgemeine und einige Sonderfälle entwickelt. Andere wurden aufgrund von Fehlern in unserer SQL-Engine eingerichtet, die möglicherweise auf die Core-Engine zurückzuführen sind oder nicht.

Bei unserem verschachtelten Sperrmodell müssen wir sicherstellen, dass alle Aktualisierungen ACID sind. In Bezug auf das Sperren hat dies bestimmte Auswirkungen. Beispielsweise müssen wir bei einem Update in Kombination mit einem Lesevorgang sicherstellen, dass die Lesesperre beibehalten wird, bis das Update festgeschrieben wird, obwohl die Anwendung die Sperre freigegeben hat. Ein Test kann dies nicht über die Standard-API beobachten, ohne eine zweite Datenbankverbindung zu verwenden. Wir haben Single-Threaded-Tests, die dies bestätigen. Dies erleichtert das Reproduzieren und Auffinden von Fehlern.

Wir führen auch Lock-Fuzzy-Tests durch, indem wir über die öffentliche API zufällige Aufrufe an den Lock-Manager senden. Dies erzeugt eine enorme Anzahl von Kombinationen, die sonst nur sehr schwer zu erfassen wären. Der im Test verwendete Algorithmus zur Überprüfung der korrekten Sperrung wurde unabhängig vom Sperrmanagercode im Produkt entwickelt. Dieser Test bietet auch die Möglichkeit, Testcode für die genaue Reihenfolge der verwendeten API-Aufrufe zu schreiben. Mit diesem Test gefundene Fehler wurden unserer Reihe von Regressionstests hinzugefügt, um die Reproduzierbarkeit zu vereinfachen und den Code vor zukünftigen Änderungen zu schützen.

Memcheck-Tests

Wir verwenden Valgrind mit dem Standard-Tool-Memcheck unter Linux oder Purify unter Windows, um Probleme mit dem Softwarespeicher zu finden. Diese Tools haben sich bei der Suche nach vielen Arten von Fehlern als wertvoll erwiesen.

Die in RDM verwendeten Standardzuweiser verwenden jedoch nicht die C-Bibliothekszuweiser wie malloc, calloc, realloc und free. Wir verwenden stattdessen unsere eigenen Allokatoren, bei denen der Speicher in größeren Blöcken vom Betriebssystem abgerufen oder über die öffentliche RDM-API bereitgestellt wird. Diese Tools sind daher nicht sehr nützlich, um Speicherprobleme zu finden, wenn sie mit unseren Standardspeicherzuordnungen verwendet werden.

Um dies zu beheben, haben wir eine alternative Implementierung zu unseren Standardspeicherzuordnungen, die die oben genannten C-Bibliotheksfunktionen verwendet. Diese Implementierung in Kombination mit Valgrind oder Purify wird verwendet, um Probleme mit dem Softwarespeicher zu finden. Die vollständige Ausführung unserer Standardtests für C und C ++ mit diesem Ansatz dauert mehrere Tage.

Datenbanktests Raima-Testsoftware, die alle Geräte testet, findet Fehler und Tester

Simulation eines Speicherzuordnungsfehlers

Wie im vorherigen Abschnitt erläutert, können unsere Speicherzuordnungen ausgeschaltet werden. Dies kann mithilfe von Präprozessordefinitionen zur Kompilierungszeit oder durch Vorladen der Laufzeitbibliothek unter Linux erfolgen. Im folgenden Abschnitt beschreiben wir eine dritte Implementierung für unsere Standardspeicherzuordnungen.

Diese Implementierung verwendet auch malloc und free sowie einige zusätzliche Header-Daten für jede Zuordnung, um falsche Verwendungen unserer Standard-Speicherzuweisungs-API zu erkennen. Mit einigen Instrumenten aus dem C / C ++ QA Framework können auch Speicherzuordnungsfehler simuliert werden. Das QA Framework überwacht die Anzahl der Speicherzuordnungen und kann diese erneut ausführen, wenn eine bestimmte Speicherzuweisung fehlschlägt. Es wird erwartet, dass solche Läufe mit eNOMEMORY fehlschlagen. Wenn dies nicht wie erwartet fehlschlägt, werden die erforderlichen Informationen gemeldet, damit das Problem leicht reproduziert werden kann.

Efence

Efence macht eine kleine Teilmenge dessen, was Memcheck kann, ist aber viel schneller. Es war etwas nützlich, um RDM auf Pufferüberlauf zu testen bei Tests, die länger dauern.

Regressionstests

Wenn wir einen Fehler haben, der mit einem Test reproduziert werden kann, wird er als Regressionstest zu einer unserer Testsuiten hinzugefügt. Die überwiegende Mehrheit der Fehler kann leicht reproduziert werden. Eine Klasse von Fehlern, die schwer zu reproduzieren ist, sind solche, an denen mehrere Threads beteiligt sind. In Anbetracht dessen gibt es viele Tests, die standardmäßig parallel zu mehreren Instanzen von sich selbst oder parallel zu anderen Tests innerhalb einer Suite ausgeführt werden können.

Code-Abdeckung

Wir kompilieren unseren Quellcode mit gcc mit Optionen zur Erstellung der Codeabdeckung. Dann verwenden wir gcov, lcov und genhtml, um etwas zu produzieren, das visualisiert werden kann.

Helgrind-Test

Wir verwenden Valgrind mit dem Tool Helgrind, um RDM auf Thread-Sicherheit zu testen. Bibliotheken, die von Natur aus nicht wiedereintrittsfähig sind, verwenden Mutexe, um gemeinsam genutzte Datenstrukturen zu schützen. Helgrind kann Orte finden, an denen Datenstrukturen nicht ordnungsgemäß geschützt sind. Dies erfordert jedoch Tests, bei denen mehrere Threads für einige gemeinsam genutzte Datenstrukturen verwendet werden.

Unsere zuvor diskutierten datenbankinvarianten Tests sind gute Kandidaten für diese Art von Tests, da das QA-Framework mehrere Instanzen des Tests parallel ausführen kann. Andere Arten von Tests können auch parallel ausgeführt werden. Bei diesen Tests werden jedoch separate Datenbanken verwendet, wodurch Datenstrukturen, die von Datenbanken gemeinsam genutzt werden, auf Thread-Sicherheit getestet werden.

Das Schreiben von Programmen für Parallelität ist schwierig. Sie möchten keinen Mutex verwenden, es sei denn, er wird für die Richtigkeit benötigt. Die Verwendung von Mutexen wirkt sich auf die Leistung aus. Um die Auswirkungen von Mutexen auf die Leistung zu minimieren, haben wir Algorithmen verwendet, die in bestimmten Bereichen keinen Semaphorschutz für bestimmte gemeinsam genutzte Datenstrukturen erfordern. Diese Algorithmen wurden sorgfältig entwickelt, um die Richtigkeit zu gewährleisten, und wir haben im Quellcode für Helgrind eine spezielle Dekoration verwendet, um Warnungen zu unterdrücken. Eine solche Dekoration ist auch nützlich als Dokumentation und beim Debuggen des Codes.

Wiedereintrittstests

Die meisten unserer Bibliotheken sind so konzipiert, dass sie wiedereintrittsfähig sind. Abgesehen von der Verwendung von Funktionen in anderen Bibliotheken ist alles, was in der Bibliothek enthalten ist, vollständig wiedereintrittsfähig. Dies bedeutet, dass zwei Anrufer Funktionen in der Bibliothek nutzen können, ohne dass das Risiko von Rennbedingungen und Informationsverlust von einem Anrufer zu einem anderen Anrufer besteht, solange die Programmsteuerung nicht in eine andere Bibliothek geht, die nicht wiedereintrittsfähig ist. Beide verwenden separate Handles. und es gibt keine Pufferüberläufe. Diese Art von Design erleichtert das Nachdenken über die Richtigkeit.

Bei sorgfältiger Planung kann dies leicht durchgesetzt werden, indem die kompilierten Bibliotheken auf Konformität analysiert werden. Wir haben dafür automatisierte Tests durchgeführt, die alle unsere Bibliotheken analysieren, auch diejenigen, die nicht wiedereintrittsfähig sind. Der Test wird bei allen neuen Hinzufügungen von Verstößen ausgelöst. Unsere Dokumentation enthält Informationen zur Konformität für jede Bibliothek.

Behaupten

Wir verwenden Asserts in unserem gesamten Quellcode. Eine Zusicherung ist eine Aussage an einem bestimmten Punkt im Code, die immer wahr sein sollte. Die ordnungsgemäße Verwendung von Asserts erfordert ein sorgfältiges Design. Zum Beispiel müssen Asserts auch im Falle einer Fehlerbedingung gelten.

Zusicherungen sind nicht für die Behandlung von Bitfehlern im CPU-Cache oder im RAM ausgelegt. Für den Dateizugriff muss jedoch davon ausgegangen werden, dass Bitfehler auftreten können. Tatsächlich kann im allgemeinen Fall jede Art von Festplattenbeschädigung auftreten, und die Engine muss robust genug sein, um damit umzugehen. Jede Entscheidung, die auf dem Lesen von Inhalten basiert, muss validiert werden oder die Engine muss robust genug sein, um nicht abzustürzen oder in eine Endlosschleife zu geraten. Wenn der Fehler in den Benutzerdaten aufgetreten ist, gibt das Datenbankmodul möglicherweise unvollständige oder falsche Daten zurück. Wenn andererseits ein Fehler in Metadaten aufgetreten ist, kann die Engine dies feststellen. In diesem Fall wird der Fehler an den Benutzer zurückgemeldet.

Es ist konzeptionell sinnvoll anzunehmen, dass es keine Festplattenbeschädigung geben kann, aber jede Behauptung, die auf einer solchen Annahme basiert, muss speziell behandelt werden. In einer Produktionsumgebung muss ein Fehler an den Benutzer zurückgemeldet werden. Während des Testens möchten wir möglicherweise abhängig von der Art des Tests, den wir durchführen, eine Aussage treffen. Wir verwenden hierfür einen separaten Assert-Typ, der so definiert werden kann, dass er sich auf die eine oder andere Weise verhält. Auf diese Weise können wir Tests ausführen, bei denen Korruption simuliert wird, und Tests, bei denen angenommen wird, dass keine Korruption auftritt.

Ein etwas anderer Fall ist die Behandlung eines Absturzes der Datenbank-Engine. Dies ist ein Szenario, das viel wahrscheinlicher ist als eine allgemeine Festplattenbeschädigung. Für diesen Fall wird noch eine andere Art der Behauptung verwendet.

Diese speziellen Zusicherungen ermöglichen es uns, Tests mit unterschiedlichen Annahmen durchzuführen. Dies hat sich in Kombination mit der Simulation verschiedener Arten von Fehlern als hilfreich erwiesen, um Fehler zu finden und zu beheben.

Tragbarer Code

Ein wichtiger Teil des Software-Designs besteht darin, sicherzustellen, dass der Code portabel ist. Wir vermeiden daher bestimmte C-Funktionen, die nicht portierbar sind. Wir stellen auch sicher, dass die von uns verwendeten Dateiformate portabel sind. Dies wird sichergestellt, indem unsere Tests auf einer Vielzahl von Plattformen ausgeführt werden, einschließlich tatsächlicher Hardwareplattformen und simulierter Plattformen. Wir verwenden Plattformen mit unterschiedlichen Bytereihenfolgen und Ausrichtungen, wobei char standardmäßig nicht signiert und signiert ist, um nur einige zu nennen.

Statische Analyse

Wir verwenden PC-Lint und FlexeLint für die statische Analyse. Diese Tools haben wertvolle Erkenntnisse für die Suche nach Fehlern geliefert. Wir müssen jedoch vorsichtig sein, da bestimmte Arten des Umschreibens des Quellcodes leicht Fehler verbergen oder einführen können. Wir verwenden diese Tools daher, wenn bestimmte Warnungen global ignoriert werden, und für andere Warnungen dekorieren wir den Quellcode, um sie an bestimmten Stellen zu unterdrücken. Weitere Informationen finden Sie im Abschnitt zum Testen von Memchecks.

Usability-Tests

Ein Teil des QS-Prozesses besteht auch darin, sicherzustellen, dass unsere Schnittstellen fehlerfrei sind. Dazu gehört, dass die Schnittstelle und die Implementierung klar voneinander getrennt sind. Es enthält auch Namenskonventionen, die Reihenfolge der Argumente, die Sicherstellung, dass sie vollständig sind. Sonderfälle sind nicht schwieriger als einfache Fälle und im Allgemeinen einfach zu verwenden.

Die APIs, die wir für RDM entwickelt haben, haben einen strengen Prozess durchlaufen, um sicherzustellen, dass wir die Industriestandards erfüllen. Die öffentlichen Header-Dateien enthalten auch die DoxyGen-Dokumentation. Wir finden, dass es einfacher ist, die Dokumentation auf dem neuesten Stand zu halten, wenn sie mit dem Code zusammenpasst.

Wir bieten einige kleinere Tests an, um kleine Tests zu kompilieren, die nur eine öffentliche RDM-Headerdatei enthalten. Diese Kompilierung ist erforderlich, um ohne Fehler oder Warnungen erfolgreich zu sein. Dies wird mit der Kombination von zwei beliebigen Header-Dateien wiederholt. Dies geschieht sowohl für C als auch für C ++ Header-Dateien.

Deadlock-Test

Normalerweise ist es erforderlich, dass ein System nicht blockiert. RDM wurde jedoch mit einer API entwickelt, mit der der Benutzer Sperren explizit anfordern kann. Mit einer solchen API ist es möglich, eine Anwendung zu schreiben, deren Deadlock garantiert ist. Wir haben daher Tests, die beim Ausführen absichtlich blockieren. Diese Tests werden nicht standardmäßig ausgeführt. Sie müssen in einer speziellen Umgebung ausgeführt werden, in der wir beobachten können, dass sie tatsächlich blockieren und fehlschlagen, wenn dies nicht der Fall ist.

Leistungstest

Die Leistung ist ein wichtiger Aspekt jeder Computersoftware, insbesondere aber für eine Datenbank. Wir messen drei Hauptfiguren. CPU-Auslastung, Festplatten-E / A und Speichernutzung.

Raima Database Manager Hochleistungstests

CPU-Lasttest

Für die CPU-Auslastung haben wir eine Reihe von Leistungstests. Das C / C ++ QA Framework unterstützt das Instanziieren von Stoppuhren, mit denen die Leistung bestimmter API-Aufrufe bequem gemessen werden kann. Wenn wir diese in vorhandenen Tests verwenden, können wir Zahlen erhalten, um zu messen, wie es uns im Vergleich zu früheren Versionen unseres Produkts geht.

Wir haben auch Leistungstests, die unser QS-Framework nicht verwenden und speziell für Kundenfälle entwickelt wurden, die RDM mit anderen Datenbanken vergleichen können.

Wir arbeiten an Verbesserungen in diesem Bereich.

Festplatten-E / A-Tests

Mit RDM 14.1 haben wir die Art und Weise, wie Daten auf die Festplatte geschrieben werden, drastisch geändert. RDM wird in einem Modus ausgeführt, in dem das Schreiben von Festplatten minimiert ist, und kann mit minimaler Festplatten-E / A Einfügungen, Aktualisierungen und Löschvorgänge ausführen. Die Kompromisse hier sind eine längere Zeit zum Öffnen der Datenbank und eine längere Zeit für die Wiederherstellung nach einem Absturz.

Das Testen der Festplatten-E / A erfolgt mithilfe einiger unserer allgemeinen Tests, indem Code vorgeladen wird, der bestimmte Betriebssystemaufrufe abfängt und Statistiken sammelt. Dies ähnelt den zuvor beschriebenen Crashtests.

Ein Vorteil dieses Ansatzes besteht darin, dass die von uns verwendete Bibliothek für jede Anwendung verwendet werden kann, ohne dass der Code neu kompiliert werden muss. Es gibt Tools unter Linux, die ähnliche Ansätze haben, aber wir haben festgestellt, dass dieser Ansatz oft besser ist. Dadurch können wir bestimmte Schreibmuster erkennen, nach denen wir suchen, und wir können besser verstehen, wie sich unterschiedliche Anwendungsfälle auf die Festplatten-E / A auswirken. Zum Beispiel ist es wichtig, dass Dateien nur dann synchronisiert werden, wenn sie synchronisiert werden sollen, und dass wir keine unnötigen Synchronisierungen oder Schreibvorgänge haben.

Ein weiterer Aspekt der Festplatten-E / A ist die Leistung des Dateisystem-Cache. Wenn möglich, sollten Daten, auf die wahrscheinlich erneut zugegriffen wird, zusammen gruppiert werden, und Daten, auf die nicht erneut zugegriffen werden sollte, sollten ebenfalls zusammengefasst werden. Auf diese Weise ist es weniger wahrscheinlich, dass der Dateisystem-Cache den Inhalt zwischenspeichert, auf den wahrscheinlich nicht erneut zugegriffen wird. Für Dateien, von denen wir wissen, dass sie von der Engine nur für bestimmte katastrophale Fehler benötigt werden, verwenden wir posix_fadvise, um den Kernel anzuweisen, die Seite zu löschen oder aus dem Dateisystem-Cache zu entfernen. Dass dies korrekt durchgeführt wird, kann auch durch Abfangen dieses Betriebssystemaufrufs überprüft werden.

Testen der Speichernutzung

Wir haben Tests, die die öffentliche API auf bestimmte Weise aufrufen, die die Speichernutzung nicht beeinflussen sollten. Wenn Sie beispielsweise eine bestimmte Funktion wiederholt mit denselben Argumenten aufrufen, sollte dies die Speichernutzung nicht erhöhen. Diese Tests schlagen fehl, wenn festgestellt wird, dass die Speichernutzung zunimmt. Bei jedem Test mit dem C / C ++ QA Framework wird die Speichernutzung im Produkt unmittelbar vor der Beendigung gemeldet.

In RDM sind auch Tools und andere Mechanismen integriert, die die Speichernutzung überwachen. Diese Mechanismen können einen besseren Einblick in das Verhalten jedes Subsystems geben. Valgrind verfügt über ein Tool namens Cachegrind, mit dem Sie die Cache-Leistung und die Verzweigungsvorhersage Ihres Codes analysieren können.

QS-Frameworks

Wir haben vier verschiedene QA-Frameworks im eigenen Haus entwickelt. Die für C / C ++ geschriebene ist die umfassendste. Darüber hinaus gibt es solche, die in Perl, Bash und Java geschrieben sind. Sie alle haben einige Gemeinsamkeiten, was es unserem Team leicht macht, zwischen ihnen zu wechseln.

Perl QA Framework

Dies ist eine spätere Ergänzung unserer Suite von QS-Frameworks. Der Hauptzweck besteht darin, RDM-Befehlszeilentools zu testen. Es unterstützt das Einspeisen von Eingaben in die Werkzeuge und kann die Ausgabe mit den erwarteten Ergebnissen vergleichen oder die Ausgabe für bestimmte Muster überprüfen. Es läuft sowohl unter Unix als auch unter Windows. Viele Tests, die zuvor Teil des Bash QA Framework waren, wurden neu geschrieben, um das Perl QA Framework zu verwenden. Auf diese Weise können wir diese Tests sowohl unter Unix als auch unter Windows ausführen. Mit diesem Framework wird viel SQL-PL getestet.

C / C ++ QA Framework

Die meisten unserer C / C ++ - Tests werden mit diesem Framework geschrieben. Es hat am meisten umfassend Reihe von Funktionen. Einzelheiten finden Sie im obigen Abschnitt über invariante Tests.

Kontinuierliche Integration

Unser Build-System kann Make-Dateien und Projektdateien für verschiedene Zielplattformen generieren. Außerdem werden Shell-Skripte und Batch-Dateien generiert, mit denen alle oder ein Teil unserer Tests in verschiedenen Konfigurationen ausgeführt werden können. Dies wird in unserer kontinuierlichen Integration stark genutzt. Es macht es Entwicklern auch einfach, dieselben Tests manuell auszuführen.