Herzlich willkommen auf dem Blog der exensio GmbH

exensio ist ein unabhängiges Software-Unternehmen von erfahrenen IT Beratern und Architekten. Zu unseren Kunden zählen namhafte deutsche Großunternehmen.

exensio verbessert das Kommunikations- und Informationsmanagement von Unternehmen. Auf Basis sinnvoller und zweckmäßiger Technologien erarbeiten wir flexible und übergreifende Lösungen für webbasierte Informationssysteme. Abhängig von den Kundenanforderungen realisieren wir Web Applikationen sowie Lösungen auf Basis von Web Content Management- und Portalsystemen. Integrativ, wirtschaftlich und anwenderfreundlich!

Hier gelangen Sie zur exensio GmbH.

Freitag, 17. Oktober 2014

Elasticsearch und IoT

Beim Search Meetup Karlsruhe mit dem Thema "Elasticsearch Performance in a Nutshell" durfte ich neben dem Hauptvortrag von Patrick Peschlow Anwendungsszenarien zu "Elasticsearch und IoT" vorstellen.



Weitere Detail-Informationen können in der Blogpost-Reihe "Szenarien für den Einsatz von IoT und BigData" gefunden werden:

Mittwoch, 15. Oktober 2014

Big Data Expertenrunde bei Dr. Hornecker in Freiburg

Letzten Mittwoch hatte ich die Gelegenheit, bei Dr. Hornecker Software-Entwicklung und IT-Dienstleistungen über Elasticsearch im Kontext von Big Data zu referieren.

Hierbei habe ich die Vorteile von Elasticsearch und NoSQL aufgezeigt. In diesem Zusammenhang möchte ich darauf hinweisen, dass man bereits mit kleinen (strukturierten bzw. unstrukturierten) Datenmengen sinnvolle Anwendungen realisieren kann, die mit der gealterten SQL-Technologie nicht so einfach - wenn überhaupt - umsetzbar sind.



Des Weiteren habe ich folgende Einsatzszenarien für Elasticsearch skizziert:

  • NoSQL Document Store (JSON)
    • Bigdata mittels Sharding
    • Keine Transkationen im Vergleich zu MongoDB
  • Query Engine für strukturierte Daten
    • Daten werden in SQL DB gespeichert
    • Abfragen laufen über Elasticsearch
    • Vereinfachung von komplexen SQL Queries (insb. bei hierarchischen Abfragen)
  • Volltextsuche bzw. Facettierte Suche 
    • Wissensportale
    • Suche in strukturierten (Datenbanken, CRM, ERP, …) sowie unstrukturierten Daten (Content, Dokumente)
  • Geo-Suche (viel einfacher als bei Oracle DB)
    • PLZ-Umkreissuche (Filialen)
    • Flottenmanagement
    • Logistik
  • Logfile-Analyse
    • IT-Forensik
    • Sortimentslücken entdecken
  • Business Analytics (schneller und kostengünstiger vgl. mit DW)
    • Competitive Intelligence (Search Engine sehr gut geeignet, wenn Mapping über eindeutige Id wie EAN Code nicht möglich)
    • Datawarehouse (Aggregationen ersetzen Dimensionen im Star-Schema)
  • Alerts (Percolator -> indiziertes Dokument passt zu gespeicherter Query)
    • News Alerts
    • Internet Of Things (Alarm bspw. Temperatur steigt über Schwellwert)
    • Preis-Monitor
    • Online-Werbung 
Die weiteren Vorträge kamen von Dr. Michael Jachan (Brain Products) über die Grundlagen maschinellen Lernens. Und Dr. Achim Hornecker ergänzte die Runde mit dem dritten Vortrag. Er skizzierte die Entwicklung, die sich in den vergangenen Monaten ausgehend von Hadoop hin zur interaktiven Verarbeitung von großen Datenmengen bis zu Echtzeitanwendungen getan hat.

Weitere Infos auf der Homepage von Dr. Hornecker.

Dienstag, 7. Oktober 2014

Competitive Intelligence mit Elasticsearch und Kapow

In diesem Blog-Post möchte ich über ein interessantes Vorhaben - in das wir aktuell mit einer Machbarkeitsstudie involviert sind - eines bekannten deutschen Handelskonzerns berichten. In aller Kürze: Es handelt sich um die Analyse von Online-Webshops des Wettbewerbs. Ich habe - auch weil ich gerne Wein trinke :-) - für den Blog-Post als Beispiel die Konkurrenz-Beobachtung von Online-Wein-Händlern herangezogen.

Für dieses Szenario  gilt, dass die zu vergleichenden Produkte nicht über einen eindeutigen Kenner, wie bspw. den Barcode (EAN / GTIN) verglichen werden können. Dies ist der Grund, dass das Matching über eine Suchmaschine erfolgt. Das Fehlen eines unverkennbaren Identifikators wie bei Wein ist auch bei Tee oder Kaffee gegeben. Die Betrachtung von elektronischen Geräten kann hingegen fast ausschließlich mittels EAN-Code erfolgen.



Was ist Competitive Intelligence genau genommen?

In Wikipedia findet sich eine besonders brauchbare Erklärung hierfür. Bedeutsam ist hierbei die Abgrenzung von Competitive Intelligence (CI) zu Business Intelligence (BI) inklusive des Vergleichs von strukturierten (BI) zu unstrukturierten Informationen (CI). Für die Speicherung von unstrukturierten Daten bietet sich hier vorzüglich NoSQL bzw. Elasticsearch [1] - wie in unserem Fall - an.

