13 expected_postquery_event = (postquery["hits"]["total"] == 1)
14 unexpected_connectionfailed_event = (connectionfailed["hits"]["total"] == 0)
15
16 expected_prequery_event && expected_postquery_event && unexpected_connectionfailed_event
我們使用'json' Ruby gem包去解析查詢前后的curl搜索結(jié)果,這些結(jié)果是我們先前保存在重命名后的文件中的(前10行)。第12行到第14行說明了我們對測試結(jié)果的預(yù)期(即日志流中應(yīng)該包含一個單一的DatabasePreQuery事件,一個單一的DatabasePostQuery事件,并且沒有DatabaseConnectionFailed或其他事件)。最后一行是實際的測試(如果我們的期望都是正確的Ruby將返回“ture”,否則就會返回false)。
更復(fù)雜的測試(或?qū)κ录姆治?可能,比如說,需要在給定時間內(nèi)搜索所有數(shù)據(jù)庫事件、計算查詢次數(shù)、故障等。然而,使用的方法和上面描述的是一樣的,只是在一個較大的JSON響應(yīng)包中要執(zhí)行稍微復(fù)雜的迭代代碼。
這是一個對這類測試進行curl查詢的例子(你也可以在 GitHub 找到它):
$ curl -XGET 'http://localhost:9200/_search?q=message:Database*&pretty' -d '
{
"query" : {
"range" : {
"@timestamp" : {
"gte" : "now-10m/m"
}
}
}
}'
我們也可以在系統(tǒng)中跟蹤一條單一的執(zhí)行路徑,使用當活動最初被啟動時我們注入系統(tǒng)的相關(guān)的ID:比如,用戶點擊一個按鈕或一個批量作業(yè)開始。只要關(guān)聯(lián)ID對于我們在日志聚合工具中的搜索是能夠保證唯一的,我們將看到只與該查詢有關(guān)的結(jié)果。

通過搜索關(guān)聯(lián)ID,我們就可以精確地確定到底是哪些服務(wù)器或容器參與了請求的處理和重建請求的過程。有一些商業(yè)工具能提供這樣的功能,但通過我們自己建立這些功能中的一部分功能,我們也可以獲得對系統(tǒng)運行情況的有益見解。
測試日志的用戶故事
比如說,我們有一個關(guān)于法律市場的基于瀏覽器的系統(tǒng),這個系統(tǒng)允許專業(yè)的法律從業(yè)者來編輯和保存文檔。將文檔數(shù)據(jù)保存到文檔存儲數(shù)據(jù)庫,并將消息放在消息隊列上。然而,作為一個國家的監(jiān)管制度的一部分,我們需要確保該文件符合一定的要求,所以需要提供“審計”服務(wù)監(jiān)聽消息隊列上的消息,然后檢查最近更新過的文檔:

在這里,我們已經(jīng)有了一個異步的、分布式的系統(tǒng)。當在瀏覽器中應(yīng)用程序明確地顯示了成功——該文檔已經(jīng)成功更新時,可能實際上還需要啟動進一步的工作流程(例如,如果文檔審計發(fā)現(xiàn)了文件的問題)。
通過使用事件ID和事務(wù)跟蹤的日志聚合功能,我們就有能力斷言,基于在主要事務(wù)系統(tǒng)中的某些操作,某些特定的日志消息應(yīng)該出現(xiàn)在日志聚合系統(tǒng)之中:

具體來說,如果我們知道,審計服務(wù)應(yīng)以事件ID“AuditRecordCreated”寫一條日志信息,我們在Web應(yīng)用程序的用戶搜索完成后,就可以運行一個測試來尋找那個ID:

有了這個能力去斷言我們對系統(tǒng)的行為的期望之后,我們可以寫出類似這樣的行為水平測試:
Given I run a scenario as a Lawyer
And I create a document
[And I wait 5 seconds]
When I search the logs API
Then I should find a recent entry for “AuditRecordCreated”
這意味著,日志記錄已經(jīng)成為了一種可以擴展我們對分布式系統(tǒng)的測試的方式,只要能夠明確在某些具體時刻我們期望哪些行為或事件會被記錄下來,然后再去搜索就好了。
結(jié)論
對分布式的、可擴展的系統(tǒng)(通常包含不穩(wěn)定的基礎(chǔ)設(shè)施)進行故障排除,取決于是否有足夠的日志記錄和搜索設(shè)備。我們需要記錄發(fā)生在我們的系統(tǒng)中的重要的事件,并通過一個唯一的關(guān)聯(lián)ID將它們關(guān)聯(lián)到一個特定的業(yè)務(wù)交易(如包裹快遞)上。日志聚合和搜索工具使我們能夠用一個簡單的ID查詢來跟蹤終端到終端的業(yè)務(wù)交易。我們也可以查詢一個類別的事件以調(diào)查組件或系統(tǒng)故障(例如,為了找到導(dǎo)致某次故障的所有的數(shù)據(jù)庫事件)。最后,我們看到,我們可以而且我們也應(yīng)該以與功能需求類似的方式來測試這些操作需求,即通過用戶故事和BDD的場景。