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