Auszug aus Wikipedia-Artikel [2]:
»Die Begriffe Competitive Intelligence und Business Intelligence sind zwei unterschiedliche Ansätze, die sich ergänzen. Während Competitive Intelligence überwiegend Daten über Unternehmen analysiert, die außerhalb eines Unternehmens zu finden sind, befasst sich Business Intelligence fast ausschließlich mit der Auswertung firmeninterner Daten. Competitive Intelligence nutzt auch die internen Daten eines Unternehmens, wie etwa Zahlen aus dem Jahresabschluss, die der breiten Öffentlichkeit zur Verfügung gestellt werden. Es bedient sich jedoch überwiegend der unstrukturierten Daten aus dem Internet, oder anderer öffentlicher Informationsquellen. Business Intelligence wiederum basiert fast ausschließlich auf Zahlen aus dem Unternehmen und weniger auf unstrukturierten Daten. Es gibt Bestrebungen auch hier mehr Daten von außerhalb des Unternehmens einzubinden und durch die Einbettung von unstrukturierten Daten, sei es aus dem Unternehmen, oder von außerhalb des Unternehmens, den Zahlen einen Kontext zu verschaffen, kausale Erklärungen für bestimmte Kennzahlen anzubieten.«

Web-Crawling mit Kapow

Es gibt unzählige Tools, die für das Web-Crawling benutzt werden können. Kapow [3] besticht hier vor
allem mit seiner intuitiven Oberfläche, die mit einer kurzen Einarbeitungszeit rasch - für die Umsetzung von Robots - angewendet werden kann. Zusätzlich unterstützt Kapow, im Vergleich zu alternativen Produkten, besonders effektiv JavaScript. Dies ist existentiell, da heutzutage fast jede Web-Seite JavaScript verwendet. Die Workflow-Eigenschaften von Kapow sollten nicht unerwähnt bleiben. Von Projekt zu Projekt muss dann entschieden werden, ob Kapow auch im Bereich Workflow einsetzbar ist. Ein weiterer bedeutender Punkt ist die Normalisierung der Daten. So heißt es „Weißwein“ in einem Shop und in einem anderen „Weisswein“. Mit Kapow ist es – vergleichbar mit einem ETL-Tool von einem Data-Warehouse – machbar, die Daten über die einzelnen Shops hinweg zu normalisieren. Als zusätzliches Beispiel könnte man die Vereinheitlichung von Bewertungen aufführen, die in einem Shop mit 5 Sternen und in einem anderen mit Prozentzahlen angegeben werden.

Warum eine Suchmaschine - wie Elasticsearch - verwenden?

Für den Vergleich von Preisen über unterschiedliche Shops hinweg ist eine eindeutige Kennung notwendig. Hierzu wird bspw. der EAN / GTIN Code benutzt. Die einzelnen Wein-Shops benutzen in unserem Fall allerdings proprietäre Kundennummern. Unter Zuhilfenahme einer Suchmaschine ist es jedoch machbar, die Artikel anhand ihres Artikelnamens - der während der Indizierung eine Trennung der Wörter durchführt - zu finden. Des Weiteren bietet eine Suchmaschine die Möglichkeit, eine Facettierte Suche – wie von Amazon bekannt – bereitzustellen. Eine Facettierte Suche mit blankem SQL aufzubauen ist ein äußerst aufwändiges Unterfangen, da SQL nicht für hierarchische Abfragen entwickelt wurde. Zusätzlich kann eine Suchmaschine wie Elasticsearch auch ausgesprochen umfangreiche Datenmengen (Big Data) verwalten. Auch sollte hierbei nicht vergessen werden, dass dieser Lösungsansatz das Projektbudget im Vergleich zu einer reinen Business-Intelligence-Lösung weniger belastet.

Facettierte Suche

Im nebenstehnden Bild sieht man auf der linken Seite die facettierte Suche. Mit dieser besteht die Möglichkeit
Weine auf Shop-Ebene, Kategorie, Herkunftsland, Anbauregion, Winzer, Preise usw. zu filtern. Zusätzlich ist es denkbar, eine Volltext-Suche bzw. eine Fuzzy-Suche abzusetzen. Mit der Fuzzy-Suche kann man Informationen zu Weinen zu finden, bei denen bspw. der Weinname oder das Weingut falsch geschrieben wurden.

Analysen

Es können verschiedene Analysen durchgeführt werden. Das Beispiel rechts zeigt die Möglichkeit, ein Weingut zu suchen, um zu sehen, bei welchen weiteren Shops dieses zu finden ist. Es werden auch die Weine angezeigt, die ein Shop von einem Weingut führt. Dies kann bspw. interessant sein, wenn ein frischer Katalog geplant wird und man
nicht dieselben Weingüter wie die Konkurrenz führen möchte.

Das Bild rechts veranschaulicht, wie eine grafische Auswertung aussehen könnte. Hierbei wird der prozentuale Anteil von Weinen, die ein
Shop pro Land führt, angezeigt. Diese Grafiken könnten auch für weitere Informationen, wie Visualisierung von Preisspannen etc. dienen. In unserm Fall lässt der Screenshot erkennen, dass  dass bspw. ein Shop (grüner Balken) die meisten deutschen Weine führt. Ein anderer hingegen auf Weine aus Frankreich und Italien führt.

Preisvergleich

Wie oben erwähnt können wir die Preise der unterschiedlichen Shops nicht mit einem eindeutigen Kenner, wie den Barcode (EAN - Code) identifizieren. Hier kommt Elasticsearch ins Spiel. Über ein Groovy-Script werden alle Weine des Ausgangs-Shops mit denen des Wettbewerbs verglichen. Die Ergebnisse dienen zum Aufbau des Preisvergleichs-Index. Des Weiteren haben wir noch das Scoring getuned, z.B. Preise, die um mehr als 50% divergieren, werden ans Ende der Liste gestellt. Schaut man sich das Ergebnis an, so erhält man ein valides Matching von ca. 80% an Weinen, die beim Mitbewerb günstiger bzw. teurer sind. 100% sind nicht zu erreichen, da wir in unserem Fall keinen eindeutigen Kenner haben.

Fazit

