xrpld
Loading...
Searching...
No Matches
ValidatorSite_test.cpp
1#include <test/jtx/Env.h>
2#include <test/jtx/TrustedPublisherServer.h>
3#include <test/jtx/envconfig.h>
4#include <test/unit_test/FileDirGuard.h>
5#include <test/unit_test/SuiteJournal.h>
6
7#include <xrpld/app/misc/ValidatorSite.h>
8
9#include <xrpl/basics/chrono.h>
10#include <xrpl/basics/strHex.h>
11#include <xrpl/beast/unit_test/suite.h>
12#include <xrpl/beast/utility/Journal.h>
13#include <xrpl/json/json_value.h>
14#include <xrpl/json/to_string.h>
15#include <xrpl/protocol/jss.h>
16
17#include <boost/algorithm/string/join.hpp>
18#include <boost/filesystem/directory.hpp>
19#include <boost/filesystem/operations.hpp>
20#include <boost/range/adaptor/transformed.hpp>
21
22#include <date/date.h>
23
24#include <chrono>
25#include <fstream>
26#include <memory>
27#include <ostream>
28#include <sstream>
29#include <string>
30#include <utility>
31#include <vector>
32
33namespace xrpl {
34namespace detail {
35constexpr char const*
37{
38 return R"vl({
39 "public_key": "ED2677ABFFD1B33AC6FBC3062B71F1E8397C1505E1C42C64D11AD1B28FF73F4734",
40 "manifest": "JAAAAAFxIe0md6v/0bM6xvvDBitx8eg5fBUF4cQsZNEa0bKP9z9HNHMh7V0AnEi5D4odY9X2sx+cY8B3OHNjJvMhARRPtTHmWnAhdkDFcg53dAQS1WDMQDLIs2wwwHpScrUnjp1iZwwTXVXXsaRxLztycioto3JgImGdukXubbrjeqCNU02f7Y/+6w0BcBJA3M0EOU+39hmB8vwfgernXZIDQ1+o0dnuXjX73oDLgsacwXzLBVOdBpSAsJwYD+nW8YaSacOHEsWaPlof05EsAg==",
41 "blob" : "eyJzZXF1ZW5jZSI6MzcsImV4cGlyYXRpb24iOjU5NDE3MjgwMCwidmFsaWRhdG9ycyI6W3sidmFsaWRhdGlvbl9wdWJsaWNfa2V5IjoiRUQ0OUY4RUI4MDcxRTI2RDRFMDY3MjM4RDYyRDY3Q0E2RUJGQjI5OEI0QTcyRENGQUQ1MzZBN0VDODkyNUM1MTlCIiwibWFuaWZlc3QiOiJKQUFBQUFGeEllMUorT3VBY2VKdFRnWnlPTll0WjhwdXY3S1l0S2N0ejYxVGFuN0lrbHhSbTNNaEFvZ01tUVRSQUZLLyttL1hXUWZKdlhUZU1jYWl5RjZna2hnQXNzZExPY2lJZGtZd1JBSWdOeFlhdkpQeUhBTnV4b2dRWTdSTkJQOXRab2daSnhGMXdacXptNGEzN0dnQ0lCT3ZiZVE4K1A0NkNDSWN5NFpDWkE1clpaKzkzSDBhS0paUTMrSUEwT091Y0JKQUFTVHBRS3RFSmtlcXdIeitqS1dOdldsMHNIUlFaU1NKdVlpTXl5VWE3eXRwc2V2Nk5Hb0ZuMWJOcFlUZ3ZzYVB4b3o3dkhza0RoMlo2Z2ViU0RDUkNBPT0ifSx7InZhbGlkYXRpb25fcHVibGljX2tleSI6IkVEODEwOEY3RDlFRTc3OURDMTA3NUVDM0NGOEVCOTAwNERERjg0Q0QwQTBGRjU3NzVDOUUzNzVDQ0FDREFBMzAyMiIsIm1hbmlmZXN0IjoiSkFBQUFBRnhJZTJCQ1BmWjduZWR3UWRldzgrT3VRQk4zNFROQ2cvMWQxeWVOMXpLemFvd0luTWhBbHZQSkFOUWNSVVNOVVIrTmxadW80a0dwWUY4bDlwSFBQMVpST09VY05ZUmRrWXdSQUlnUldaWnVKTEFmM1NOTUdvRnlnVWx1K2VBRDUxWm9IRk1jeW9pY24wV0t1Y0NJR3c0bjljVkRQT0JHQzh3bEpEeTkyODJ4OVJkT3dvMWNvMmcrTlpsYy9ETmNCSkFLSmhLL2FtNkw3S0U0NTBOVnpocFZWb0w4T0ZNbzBtRnhrOEJERzZRTzJjU05NTjNPeXdmNDBEK0lsZXM5TFh4eHZ2UEI2Z1dTbVBsd0Y3ZE5SOUdBUT09In0seyJ2YWxpZGF0aW9uX3B1YmxpY19rZXkiOiJFRDdFM0JBRkY5MDFERTUyNUIwMEIyQzFGRTE5QUY0NDlBMDgwQjVGMzEwMEM2RUMxODJDODY3QUY2MUY3MTBGRkQiLCJtYW5pZmVzdCI6IkpBQUFBQUZ4SWUxK082LzVBZDVTV3dDeXdmNFpyMFNhQ0F0Zk1RREc3QmdzaG5yMkgzRVAvWE1oQTUrR0RKaDJBcFdLQ2gyTjVvbXg0RkFPRkVxWE1qcXkxSEo1RTdXQTNGck9ka2N3UlFJaEFNUmV6d2pUQUwzNWpwamoxNWpxb0hVdlJtNys3aUhwVTQ3YUtFNkhFQ2haQWlCU01JWmFNV3Y2cU5KSG5pWXBzWUh4NE9QUHBCb0NNTWRNVkFHZkZpOWZLM0FTUUUwVFlpSXNHdjAveWxwcUdFQmlMa2syWGpyQTgrK0FrenByOXZjVHRya0hpRERvMGNIS085bVJVTEFYZXNSck95RmI1UWNPMGwwVnN3ZXZENWpsc3drPSJ9LHsidmFsaWRhdGlvbl9wdWJsaWNfa2V5IjoiRUQ0NUU4MEEwNEQ3OUNCOURGMDBBRUJEODZEQ0RDMTY4NkQ2NDE5RUE5RTVFMEU3MUYxQTgxN0UwOEI1MDc2QTU1IiwibWFuaWZlc3QiOiJKQUFBQUFGeEllMUY2QW9FMTV5NTN3Q3V2WWJjM0JhRzFrR2VxZVhnNXg4YWdYNEl0UWRxVlhNaEF4Wm8xNTdwY0I5ZGU2U21rN2hvSzN3TkNBcjRhRlp0ZkFQaTdDRTRtTkpsZGtjd1JRSWhBTGxWalhDZml5L210WEJXc050Nzd0NGpLY05FQnBSVjh6ditTcFU1bENoMEFpQmE4dm84eHhwdmlZbGY0emRHK25RaEIyT2dma1FaWlBNSE90N0NhWHpYZ1hBU1FMOE81cDA4M21nNEtLTDh1WmZNYVVxZGd6dUowR3RhMWx5VVdQY3RUUEN4WTEzNVh3SytuSkFkRnNJVUZOSjlNUGpucENtU2pZVnpWYTZNNS9uQWNBST0ifSx7InZhbGlkYXRpb25fcHVibGljX2tleSI6IkVERDhDODg2NDI3OTVDRTY5QzVCNzgwRTAxNzAyQzM3MEY5NTA3RDBCNjQ0MzNGMTdFRkU3MEYyNjM3QTQwQURCNyIsIm1hbmlmZXN0IjoiSkFBQUFBRnhJZTNZeUlaQ2VWem1uRnQ0RGdGd0xEY1BsUWZRdGtRejhYNytjUEpqZWtDdHQzTWhBbkZmcityOUJYZHNYRS9jQmxKTXlkL1hzTzFBNVhFWUNjdHJzdkxFWCtEbWRrY3dSUUloQU5SY1JNZzlTQVhvYU92SERaMmF2OVJ6RWFaYVZFTmZRaVZnc2krT3gzRjBBaUIyc25TSU9tNmM0L2luYnRVMFVtV0xRVHp1d2tPZFVGUElCOEF4OGRtR3VIQVNRTVVJZlhNajk2a2NGVFNKbk1GQy9tVy9BUThiS1hrRnJyazBDVVRGRkt3ZUVqVHErU1RyRmk2cUxMMk1UN252ZUd4c1hCQ2d6dGpjMHFHYXM5S0ZXZ009In0seyJ2YWxpZGF0aW9uX3B1YmxpY19rZXkiOiJFREJERUI5MDFGN0M3NUQwRTIwQzZDNDJBRjAzQkUwREE0MDM3N0FGMTkzOUExOEIzQ0IzNjc5NjYxREQ1RjlGNzQiLCJtYW5pZmVzdCI6IkpBQUFBQUZ4SWUyOTY1QWZmSFhRNGd4c1FxOER2ZzJrQTNldkdUbWhpenl6WjVaaDNWK2ZkSE1oQWczY3lLTlBNUHFLZ1I3a0lpN2MvOEdML1lnZEJ0ZzRtU0FXdndtYWV2Vkdka1l3UkFJZ1d6RzhHcVlnM1lwd0RzOHhYYTlYcUxIc3M3NktUMnVBSFJoVVhGVlVxQ1FDSUcyRXZiRktueGV6UmQ5Y3BQSFN0MzJIWEsrUDQrYUwzcDIrdnFsQ3hSUjljQkpBYm9YVG1ZVGF5b2NBM3pmOWRXRVh0eWFlT0dDMWs1V2RZVVJ6UGxlZXZ2YWxSNHhWb1h6czM4aUdQeEZyL3BBOW5MK000ZHV1MEdLQ0hsVmlyK2ZCQWc9PSJ9LHsidmFsaWRhdGlvbl9wdWJsaWNfa2V5IjoiRURBMTc4NzFFNzJCMEM1NzBBQzQzNDVDNjBDRjAyQUZCQkI3NDBBNjMxQjdBRDBFMUU1NzMyMTY1NzREOUFFQTAyIiwibWFuaWZlc3QiOiJKQUFBQUFGeEllMmhlSEhuS3d4WENzUTBYR0RQQXErN3QwQ21NYmV0RGg1WE1oWlhUWnJxQW5NaEFvanl1emd0cmVRa3hRajhwckh4T3NiRGNGNWZ1NFhYYjBLeEVML1BxNUhoZGtjd1JRSWhBTmZQRExaUDQ3YUNXd3Q1a0JucDc1QnV1Q2dwOWM0QmZKUGQ2NlNGQ3c2MUFpQUp2ZWdCdnZQSXJlYytYT1N6S1JmaTV1dVhXeHRsOUV5cjJhUEJZWHZiUkhBU1FNVUxZRW83YmVSZm9VQ25qazFzVFl5WTkxdExJR0xnbm5hV1hoVW04MCt6czVJR2VnazhxaWpLQXRCT011QkM3MWxBQjRLaEpjK2RCMnJwTU9GYzVndz0ifSx7InZhbGlkYXRpb25fcHVibGljX2tleSI6IkVERjQ2RUUyN0FEMEUxQTcxNEFGRUNEQTgxNkVBQjcxMTQ2MTRGQ0I5MkQwQ0I0RDk3QjZBODhFRDQzNDM0QUZDOSIsIm1hbmlmZXN0IjoiSkFBQUFBRnhJZTMwYnVKNjBPR25GSy9zMm9GdXEzRVVZVS9Ma3RETFRaZTJxSTdVTkRTdnlYTWhBdzBBVFdqVlR0NEZmZUtPN2t2NmZGZ2QvZ28yK2Q1QlN5VWNVUm1SV25UdGRrY3dSUUloQU13T2dEZWM3UVlZTm5nc3BnOTB3RXZWYnNvaDJ1eDE0UlBUdytHSGFYTmxBaUFMZ2ZFc3orQUY0ZXlYL1k1aTQ0VnJGakZGSU1XVWZPWmFRSnRzeHRlTTFYQVNRTE9hRjB0MlpwcVZLZDhKRVNRVlkrelU1NjdpQUFHMmFtVFBaeDk1ODc1UzlBNlBsK2tINVRHSE1BZVdqZ1dTcWZoM20ySEJKWDdOSWNYYjk4dnk5QUE9In0seyJ2YWxpZGF0aW9uX3B1YmxpY19rZXkiOiJFRDZFNEM0MUU1OUZGQkVCNTE3MjZFNTQ0Njg1MDJGRTY0MzcyMzhGQTc4RUE1MTYzNEU3QkYwRDA5MTcxQUVFOEYiLCJtYW5pZmVzdCI6IkpBQUFBQUZ4SWUxdVRFSGxuL3ZyVVhKdVZFYUZBdjVrTnlPUHA0NmxGalRudncwSkZ4cnVqM01oQXV6dEdXYi9PaTEvVjVtNWR1aldyOUhtYktSeUs0WFlrK2ttdUZQU2dBRnJka1l3UkFJZ2ZRK0JnWFg2UWJsWnk0SDA1bzdHUFNJd3FTN1FRUlVXN2RxRjU0SUFpaU1DSUg0WGZMdzk1NmlFYW94Wk9rN0tjdGluMlg5aE1mYUxON3d5czl5QVVGb1pjQkpBdWVFaTg0WFIzTGwxR0xKV2FuVzFnMU1kVWovMFBBeEpidzZFRVFSdUczemRudVJITlhsZDZVWkFiSWtWY1AwenRmcXVsQnpqYmNzTERPS0ZFaWNTQmc9PSJ9LHsidmFsaWRhdGlvbl9wdWJsaWNfa2V5IjoiRURCNkZDOEU4MDNFRThFREMyNzkzRjFFQzkxN0IyRUU0MUQzNTI1NTYxOERFQjkxRDNGOUIxRkM4OUI3NUQ0NTM5IiwibWFuaWZlc3QiOiJKQUFBQUFGeEllMjIvSTZBUHVqdHduay9Ic2tYc3U1QjAxSlZZWTNya2RQNXNmeUp0MTFGT1hNaEE4VmR2SEZ5U2NCeVFHVFlOR2VPdkIwKzY3Z1dhcWVmY2Z2Ums1K0t3Z1YxZGtZd1JBSWdaRnVsTy9BaU1vY3puZzZpLzRCa2Z6VDdqOWx4RjRQUDF1ZmdyT1FhSjhzQ0lCWC9FOFpicG43dFdxZ0F5TnlXcFZQa2hGbWFVTXFFcnk4V29VVDFmZEdRY0JKQXY1MVJxSnhnZy9Wcm5yWndpTEsyRGMwQ0tiaUxQTzVISjRaTXNqZFBUMmdSYzk3cldrQVh1VjJMNlBORk81OXh5dW9hWm1TTWxaWXZxU0dQcGZGN0J3PT0ifSx7InZhbGlkYXRpb25fcHVibGljX2tleSI6IkVENjkxMzAzOTkyRkVDNjRFNkJDNEJBQ0QzNkFFNkU1QUVEQzIzRjI4NjFCNkQ4RUZCOUZENzdFRTNFQURFMzQzNSIsIm1hbmlmZXN0IjoiSkFBQUFBRnhJZTFwRXdPWkwreGs1cnhMck5OcTV1V3UzQ1B5aGh0dGp2dWYxMzdqNnQ0ME5YTWhBaTJBWEpRZ28vSnVXM3I3Zi82Q2NWc0dOMVltSWoxMUdpSUVTSEJuUVNrOGRrY3dSUUloQU5DREVReW1yZDZ2ZVQzb3VhY0Y2ZmhCcjV3THczR21YZzFyTUNMVnZCelpBaUE4dVdRK3RxZDQ2V21mQmV4alNCUTJKZDZVQUdkckh2amNDUTJaZ1Nvb0NuQVNRRmtIbCtENy9VM1dCeVlQMzg0K3BjRkRmMkdpNFdJUkhWVG81OGNxZGs1Q0Rpd2MxVDByRG9MaG1vNDFhM2YrZHNmdGZ3UjRhTW13RmNQWExucmpyQUk9In0seyJ2YWxpZGF0aW9uX3B1YmxpY19rZXkiOiJFREFEMTY2NjdGMDE4NUREQkI3RkE2NUIyMkY0QjdEMzEwQkY1QzNFMkQ5QjgyM0ZCMDZBM0E0MUFGOEFDODNCQzEiLCJtYW5pZmVzdCI6IkpBQUFBQUZ4SWUydEZtWi9BWVhkdTMrbVd5TDB0OU1RdjF3K0xadUNQN0JxT2tHdmlzZzd3WE1oQXF3ZUUzUElTM0U0NEtoTXFLakt0YmtCZThIOEdiaXVvQVhBWURSb1ZSSG9ka1l3UkFJZ2FnR2tYdG93VXliZGx0S29qdjBsdnZmbHJsUTlJUm5QT2pla0Y2MGlIemdDSUNnNlpvY0lNemtVdXZPOTFCRW9ybUlXbVg0Ry9NR1QyenJvNkkvUHZCOFhjQkpBY0pMWGt0L3cva2N3RXZOaVptaTJpMm5NbjF3aVAzTFM5TkpqQlBqdThLRkxBTWcwTzl5ZFFUNjdVL0FMWU9lVFBUTzIvaTJZdzlPU2xpYnRxaGd6REE9PSJ9LHsidmFsaWRhdGlvbl9wdWJsaWNfa2V5IjoiRURDMjQ1MDI3QTUyRUU1MzE4MDk1NTk4RUMzQUI2NUZGNEEzQjlGOTQyOEUxMEIyRjNDNkYzOURFMTVBMTVDOTBBIiwibWFuaWZlc3QiOiJKQUFBQUFGeEllM0NSUUo2VXU1VEdBbFZtT3c2dGwvMG83bjVRbzRRc3ZQRzg1M2hXaFhKQ25NaEEvOC85cktVZEE2MWovZklFUC9jcUxweEJsbUloUDJyZzFkN05hRVB5S1YrZGtjd1JRSWhBSXhFME0vRko1MHZmWlc2ZlBweTR5Q1p1bVk5bjBvYnJPb2pVa2ptNTVhMEFpQmo1Nk8wTXBvcEdvWTlIeEMvKzR3Tk8zNkhvN0U5Q1FlSHNuS3JlRGRzQVhBU1FJWVVkODFqYmlWVWxFVDRkR29HMnArY2YrMkdxRVhYNWZKTVNTeVgvcWUwWGZSNGNPKzRxbGdtak1RZENSREJXQUJIVnZkTi95WnlpL3JMMmMrV3JRYz0ifSx7InZhbGlkYXRpb25fcHVibGljX2tleSI6IkVENDI0NkFBM0FFOUQyOTg2Mzk0NDgwMENDQTkxODI5RTQ0NDc0OThBMjBDRDlDMzk3M0E2QjU5MzQ2Qzc1QUI5NSIsIm1hbmlmZXN0IjoiSkFBQUFBRnhJZTFDUnFvNjZkS1lZNVJJQU15cEdDbmtSSFNZb2d6Wnc1YzZhMWswYkhXcmxYTWhBa20xbHowYzhRWFdmSjliMXZCNzJkTGFidzh3WUlkOE10bnBzSEhCRUM4cGRrWXdSQUlnUWxiNkhKNTNoc1RBZlZpZCtBT2RCVnZNRjdyYWhJS05MQkhVZ241MnpCRUNJR0xVcUZ1OGExQUFIUkpjVm9uS1lFbm1oSndiQ1hMbitqZTduYTFXRDEvb2NCSkFFNHZmdnJHU21aQzJ1QVVHbU01ZElCdG9TZ0VVZXkrMlZsZURZRXNjZTk0dHhZY2pSOFo3UUxOYWxpRDh3L2JENS9odllROG1lVjFXZzFqSkZOZTBDQT09In0seyJ2YWxpZGF0aW9uX3B1YmxpY19rZXkiOiJFRDJDMTQ2OEI0QTExRDI4MUY5M0VGMzM3Qzk1RTRBMDhERjAwMDBGREVGQjZEMEVBOUJDMDVGQkQ1RDYxQTFGNUEiLCJtYW5pZmVzdCI6IkpBQUFBQUZ4SWUwc0ZHaTBvUjBvSDVQdk0zeVY1S0NOOEFBUDN2dHREcW04QmZ2VjFob2ZXbk1oQWtNVW1DRDJhUG1nRkREUm1pbXZTaWNTSVNjdzZZTnI0MkR3NFJBZHdyT0Fka2N3UlFJaEFKRk9ITWc2cVRHOHY2MGRocmVuWVlrNmN3T2FSWHEwUk5tTGp5eUNpejVsQWlBZFUwWWtEVUpRaG5OOFJ5OHMrNnpUSkxpTkxidE04b08vY0xudXJWcFJNM0FTUUdBTGFySEFzSmtTWlF0R2RNMkFhUi9qb0ZLL2poRFU1NytsK1JTWWpyaS95ZEUyMERhS2Fud2tNRW9WbEJUZzdsWDRoWWpFbm1rcW83M3dJdGhMT0FRPSJ9LHsidmFsaWRhdGlvbl9wdWJsaWNfa2V5IjoiRURBNTRDODVGOTEyMTlGRDI1OTEzNEI2QjEyNkFENjRBRTcyMDRCODFERDQwNTI1MTA2NTdFMUE1Njk3MjQ2QUQyIiwibWFuaWZlc3QiOiJKQUFBQUFKeEllMmxUSVg1RWhuOUpaRTB0ckVtcldTdWNnUzRIZFFGSlJCbGZocFdseVJxMG5NaEFsOGNKZXJQdit2bzFCSzYxMXhWVHBHeGpqci9DdXhQVGdVOFVSTTRlVFo1ZGtZd1JBSWdkSzNjUVYyWS92aVpuZS9QYm9LU0tld25nVHVJTjJNNmM4YXp3cWMyMHVVQ0lBYzZHb05UK1AyWUJ5NDlnZGF1NFA3eVN3V29RWDVuZjlkUXhpUWF2NXdJY0JKQXFpQ0swZDZRUlpTcGlWSHA4TzlubEtYQ1NFaHNpU05jV2NFRm0vZkdoSkFuQU4wT3Y5SElOSWQxcHhyQm4yZEtSZWdMVHZZRzNCcGJ6Ly9ITGdFZERBPT0ifSx7InZhbGlkYXRpb25fcHVibGljX2tleSI6IkVEOUFFNEY1ODg3QkEwMjlFQjdDMDg4NDQ4NkQyM0NGMjgxOTc1Rjc3M0Y0NEJEMjEzMDU0MjE5ODgyQzQxMUNDNyIsIm1hbmlmZXN0IjoiSkFBQUFBRnhJZTJhNVBXSWU2QXA2M3dJaEVodEk4OG9HWFgzYy9STDBoTUZRaG1JTEVFY3gzTWhBbUcyemd2OEZCWnNaSlU4YVBhcHdvOWNJcVF2NC9NU1Mxb1ZBNWVWTWl3TGRrWXdSQUlnRitMT2U0ZVkwZ3A5dHRxaDJnbnYrejc1T3FMeU9RTXBHUEFMZ20rTnRPc0NJQ0RYQlpWUHRwcm1CRGtCSmtQRlNuRTU1RDllS1lSSDh6L2lZMUV0cE5wbGNCSkFBREVXR1ZUODBPd2hkMWxoMkpzVS9vWmxtZU5GNVdON1l2bEI4bGxFeGFSS0VWQytHVzlXZytpTklRM3JtVjdQOGFOYVZ1YWFiRzAwZk9na2d6TmhEdz09In0seyJ2YWxpZGF0aW9uX3B1YmxpY19rZXkiOiJFREE4RDI5RjQwQ0VCMjg5OTU2MTc2NDFBM0JDNDI2OTJFMURFODgzMjE0RjYxMkZCQjYyMDg3QTE0OEU1RjZGOUEiLCJtYW5pZmVzdCI6IkpBQUFBQUZ4SWUybzBwOUF6cktKbFdGMlFhTzhRbWt1SGVpRElVOWhMN3RpQ0hvVWpsOXZtbk1oQW5ZblA3RWc2VmdObkVVVFJFMjlkNjRqUVQvaUJjV1RRdE5yVXp5RDZNSitka2N3UlFJaEFPRXNWNWFuVGtsb1NtVFpSYmltTXlCS3FIb0pZWGNCQmU4bExpUFlDN21VQWlBejJhTk9wZlEvMUx5Y1dsb0lNdmRoeHppbnE1WDdVYXMvdU9TYjl3aDhkM0FTUUxWa2ZwVy9HTzZ3ZFQ2QXV1U0o1NlR0TTM0M3BETkgraVN6eGx0SWZkclBpVXhUNXJmNGsyMWxRUXVQQ2xYbTkrU2ZLckNpVVhaSzdkajAvR1dUWVFnPSJ9LHsidmFsaWRhdGlvbl9wdWJsaWNfa2V5IjoiRUQzOEIwMjg4RUEyNDBCNENERUMxOEExQTYyODlFQjQ5MDA3RTRFQkMwREU5NDQ4MDNFQjdFRjE0MUM1NjY0MDczIiwibWFuaWZlc3QiOiJKQUFBQUFGeEllMDRzQ2lPb2tDMHpld1lvYVlvbnJTUUIrVHJ3TjZVU0FQcmZ2RkJ4V1pBYzNNaEFnT0tjdkl1Y2hhbHJady9nbFR1T3hWM0lPQ2Nwb3J4TUI3SnFBVnVwazFlZGtjd1JRSWhBT3ZSenBlK0lZWksxTXlJbklRWjg3SnZQMko4U0lYQ1haTVBCQ2RJVEJhbUFpQVNhdkpYaTlwd3M4ckRESlN4aEdNbG1FN3pJNWJTQThpdnRSQzlMZ3ErVVhBU1FEbDNlb3FMSUQrRVRKTk0remJNdXZ3dmNIRUl4ZUJaa1o5ZnA1akp2Nk9DVFB3bGo0VEpTdXkxYXZFV3FVWVMycml2NUR2bDJoYUZVb0NIZjR5YXdBQT0ifSx7InZhbGlkYXRpb25fcHVibGljX2tleSI6IkVERUUxMERDMzZBQ0Q5OTVDOEUwRTg2RTNDRDJGQkY4MzAxQTRBQzJCODg0N0I2MUExOTM1REU0OTczQjQwN0MwRSIsIm1hbmlmZXN0IjoiSkFBQUFBRnhJZTN1RU53MnJObVZ5T0RvYmp6UysvZ3dHa3JDdUlSN1lhR1RYZVNYTzBCOERuTWhBbVgwdmI3aitsZ0JqRmpiTjlSbEE4Nko3QU8yVm42SExxdU8zYWlzSzRtd2RrWXdSQUlnZnhCTG43aTRqZy9kaTBVMjVxNmtJYlZmVHpxYkEwU0NwUTBJNTdUT0ZrY0NJRk10SlFwRU5qQjJLMkVtdkJIUHZOY3d1U1BjM3ZzRWVxRTJyTkovY1Q1RGNCSkFmNjhYUEZ1NVJqQ2VMZ3BGSk03UEtGTGdvVjhlMW54TzVld2pxOVErVEFFR25GeVMwSU93ZjZwT090SVZNZFZlWHUxdjZwNGZoWFFrZGloSHQxeDZBZz09In0seyJ2YWxpZGF0aW9uX3B1YmxpY19rZXkiOiJFRDU4M0VDRDA2QzNCNzM2OTk4MEU2NUM3OEM0NDBBNTI5MzAwRjU1N0VEODEyNTYyODNGN0RENUFBMzUxM0EzMzQiLCJtYW5pZmVzdCI6IkpBQUFBQUZ4SWUxWVBzMEd3N2MybVlEbVhIakVRS1VwTUE5VmZ0Z1NWaWcvZmRXcU5ST2pOSE1oQXl1VW56WloxbjIvR2FUbUUxbTdIL3Y5WWxaeURFd0hZM2dTSFVBM0lDTDlka1l3UkFJZ0h4MlBIdmlkb04rNXlHOVdlQVMyazdud0lNOGFqeFFXNndqdnQ4a0JlbkFDSUROeFFQUWtEeURKSDlzZVM1QzYybUFhclFtZ2lOODlZUzNqaE50bnZFSXFjQkpBajdKaDBLYWMrYUpkcG9lcHUvK2VKS25uRlE3WUJ5WkI4ZU1aK1NTMXpMaEUrbGlwLzQ5cXFWTmNwQXhFcWZhR3R4SnpvREREMS9RYnVVN05PU1BrQ2c9PSJ9LHsidmFsaWRhdGlvbl9wdWJsaWNfa2V5IjoiRUQ5NUM1MTcyQjJBRDdEMzk0MzRFRUJDNDM2QjY1QjNCQjdFNThENUMxQ0VGQzgyMEI2OTcyQUNBRDc3NkUyODZBIiwibWFuaWZlc3QiOiJKQUFBQUFGeEllMlZ4UmNyS3RmVGxEVHV2RU5yWmJPN2ZsalZ3Yzc4Z2d0cGNxeXRkMjRvYW5NaEFpcWNSZGUzTVFaMDc1ZmE0Wk5OeVJhWUpHTWRCTmtCbm4zYlFyS3NlQkRRZGtZd1JBSWdVK0xmY0U3MURQVnJPK0t0VUJqUTlEMnUway9QcjdsdWtPMW5QUmo2aFNBQ0lETkxZQy9KRmdvYkNzSWEwQkd3KzZiVW5PdzltZVUzRmRYZ1I3UTdTb3FKY0JKQVhRYWtPb1FuUHAzcGNMTDd6ZEtDUFVYNGIrL0ZDOVVuaHFwK085eFFGblJhQ1dWR21rNU1KT0lNczRXT1FkcE0xajNPZ1NzQUJtUnVDWFl2d28vbkR3PT0ifSx7InZhbGlkYXRpb25fcHVibGljX2tleSI6IkVEOTAxNjNEMkJGMEI3Nzg4OTA0QzRBNDExOEQ3RDk2ODkyMEU4NDdEODhCNzkxNzgzOTA4MzdERTNDQTI2MTU2MiIsIm1hbmlmZXN0IjoiSkFBQUFBRnhJZTJRRmowcjhMZDRpUVRFcEJHTmZaYUpJT2hIMkl0NUY0T1FnMzNqeWlZVlluTWhBNzJWVFJpR2hrSkJ0cWdHSER6SGo3WWJDNitOc0VLckZITnVFL0xPM1RuNWRrWXdSQUlnZjhzK2ZZdDBsbHJLUTJxaVdQbkdtYjZxSlBvZThPbkNNM1ZTMjlYS2JZWUNJSEdubEo0T1RzMmRYdWdPNkJ0bzYzTnBEdnZxSitXSXdkWUtxWjZCaUJmemNCSkFHdk50a29nNHBmRTVkWlJ3bWljODdaQmVldW5PaDRZcEwwU0VSZHhXajQzQ3M5ODE1ekZKdVp5c1NhVVgyUi92ZEUyVktxdlNncXF0REVuck1vMm9Bdz09In1dfQ==",
42 "signature" : "9FF30EDC4DED7ABCD0D36389B7C716EED4B5E4F043902853534EBAC7BE966BB3813D5CF25E4DADA5E657CCF019FFD11847FD3CC44B5559A6FCEEE4C3DCFF8D0E",
43 "version": 1
44}
45)vl";
46}
47
48constexpr auto kDefaultExpires = std::chrono::seconds{3600};
50} // namespace detail
51
52namespace test {
54{
55private:
57
58 void
60 {
61 testcase("Config Load");
62
63 using namespace jtx;
64
65 Env env(*this, envconfig(), nullptr, beast::Severity::Disabled);
66 auto trustedSites = std::make_unique<ValidatorSite>(env.app(), env.journal);
67
68 // load should accept empty sites list
69 std::vector<std::string> const emptyCfgSites;
70 BEAST_EXPECT(trustedSites->load(emptyCfgSites));
71
72 // load should accept valid validator site uris
73 std::vector<std::string> const cfgSites(
74 {"http://ripple.com/",
75 "http://ripple.com/validators",
76 "http://ripple.com:8080/validators",
77 "http://207.261.33.37/validators",
78 "http://207.261.33.37:8080/validators",
79 "https://ripple.com/validators",
80 "https://ripple.com:443/validators",
81 "file:///etc/xrpld/validators.txt",
82 "file:///C:/Lib/validators.txt"
83#if !_MSC_VER
84 ,
85 "file:///"
86#endif
87 });
88 BEAST_EXPECT(trustedSites->load(cfgSites));
89
90 // load should reject validator site uris with invalid schemes
91 std::vector<std::string> badSites({"ftp://ripple.com/validators"});
92 BEAST_EXPECT(!trustedSites->load(badSites));
93
94 badSites[0] = "wss://ripple.com/validators";
95 BEAST_EXPECT(!trustedSites->load(badSites));
96
97 badSites[0] = "ripple.com/validators";
98 BEAST_EXPECT(!trustedSites->load(badSites));
99
100 // Host names are not supported for file URLs
101 badSites[0] = "file://ripple.com/vl.txt";
102 BEAST_EXPECT(!trustedSites->load(badSites));
103
104 // Even local host names are not supported for file URLs
105 badSites[0] = "file://localhost/home/user/vl.txt";
106 BEAST_EXPECT(!trustedSites->load(badSites));
107
108 // Nor IP addresses
109 badSites[0] = "file://127.0.0.1/home/user/vl.txt";
110 BEAST_EXPECT(!trustedSites->load(badSites));
111
112 // File URL path can not be empty
113 badSites[0] = "file://";
114 BEAST_EXPECT(!trustedSites->load(badSites));
115
116#if _MSC_VER // Windows paths strip off the leading /, leaving the path empty
117 // File URL path can not be a directory
118 // (/ is the only path we can reasonably assume is a directory)
119 badSites[0] = "file:///";
120 BEAST_EXPECT(!trustedSites->load(badSites));
121#endif
122 }
123
136 void
138 {
139 testcase << "Fetch list - "
140 << boost::algorithm::join(
141 paths | boost::adaptors::transformed([](FetchListConfig const& cfg) {
142 return cfg.path + (cfg.ssl ? " [https] v" : " [http] v") +
143 std::to_string(cfg.serverVersion) + " " + cfg.msg;
144 }),
145 ", ");
146
147 using namespace jtx;
148 using namespace std::chrono_literals;
149
150 Env env(*this, [&]() {
151 auto p = test::jtx::envconfig();
152 p->legacy("database_path", good.subdir().string());
153 return p;
154 }());
155 auto& trustedKeys = env.app().getValidators();
156 env.timeKeeper().set(env.timeKeeper().now() + 30s);
157
158 test::StreamSink sink;
159 beast::Journal journal{sink};
160
161 std::vector<std::string> const emptyCfgKeys;
162 struct Publisher
163 {
164 Publisher(FetchListConfig const& c) : cfg{c}
165 {
166 }
169 std::string uri;
170 FetchListConfig const& cfg;
171 bool isRetry{};
172 };
174
175 static constexpr auto kListSize = 20;
176 std::vector<std::string> cfgPublishers;
177
178 for (auto const& cfg : paths)
179 {
180 servers.emplace_back(cfg);
181 auto& item = servers.back();
182 item.isRetry = cfg.path == "/bad-resource";
183 item.list.reserve(kListSize);
184 while (item.list.size() < kListSize)
185 item.list.push_back(TrustedPublisherServer::randomValidator());
186
187 NetClock::time_point const expires = env.timeKeeper().now() + cfg.expiresFromNow;
188 NetClock::time_point const effective2 = expires - cfg.effectiveOverlap;
189 NetClock::time_point const expires2 = effective2 + cfg.expiresFromNow;
190 item.server = makeTrustedPublisherServer(
191 env.app().getIOContext(),
192 item.list,
193 expires,
194 {{effective2, expires2}},
195 cfg.ssl,
196 cfg.serverVersion);
197 std::string const pubHex = strHex(item.server->publisherPublic());
198 cfgPublishers.push_back(pubHex);
199
200 if (item.cfg.failFetch)
201 {
202 // Create a cache file
203 auto const name = good.subdir() / ("cache." + pubHex);
204 std::ofstream o(name.string());
205 o << "{}";
206 }
207
209 uri << (cfg.ssl ? "https://" : "http://") << item.server->localEndpoint() << cfg.path;
210 item.uri = uri.str();
211 }
212
213 BEAST_EXPECT(trustedKeys.load({}, emptyCfgKeys, cfgPublishers));
214
215 // Normally, tests will only need a fraction of this time,
216 // but sometimes DNS resolution takes an inordinate amount
217 // of time, so the test will just wait.
218 auto sites = std::make_unique<ValidatorSite>(env.app(), journal, 12s);
219
221 for (auto const& u : servers)
222 {
223 log << "Testing " << u.uri << std::endl;
224 uris.push_back(u.uri);
225 }
226 sites->load(uris);
227 sites->start();
228 sites->join();
229
230 auto const jv = sites->getJson();
231 for (auto const& u : servers)
232 {
233 for (auto const& val : u.list)
234 {
235 BEAST_EXPECT(trustedKeys.listed(val.masterPublic) != u.cfg.failApply);
236 BEAST_EXPECT(trustedKeys.listed(val.signingPublic) != u.cfg.failApply);
237 }
238
239 json::Value myStatus;
240 for (auto const& vs : jv[jss::validator_sites])
241 {
242 if (vs[jss::uri].asString().contains(u.uri))
243 myStatus = vs;
244 }
245 BEAST_EXPECTS(
246 myStatus[jss::last_refresh_message].asString().empty() != u.cfg.failFetch,
247 to_string(myStatus) + "\n" + sink.messages().str());
248
249 if (!u.cfg.msg.empty())
250 {
251 BEAST_EXPECTS(sink.messages().str().contains(u.cfg.msg), sink.messages().str());
252 }
253
254 if (u.cfg.expectedRefreshMin != 0)
255 {
256 BEAST_EXPECTS(
257 myStatus[jss::refresh_interval_min].asInt() == u.cfg.expectedRefreshMin,
258 to_string(myStatus));
259 }
260
261 if (u.cfg.failFetch)
262 {
263 using namespace std::chrono;
264 std::stringstream nextRefreshStr{myStatus[jss::next_refresh_time].asString()};
265 system_clock::time_point nextRefresh;
266 date::from_stream(nextRefreshStr, "%Y-%b-%d %T", nextRefresh);
267 BEAST_EXPECT(!nextRefreshStr.fail());
268 auto now = system_clock::now();
269 BEAST_EXPECTS(
270 nextRefresh <= now + (u.isRetry ? seconds{30} : minutes{5}),
271 "Now: " + to_string(now) + ", NR: " + nextRefreshStr.str());
272 }
273 }
274 }
275
276 void
278 {
279 testcase << "File list - " << paths[0].first
280 << (paths.size() > 1 ? ", " + paths[1].first : "");
281
282 using namespace jtx;
283
284 Env env(*this);
285
286 test::StreamSink sink;
287 beast::Journal journal{sink};
288
289 struct Publisher
290 {
291 std::string uri;
292 std::string expectMsg;
293 bool shouldFail;
294 };
296
297 for (auto const& cfg : paths)
298 {
299 servers.push_back({});
300 auto& item = servers.back();
301 item.shouldFail = !cfg.second.empty();
302 item.expectMsg = cfg.second;
303
305 uri << "file://" << cfg.first;
306 item.uri = uri.str();
307 }
308
309 auto sites = std::make_unique<ValidatorSite>(env.app(), journal);
310
312 uris.reserve(servers.size());
313 for (auto const& u : servers)
314 uris.push_back(u.uri);
315 sites->load(uris);
316 sites->start();
317 sites->join();
318
319 for (auto const& u : servers)
320 {
321 auto const jv = sites->getJson();
322 json::Value myStatus;
323 for (auto const& vs : jv[jss::validator_sites])
324 {
325 if (vs[jss::uri].asString().contains(u.uri))
326 myStatus = vs;
327 }
328 BEAST_EXPECTS(
329 myStatus[jss::last_refresh_message].asString().empty() != u.shouldFail,
330 to_string(myStatus));
331 if (u.shouldFail)
332 {
333 BEAST_EXPECTS(sink.messages().str().contains(u.expectMsg), sink.messages().str());
334 }
335 }
336 }
337
338 void
340 {
341 auto fullPath = [](detail::FileDirGuard const& guard) {
342 auto absPath = absolute(guard.file()).string();
343 if (absPath.front() != '/')
344 absPath.insert(absPath.begin(), '/');
345 return absPath;
346 };
347 {
348 // Create a file with a real validator list
349 detail::FileDirGuard const good(
350 *this, "test_val", "vl.txt", detail::realValidatorContents());
351 // Create a file with arbitrary content
352 detail::FileDirGuard const hello(*this, "test_val", "helloworld.txt", "Hello, world!");
353 // Create a file with malformed Json
355 *this, "test_val", "json.txt", R"json({ "version": 2, "extra" : "value" })json");
356 auto const goodPath = fullPath(good);
357 auto const helloPath = fullPath(hello);
358 auto const jsonPath = fullPath(json);
359 auto const missingPath = jsonPath + ".bad";
361 {goodPath, ""},
362 {helloPath, "Unable to parse JSON response from file://" + helloPath},
363 {jsonPath, "Missing fields in JSON response from file://" + jsonPath},
364 {missingPath, "Problem retrieving from file://" + missingPath},
365 });
366 }
367 }
368
369public:
370 void
371 run() override
372 {
374
375 detail::DirGuard const good(*this, "test_fetch");
376 for (auto ssl : {true, false})
377 {
378 // fetch single site
379 testFetchList(good, {{.path = "/validators", .msg = "", .ssl = ssl}});
380 testFetchList(good, {{.path = "/validators2", .msg = "", .ssl = ssl}});
381 // fetch multiple sites
383 good,
384 {{.path = "/validators", .msg = "", .ssl = ssl},
385 {.path = "/validators", .msg = "", .ssl = ssl}});
387 good,
388 {{.path = "/validators", .msg = "", .ssl = ssl},
389 {.path = "/validators2", .msg = "", .ssl = ssl}});
391 good,
392 {{.path = "/validators2", .msg = "", .ssl = ssl},
393 {.path = "/validators", .msg = "", .ssl = ssl}});
395 good,
396 {{.path = "/validators2", .msg = "", .ssl = ssl},
397 {.path = "/validators2", .msg = "", .ssl = ssl}});
398 // fetch single site with single redirects
399 testFetchList(good, {{.path = "/redirect_once/301", .msg = "", .ssl = ssl}});
400 testFetchList(good, {{.path = "/redirect_once/302", .msg = "", .ssl = ssl}});
401 testFetchList(good, {{.path = "/redirect_once/307", .msg = "", .ssl = ssl}});
402 testFetchList(good, {{.path = "/redirect_once/308", .msg = "", .ssl = ssl}});
403 // one redirect, one not
405 good,
406 {{.path = "/validators", .msg = "", .ssl = ssl},
407 {.path = "/redirect_once/302", .msg = "", .ssl = ssl}});
409 good,
410 {{.path = "/validators2", .msg = "", .ssl = ssl},
411 {.path = "/redirect_once/302", .msg = "", .ssl = ssl}});
412 // UNLs with a "gap" between validUntil of one and validFrom of the
413 // next
415 good,
416 {{.path = "/validators2",
417 .msg = "",
418 .ssl = ssl,
419 .failFetch = false,
420 .failApply = false,
421 .serverVersion = 1,
422 .expiresFromNow = detail::kDefaultExpires,
423 .effectiveOverlap = std::chrono::seconds{-90}}});
424 // fetch single site with unending redirect (fails to load)
426 good,
427 {{.path = "/redirect_forever/301",
428 .msg = "Exceeded max redirects",
429 .ssl = ssl,
430 .failFetch = true,
431 .failApply = true}});
432 // two that redirect forever
434 good,
435 {{.path = "/redirect_forever/307",
436 .msg = "Exceeded max redirects",
437 .ssl = ssl,
438 .failFetch = true,
439 .failApply = true},
440 {.path = "/redirect_forever/308",
441 .msg = "Exceeded max redirects",
442 .ssl = ssl,
443 .failFetch = true,
444 .failApply = true}});
445 // one unending redirect, one not
447 good,
448 {{.path = "/validators", .msg = "", .ssl = ssl},
449 {.path = "/redirect_forever/302",
450 .msg = "Exceeded max redirects",
451 .ssl = ssl,
452 .failFetch = true,
453 .failApply = true}});
454 // one unending redirect, one not
456 good,
457 {{.path = "/validators2", .msg = "", .ssl = ssl},
458 {.path = "/redirect_forever/302",
459 .msg = "Exceeded max redirects",
460 .ssl = ssl,
461 .failFetch = true,
462 .failApply = true}});
463 // invalid redir Location
465 good,
466 {{.path = "/redirect_to/ftp://invalid-url/302",
467 .msg = "Invalid redirect location",
468 .ssl = ssl,
469 .failFetch = true,
470 .failApply = true}});
472 good,
473 {{.path = "/redirect_to/file://invalid-url/302",
474 .msg = "Invalid redirect location",
475 .ssl = ssl,
476 .failFetch = true,
477 .failApply = true}});
478 // invalid json
480 good,
481 {{.path = "/validators/bad",
482 .msg = "Unable to parse JSON response",
483 .ssl = ssl,
484 .failFetch = true,
485 .failApply = true}});
487 good,
488 {{.path = "/validators2/bad",
489 .msg = "Unable to parse JSON response",
490 .ssl = ssl,
491 .failFetch = true,
492 .failApply = true}});
493 // error status returned
495 good,
496 {{.path = "/bad-resource",
497 .msg = "returned bad status",
498 .ssl = ssl,
499 .failFetch = true,
500 .failApply = true}});
501 // location field missing
503 good,
504 {{.path = "/redirect_nolo/308",
505 .msg = "returned a redirect with no Location",
506 .ssl = ssl,
507 .failFetch = true,
508 .failApply = true}});
509 // json fields missing
511 good,
512 {{.path = "/validators/missing",
513 .msg = "Missing fields in JSON response",
514 .ssl = ssl,
515 .failFetch = true,
516 .failApply = true}});
518 good,
519 {{.path = "/validators2/missing",
520 .msg = "Missing fields in JSON response",
521 .ssl = ssl,
522 .failFetch = true,
523 .failApply = true}});
524 // timeout
526 good,
527 {{.path = "/sleep/13",
528 .msg = "took too long",
529 .ssl = ssl,
530 .failFetch = true,
531 .failApply = true}});
532 // bad manifest format using known versions
533 // * Retrieves a v1 formatted list claiming version 2
535 good,
536 {{.path = "/validators",
537 .msg = "Missing fields",
538 .ssl = ssl,
539 .failFetch = true,
540 .failApply = true,
541 .serverVersion = 2}});
542 // * Retrieves a v2 formatted list claiming version 1
544 good,
545 {{.path = "/validators2",
546 .msg = "Missing fields",
547 .ssl = ssl,
548 .failFetch = true,
549 .failApply = true,
550 .serverVersion = 0}});
551 // bad manifest version
552 // Because versions other than 1 are treated as v2, the v1
553 // list won't have the blobs_v2 fields, and thus will claim to have
554 // missing fields
556 good,
557 {{.path = "/validators",
558 .msg = "Missing fields",
559 .ssl = ssl,
560 .failFetch = true,
561 .failApply = true,
562 .serverVersion = 4}});
564 good,
565 {{.path = "/validators2",
566 .msg = "1 unsupported version",
567 .ssl = ssl,
568 .failFetch = false,
569 .failApply = true,
570 .serverVersion = 4}});
571 using namespace std::chrono_literals;
572 // get expired validator list
574 good,
575 {{.path = "/validators",
576 .msg = "Applied 1 expired validator list(s)",
577 .ssl = ssl,
578 .failFetch = false,
579 .failApply = false,
580 .serverVersion = 1,
581 .expiresFromNow = 0s}});
583 good,
584 {{.path = "/validators2",
585 .msg = "Applied 1 expired validator list(s)",
586 .ssl = ssl,
587 .failFetch = false,
588 .failApply = false,
589 .serverVersion = 1,
590 .expiresFromNow = 0s,
591 .effectiveOverlap = -1s}});
592 // force an out-of-range validUntil value
594 good,
595 {{.path = "/validators",
596 .msg = "1 invalid validator list(s)",
597 .ssl = ssl,
598 .failFetch = false,
599 .failApply = true,
600 .serverVersion = 1,
601 .expiresFromNow = std::chrono::seconds{json::Value::kMinInt}}});
602 // force an out-of-range validUntil value on the future list
603 // The first list is accepted. The second fails. The parser
604 // returns the "best" result, so this looks like a success.
606 good,
607 {{.path = "/validators2",
608 .msg = "",
609 .ssl = ssl,
610 .failFetch = false,
611 .failApply = false,
612 .serverVersion = 1,
613 .expiresFromNow = std::chrono::seconds{json::Value::kMaxInt - 300},
614 .effectiveOverlap = 299s}});
615 // force an out-of-range validFrom value
616 // The first list is accepted. The second fails. The parser
617 // returns the "best" result, so this looks like a success.
619 good,
620 {{.path = "/validators2",
621 .msg = "",
622 .ssl = ssl,
623 .failFetch = false,
624 .failApply = false,
625 .serverVersion = 1,
626 .expiresFromNow = std::chrono::seconds{json::Value::kMaxInt - 300},
627 .effectiveOverlap = 301s}});
628 // force an out-of-range validUntil value on _both_ lists
630 good,
631 {{.path = "/validators2",
632 .msg = "2 invalid validator list(s)",
633 .ssl = ssl,
634 .failFetch = false,
635 .failApply = true,
636 .serverVersion = 1,
638 .effectiveOverlap = std::chrono::seconds{json::Value::kMaxInt - 6000}}});
639 // verify refresh intervals are properly clamped
641 good,
642 {{.path = "/validators/refresh/0",
643 .msg = "",
644 .ssl = ssl,
645 .failFetch = false,
646 .failApply = false,
647 .serverVersion = 1,
648 .expiresFromNow = detail::kDefaultExpires,
649 .effectiveOverlap = detail::kDefaultEffectiveOverlap,
650 .expectedRefreshMin = 1}}); // minimum of 1 minute
652 good,
653 {{.path = "/validators2/refresh/0",
654 .msg = "",
655 .ssl = ssl,
656 .failFetch = false,
657 .failApply = false,
658 .serverVersion = 1,
659 .expiresFromNow = detail::kDefaultExpires,
660 .effectiveOverlap = detail::kDefaultEffectiveOverlap,
661 .expectedRefreshMin = 1}}); // minimum of 1 minute
663 good,
664 {{.path = "/validators/refresh/10",
665 .msg = "",
666 .ssl = ssl,
667 .failFetch = false,
668 .failApply = false,
669 .serverVersion = 1,
670 .expiresFromNow = detail::kDefaultExpires,
671 .effectiveOverlap = detail::kDefaultEffectiveOverlap,
672 .expectedRefreshMin = 10}}); // 10 minutes is fine
674 good,
675 {{.path = "/validators2/refresh/10",
676 .msg = "",
677 .ssl = ssl,
678 .failFetch = false,
679 .failApply = false,
680 .serverVersion = 1,
681 .expiresFromNow = detail::kDefaultExpires,
682 .effectiveOverlap = detail::kDefaultEffectiveOverlap,
683 .expectedRefreshMin = 10}}); // 10 minutes is fine
685 good,
686 {{.path = "/validators/refresh/2000",
687 .msg = "",
688 .ssl = ssl,
689 .failFetch = false,
690 .failApply = false,
691 .serverVersion = 1,
692 .expiresFromNow = detail::kDefaultExpires,
693 .effectiveOverlap = detail::kDefaultEffectiveOverlap,
694 .expectedRefreshMin = 60 * 24}}); // max of 24 hours
696 good,
697 {{.path = "/validators2/refresh/2000",
698 .msg = "",
699 .ssl = ssl,
700 .failFetch = false,
701 .failApply = false,
702 .serverVersion = 1,
703 .expiresFromNow = detail::kDefaultExpires,
704 .effectiveOverlap = detail::kDefaultEffectiveOverlap,
705 .expectedRefreshMin = 60 * 24}}); // max of 24 hours
706 }
707 using namespace boost::filesystem;
708 for (auto const& file : directory_iterator(good.subdir()))
709 {
710 remove_all(file);
711 }
712
713 testFileURLs();
714 }
715};
716
718
719} // namespace test
720} // namespace xrpl
T back(T... args)
A generic endpoint for log messages.
Definition Journal.h:38
A testsuite class.
Definition suite.h:50
LogOs< char > log
Logging output stream.
Definition suite.h:146
TestcaseT testcase
Memberspace for declaring test cases.
Definition suite.h:149
Represents a JSON value.
Definition json_value.h:130
static constexpr Int kMaxInt
Definition json_value.h:143
static constexpr Int kMinInt
Definition json_value.h:142
std::string asString() const
Returns the unquoted string value.
std::chrono::time_point< NetClock > time_point
Definition chrono.h:46
virtual ValidatorList & getValidators()=0
Create a directory and remove it when it's done.
path const & subdir() const
Write a file in a directory and remove when done.
std::stringstream const & messages() const
TrustedPublisherServer::Validator Validator
void testFileList(std::vector< std::pair< std::string, std::string > > const &paths)
void testFetchList(detail::DirGuard const &good, std::vector< FetchListConfig > const &paths)
void run() override
Runs the suite.
A transaction testing environment.
Definition Env.h:143
Application & app()
Definition Env.h:280
beast::Journal const journal
Definition Env.h:184
T emplace_back(T... args)
T empty(T... args)
T endl(T... args)
T fail(T... args)
T make_unique(T... args)
JSON (JavaScript Object Notation).
Definition json_errors.h:5
constexpr auto kDefaultEffectiveOverlap
constexpr auto kDefaultExpires
constexpr char const * realValidatorContents()
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Definition envconfig.h:28
std::shared_ptr< TrustedPublisherServer > makeTrustedPublisherServer(boost::asio::io_context &ioc, std::vector< TrustedPublisherServer::Validator > const &validators, NetClock::time_point validUntil, std::vector< std::pair< NetClock::time_point, NetClock::time_point > > const &futures, bool useSSL=false, int version=1, bool immediateStart=true, int sequence=1)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
std::string strHex(FwdIt begin, FwdIt end)
Definition strHex.h:10
BEAST_DEFINE_TESTSUITE_PRIO(AccountSet, app, xrpl, 1)
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:633
T push_back(T... args)
T reserve(T... args)
T size(T... args)
T str(T... args)
T to_string(T... args)