1 /***********************************************************************************************************************************
2 Harness for Loading Test Configurations
3 ***********************************************************************************************************************************/
4 #include "build.auto.h"
5 
6 #include <string.h>
7 
8 #include "common/assert.h"
9 #include "common/crypto/hash.h"
10 #include "common/io/bufferRead.h"
11 #include "common/io/filter/filter.h"
12 #include "common/type/json.h"
13 #include "info/info.h"
14 #include "version.h"
15 
16 #include "common/harnessDebug.h"
17 #include "common/harnessInfo.h"
18 
19 /***********************************************************************************************************************************
20 Add header and checksum to an info file
21 
22 This prevents churn in headers and checksums in the unit tests.  We purposefully do not use the checksum macros from the info module
23 here as a cross-check of that code.
24 ***********************************************************************************************************************************/
25 typedef struct HarnessInfoChecksumData
26 {
27     MemContext *memContext;                                         // Mem context to use for storing data in this structure
28     String *sectionLast;                                            // The last section seen during load
29     IoFilter *checksum;                                             // Checksum calculated from the file
30 } HarnessInfoChecksumData;
31 
32 static void
harnessInfoChecksumCallback(void * callbackData,const String * section,const String * key,const String * value,const Variant * valueVar)33 harnessInfoChecksumCallback(
34     void *callbackData, const String *section, const String *key, const String *value, const Variant *valueVar)
35 {
36     HarnessInfoChecksumData *data = (HarnessInfoChecksumData *)callbackData;
37     (void)valueVar;
38 
39     // Calculate checksum
40     if (data->sectionLast == NULL || !strEq(section, data->sectionLast))
41     {
42         if (data->sectionLast != NULL)
43             ioFilterProcessIn(data->checksum, BUFSTRDEF("},"));
44 
45         ioFilterProcessIn(data->checksum, BUFSTRDEF("\""));
46         ioFilterProcessIn(data->checksum, BUFSTR(section));
47         ioFilterProcessIn(data->checksum, BUFSTRDEF("\":{"));
48 
49         MEM_CONTEXT_BEGIN(data->memContext)
50         {
51             data->sectionLast = strDup(section);
52         }
53         MEM_CONTEXT_END();
54     }
55     else
56         ioFilterProcessIn(data->checksum, BUFSTRDEF(","));
57 
58     ioFilterProcessIn(data->checksum, BUFSTR(jsonFromStr(key)));
59     ioFilterProcessIn(data->checksum, BUFSTRDEF(":"));
60     ioFilterProcessIn(data->checksum, BUFSTR(value));
61 }
62 
63 Buffer *
harnessInfoChecksum(const String * info)64 harnessInfoChecksum(const String *info)
65 {
66     FUNCTION_HARNESS_BEGIN();
67         FUNCTION_HARNESS_PARAM(STRING, info);
68     FUNCTION_HARNESS_END();
69 
70     ASSERT(info != NULL);
71 
72     Buffer *result = NULL;
73 
74     MEM_CONTEXT_TEMP_BEGIN()
75     {
76         // Initialize callback data
77         HarnessInfoChecksumData data =
78         {
79             .memContext = MEM_CONTEXT_TEMP(),
80             .checksum = cryptoHashNew(HASH_TYPE_SHA1_STR),
81         };
82 
83         // Create buffer with space for data, header, and checksum
84         result = bufNew(strSize(info) + 256);
85 
86         bufCat(result, BUFSTRDEF("[backrest]\nbackrest-format="));
87         bufCat(result, BUFSTR(jsonFromUInt(REPOSITORY_FORMAT)));
88         bufCat(result, BUFSTRDEF("\nbackrest-version="));
89         bufCat(result, BUFSTR(jsonFromStr(STRDEF(PROJECT_VERSION))));
90         bufCat(result, BUFSTRDEF("\n\n"));
91         bufCat(result, BUFSTR(info));
92 
93         // Generate checksum by loading ini file
94         ioFilterProcessIn(data.checksum, BUFSTRDEF("{"));
95         iniLoad(ioBufferReadNew(result), harnessInfoChecksumCallback, &data);
96         ioFilterProcessIn(data.checksum, BUFSTRDEF("}}"));
97 
98         // Append checksum to buffer
99         bufCat(result, BUFSTRDEF("\n[backrest]\nbackrest-checksum="));
100         bufCat(result, BUFSTR(jsonFromVar(ioFilterResult(data.checksum))));
101         bufCat(result, BUFSTRDEF("\n"));
102 
103         bufMove(result, memContextPrior());
104     }
105     MEM_CONTEXT_TEMP_END();
106 
107     FUNCTION_HARNESS_RETURN(BUFFER, result);
108 }
109 
110 Buffer *
harnessInfoChecksumZ(const char * info)111 harnessInfoChecksumZ(const char *info)
112 {
113     FUNCTION_HARNESS_BEGIN();
114         FUNCTION_HARNESS_PARAM(STRINGZ, info);
115     FUNCTION_HARNESS_END();
116 
117     ASSERT(info != NULL);
118 
119     FUNCTION_HARNESS_RETURN(BUFFER, harnessInfoChecksum(STR(info)));
120 }
121 
122 /***********************************************************************************************************************************
123 Test callback that logs the results to a string
124 ***********************************************************************************************************************************/
125 void
harnessInfoLoadNewCallback(void * callbackData,const String * section,const String * key,const Variant * value)126 harnessInfoLoadNewCallback(void *callbackData, const String *section, const String *key, const Variant *value)
127 {
128     if (callbackData != NULL)
129         strCatFmt((String *)callbackData, "[%s] %s=%s\n", strZ(section), strZ(key), strZ(jsonFromVar(value)));
130 }
131