Für die Begutachtung werden die Inhalte der Konkurrenz-Web-Seiten in eine Datenbank geladen und im selben Schritt gleichzeitig bereinigt. Für die Analyse wird eine Suchmaschine benutzt, die das Problem eines über alle Web-Shops nicht vorhanden EAN (Barcodes) löst.
Für die Analyse stehen vielfältige Möglichkeiten zur Verfügung:
  • Facettierte Filterung (analog zu Amazon) und Volltextsuche
  • Analysen der Weingüter, Preisspannen, Preisvergleich, Sortimentsverteilung, etc. eines Shops im Vergleich zum Wettbewerb
  • Graphische Darstellungen, bspw. Verteilung der Länder des Sortiments auf die einzelnen Web-Shops, etc.
Neben Elasticsearch wurde für das Analysefrontend Twitter-Bootstrap und AngularJS verwendet.

Links:

[1] http://www.elasticsearch.org http://www.elasticsearch.com
[2] http://de.wikipedia.org/wiki/Competitive_Intelligence
[3] http://www.kapowsoftware.com/de/

Montag, 6. Oktober 2014

Automatische Tests des User Interface einer Web Applikation: Se Builder automatisieren (Teil 6)

Diese 6-teilige Blogpost-Reihe befasst sich mit dem Thema Test-Automatisierung für grafische Benutzeroberflächen von Webanwendungen. Im Wesentlichen kommt die Selenium Test Tool Suite zum Einsatz. Im Speziellen wird der Umgang mit dem Tool Se Builder erklärt, mit dem Tests aufgenommen und abgespielt werden können.

Der ersten Teil [1] gab eine kurze Einführung zum Tool Selenium Builder, die Installation sowie einen Vergleich des Tools mit der Selenium IDE. Im zweiten Teil [2] haben wir das Selenium JSON-Format untersucht und eine Test-Suite erstellt. Im dritten und vierten Teil [3][4] habe ich Einblicke in meine Arbeit gegeben und versucht, Fallstricke aufzuzeigen.

Im letzten Teil dieser Reihe will ich demonstrieren, wie man Testläufe im CI Server Jenkinks mit Selenium Grid automatisieren kann.

Beschreibung Testumgebung

Uns steht ein Selenium Grid mit einem Hub und 4 Nodes zur Verfügung. Beim Hub handelt es sich gleichzeitig um unseren Jenkins Master, er hat ein Linux Betriebssystem und dient in unserem Fall nur zur Verteilung der Jobs. Die Nodes laufen unter Windows Vista bzw. Windows 7. Es handelt sich um VMs von modern.ie, jeweils mit einer unterschiedlichen Version des Internet Explorers. Die vier VMs haben die Namen exensiovistaie7, exensiowin7ie8, exensiowin7ie9 und exensiowin7ie10. Bei der zu testenden Applikation handelt es sich um unser Claret Portal. Die Testumgebung ist nur in unserem Intranet verfügbar. Alle VMs sind wie im Teil 5 dieser Blogpost Serie beschrieben vorbereitet. Das bedeutet, alle VMs:
  • sind gestartet
  • es ist unser Standardbenutzer eingeloggt
  • alle Programme im Autostart Verzeichnis des Standardbenutzer wurden ausgeführt
    • Insbesondere also Selenium Grid (mit der Rolle Node)
    • VNC Server
  • haben vorbereitete Einstellungen für den Internet Explorer (identische Sicherheitseinstellungen, Updates deaktiviert, etc.)

Anforderungen

Ich gehe davon aus, dass Testfälle in den meisten Fällen mit dem Selenium Builder aufgezeichnet werden. Danach wird manuell geprüft, ob die so erstellen Testfälle lokal und remote wie erwartet durchlaufen. Laufen die Testfälle stabil, können sie Jenkins übergeben werden. Mit dieser Anforderung werden direkt die mit Selenium Builder erstellen JSON Dateien zum Test herangezogen. Die Anforderung hat den Vorteil, dass kein Export der JSON Dateien erforderlich ist. Möchte man stattdessen z. B. mit Java/JUnit testen, wäre eine Konvertierung des JSON Skripts notwendig. Die erforderliche Export-Funktion bringt Selenium Builder bereits mit. Folgende Exporte sind möglich:
Aktuell sind noch nicht alle Funktionen des Selenium Builders in die Export-Funktion eingebaut. Dadurch kommt es häufig zu Einschränkungen beim Export. Ein relativ simples JSON Skript für den Logout vom Claret Portal führt beispielsweise dazu, dass einige Exportformate nicht mehr möglich sind.

Testfall

Um die Integration von Selenium Builder bzw. Grid in Jenkins zu demonstrieren, habe ich einen relativ einfachen Testfall erstellt. Er besteht aus folgenden Komponenten:
  • JSON Suite test_blogpost_teil_6_suite.json mit den Skripten
    • test_blogpost_teil_6_login.json
    • test_blogpost_teil_6_doSomething.json
      • ruft test_blogpost_teil_6.csv auf
    • test_blogpost_teil_6_logout.json
Der Testfall kann jederzeit mit dem Selenium Builder gestartet und lokal oder remote ausgeführt werden. Der Ablauf beginnt mit dem Einloggen in die zu testende Applikation. Danach wird das „doSomething“ Skript aufgerufen, welches seinerseits die CSV Datei lädt und darin befindliche Parameter einliest. In unserem Fall wird der Parameter retval eingelesen, nachdem anschließend in der Applikation gesucht wird. Am Ende des Testfalls steht der Logout aus der Applikation.

Hinweis CSV Datei: Data-Driven Testing

Selenium Builder bietet die Möglichkeit, externe Variablen einzulesen. Zu finden ist die Funktion unterhalb des Data Menüs. Die Funktion bietet sich an für datenbezogene Tests, wenn eine Reihe von Testfällen mit unterschiedlichen Variablen gefahren werden soll. Zur Verfügung stehen die folgenden Eingabeformate: JSON, XML und CSV:

Ich zeige anhand des folgenden Beipsiel-Skripts, wie auf externe Variablen zugegriffen werden kann und in welcher Form sie eingelesen werden können. Zuerst das Skript für JSON Input Data:
{
  "type": "script",
  "seleniumVersion": "2",
  "formatVersion": 2,
  "steps": [
    {
      "type": "print",
      "text": "${retval}"
    }
  ],
  "data": {
    "configs": {
      "manual": {
        "retval": "exensio"
      },
      "csv": {
        "path": "test_blogpost_teil_6_data.csv"
      }
    },
    "source": "csv"
  },
  "inputs": [
    [
      "retval",
      "string"
    ]
  ],
  "timeoutSeconds": 60
}

Die zugehörige JSON Daten-Datei sieht wie folgt aus:
[ {"retval": "exensio"}, 
  {"retval": "consulting"}, 
  {"retval": "claret"},
  {"retval": "selenium"}
]
Die externen Daten, ein eindimensionales Array, wird als Variable “retval” eingelesen. Im Selenium Builder Skript kann auf die Variable mit ${retval} zugegriffen werden. Auf dieselbe Weise kann man XML- und CSV-Daten verwenden. Die Formate sind wie folgt:
retval
exensio
consulting
claret
selenium
und
<testdata>
<test retval="exensio">
<test retval="consulting">
<test retval="claret">
<test retval="selenium">
</testdata>

Natürlich muss im Selenium Builder Skript jeweils der Dateinamen und der Wert von Source angepasst werden. In den oben gezeigten Fällen haben alle Input Data-Dateien jeweils 4 Werte bzw. Schlüssel-Wert-Paare. Je Wert wird der komplette Testfall einmal durchlaufen. Bei meinem Testfall führt dies also zu vier Durchläufen.

Hinweis WebDriver Capabilities

Das Verhalten des WebDriver (aller Klassen von WebDriver) kann über die sog. Capabilities gesteuert werden. Die wichtigsten Capabilities, speziell für den InternetExplorerDriver sind:
  • browserAttachTimeout [5]
    "Gets or sets the amount of time the driver will attempt to look for a newly launched instance of Internet Explorer."
  • enablePersistentHover [6]
    "Gets or sets a value indicating whether to enable persistently sending WM_MOUSEMOVE messages to the IE window during a mouse hover."
  • ie.forceCreateProcessApi [7]
    "Gets or sets a value indicating whether to force the use of the Windows CreateProcess API when launching Internet Explorer. The default value is false."
  • ie.usePerProcessProxy [8]
    "Gets or sets a value indicating whether to use the supplied Proxy settings on a per-process basis, not updating the system installed proxy setting. This property is only valid when setting a Proxy, where the Kind property is either Direct, System, or Manual, and is otherwise ignored. Defaults to false. "
  • ignoreZoomSetting
    -
  • handlesAlerts [9]
    "Capability name used to indicate whether the browser can handle alerts."
  • nativeEvents [10]
    "Gets or sets a value indicating whether to use native events in interacting with elements."
  • ie.ensureCleanSession [11]
    "Gets or sets a value indicating whether to clear the Internet Explorer cache before launching the browser. When set to true, clears the system cache for all instances of Internet Explorer, even those already running when the driven instance is launched. Defaults to false."
  • elementScrollBehavior [12]
    "Gets or sets the value for describing how elements are scrolled into view in the IE driver. Defaults to scrolling the element to the top of the viewport."
  • ie.browserCommandLineSwitches
    -
  • requireWindowFocus [13]
    "Gets or sets a value indicating whether to require the browser window to have focus before interacting with elements."
  • takesScreenshot [14]
    "Indicates a driver that can capture a screenshot and store it in different ways."
  • javascriptEnabled
    -
  • ignoreProtectedModeSettings
    -
  • enableElementCacheCleanup
    -
  • cssSelectorsEnabled
    -
  • unexpectedAlertBehaviour [15]
    "Determines how unhandled alerts should be handled."
Die Beeinflussung des Verhaltens des Browsers ist mit Vorsicht zu genießen. Manche Optionen sind hilfreich, andere führen zu Abstürzen. Beim Claret Portal kommt das Spring Security Framework zum Einsatz. Mit der Option ie.ensureCleanSession=true möchte ich sicherstellen, dass jeder Testlauf mit leerem Cache startet und auf diese Weise auch der erfolgreiche Login inkl. Cookie und Session getestet wird. Andererseits führte die Verwendung der Option browserAttachTimeout=<integer> zu sofortigen Abstürzen des WebDrivers.

Testaufbau

Für den automatischen Start der Testfälle in Jenkins verwende ich das Tool SeInterpreter [16] in Verbindung mit einem parametrisierten Free Style Job und einem Shell-Aufruf als Buildverfahren. Als Parameter habe ich angelegt:



Eigentlich würden schon die beiden ersten Parameter ausreichen, da ich ja jeweils nur Browser und Version steuern können möchte. Über den Parameter script gebe ich den Pfad zu meiner JSON Suite von Selenium Builder an. Denkbar wäre an der Stelle aber auch den Pfad zu einem Repository zu hinterlegen und somit tatsächliche kontinuierliche Integration zu gewährleisten.

Natürlich erlaube ich in meinem Job die Parallele Ausführung der Builds.
Als Build-Auslöser habe ich die Option "skriptgesteuert" gewählt und dafür einen Token angelegt.
Mit dieser Lösung kann ich später meinen Testfall an unseren DevJob für das Claret Portal knüpfen. Beispielsweise, nachdem das Portal erfolgreich gebaut wurde und alle Unit- und Integrations-Tests durchlaufen wurden, schließen sich die Funktionalen Tests an.
Anstatt des Shell Aufrufs als Buildverfahren wäre auch der Einsatz des Selenium Builder Plugins [17] denkbar. Die Funktionalität dürfte identisch sein.

Mit diesen Einstellungen ist der Testfall bereits vorbereitet für die parallele Ausführung. Für den WebDriver sind parallele Instanzen kein Problem. Allerdings sollte man auf die maximale Anzahl gleichzeitig ablaufender Instanzen auf einem Node achten. Dazu haben wir in Teil 5 der Blogpost Serie die Selenium Grid Nodes mit einer JSON Konfigurationsdatei gestartet.

