Wenn Geschwindigkeit und Skalierung benötigt werden: Server von verteilten iOS-Geräten



    Viele Entwickler von iOS-UI-Tests sind wahrscheinlich mit dem Problem der Testlaufzeit vertraut. Badoo führt für jeden Regressionslauf über 1.400 End-to-End-Tests für iOS-Anwendungen durch. Dies sind mehr als 40 Maschinenstunden Tests, die in 30 realen Minuten bestanden werden.

    Nikolai Abalov von Badoo berichtete, wie er es geschafft hat, die Testausführung von 1,5 Stunden auf 30 Minuten zu beschleunigen. wie sie die eng verwandten Tests und die iOS-Infrastruktur entschlüsseln, indem sie zum Geräteserver gehen; wie es einfacher war, Tests parallel auszuführen und Tests und Infrastruktur einfacher zu unterstützen und zu skalieren.

    Sie erfahren, wie einfach es ist, Tests parallel zu Tools wie fbsimctl auszuführen, und wie die Trennung von Tests und Infrastruktur das Hosten, Unterstützen und Skalieren Ihrer Tests erleichtert.

    Zunächst präsentierte Nikolai auf der Heisenbug-Konferenz einen Bericht (Sie können das Video ansehen ), und jetzt haben wir für Habr eine Textversion des Berichts erstellt. Als nächstes folgt die

    Ich -Erzählung: Hallo allerseits, heute werde ich über Skalierungstests für iOS sprechen. Mein Name ist Nicholas, ich beschäftige mich hauptsächlich mit der iOS-Infrastruktur bei Badoo. Davor arbeitete er drei Jahre für 2GIS, war in der Entwicklung und Automatisierung tätig, insbesondere schrieb er Winium.Mobile - eine Implementierung von WebDriver für Windows Phone. Ich wurde nach Badoo gebracht, um an der Windows Phone-Automatisierung zu arbeiten, aber nach einer Weile beschloss das Unternehmen, die Entwicklung dieser Plattform auszusetzen. Und mir wurden interessante Aufgaben für die Automatisierung von iOS angeboten, darüber werde ich Ihnen heute erzählen.

    Worüber werden wir reden? Der Plan ist wie folgt:

    • Eine informelle Erklärung des Problems, eine Einführung in die verwendeten Tools: wie und warum.
    • Parallele Tests auf iOS und wie es sich entwickelt hat (insbesondere gemäß der Geschichte unseres Unternehmens, seit wir 2015 damit begonnen haben, daran zu arbeiten).
    • Der Geräteserver ist der Hauptteil des Berichts. Unser neues Modell zur Parallelisierung von Tests.
    • Die Ergebnisse haben wir mit dem Server erzielt.
    • Wenn Sie nicht über 1500 Tests verfügen, benötigen Sie möglicherweise keinen Geräteserver, aber Sie können trotzdem interessante Dinge daraus ziehen, und wir werden darüber sprechen. Sie können angewendet werden, wenn Sie 10-25 Tests haben, und dies gibt immer noch entweder Beschleunigung oder zusätzliche Stabilität.
    • Und schließlich eine Nachbesprechung.

    Die Werkzeuge


    Das erste ist ein wenig darüber, wer was verwendet. Unser Stack ist ein wenig nicht standardisiert, da wir sowohl Calabash als auch WebDriverAgent verwenden (was uns Geschwindigkeit und Calabash-Backdoors für die Automatisierung unserer Anwendung und gleichzeitig den vollständigen Zugriff auf das System und andere Anwendungen über WebDriverAgent bietet). WebDriverAgent ist eine Facebook-Implementierung von WebDriver für iOS, die von Appium intern verwendet wird. Und Calabash ist ein eingebetteter Server für die Automatisierung. Wir schreiben die Tests selbst in lesbarer Form mit Cucumber. Das heißt, in unserer Firma Pseudo-BDD. Und weil wir Gurke und Kalebasse verwendet haben, haben wir Ruby geerbt, der gesamte Code ist darauf geschrieben. Es gibt viel Code und Sie müssen weiterhin in Ruby schreiben. Um Tests parallel auszuführen, verwenden wir parallel_cucumber, ein Tool, das von einem meiner Kollegen bei Badoo geschrieben wurde.

    Beginnen wir mit dem, was wir hatten. Als ich anfing, den Bericht zu erstellen, gab es 1200 Tests. Als sie fertig waren, war es 1300. Als ich hier ankam, gab es bereits 1400 Tests. Dies sind End-to-End-Tests, keine Unit-Tests und Integrationstests. Sie machen 35-40 Stunden Computerzeit auf einem Simulator aus. Sie vergingen früher in anderthalb Stunden. Ich werde Ihnen sagen, wie sie in 30 Minuten zu vergehen begannen.

    Wir haben einen Workflow in unserem Unternehmen mit Niederlassungen, Überprüfungen und laufenden Tests für diese Niederlassungen. Entwickler erstellen ungefähr 10 Anfragen an das Haupt-Repository unserer Anwendung. Es enthält jedoch auch Komponenten, die mit anderen Anwendungen gemeinsam genutzt werden, sodass manchmal mehr als zehn vorhanden sind. Infolgedessen werden mindestens 30 Testläufe pro Tag durchgeführt. Da die Entwickler pushen, stellen sie fest, dass sie mit Fehlern angefangen haben, neu laden und all dies eine vollständige Regression auslöst, einfach weil wir sie ausführen können. Auf derselben Infrastruktur starten wir zusätzliche Projekte wie Liveshot, die Screenshots der Anwendung in den Hauptbenutzerskripten in allen Sprachen erstellen, damit Übersetzer die Richtigkeit der Übersetzung überprüfen können, unabhängig davon, ob sie auf den Bildschirm passt usw. Infolgedessen ergeben sich derzeit etwa anderthalbtausend Stunden Maschinenzeit.

    Zunächst möchten wir, dass Entwickler und Tester der Automatisierung vertrauen und sich darauf verlassen, um die manuelle Regression zu reduzieren. Dazu ist es notwendig, einen schnellen und vor allem stabilen und zuverlässigen Betrieb durch Automatisierung zu erreichen. Wenn die Tests in anderthalb Stunden bestanden sind, wird der Entwickler es leid sein, auf die Ergebnisse zu warten, er wird anfangen, eine andere Aufgabe zu erledigen, sein Fokus wird wechseln. Und wenn einige Tests fallen, wird er nicht glücklich sein, dass er zurückkommen, seine Aufmerksamkeit wechseln und etwas reparieren muss. Wenn die Tests unzuverlässig sind, werden sie im Laufe der Zeit nur noch als Barriere wahrgenommen. Sie fallen ständig, obwohl der Code keine Fehler enthält. Dies sind schuppige Tests, eine Art Hindernis. Dementsprechend wurden diese beiden Punkte in diesen Anforderungen offenbart:

    • Tests sollten 30 Minuten oder schneller dauern.
    • Sie müssen stabil sein.
    • Sie müssen skalierbar sein, damit wir eine halbe Stunde hinzufügen können, um weitere hundert Tests hinzuzufügen.
    • Die Infrastruktur sollte leicht zu warten und auszubauen sein.
    • Bei Simulatoren und physischen Geräten sollte alles auf die gleiche Weise beginnen.

    Wir führen Tests hauptsächlich mit Simulatoren und nicht mit physischen Geräten durch, da diese schneller, stabiler und einfacher sind. Physische Geräte werden nur für Tests verwendet, die dies wirklich erfordern. Zum Beispiel Kamera, Push-Benachrichtigungen und dergleichen.

    Wie kann man diese Anforderungen erfüllen und alles gut machen? Die Antwort ist sehr einfach: Wir entfernen zwei Drittel der Tests! Diese Lösung passt in 30 Minuten (da nur noch ein Drittel der Tests übrig ist), lässt sich leicht skalieren (weitere Tests können gelöscht werden) und erhöht die Zuverlässigkeit (da wir als Erstes die unzuverlässigsten Tests entfernen). Das ist alles für mich. Fragen?

    Aber im Ernst, in jedem Witz steckt etwas Wahres. Wenn Sie viele Tests haben, müssen Sie diese überprüfen und verstehen, welche echte Vorteile bringen. Wir hatten eine andere Aufgabe und beschlossen zu sehen, was getan werden kann.

    Der erste Ansatz ist das Filtern von Tests basierend auf Abdeckung oder Komponenten. Wählen Sie also die entsprechenden Tests basierend auf Dateiänderungen in der Anwendung aus. Ich werde nicht darüber sprechen, aber dies ist eine der Aufgaben, die wir derzeit lösen.

    Eine andere Möglichkeit besteht darin, die Tests selbst zu beschleunigen und zu stabilisieren. Sie machen einen bestimmten Test, sehen, welche Schritte die meiste Zeit in Anspruch nehmen und ob sie irgendwie optimiert werden können. Wenn einige von ihnen sehr oft sehr instabil sind, korrigieren Sie sie, da dadurch Testneustarts reduziert werden und alles schneller geht.

    Und schließlich eine ganz andere Aufgabe: Tests parallelisieren, auf eine große Anzahl von Simulatoren verteilen und eine skalierbare und stabile Infrastruktur bereitstellen, sodass es viel zu parallelisieren gibt.

    In diesem Artikel werden wir hauptsächlich über die letzten beiden Punkte sprechen und am Ende in Tipps und Tricks den Punkt über Geschwindigkeit und Stabilisierung ansprechen.



    Parallele Tests für iOS


    Beginnen wir mit der Geschichte des parallelen Testens für iOS im Allgemeinen und Badoo im Besonderen. Zunächst einfache Arithmetik, hier gibt es jedoch einen Fehler in der Formel, wenn wir die Dimensionen vergleichen:



    Es gab 1300 Tests für einen Simulator, es stellt sich heraus, 40 Stunden. Dann kommt Satish, mein Anführer, und sagt, dass er eine halbe Stunde braucht. Du musst etwas erfinden. X erscheint in der Formel: Wie viele Simulatoren sollen ausgeführt werden, damit in einer halben Stunde alles läuft. Die Antwort sind 80 Simulatoren. Und sofort stellt sich die Frage, wo diese 80 Simulatoren platziert werden sollen, weil sie nirgendwo passen.

    Es gibt verschiedene Möglichkeiten: Sie können zu Clouds wie SauceLabs, Xamarin oder AWS Device Farm wechseln. Und Sie können zu Hause an alles denken und es gut machen. Da dieser Artikel existiert, haben wir zu Hause alles gut gemacht. Wir haben uns dafür entschieden, weil eine Cloud mit einer solchen Größe ziemlich teuer wäre und es auch eine Situation gab, in der iOS 10 herauskam und Appium fast einen Monat lang Support dafür veröffentlichte. Dies bedeutet, dass wir in SauceLabs einen Monat lang iOS 10 nicht automatisch testen konnten, was uns überhaupt nicht zusagte. Außerdem sind alle Wolken geschlossen und können nicht beeinflusst werden.

    Also beschlossen wir, alles im eigenen Haus zu erledigen. Wir haben irgendwo im Jahr 2015 angefangen, dann konnte Xcode nicht mehr als einen Simulator ausführen. Wie sich herausstellte, kann er nicht mehr als einen Simulator unter einem Benutzer auf demselben Computer ausführen. Wenn Sie viele Benutzer haben, können Sie Simulatoren so oft ausführen, wie Sie möchten. Mein Kollege Tim Bawerstock hat sich ein Modell ausgedacht, nach dem wir lange genug gelebt haben.



    Es gibt einen Agenten (TeamCity, Jenkins Node und dergleichen), der parallel_cucumber ausführt, der einfach über ssh an entfernte Maschinen geht. Das Bild zeigt zwei Autos für zwei Benutzer. Alle erforderlichen Dateien wie Tests werden kopiert und über ssh auf Remotecomputern ausgeführt. Bei den Tests wird der Simulator bereits lokal auf dem aktuellen Desktop ausgeführt. Damit dies funktioniert, mussten Sie zuerst zu jedem Computer gehen, beispielsweise 5 Benutzer erstellen. Wenn Sie 5 Simulatoren möchten, einen Benutzer automatisch anmelden und für den Rest die Bildschirmfreigabe öffnen, damit sie immer einen Desktop haben. Konfigurieren Sie den ssh-Daemon so, dass er Zugriff auf Prozesse auf dem Desktop hat. Auf so einfache Weise haben wir begonnen, Tests parallel durchzuführen. In diesem Bild gibt es jedoch einige Probleme. Erstens steuern die Tests den Simulator, sie befinden sich am selben Ort, Wo ist der Simulator selbst? Das heißt, sie müssen immer auf Mohnblumen laufen, sie verbrauchen Ressourcen, die für den Betrieb von Simulatoren ausgegeben werden könnten. Infolgedessen haben Sie weniger Simulatoren auf der Maschine und sie kosten mehr. Ein weiterer Punkt ist, dass Sie zu jedem Computer gehen und Benutzer konfigurieren müssen. Und dann stolpern Sie einfach in das globale Ulimit. Wenn es fünf Benutzer gibt, die viele Prozesse auslösen, enden die Deskriptoren irgendwann im System. Wenn das Limit erreicht ist, fallen die Tests ab, wenn versucht wird, neue Dateien zu öffnen und neue Prozesse zu starten. Und dann stolpern Sie einfach in das globale Ulimit. Wenn es fünf Benutzer gibt, die viele Prozesse auslösen, enden die Deskriptoren irgendwann im System. Wenn das Limit erreicht ist, fallen die Tests ab, wenn versucht wird, neue Dateien zu öffnen und neue Prozesse zu starten. Und dann stolpern Sie einfach in das globale Ulimit. Wenn es fünf Benutzer gibt, die viele Prozesse auslösen, enden die Deskriptoren irgendwann im System. Wenn das Limit erreicht ist, fallen die Tests ab, wenn versucht wird, neue Dateien zu öffnen und neue Prozesse zu starten.



    In den Jahren 2016-2017 haben wir beschlossen, auf ein etwas anderes Modell umzusteigen. Sah Bericht Lawrence Lomax von Facebook - sie präsentiert fbsimctl, und einige haben gesagt , wie die Infrastruktur zu Facebook. Es gab auch einen Bericht von Viktor Koronevich über dieses Modell. Das Bild unterscheidet sich nicht sehr vom vorherigen - wir haben gerade die Benutzer losgeworden, aber dies ist ein großer Schritt nach vorne, da es jetzt nur noch einen Desktop gibt, weniger Prozesse gestartet werden und Simulatoren billiger geworden sind. In diesem Bild gibt es drei Simulatoren, nicht zwei, da Ressourcen freigegeben wurden, um einen weiteren zu starten. Wir haben sehr lange mit diesem Modell gelebt, bis wir Mitte Oktober 2017 begannen, auf unseren Server für Remote-Geräte umzusteigen.



    Es sah also aus wie Eisen. Links ist eine Box mit Macbooks. Warum wir alle Tests mit ihnen durchgeführt haben, ist eine separate große Geschichte. Die Tests mit den Macbooks durchzuführen, die wir in die Eisenbox eingelegt haben, war keine gute Idee, da sie irgendwann am Nachmittag zu überhitzen begannen, weil die Hitze sie nicht gut verlässt, wenn sie so auf der Oberfläche liegen. Die Tests wurden instabil, insbesondere als die Simulatoren beim Laden abstürzten.

    Wir haben es einfach entschieden: Wir haben die Laptops „in Zelte“ gestellt, die Luftströmungsfläche vergrößert und die Stabilität der Infrastruktur plötzlich erhöht.



    Manchmal muss man sich also nicht mit Software beschäftigen, sondern dreht Laptops.

    Wenn Sie sich dieses Bild ansehen, gibt es ein Durcheinander von Drähten, Adaptern und im Allgemeinen Zinn. Dies ist der eiserne Teil, und es war immer noch gut. In der Software wurde eine vollständige Verflechtung der Tests mit der Infrastruktur durchgeführt, und es war unmöglich, so weiterzuleben.

    Wir haben die folgenden Probleme festgestellt:

    • Die Tatsache, dass die Tests eng mit der Infrastruktur verbunden waren, Simulatoren starteten und ihren gesamten Lebenszyklus verwalteten.
    • Dies machte die Skalierung schwierig, da das Hinzufügen eines neuen Knotens das Einrichten sowohl für Tests als auch für das Ausführen von Simulatoren bedeutete. Wenn Sie beispielsweise Xcode aktualisieren möchten, müssen Sie den Tests direkt eine Problemumgehung hinzufügen, da diese auf verschiedenen Xcode-Versionen ausgeführt werden. Einige, wenn Haufen den Simulator ausführen.
    • Tests sind an die Maschine gebunden, auf der sich der Simulator befindet, und dies kostet einen hübschen Cent, da sie auf Mohnblumen anstatt auf * nix ausgeführt werden müssen, die billiger sind.
    • Und es war immer sehr einfach, in den Simulator einzutauchen. In einigen Tests gingen wir zum Dateisystem des Simulators, löschten dort einige Dateien oder änderten sie, und alles war in Ordnung, bis es auf drei verschiedene Arten in drei verschiedenen Tests durchgeführt wurde, und dann begann unerwartet der vierte abzustürzen, wenn er nicht das Glück hatte, danach zu starten diese drei.
    • Und im letzten Moment wurden die Ressourcen überhaupt nicht durchsucht. Beispielsweise gab es vier TeamCity-Agenten, an die jeweils fünf Computer angeschlossen waren, und Tests konnten nur auf ihren fünf Computern ausgeführt werden. Es gab kein zentrales Ressourcenmanagementsystem. Aus diesem Grund wurde nur eine Aufgabe auf fünf Computern ausgeführt, und alle anderen 15 waren inaktiv. Aus diesem Grund haben Builds sehr lange gedauert.



    Neues Modell


    Wir haben uns entschieden, auf ein schönes neues Modell umzusteigen.



    Alle Tests auf einem Computer entfernt, auf dem TeamCity Agent. Dieser Computer kann jetzt unter * nix oder sogar unter Windows ausgeführt werden, wenn Sie dies wünschen. Sie kommunizieren über HTTP mit etwas, das wir als Geräteserver bezeichnen. Alle Simulatoren und physischen Geräte befinden sich irgendwo dort, und hier werden Tests ausgeführt. Fordern Sie das Gerät über HTTP an und arbeiten Sie weiter damit. Das Diagramm ist sehr einfach, es gibt nur zwei Elemente im Diagramm.



    In Wirklichkeit blieben ssh und mehr natürlich hinter dem Server zurück. Aber jetzt stört das niemanden, denn die Leute, die die Tests schreiben, stehen in diesem Diagramm ganz oben und haben eine spezielle Schnittstelle für die Arbeit mit einem lokalen oder Remote-Simulator, also sind sie in Ordnung. Und jetzt arbeite ich unten und ich habe alles so wie es war. Wir müssen damit leben.

    Was gibt es?

    • Erstens die Aufteilung der Verantwortung. Irgendwann beim Testen der Automatisierung sollten Sie dies als normale Entwicklung betrachten. Es verwendet dieselben Prinzipien und Ansätze wie Entwickler.
    • Das Ergebnis ist eine streng definierte Schnittstelle: Sie können nicht direkt etwas mit dem Simulator tun, dafür müssen Sie ein Ticket auf dem Geräteserver öffnen, und wir werden herausfinden, wie dies optimal funktioniert, ohne andere Tests zu unterbrechen.
    • Die Testumgebung ist billiger geworden, weil wir sie in * nix erstellt haben, die viel billiger sind als Service-Mohnblumen.
    • Und die gemeinsame Nutzung von Ressourcen wurde angezeigt, da es eine einzige Ebene gibt, mit der jeder kommuniziert. Sie kann die Verteilung der dahinter befindlichen Maschinen planen, d. H. gemeinsame Nutzung von Ressourcen zwischen Agenten.



    Oben ist dargestellt, wie es vorher war. Auf der linken Seite befinden sich herkömmliche Zeiteinheiten, beispielsweise zehn Minuten. Es gibt zwei Agenten, an die jeweils 7 Simulatoren angeschlossen sind. Zum Zeitpunkt 0 kommt der Build und dauert 40 Minuten. Nach 20 Minuten kommt ein anderer an und nimmt sich die gleiche Zeit. Alles scheint großartig. Aber da und da sind graue Quadrate. Sie bedeuten, dass wir Geld verloren haben, weil wir die verfügbaren Ressourcen nicht genutzt haben.



    Sie können dies tun: Der erste Build kommt herein und sieht alle freien Simulatoren, wird verteilt und die Tests werden zweimal beschleunigt. Es gab nichts zu tun. In der Realität geschieht dies häufig, weil Entwickler ihre Brunchs selten gleichzeitig pushen. Obwohl dies manchmal passiert und "Dame", "Pyramiden" und dergleichen beginnen. In den meisten Fällen kann jedoch eine kostenlose Beschleunigung zweimal erzielt werden, indem einfach ein zentrales Verwaltungssystem für alle Ressourcen installiert wird.

    Andere Gründe, um weiterzumachen:

    • Black Boxing, das heißt, jetzt ist der Geräteserver eine Black Box. Wenn Sie Tests schreiben, denken Sie nur an Tests und denken, dass diese Black Box immer funktioniert. Wenn es nicht funktioniert, klopfen Sie einfach an, wer es tun soll, das heißt an mich. Und ich muss es reparieren. Nicht nur ich, sondern mehrere Personen sind an der gesamten Infrastruktur beteiligt.
    • Sie können das Innere des Simulators nicht verderben.
    • Sie müssen nicht eine Million Dienstprogramme auf dem Computer installieren, damit alles gestartet werden kann. Sie müssen nur ein Dienstprogramm installieren, das die gesamte Arbeit auf dem Geräteserver verbirgt.
    • Es ist einfacher geworden, die Infrastruktur zu aktualisieren, worüber wir am Ende noch sprechen werden.

    Eine vernünftige Frage: Warum nicht Selenium Grid? Erstens hatten wir viel Legacy-Code, 1.500 Tests und 130.000 Codezeilen für verschiedene Plattformen. Und all dies wurde von parallel_cucumber gesteuert, wodurch der Lebenszyklus des Simulators außerhalb des Tests erstellt wurde. Das heißt, es gab ein spezielles System, das den Simulator lud, darauf wartete, dass er bereit war, und ihn dem Test gab. Um nicht alles neu zu schreiben, haben wir uns entschlossen, Selenium Grid nicht zu verwenden.

    Wir haben auch viele nicht standardmäßige Aktionen und verwenden WebDriver sehr selten. Der Hauptteil der Tests auf Calabash und WebDriver ist nur ein Hilfsprogramm. Das heißt, wir verwenden in den meisten Fällen kein Selen.

    Und natürlich wollten wir, dass alles flexibel und einfach zu prototypisieren ist. Weil das gesamte Projekt einfach mit der Idee begann, dass sie beschlossen, zu testen, in einem Monat implementiert, begann alles und es wurde die Hauptentscheidung in unserem Unternehmen. Übrigens haben wir zuerst in Ruby geschrieben und dann den Geräteserver in Kotlin umgeschrieben. Es stellte sich heraus, dass die Tests auf Ruby und der Server auf Kotlin durchgeführt wurden.



    Geräteserver


    Nun mehr über den Geräteserver selbst, wie er funktioniert. Als wir dieses Problem zum ersten Mal untersuchten, verwendeten wir die folgenden Tools:

    • xcrun simctl und fbsimctl - Befehlszeilenprogramme zum Verwalten von Simulatoren (das erste ist offiziell von Apple, das zweite von Facebook, es ist etwas bequemer zu bedienen)
    • WebDriverAgent, ebenfalls von Facebook, um Anwendungen außerhalb des Prozesses zu starten, wenn eine Push-Benachrichtigung eintrifft oder ähnliches
    • ideviceinstaller, um die Anwendung auf physischen Geräten zu platzieren und dann irgendwie auf dem Gerät zu automatisieren.

    Als wir mit dem Schreiben des Geräteservers begannen, hatten wir dies untersucht. Es stellte sich heraus, dass fbsimctl zu diesem Zeitpunkt bereits alles konnte, was xcrun simctl und ideviceinstaller konnten, also haben wir sie einfach weggeworfen und nur fbsimctl und WebDriverAgent übrig gelassen. Dies ist bereits eine Vereinfachung. Dann dachten wir: Warum müssen wir etwas schreiben, sicher ist Facebook fertig. In der Tat kann fbsimctl als Server fungieren. Sie können es folgendermaßen starten:



    Dadurch wird der Simulator angehoben und der Server gestartet, der die Befehle abhört.



    Wenn Sie den Server stoppen, wird der Simulator automatisch heruntergefahren.

    Welche Befehle kann ich senden? Wenn Sie beispielsweise die Curl-Sendeliste verwenden, werden vollständige Informationen zu diesem Gerät angezeigt:



    Und alles in JSON, das heißt, es lässt sich leicht aus dem Code analysieren und es ist einfach, damit zu arbeiten. Sie haben eine Vielzahl von Befehlen implementiert, mit denen Sie alles mit dem Simulator tun können.



    Genehmigen Sie beispielsweise, dass Sie die Erlaubnis zur Verwendung der Kamera, des Standorts und der Benachrichtigung erteilen. Mit dem Befehl open können Sie Deep Links in einer Anwendung öffnen. Es scheint, dass Sie nichts schreiben können, sondern fbsimctl nehmen. Es stellte sich jedoch heraus, dass es nicht genügend solche Befehle gibt:



    Hier ist leicht zu erraten, dass Sie ohne sie keinen neuen Simulator starten können. Das heißt, jemand muss im Voraus zum Auto gehen und den Simulator abholen. Und vor allem: Sie können keine Tests auf dem Simulator ausführen. Ohne diese Befehle kann der Server nicht vollständig remote verwendet werden. Daher haben wir beschlossen, eine vollständige Liste der zusätzlichen Anforderungen zu erstellen, die wir benötigen.

    • Das erste ist das Erstellen und Laden von Simulatoren nach Bedarf. Das heißt, Liveshots können jederzeit nach dem iPhone X und dann nach dem iPhone 5S fragen, aber die meisten Tests werden auf dem iPhone 6s ausgeführt. Wir müssen in der Lage sein, bei Bedarf die richtige Anzahl von Simulatoren für jeden Typ zu erstellen.
    • Wir müssen auch in der Lage sein, WebDriverAgent oder andere XCUI-Tests auf Simulatoren oder physischen Geräten auszuführen, um die Automatisierung selbst voranzutreiben.
    • Und wir wollten die Erfüllung der Anforderungen vollständig verbergen. Wenn Ihre Tests unter iOS 8 etwas auf Abwärtskompatibilität testen möchten, müssen sie nicht wissen, auf welchem ​​Computer dieses Gerät installiert werden soll. Sie fragen einfach den Geräteserver nach iOS 8, und wenn es einen solchen Computer gibt, wird er ihn selbst finden, das Gerät irgendwie vorbereiten und von diesem Computer zurückgeben. Dies war nicht in fbsimctl.
    • Schließlich sind dies verschiedene zusätzliche Schritte, wie das Löschen von Cookies in Tests, wodurch Sie bei jedem Test eine ganze Minute sparen, und andere verschiedene Tricks, über die wir am Ende sprechen werden.
    • Und der letzte Moment ist das Bündeln von Simulatoren. Wir hatten die Idee, dass es möglich ist, alle darin enthaltenen Simulatoren gleichzeitig auszuführen, da der Geräteserver jetzt getrennt von den Tests ausgeführt wird. Wenn die Tests eintreffen, ist der Simulator sofort einsatzbereit, was uns Zeit spart. Infolgedessen haben wir dies nicht getan, da das Laden der Simulatoren bereits sehr schnell war. Und das wird auch ganz am Ende sein, das sind die Spoiler.



    Das Bild ist nur ein Beispiel für eine Schnittstelle. Wir haben eine Art Wrapper geschrieben, einen Client für die Arbeit mit diesem Remote-Gerät. Hier sind die Punkte die verschiedenen Facebook-Methoden, die wir gerade dupliziert haben. Alles andere sind eigene Methoden, z. B. schnelles Zurücksetzen eines Geräts, Bereinigen von Cookies und Empfangen verschiedener Diagnosen.



    Das gesamte Schema sieht ungefähr so ​​aus: Es gibt einen Test Runner, der Tests ausführt und die Umgebung vorbereitet. Es gibt einen Geräteanbieter, einen Client für den Geräteserver, der Geräte von diesem anfordert. Remote-Gerät ist ein Wrapper über ein Remote-Gerät. Geräteserver - Der Geräteserver selbst. Alles dahinter ist vor den Tests verborgen. Es gibt einige Hintergrund-Streams zum Bereinigen der Festplatte und zum Ausführen anderer wichtiger Aktionen und von fbsimctl mit WebDriverAgent.

    Wie funktioniert das alles? Von Tests oder von Test Runner fordern wir ein Gerät mit einer bestimmten Funktion an, z. B. iPhone 6. Die Anfrage geht an den Geräteanbieter und sendet den Geräteserver, der einen geeigneten Computer findet, startet den Hintergrund-Stream darauf, um den Simulator vorzubereiten, und gibt sofort einen Verweis auf die Tests zurück , Token, versprechen, dass das Gerät in Zukunft erstellt und geladen wird. Entsprechend diesem Token können Sie zum Geräteserver gehen und nach einem Gerät fragen. Wir verwandeln dieses Token in eine Instanz der RemoteDevice-Klasse und es wird möglich sein, bereits in Tests damit zu arbeiten.

    All dies geschieht fast augenblicklich und im Hintergrund beginnt das parallele Laden des Simulators mit fbsimctl. Jetzt laden wir zum Beispiel Simulatoren im Headless-Modus. Wenn sich jemand an das erste Bild mit Eisen erinnert, konnten Sie viele Simulatorfenster darauf sehen, bevor wir sie nicht im kopflosen Modus geladen haben. Sie sind irgendwie geladen, Sie werden nicht einmal etwas sehen. Wir warten nur, bis der Simulator vollständig geladen ist. Beispielsweise wird im Syslog ein Eintrag zu SpringBoard und anderen Heuristiken angezeigt, um die Simulatorbereitschaft zu bestimmen.

    Sobald es hochfährt, führen Sie XCTest aus, wodurch WebDriverAgent tatsächlich ausgelöst wird, und wir werden ihn nach healthCheck fragen, da WebDriverAgent manchmal nicht ansteigt, insbesondere wenn das System sehr stark ausgelastet ist. Parallel dazu beginnt zu diesem Zeitpunkt ein Zyklus, der auf den Status „Bereit“ auf dem Gerät wartet. Dies sind eigentlich die gleichen HealthCheck. Sobald das Gerät vollständig geladen und zum Testen bereit ist, verlassen Sie die Schleife.



    Jetzt können Sie die Anwendung einfach darauf platzieren, indem Sie eine Anfrage an fbsimctl senden. Hier ist alles elementar. Sie können weiterhin einen Treiber erstellen, die Anforderung wird an WebDriverAgent weitergeleitet und eine Sitzung erstellt. Danach können Sie die Tests ausführen.

    Tests sind ein so kleiner Teil dieses gesamten Schemas, dass Sie weiterhin mit dem Geräteserver kommunizieren können, um Aktionen wie das Löschen von Cookies, das Empfangen von Videos, das Starten der Aufzeichnung usw. auszuführen. Am Ende müssen Sie das Gerät freigeben (Release), es endet, es löscht alle Ressourcen, leert den Cache und dergleichen. Das Gerät tatsächlich freizugeben ist optional. Es ist klar, dass der Geräteserver dies selbst tut, da Tests manchmal zusammen mit Test Runner fehlschlagen und die Geräte nicht explizit freigeben. Dieses Schema ist stark vereinfacht, es enthält nicht viele Elemente und Hintergrundarbeiten, die wir ausführen, sodass der Server einen Monat lang ohne Probleme arbeiten und neu starten kann.

    Ergebnisse und nächste Schritte


    Der interessanteste Teil sind die Ergebnisse. Sie sind einfach. Von 30 Maschinen gingen auf 60. Dies sind virtuelle Maschinen, keine physischen Maschinen. Vor allem haben wir die Zeit von eineinhalb Stunden auf 30 Minuten reduziert. Und hier stellt sich die Frage: Wenn sich die Anzahl der Autos verdoppelt hat, warum hat sich die Zeit dann dreimal verkürzt?

    In der Tat ist alles einfach. Ich habe ein Bild über die gemeinsame Nutzung von Ressourcen gezeigt - dies ist der erste Grund. In den meisten Fällen erhöhte er die Geschwindigkeit zusätzlich, wenn Entwickler zu unterschiedlichen Zeiten Aufgaben starteten.

    Der zweite Punkt ist die Trennung von Test und Infrastruktur. Danach haben wir endlich verstanden, wie alles funktioniert, und konnten jedes der Teile einzeln optimieren und dem System etwas mehr Beschleunigung hinzufügen. Die Trennung von Bedenken ist eine sehr wichtige Idee, denn wenn alles miteinander verflochten ist, wird es unmöglich, das System vollständig zu erfassen.

    Es ist einfacher geworden, Updates durchzuführen. Als ich zum Beispiel zum ersten Mal in das Unternehmen eintrat, haben wir ein Upgrade auf Xcode 9 durchgeführt, was mit diesen wenigen Maschinen mehr als eine Woche dauerte. Das letzte Mal, als wir Xcode 9.2 aktualisiert haben, dauerte es buchstäblich anderthalb Tage, wobei die meiste Zeit Dateien kopiert wurden. Wir haben nicht teilgenommen, es hat dort etwas getan.

    Wir haben den Test Runner, der rsync, ssh und andere Logik enthielt, stark vereinfacht. Jetzt wird alles weggeworfen und funktioniert irgendwo auf * nix in Docker-Containern.

    Nächste Schritte: Vorbereiten des Geräteservers für Open Source (nach dem Bericht, der auf GitHub gehostet wurde ) , und wir denken darüber nach, ssh zu entfernen, da dies eine zusätzliche Konfiguration auf den Computern erfordert und in den meisten Fällen die Logik und Unterstützung des gesamten Systems verkompliziert. Jetzt können Sie den Geräteserver auf allen SSH-Computern aktivieren und die Tests funktionieren problemlos.



    Tipps & Tricks


    Das Wichtigste sind nun alle möglichen Tricks und nur nützliche Dinge, die wir beim Erstellen eines Geräteservers und dieser Infrastruktur gefunden haben.

    Der erste ist der einfachste. Wie Sie sich erinnern, hatten wir ein MacBook Pro, alle Tests wurden auf Laptops ausgeführt. Jetzt starten wir sie auf Mac Pro.



    Hier sind zwei Konfigurationen. Dies sind tatsächlich die Top-Versionen der einzelnen Geräte. Auf dem MacBook konnten wir 6 Simulatoren stabil parallel betreiben. Wenn Sie versuchen, mehr gleichzeitig zu laden, versagen die Simulatoren aufgrund der Tatsache, dass sie den Prozessor stark laden, über gegenseitige Sperren verfügen und so weiter. Sie können 18 auf dem Mac Pro ausführen - es ist sehr einfach zu berechnen, da anstelle von 4 12 Kerne vorhanden sind. Wir multiplizieren mit drei - Sie erhalten ungefähr 18 Simulatoren. In der Tat können Sie versuchen, ein wenig mehr zu laufen, aber sie müssen irgendwie zeitlich getrennt sein, Sie können zum Beispiel nicht in einer Minute laufen. Obwohl es mit diesen 18 Simulatoren einen Trick geben wird, ist es nicht so einfach.



    Und das ist ihr Preis. Ich kann mich nicht erinnern, wie viel es in Rubel ist, aber es ist klar, dass sie viel kosten. Die Kosten für jeden Simulator für das MacBook Pro betragen fast 400 GBP und für das Mac Pro fast 330 GBP. Dies entspricht bereits einer Einsparung von ca. 70 GBP für jeden Simulator.

    Außerdem mussten diese Macbooks auf eine bestimmte Weise installiert werden, sie wurden auf Magneten aufgeladen, die auf Klebeband geklebt werden mussten, weil sie manchmal abfielen. Und Sie mussten einen Adapter kaufen, um Ethernet zu verbinden, da so viele Geräte in der Nähe der Eisenbox auf Wi-Fi tatsächlich nicht funktionieren, dass es instabil wird. Der Adapter kostet außerdem etwa 30 Euro. Wenn Sie durch 6 dividieren, erhalten Sie für jedes Gerät weitere 5 Euro. Wenn Sie diese Super-Parallelisierung jedoch nicht benötigen, haben Sie nur 20 Tests und 5 Simulatoren. Es ist tatsächlich einfacher, ein MacBook zu kaufen, da Sie es in jedem Geschäft finden können und Sie müssen auf den Top-End-Mac Pro bestellen und warten. Übrigens haben sie uns etwas billiger gekostet, weil wir sie in großen Mengen genommen haben und es eine Art Rabatt gab. Sie können auch einen Mac Pro mit wenig Speicher kaufen.

    Aber mit dem Mac Pro gibt es einen Trick. Wir mussten sie in drei virtuelle Maschinen aufteilen und ESXi dort platzieren. Dies ist eine Bare-Metal-Virtualisierung, dh ein Hypervisor, der auf einem Bare-Computer und nicht auf dem Host-System installiert ist. Er ist selbst der Host, sodass wir drei virtuelle Maschinen ausführen können. Wenn Sie unter macOS eine normale Virtualisierung installieren, z. B. Parallels, können Sie aufgrund von Apple-Lizenzbeschränkungen nur zwei virtuelle Maschinen ausführen. Ich musste brechen, weil in CoreSimulator, dem Hauptdienst, der die Simulatoren ausführt, interne Sperren vorhanden waren und gleichzeitig mehr als 6 Simulatoren einfach nicht geladen wurden, sie auf etwas in der Warteschlange warten und die Gesamtladezeit von 18 Simulatoren inakzeptabel wird. ESXi kostet übrigens £ 0, es ist immer schön, wenn etwas nichts wert ist, aber es funktioniert gut.

    Warum haben wir nicht gepoolt? Zum Teil, weil wir das Zurücksetzen des Simulators beschleunigt haben. Angenommen, der Test stürzt ab, Sie möchten den Simulator vollständig bereinigen, damit der nächste nicht abstürzt, weil im Dateisystem unklare Dateien verbleiben. Die einfachste Lösung besteht darin, den Simulator herunterzufahren, explizit zu löschen (löschen) und zu booten (booten).



    Sehr einfach, eine Zeile, dauert aber 18 Sekunden. Und vor sechs Monaten oder einem Jahr dauerte es fast eine Minute. Vielen Dank an Apple für die Optimierung, aber Sie können es schwieriger machen. Laden Sie den Simulator herunter und kopieren Sie die Arbeitsverzeichnisse in den Sicherungsordner. Und dann schalten Sie den Simulator aus, löschen das Arbeitsverzeichnis und kopieren die Sicherung, starten den Simulator.



    Es stellt sich heraus, 8 Sekunden: Der Download wurde mehr als zweimal beschleunigt. Gleichzeitig war nichts kompliziertes zu tun, dh im Ruby-Code werden buchstäblich zwei Zeilen benötigt. Auf dem Bild gebe ich ein Beispiel für eine Bash, damit es leicht in andere Sprachen übersetzt werden kann.

    Der nächste Trick. Es gibt eine Bumble-Anwendung, die Badoo ähnelt, aber mit einem etwas anderen Konzept viel interessanter ist. Dort müssen Sie sich über Facebook anmelden. Da wir in all unseren Tests jedes Mal einen neuen Benutzer aus dem Pool verwenden, mussten wir uns vom vorherigen abmelden. Dazu haben wir mit WebDriverAgent Safari geöffnet, sind zu Facebook gegangen und haben auf Abmelden geklickt. Es scheint gut zu sein, aber es dauert fast eine Minute in jedem Test. Hundert Tests. Einhundert zusätzliche Minuten.

    Außerdem führt Facebook manchmal gerne A / B-Tests durch, damit sie die Locators und den Text auf den Schaltflächen ändern können. Plötzlich werden einige Tests fallen und alle werden äußerst unglücklich sein. Daher erstellen wir über fbsimctl list_apps, die alle Anwendungen findet.



    Wir finden MobileSafari:



    Und es gibt einen Pfad zum DataContainer und eine Binärdatei mit Cookies:



    Wir löschen sie einfach - es dauert 20 ms. Tests begannen 100 Minuten schneller zu vergehen, wurden stabiler, weil sie wegen Facebook nicht fallen können. Daher ist eine Parallelisierung manchmal nicht erforderlich. Sie können Orte für die Optimierung finden, es ist einfach minus 100 Minuten, nichts muss getan werden. Im Code sind dies zwei Zeilen.

    Weiter: Wie bereiten wir Host-Maschinen für die Ausführung von Simulatoren vor?



    Mit dem ersten Beispiel sind viele, die Appium gestartet haben, mit dem Deaktivieren der Festplattentastatur vertraut. Der Simulator hat die Angewohnheit, die Hardwaretastatur am Computer anzuschließen, wenn Text in den Simulator eingegeben wird, und die virtuelle Tastatur vollständig auszublenden. Und Appium verwendet eine virtuelle Tastatur, um Text einzugeben. Dementsprechend können nach einem lokalen Debugging von Eingabetests andere Tests aufgrund des Fehlens einer Tastatur fehlschlagen. Mit diesem Befehl können Sie die Hardtastatur deaktivieren. Dies tun wir, bevor wir jeden Testknoten anheben.



    Der nächste Absatz ist für uns relevanter, da die Anwendung geolokalisierungsbezogen ist. Und sehr oft müssen Sie Tests ausführen, damit es zunächst deaktiviert wird. Sie können 3101 im LocationMode einstellen. Warum? Früher gab es einen Artikel in der Apple-Dokumentation, aber dann wurde er aus irgendeinem Grund gelöscht. Jetzt ist es nur eine magische Konstante im Code, für die wir alle beten und hoffen, dass sie nicht kaputt geht. Denn sobald es kaputt geht, sind alle Benutzer in San Francisco, weil fbsimctl beim Laden einen solchen Ort angibt. Auf der anderen Seite werden wir es leicht herausfinden, weil jeder in San Francisco sein wird.



    Als nächstes wird Chrome deaktiviert, ein Rahmen um den Simulator mit verschiedenen Schaltflächen. Beim Ausführen von Autotests wird dies nicht benötigt. Zuvor konnten Sie durch Deaktivieren mehr Simulatoren von links nach rechts platzieren, um zu sehen, wie alles parallel läuft. Jetzt machen wir das nicht, weil alles kopflos ist. Wie viele nicht ins Auto steigen, sind die Simulatoren selbst nicht sichtbar. Wenn dies erforderlich ist, können Sie vom gewünschten Simulator streamen.



    Es gibt auch eine Reihe verschiedener Optionen, die Sie ein- und ausschalten können. Von diesen werde ich nur SlowMotionAnimation erwähnen, weil ich einen sehr interessanten zweiten oder dritten Arbeitstag hatte. Ich habe die Tests durchgeführt, und alle haben angefangen, Zeitüberschreitungen zu erleiden. Sie fanden die Elemente nicht im Inspektor, obwohl er es war. Es stellte sich heraus, dass ich zu diesem Zeitpunkt Chrome gestartet und cmd + T gedrückt habe, um einen neuen Tab zu öffnen. Zu diesem Zeitpunkt wurde der Simulator aktiv und fing das Team ab. Und für ihn ist cmd + T eine 10-fache Verlangsamung aller Animationen, um die Animation zu debuggen. Diese Option sollte auch immer automatisch deaktiviert werden, wenn Sie Tests auf Computern ausführen möchten, auf die Benutzer Zugriff haben, da sie versehentlich Tests unterbrechen können, indem sie Animationen verlangsamen.

    Das wahrscheinlich interessanteste für mich, da ich dies vor nicht allzu langer Zeit getan habe, ist das Management all dieser Infrastrukturen. 60 virtuelle Hosts (tatsächlich 64 + 6 TeamCity-Agenten), die niemand manuell ausrollen möchte. Wir haben das Dienstprogramm xcversion gefunden- Dies ist Teil von Fastlane, einem Ruby-Juwel, das als Befehlszeilenprogramm verwendet werden kann: Es automatisiert teilweise die Installation von Xcode. Dann nahmen wir Ansible, schrieben Playbooks, rollten fbsimctl überall in der gewünschten Version, Xcode und stellten Konfigurationen für den Geräteserver selbst bereit. Und Ansible zum Entfernen und Aktualisieren von Simulatoren. Wenn wir zu iOS 11 wechseln, verlassen wir iOS 10. Wenn das Testteam jedoch angibt, dass das automatische Testen unter iOS 10 vollständig aufgegeben wird, gehen wir einfach durch Ansible und bereinigen die alten Simulatoren. Andernfalls belegen sie viel Speicherplatz.



    Wie funktioniert es Wenn Sie nur xcversion nehmen und es auf jedem der 60 Computer aufrufen, wird es viel Zeit in Anspruch nehmen, da es auf die Apple-Website geht und alle Bilder herunterlädt. Um die im Park befindlichen Computer zu aktualisieren, müssen Sie einen funktionierenden Computer auswählen, xcversion install mit der erforderlichen Version von Xcode darauf ausführen, aber nichts installieren oder löschen. Das Installationspaket wird in den Cache heruntergeladen. Das gleiche kann für jede Version des Simulators durchgeführt werden. Das Installationspaket befindet sich in ~ / Library / Caches / XcodeInstall. Dann laden Sie alles mit Ceph und starten es in diesem Verzeichnis, wenn es nicht vorhanden ist. Ich bin an Python gewöhnt, daher führe ich einen Python-Python-Server auf Computern aus.



    Jetzt können Sie auf jedem anderen Computer des Entwicklers oder Testers xcversion installieren und den Link zum erhöhten Server angeben. Es lädt xip von dem angegebenen Computer herunter (wenn das lokale Netzwerk schnell ist, geschieht dies fast sofort), entpackt das Paket, bestätigt die Lizenz - im Allgemeinen erledigt es alles für Sie. Es wird einen voll funktionsfähigen Xcode geben, in dem Simulatoren und Tests ausgeführt werden können. Leider waren sie mit Simulatoren nicht so praktisch, daher müssen Sie Curl oder Wget ausführen, ein Paket von diesem Server auf Ihren lokalen Computer im selben Verzeichnis herunterladen und xcversion-Simulatoren ausführen --install. Wir haben diese Aufrufe in Ansible-Skripten platziert und 60 Computer pro Tag aktualisiert. Die Hauptzeit wurde durch Kopieren von Netzwerkdateien benötigt. Außerdem bewegten wir uns in diesem Moment, das heißt, einige der Autos wurden ausgeschaltet. Wir haben Ansible zwei- oder dreimal neu gestartet.

    Eine kleine Nachbesprechung. Im ersten Teil: Es scheint mir, dass Prioritäten wichtig sind. Das heißt, zuerst sollten Sie Stabilität und Zuverlässigkeit der Tests und dann Geschwindigkeit haben. Wenn Sie nur Geschwindigkeit anstreben, alles parallelisieren, funktionieren die Tests schnell, aber niemand wird sie jemals ansehen. Sie werden einfach alles neu starten, bis plötzlich alles vorbei ist. Oder sogar bei Tests punkten und zum Meister schieben.

    Der nächste Punkt: Automatisierung ist dieselbe Entwicklung. Sie können also einfach die Muster, die Sie sich bereits für uns ausgedacht haben, verwenden. Wenn Ihre Infrastruktur jetzt eng mit Tests verbunden ist und eine Skalierung geplant ist, ist dies ein guter Moment, um zuerst zu teilen und dann zu skalieren.

    Und der letzte Punkt: Wenn die Aufgabe darin besteht, die Tests zu beschleunigen, müssen Sie zunächst mehr Simulatoren hinzufügen, um sie um einen bestimmten Faktor zu beschleunigen. Tatsächlich müssen Sie den Code sehr oft nicht hinzufügen, sondern sorgfältig analysieren und alles mit ein paar Zeilen optimieren, wie im Beispiel mit Cookies. Dies ist besser als die Parallelisierung, da 100 Minuten mit zwei Codezeilen gespeichert wurden. Für die Parallelisierung müssen Sie viel Code schreiben und dann den eisernen Teil der Infrastruktur unterstützen. Für Geld und Ressourcen wird es viel mehr kosten.

    Diejenigen, die an diesem Bericht der Heisenbug-Konferenz interessiert sind, könnten auch an folgendem Heisenbug interessiert sein : Er findet vom 6. bis 7. Dezember in Moskau statt, und die Konferenzwebsite enthält bereits Beschreibungen einer Reihe von Berichten (und die Annahme von Berichtsanträgen ist übrigens noch offen).

    Jetzt auch beliebt: