Buduję usługę w oparciu o Google App Engine Datastore, który jest ostatecznie spójnym magazynem danych. Dla mojej aplikacji jest w porządku.
Jednak rozwijam testy, które robią takie rzeczy jak obiekt PUT, a następnie GET obiekt i sprawdzanie właściwości na zwróconym obiekcie. Niestety, ponieważ magazyn danych jest ostatecznie spójny, te proste testy nie są powtarzalne.
Jak testujesz ostatecznie spójną usługę?
google-app-engine
eventual-consistency
google-cloud-datastore
Doug Richardson
źródło
źródło
How can I reproducibly test an eventually consistent service?
- Nie możesz. Musisz usunąć słowo „odtwarzalnie” lub słowo „w końcu”; nie możesz mieć obu.Odpowiedzi:
Podczas projektowania testów funkcjonalnych weź pod uwagę niefunkcjonalne wymagania - jeśli twoja usługa ma niefunkcjonalne wymaganie „Spójne w ciągu x (sekund / minut / etc)”, po prostu uruchom żądania PUT, poczekaj x, a następnie uruchom żądania GET.
W tym momencie, jeśli dane jeszcze nie „dotarły”, możesz uznać żądanie PUT za niezgodne z Twoimi wymaganiami.
źródło
Naprawdę chcesz, aby twoje testy były szybkie i spójne. Jeśli zaczniesz tworzyć testy, które czasami mogą się nie powieść ze względu na ostateczną spójność, zignorujesz test, gdy się nie powiedzie, a następnie jaki jest jego użytek?
Utwórz fałszywą usługę, która obsługuje żądania PUT i GET, ale ma dodatkową operację zapewniającą spójność. Twój test to:
Pozwala to przetestować zachowanie oprogramowania, gdy GET pomyślnie pobiera obiekt PUT. Pozwala także przetestować zachowanie oprogramowania, gdy GET nie znajduje obiektu (lub poprawnego obiektu) z powodu niespójności usługi. Po prostu pomiń połączenie z
make_consistent()
.Wciąż warto mieć testy, które wchodzą w interakcję z prawdziwą usługą, ale powinny one działać poza normalnym procesem programowania, ponieważ nigdy nie będą w 100% niezawodne (np. Jeśli usługa nie działa). Testy te powinny być wykorzystane do:
źródło
Ok, więc. „Co testujesz” to kluczowe pytanie.
W takim przypadku powinieneś wyśmiewać usługi Google i zawsze zwracać odpowiedź.
W takim przypadku powinieneś wyśmiewać usługi Google i zawsze zwracać przejściowy błąd przed prawidłową odpowiedzią
Powinieneś wstrzyknąć prawdziwe usługi Google i uruchomić test. Ale! Testowany kod powinien mieć wbudowaną obsługę błędów przejściowych (ponownych prób). Więc powinieneś otrzymać spójną odpowiedź. (chyba że Google zachowuje się bardzo źle)
źródło
Użyj jednego z poniższych:
Niestety musisz wybrać magiczne wartości (N lub czas snu) dla obu tych technik.
źródło
Jak rozumiem, magazyn danych Google Cloud umożliwia zarówno bardzo spójne, jak i ostatecznie spójne zapytania .
Kompromis polega na tym, że bardzo spójne zapytania są dość mocno ograniczone stawką (coś, z czym można żyć podczas testowania).
Jedną z możliwości może być umieszczenie zapytań w magazynie danych w opakowaniu, które może zapewnić silną spójność do celów testowych.
Na przykład możesz mieć wywołane metody
start_debug_strong_consistency()
iend_debug_strong_consistency()
.Metoda początkowa utworzyłaby klucz, który może być użyty jako klucz nadrzędny dla wszystkich kolejnych zapytań, a metoda końcowa usunęłaby klucz.
Jedyną zmianą rzeczywistych zapytań, które testujesz, byłoby wywołanie,
setAncestor(your_debug_key)
jeśli ten klucz istnieje.źródło
Jednym z podejść, które jest dobre w teorii, ale nie zawsze praktyczne, jest uczynienie wszystkich operacji zapisu w testowanym systemie idempotentnymi . Oznacza to, że zakładając, że kod testowy testuje rzeczy w ustalonej kolejności sekwencyjnej, możesz ponowić wszystkie odczyty i wszystkie zapisy pojedynczo, aż uzyskasz oczekiwany wynik, ponawiając próbę, aż przekroczony zostanie limit czasu zdefiniowany w kodzie testowym. To znaczy, zrób rzecz A1, ponów próbę, jeśli to konieczne, aż wynik będzie B1, a następnie zrób rzecz A2, ponów próbę, jeśli to konieczne, aż wynik będzie B2 i tak dalej.
Następnie nie musisz się martwić, aby sprawdzić warunki wstępne operacji zapisu, ponieważ operacje zapisu będą już je sprawdzać, a ty po prostu ponów próbę, aż się powiedzie!
Używaj tych samych „domyślnych” limitów czasu, jak to tylko możliwe, które można zwiększyć, jeśli cały system działa wolniej, i zastępuj wartości domyślne indywidualnie podczas ponawiania szczególnie wolnych operacji.
źródło
Usługa taka jak Google App Engine Datastore opiera się na replikacji danych w kilku globalnie rozmieszczonych punktach obecności (POP). Każdy test integracyjny dla ostatecznie spójnej usługi jest tak naprawdę sprawdzianem szybkości replikacji tej usługi w całym zestawie POP. Szybkość rozprzestrzeniania się treści na każdy POP w danej usłudze nie będzie taka sama dla każdego POP w ramach usługi, w zależności od wielu czynników, takich jak metoda replikacji i różne problemy z transportem internetowym - to dwa przykłady które stanowią większość raportów w dowolnej ostatecznie spójnej usłudze magazynu danych (przynajmniej takie było moje doświadczenie podczas pracy dla dużej sieci CDN).
Aby skutecznie przetestować replikację obiektu na danej platformie, należy ustawić test tak, aby żądał tego samego ostatnio umieszczonego obiektu od konkretnie każdego z punktów POP usługi. Sugeruję przetestowanie listy POP jeden do pięciu razy lub do czasu, aż wszystkie POP na liście POP zgłoszą posiadanie obiektu. Oto zestaw interwałów, w których można wykonać test, który możesz dostosować: 1, 5, 60 minut, 12 godzin, 25 godzin po umieszczeniu go w magazynie danych. Kluczem jest rejestrowanie wyników w każdym interwale w celu późniejszego przeglądu i analizy w celu sprawdzenia zdolności danej usługi do globalnej replikacji obiektów. Często usługi magazynu danych pobierają lokalną kopię do POP tylko wtedy, gdy zażądano jej lokalnie [routing odbywa się za pomocą protokołu BGP, dlatego test musi żądać obiektu od każdego konkretnego POP, aby był globalnie ważny dla danej platformy] . W przypadku magazynu danych Google zastanawiasz się nad przygotowaniem testu do zapytania danego obiektu z „ponad 70 punktów obecności w 33 krajach”; prawdopodobnie będziesz musiał uzyskać listę adresów URL określonych adresów POP od pomocy technicznej Google [zob .:https://cloud.google.com/about/locations/ ] lub jeśli Google używa Fastly do replikacji, Fastly Support [ https://www.fastly.com/resources ].
Kilka zalet tej metody: 1) Poznasz platformę replikacji danej usługi, poznasz jej zalety i słabe punkty jako całość w skali globalnej [tak jak było podczas testu integracji]. 2) Dla każdego testowanego obiektu będziesz mieć narzędzie do podgrzewania treści [zrób pierwsze żądanie, które tworzy kopię na danym lokalnym POP] - zapewniając w ten sposób sposób na globalne rozpowszechnianie treści, zanim klienci zażądają tego od gdziekolwiek na ziemi.
źródło
Mam doświadczenie z Google App Engine Datastore. Dziwne, działając lokalnie, często jest bardziej „w końcu” niż „konsekwentne”. Najprostszy przykład: utwórz nowy byt, a następnie pobierz go. Często w ciągu ostatnich 5 lat widziałem lokalnie działający zestaw SDK nie znajdujący nowego obiektu natychmiast, ale znajdujący go po około pół sekundy.
Jednak w porównaniu z prawdziwymi serwerami Google nie widziałem takiego zachowania. Starają się, aby klient Datastore zawsze działał na tym samym serwerze po swojej stronie, więc zwykle wszelkie zmiany są natychmiast odzwierciedlane w zapytaniach.
Moja rada dotycząca testów integracyjnych polega na uruchomieniu ich na prawdziwych serwerach, a wtedy prawdopodobnie nie będziesz musiał wprowadzać fałszywych zapytań ani opóźnień, aby uzyskać wyniki.
źródło