Zur Verteilung der Testfälle bzw. für den parallelen Start mehrerer Testfälle auf unterschiedlichen Nodes lege ich mir einen weiteren Jenkins Job an, dieses Mal vom Typ Build Flow. Natürlich muss vorher das zugehörige Build Flow Plugin [18] installiert werden. Die Einstellungen dieses Jobs sind sehr simpel, einfach den Flow angeben:
Mit diesen Einstellungen starte ich bei jedem Aufruf des Jobs meinen Testfall fünf Mal parallel. Der Testfall wird mit vier unterschiedlichen Internet Explorer Versionen und einmal mit einem Firefox gestartet. Dabei wird die Firefox Instanz auf einem beliebigen Node ausgeführt. Die IE Instanzen werden parallel auf den jeweiligen Nodes ausgeführt.


Hinweis Stabilität

Die vorgestellte Lösung kann leider nicht als stabil angesehen werden. Trotz einiger Tweaks in Verbindung mit dem InternetExplorerDriver von Selenium kommt es relativ häufig vor, dass sich ein Test aufhängt. Speziell der IE8 bleibt dann scheinbar grundlos stehen bzw. der Test wird nicht sauber beendet. Selbst unter Zuhilfenahme des Build-timeout Plugins [19] gelingt es nicht, das Problem in den Griff zu bekommen. Das Build-timeout Plugin sorgt zwar dafür, dass abgebrochene Jobs auf Jenkins-Seite irgendwann gestoppt und als fehlgeschlagen markiert werden. Es führt aber nicht dazu, dass der laufende Job auf dem Node ebenfalls abgebrochen wird. Je nach Node-Einstellung (Anzahl zu akzeptierten Instanzen), nimmt der Node evtl. keine neuen Jobs mehr an. Das problematische Verhalten des InternetExplorerDrivers bzw. des Internet Explorers selbst ist bekannt. Eine mögliche Lösung könnte von Selenium-Grid-Extras [20] kommen. In dem Projekt wird eine Erweiterung für Selenium Grid entwickelt, die das aktive Beenden aller IE Instanzen auf einem Node ermöglicht. Eine genauere Untersuchung folgt hier in einem neuen Blogpost.

Links

[1] http://blog.exensio.de/2014/07/automatische-browsertests-mit-selenium.html
[2] http://blog.exensio.de/2014/08/automatische-browsertests-mit-selenium.html
[3] http://blog.exensio.de/2014/08/automatische-browsertests-mit-selenium_21.html
[4] http://blog.exensio.de/2014/09/automatische-tests-des-user-interface.html
[5] https://selenium.googlecode.com/git/docs/api/dotnet/html/P_OpenQA_Selenium_IE_InternetExplorerOptions_BrowserAttachTimeout.htm
[6] https://selenium.googlecode.com/git/docs/api/dotnet/html/P_OpenQA_Selenium_IE_InternetExplorerOptions_EnablePersistentHover.htm
[7] https://selenium.googlecode.com/git/docs/api/dotnet/html/P_OpenQA_Selenium_IE_InternetExplorerOptions_ForceCreateProcessApi.htm
[8] https://selenium.googlecode.com/git/docs/api/dotnet/html/P_OpenQA_Selenium_IE_InternetExplorerOptions_UsePerProcessProxy.htm
[9] https://selenium.googlecode.com/svn/trunk/docs/api/dotnet/html/F_OpenQA_Selenium_Remote_CapabilityType_HandlesAlerts.htm
[10] http://www.nudoq.org/#!/Packages/Selenium.WebDriver/WebDriver/InternetExplorerOptions/P/EnableNativeEvents
[11] https://selenium.googlecode.com/git/docs/api/dotnet/html/P_OpenQA_Selenium_IE_InternetExplorerOptions_EnsureCleanSession.htm
[12] https://selenium.googlecode.com/git/docs/api/dotnet/html/P_OpenQA_Selenium_IE_InternetExplorerOptions_ElementScrollBehavior.htm
[13] http://www.nudoq.org/#!/Packages/Selenium.WebDriver/WebDriver/InternetExplorerOptions/P/RequireWindowFocus
[14] https://selenium.googlecode.com/git/docs/api/java/org/openqa/selenium/TakesScreenshot.html
[15] https://stackoverflow.com/questions/12913453/how-to-handle-an-alert-with-unexpectedalertbehaviour-capability-in-selenium
[16] https://github.com/sebuilder/se-builder/tree/master/tools/seinterpreter
[17] https://wiki.jenkins-ci.org/display/JENKINS/Selenium+Builder+Plugin
[18] https://wiki.jenkins-ci.org/display/JENKINS/Build+Flow+Plugin
[19] https://wiki.jenkins-ci.org/display/JENKINS/Build-timeout+Plugin
[20] https://github.com/groupon/Selenium-Grid-Extras

Montag, 29. September 2014

Automatische Browsertests mit Selenium: Se Builder in Verbindung mit Selenium Grid (Teil 5)

Diese 6-teilige Blogpost-Reihe befasst sich mit dem Thema Test-Automatisierung für grafische Benutzeroberflächen von Webanwendungen. Im Wesentlichen kommt die Selenium Test Tool Suite zum Einsatz. Im Speziellen wird der Umgang mit dem Tool Se Builder erklärt, mit dem Tests aufgenommen und abgespielt werden können.

Der ersten Teil [1] gab eine kurze Einführung zum Tool Selenium Builder, die Installation sowie einen Vergleich des Tools mit der Selenium IDE. Im zweiten Teil [2] haben wir das Selenium JSON-Format untersucht und eine Test-Suite erstellt. Im dritten und vierten Teil [3][4] habe ich Einblicke in meine Arbeit gegeben und versucht, Fallstricke aufzuzeigen.

In diesem Teil zeige ich, wie man ein Selenium Grid einrichtet und wie man es mit dem Se Builder verwendet. Im letzten Teil wird es dann um automatisierte Tests zusammen mit dem CI Server Jenkins.

Warum Selenium Grid?

Mit Selenium Grid lassen sich Testläufe auf unterschiedlichen Maschinen mit verschiedenen Browsern parallel ausführen. Im Wesentlichen ermöglicht Selenium Grid die verteilte Ausführung von Testläufen. Es erlaubt die Ausführung der Testläufe in einer verteilten Testumgebung. Laut Dokumentation und Kommentare der Entwickler [5], sprechen die folgenden beiden Gründe für den Einsatz von Selenium Grid:
  • Bei Testfällen mit unterschiedlichen Browsern, unterschiedlichen Betriebssystemen und parallelen Testläufen
  • Um Zeit bei der Abarbeitung der Testläufe zu sparen
Obwohl Claretportal natürlich ein Multiuser-System ist und problemlos mehrere User-Interaktionen gleichzeitig bedienen kann, beschränken wir uns bei den Testläufen auf einzelne Testszenarien. Es kommen keine parallelen Testläufe zur Anwendung. Trotzdem haben wir uns für Selenium Grid entschieden, und zwar aus den folgenden Gründen:
  • Selenium Grid im Zusammenspiel mit dem CI Server Jenkins
    Das Grid kann sehr einfach über ein PlugIn des Continous Integration Servers Jenkins in unsere bestehende Systeme eingebunden werden.
  • Unterschiedliche Browser
    Wir müssen die Kompatibilität zum Internet Explorer 8 (IE8) sicherstellen. Gleichzeitig entwickeln wir aber unter Chrome. Und natürlich wollen wir die Unterstützung moderner Browser gewährleisten. Selenium Grid bietet dafür eine große Flexibilität.

Wie funktioniert Selenium Grid?

Ich beziehe mich hier nur auf die Version 2.x von Selenium Grid, oft auch als Grid 2 oder Grid 2.0 bezeichnet. Selenium Grid verwendet ein Hub-Node-Konzept. Der Hub weiß, welche Nodes mit welchen Eigenschaften ihm zur Verfügung stehen und steuert entsprechend alle Testläufe. Als Anwender interagiert man einzig mit dem Hub.
Den Nodes wird beim Start per Parameter oder besser per JSON Konfigurationsdatei mitgeteilt, welche Eigenschaften sie anbieten können. Beispielsweise kann man einen Node starten und ihm mitteilen, er dürfe eine IE8 Instanz anbieten. Der Node meldet sich dann bei seinem Hub mit dieser Information an. Sobald der Hub eine Anfrage für einen Testlauf unter IE8 erhält, prüft er, ob er einen Node mit dieser Eigenschaft kennt und ob der Node zur Zeit zur Verfügung steht (also angemeldet und frei ist). Treffen die Kriterien zu, wird der Testlauf vom Hub angenommen und an den entsprechenden Node weiterdelegiert. Dem Node werden dann alle benötigten Informationen weitergereicht [6].

Selenium Grid Hub Installation und Konfiguration

Ich möchte hier zwei mögliche Arten der Installation zeigen. Zum einen gibt es auf der Webseite des SeleniumHQ die Standalone Variante von Selenium Grid zum Download. Damit kann man sich sein eigenes Grid, bestehend aus Nodes und Hub, einrichten und betreiben. Zum anderen gibt es das Plugin für Jenkins. Damit wird das Selenium Grid, also Nodes und Hub, in Jenkins eingebunden. Außerdem zeige ich, wie man die Nodes und den Hub mittels einer JSON Konfigurationsdatei einrichtet.

Variante 1: Standalone
  1. Voraussetzung: Java ist installiert und Classpath entsprechend gesetzt
  2. Download des selenium-server-standalone-*.jar von [7].
    Aktuell wird dort die Version 2.42.2 zur Verfügung gestellt.
  3. Hub starten durch den Kommandozeilenaufruf
    java -jar selenium-server-standalone-2.*.jar -role hub
    Dabei wird der Hub größtenteils mit Standardwerten gestartet (Timeouts, Ports).

Variante 2: Mittels Jenkins
  1. Ggf. Jenkins aktualisieren
  2. Über Verwaltung | Plugins das Plugin mit der ID selenium [8] installieren
  3. Ggf. das Plugin selenium aktualisieren
  4. Über den Link http://<jenkinsurl>/selenium/configurations kann der Hub des Selenium Grids konfiguriert werden.
Durch Variante 2 erhält man sehr einfach und schnell einen funktionierenden Selenium Grid Hub. Durch den sehr guten und stabilen Update-Mechanismus von Jenkins und die große Aktivität bei der Entwicklung des Plugins ist man auf diese Weise immer auf dem neuesten Stand.

Selenium Grid Node Installation und Konfiguration

Die Verwendung und die Konfiguration eines Selenium Grid Nodes ist unabhängig von der Verwendung und der evtl. vorhandenen Konfiguration eines Jenkins Slaves. Ein Node muss manuell eingerichtet werden. Es besteht nicht die Möglichkeit, eine fertige Node-Konfiguration vom Jenkins-Server zu beziehen. Die Konfiguration und der Start eines Selenium Grid Nodes ist sehr einfach und funktioniert wie folgt:
  1. Voraussetzung: Java ist installiert und Classpath entsprechend gesetzt
  2. Download selenium-server-standalone-*.jar von http://docs.seleniumhq.org/download Aktuell wird dort die Version 2.42.2 zur Verfügung gestellt.
  3. Node starten durch den Kommandozeilenaufruf
    java -jar selenium-server-standalone-2.*.jar -role node \
    -hub http://<jenkinsurl>:4444/grid/register
    Dabei wird der Node größtenteils mit Standardwerten gestartet (Timeouts, Ports)
Wesentlich besser und komfortabler ist die Konfiguration per JSON Konfigurationsdatei, die wie folgt aussehen kann:
{
  "capabilities":
      [
        {
          "browserName": "firefox",
          "version": "29",
          "platform": "WINDOWS",
          "maxInstances": 3,
          "seleniumProtocol": "WebDriver",
          "binary": "c:\Program Files (x86)\Mozilla Firefox\firefox.exe"
        },
        {
          "browserName": "chrome",
          "version": "35",
          "platform": "WINDOWS",
          "maxInstances": 3,
          "seleniumProtocol": "WebDriver",
          "binary": "c:\Program Files (x86)\Google\Chrome\Application\chrome.exe"
        },
        {
          "browserName": "iexplorer",
          "version": "11",
          "platform": "WINDOWS",
          "maxInstances": 1,
          "seleniumProtocol": "WebDriver"
        }
      ],
  "configuration":
  {
    "nodeTimeout":240,
    "nodePolling":2000,
    "maxSession": 3,
    "timeout":30000,
    "port": 5555,
    "host": ip,
    "register": true,
    "registerCycle": 5000,
    "cleanUpCycle":2000,
    "hubPort": 4444,
    "hubHost": 
  }
}

Hinweise:
  • Bei der Angabe von Versionsnummern (vor allem bei Chrome) bedenken, dass sich die Version durch den Auto-Update-Mechanismus des Browsers ändern kann. Also entweder die Versionsangabe gar nicht erst angeben oder die Auto-Update-Funktion deaktivieren.
  • Beim Matching des Betriebssystems (bzw. genauer der Plattform) wird empfohlen, ausschließlich Großbuchstaben zu verwenden um Missverständnisse zu vermeiden.
  • Browsernamen mit Leerzeichen (z. B. "internet explorer") vermeiden.
  • Die maximale Anzahl an Instanzen je Node sollte auf 5 oder 6 beschränkt sein. Eine größere Anzahl an Instanzen verlangsamt den Node zu sehr.
  • Als Protokoll verwende ich ausschließlich WebDriver. Stattdessen wäre aber auch Selenium möglich. Dann würde statt des WebDrivers das RC1 Protokoll von Selenium verwendet werden.
  • Natürlich muss "" durch den Servernamen oder die IP Adresse des Jenkins Servers ersetzt werden.
Entschließt man sich für die Verwendung einer JSON Konfigurationsdatei für den Node, dann sieht der Aufruf zum Start des Nodes wie folgt aus:
java -jar selenium-server-standalone-2.*.jar -role node -nodeConfig nodeconfig.json
Bei erfolgreicher Verbindung des Nodes mit dem Hub erhält man in Jenkins unter dem Link http://<jenkinsurl>/selenium/ eine gute Übersicht über die vorhandenen Nodes und deren Konfiguration.


Tipp: Autostart Selenium Grid

Für die Nodes verwenden wir VMs von modern.UI, die jeden morgen automatisch gestartet und abends heruntergefahren werden. Damit der Selenium Node automatisch gestartet wird, empfehle ich folgende Konfiguration:
  • Installation von TightVNC Server
  • Autologin eines beliebigen Users in dessen Kontext dann der Node gestartet wird
  • Batch-Skript im Autostart-Ordner des Users
  • Für IE und Chrome müssen die Treiber-Dateien IEDriverServer.exe und chromedriver.exe nach C:\Windows kopiert werden
Diese Konfiguration hat gegenüber z. B. der Konfiguration als Windows-Dienst den Vorteil, dass Screenshots am Node gemacht werden können. Denn ein Windows-Dienst hat kein grafisches Ausgabegerät. Screenshots resultieren in diesem Fall in einem schwarzen Bild. Mit der vorgeschlagenen Konfiguration können dagegen Testfälle erfolgreich auf dem Node abgespielt werden; inklusive der Erstellung von Screenshots. Dabei ist es nicht erforderlich, dass während des Abspielens ein User per VNC eingeloggt sein muss. Ist man dennoch eingeloggt, kann man die automatische Fernsteuerung des Browsers gut beobachten.

Testfall Remote ausführen

In den letzten Teilen dieser Blogpost Reihe haben wir bereits gelernt, wie man einen Testfall oder eine Test-Suite aufnimmt, ihn editiert und ihn später lokal abspielt. Der Vorteil im Grid besteht nun darin, dass Testfälle nicht mehr nur lokal abgespielt werden können, sondern auch remote auf einem anderen PC. Dabei kann man beim Absetzen des Jobs an den Hub angeben, mit welchen Eigenschaften der Job abgespielt werden soll.
In unserem Szenario steht neben unserem lokalen PC (der nicht Teil des Grids sein muss!) ein Node mit Firefox 29, Chrome 35 und IE8 zur Verfügung. Unser Testfall führt zu einer Webseite, die die User-Agent Angabe des Browsers auswertet. Das Skript sieht wie folgt aus:

{
  "type": "script",
  "seleniumVersion": "2",
  "formatVersion": 2,
  "steps": [
    {
      "type": "get",
      "url": "http://kluge.in-chemnitz.de/tools/browser.php"
    },
    {
      "type": "saveScreenshot",
      "file": "\\\\share\\myScreenshot.png"
    }
  ],
  "data": {
    "configs": {},
    "source": "none"
  },
  "inputs": [],
  "timeoutSeconds": 60
}

Das Skript öffnet die Webseite und macht einen Screenshot des Inhalts. Um den Testfall remote abzuspielen, öffne ich im Se Builder im Menü Run den Eintrag "Run on Selenium Server".


Daraufhin öffnet sich ein neuer Dialog mit dem Titel "Selenium Server Settings", in dem die IP-Adresse oder der Name des Selenium Grid Hub inkl. Port angegeben wird. Außerdem kann man dort spezifizieren, mit welchem Browser, welcher Version und auf welcher Plattform der Testlauf abgespielt werden soll. Diese Angaben sind optional und schränken die Auswahl verfügbarer Nodes ein.

Im ersten Schritt dieses Beispiels habe ich in dem neuen Dialog als Browser String den Wert "iexplorer" angegeben. Vergleiche dazu den Wert des Parameters browserName aus der JSON Konfigurationsdatei des Node, der ebenfalls "iexplorer" lautet. Außerdem habe ich als Browser Version "8" und als Platform "WINDOWS" angegeben. Nach Drücken des Knopfs "Run" ändert sich der Status rechts oben im Se Builder zu "connecting…". Gleich danach beginnt das Abspielen des Testfalls im Se Builder, parallel dazu ändert sich die Statusanzeige im Selenium Grid Hub (in unserem Fall in Jenkins -> Selenium Grid -> Status). Die freien und verfügbaren Browser-Instanzen werden dann wie folgt angegeben:

chrome 3/3, firefox 3/3, iexplorer 0/1
 
Die einzige verfügbare Internet Explorer Instanz auf diesem Node ist also derzeit belegt.
Öffnet man z. B. mittels TightVNC Viewer den Desktop des entfernten Rechners, so kann man dort das Browserfenster beobachten, wie es sich scheinbar auf magische Art und Weise von alleine öffnet und die im Testfall gespeicherten Schritte abgespielt werden. Für erfolgreiches Abspielen des Testfalls auf dem entfernten Rechner ist es nicht erforderlich, dass der Desktop mittels VNC geöffnet wird.
Ich habe den Testfall zwei Mal abgespielt und dabei den Browser String (und die Browser Version) geändert von iexplorer 8 zu firefox 29. Die Auswertung der User-Agents sieht wie folgt aus:



Bei den Selenium Tests wird also der tatsächliche User-Agent, also auch der tatsächliche Browser verwendet. Anders war es auch nicht zu erwarten, denn es wird ja mit dem Selenium WebDriver kein Browser simuliert, sondern tatsächlicher der definierte Browser verwendet.

Tipp: Unterschiedliche Browser verwenden

Bei der Verwendung von unterschiedlichen, entfernten Browsern sind folgende Dinge zu beachten:
  • Browser sollten im selben User Context gestartet werden wie der Selenium Grid Node Task.
  • Jeder Browser sollte mindestens ein Mal manuell im entsprechenden User Context gestartet werden, um die typischen Einstellungsabfragen zu deaktivieren (Standardbrowser, Seite übersetzen, etc.).
  • Automatische Update-Funktionen der Browser sollten deaktiviert werden.
  • Identische Standard-Sprache der Browser einstellen.
  • Firefox: zu verwendendes Profil definieren [10].
  • Internet Explorer: Identische Sicherheitsstufen für alle vier Zonen.
  • Identische Startseite oder keine Startseite für alle Browser.
Im letzten Teil dieser Reihe demonstriere ich ein Szenario mit Selenium Grid und dem Continous Integration Server Jenkins, mit dessen Hilfe Testläufe automatisch gestartet werden und der das Reporting übernimmt. Außerdem zeige ich, wie sich damit Testreihen realisieren lassen.

Links

[1] http://blog.exensio.de/2014/07/automatische-browsertests-mit-selenium.html
[2] href="http://blog.exensio.de/2014/08/automatische-browsertests-mit-selenium.html
[3] http://blog.exensio.de/2014/08/automatische-browsertests-mit-selenium_21.html
[4] http://blog.exensio.de/2014/09/automatische-tests-des-user-interface.html
[5] http://docs.seleniumhq.org/docs/07_selenium_grid.jsp
[6] http://guru99.com/introduction-to-selenium-grid.html
[7] http://docs.seleniumhq.org/download
[8] https://wiki.jenkins-ci.org/display/JENKINS/Selenium+Plugin
[10] https://code.google.com/p/selenium/wiki/TipsAndTricks

Mittwoch, 17. September 2014

LiMux - Software-Streit im Münchner Rathaus - eine Frage der Einstellung

Quelle: http://www.muenchen.de/
So titelte die Süddeutsche in einen Kommentar [1] über die vom frisch gewählten Münchner Oberbürgermeister Dieter Reiter losgetretene Diskussion, ob nicht doch von Linux auf Microsoft zurückgeschwenkt werden soll.

Vor ca. 10 Jahren wurde vom Münchner Stadtrat beschlossen, von Windows auf Linux zu migrieren. Der Gründe hierfür waren zum einen Kosteneinsparungen - aktuell geht man von 10 Mio Euro Einsparung aus - und eine Vorreiterrolle für offene Software zu zeigen.

Laut der offiziellen Homepage der Stadt München [2] scheint die Migration zu Linux eine Erfolgsgeschichte zu sein. Man darf sich derzeit fragen, warum überhaupt diese Diskussionen vom neuen Bürgermeister losgetreten wurden. Ein Schelm, wer hier an die Lobbyisten von Microsoft denkt.

Ehrlich gesagt fände ich es ausgesprochen positiv, wenn München bei Open-Source bliebe. In anderen Ländern innerhalb Europas scheint man ja auch den Weg gehen zu wollen. In Turin [3] steigt man von Windows auf Linux und die französische Gendarmerie [4] (es wird mit 40% Einsparung gerechnet) stellt gleichfalls auf Linux um. Womöglich handelt es sich hier also eher um einen Trend und aus diesem Grund sollte München eventuell froh sein, bereits so weit zu sein.

Open-Source ist ein bedeutsamer Gegenpol und die letzte Chance für die europäische Softwareindustrie - im Vergleich zur amerikanischen. Auch bei anderen Themen, wie Industrie 4.0 wird ebendies ein relevanter Punkt sein. Nur mit Open-Source ist es bei diesem Thema bspw. dem deutschen Maschinenbau möglich, von namhaften Softwareanbietern unabhängig zu bleiben. Dies ist um so essenzieller, da zukünftig davon auszugehen ist, dass der Maschinenbau mit digitalen Services (bspw. Predictive Analytics) rund um seine Maschinen ein überaus lukratives Zusatzgeschäft aufbauen kann.

[1] http://www.sueddeutsche.de/muenchen/software-streit-im-muenchner-rathaus-eine-frage-der-einstellung-1.2093653
[2] http://www.muenchen.de/rathaus/Stadtverwaltung/Direktorium/LiMux.html
[3] http://www.heise.de/newsticker/meldung/Turin-steigt-von-Windows-XP-auf-Linux-um-2391613.html
[4] http://www.wired.com/2013/09/gendarmerie_linux/