8c1b51f06e8654a3d379bd4fcb3f90f37c37fe1c
[platform/upstream/connectedhomeip.git] / src / lib / mdns / minimal / tests / TestResourceRecord.cpp
1 /*
2  *
3  *    Copyright (c) 2020 Project CHIP Authors
4  *    All rights reserved.
5  *
6  *    Licensed under the Apache License, Version 2.0 (the "License");
7  *    you may not use this file except in compliance with the License.
8  *    You may obtain a copy of the License at
9  *
10  *        http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *    Unless required by applicable law or agreed to in writing, software
13  *    distributed under the License is distributed on an "AS IS" BASIS,
14  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *    See the License for the specific language governing permissions and
16  *    limitations under the License.
17  */
18
19 #include <mdns/minimal/ResourceRecord.h>
20 #include <support/UnitTestRegistration.h>
21
22 #include <nlunit-test.h>
23
24 namespace {
25
26 using namespace chip;
27 using namespace mdns::Minimal;
28
29 constexpr uint16_t kTestQnameCount        = 2;
30 const char * kTestQnames[kTestQnameCount] = { "foo", "bar" };
31
32 class FakeResourceRecord : public ResourceRecord
33 {
34 public:
35     FakeResourceRecord(const char * data) : ResourceRecord(QType::ANY, kTestQnames, kTestQnameCount), mData(data) {}
36
37 protected:
38     bool WriteData(chip::BufBound & out) const override
39     {
40         out.Put(mData);
41         return out.Fit();
42     }
43
44 private:
45     const char * mData;
46 };
47
48 void CanWriteSimpleRecord(nlTestSuite * inSuite, void * inContext)
49 {
50     uint8_t headerBuffer[HeaderRef::kSizeBytes];
51     uint8_t dataBuffer[128];
52
53     HeaderRef header(headerBuffer);
54     header.Clear();
55
56     BufBound output(dataBuffer, sizeof(dataBuffer));
57     FakeResourceRecord record("somedata");
58
59     record.SetTtl(0x11223344);
60
61     const uint8_t expectedOutput[] = {
62         //
63         3,    'f',  'o',  'o',  // QNAME part: foo
64         3,    'b',  'a',  'r',  // QNAME part: bar
65         0,                      // QNAME ends
66         0,    1,                // QClass IN
67         0,    255,              // QType ANY (totally fake)
68         0x11, 0x22, 0x33, 0x44, // TTL
69         0,    8,                // data size
70         's',  'o',  'm',  'e',  'd', 'a', 't', 'a',
71     };
72
73     NL_TEST_ASSERT(inSuite, record.Append(header, ResourceType::kAnswer, output));
74     NL_TEST_ASSERT(inSuite, header.GetAnswerCount() == 1);
75     NL_TEST_ASSERT(inSuite, header.GetAuthorityCount() == 0);
76     NL_TEST_ASSERT(inSuite, header.GetAdditionalCount() == 0);
77     NL_TEST_ASSERT(inSuite, output.Needed() == sizeof(expectedOutput));
78     NL_TEST_ASSERT(inSuite, memcmp(dataBuffer, expectedOutput, sizeof(expectedOutput)) == 0);
79 }
80
81 void CanWriteMultipleRecords(nlTestSuite * inSuite, void * inContext)
82 {
83     uint8_t headerBuffer[HeaderRef::kSizeBytes];
84     uint8_t dataBuffer[128];
85
86     HeaderRef header(headerBuffer);
87     header.Clear();
88
89     BufBound output(dataBuffer, sizeof(dataBuffer));
90     FakeResourceRecord record1("somedata");
91     FakeResourceRecord record2("moredata");
92     FakeResourceRecord record3("xyz");
93
94     record1.SetTtl(0x11223344);
95     record2.SetTtl(0);
96     record3.SetTtl(0xFF);
97
98     const uint8_t expectedOutput[] = {
99         3,    'f',  'o',  'o',                      // QNAME part: foo
100         3,    'b',  'a',  'r',                      // QNAME part: bar
101         0,                                          // QNAME ends
102         0,    1,                                    // QClass IN
103         0,    255,                                  // QType ANY (totally fake)
104         0x11, 0x22, 0x33, 0x44,                     // TTL
105         0,    8,                                    // data size
106         's',  'o',  'm',  'e',  'd', 'a', 't', 'a', //
107         3,    'f',  'o',  'o',                      // QNAME part: foo
108         3,    'b',  'a',  'r',                      // QNAME part: bar
109         0,                                          // QNAME ends
110         0,    1,                                    // QClass IN
111         0,    255,                                  // QType ANY (totally fake)
112         0,    0,    0,    0,                        // TTL
113         0,    8,                                    // data size
114         'm',  'o',  'r',  'e',  'd', 'a', 't', 'a', //
115         3,    'f',  'o',  'o',                      // QNAME part: foo
116         3,    'b',  'a',  'r',                      // QNAME part: bar
117         0,                                          // QNAME ends
118         0,    1,                                    // QClass IN
119         0,    255,                                  // QType ANY (totally fake)
120         0,    0,    0,    0xFF,                     // TTL
121         0,    3,                                    // data size
122         'x',  'y',  'z',
123     };
124
125     NL_TEST_ASSERT(inSuite, record1.Append(header, ResourceType::kAnswer, output));
126     NL_TEST_ASSERT(inSuite, header.GetAnswerCount() == 1);
127     NL_TEST_ASSERT(inSuite, header.GetAuthorityCount() == 0);
128     NL_TEST_ASSERT(inSuite, header.GetAdditionalCount() == 0);
129
130     NL_TEST_ASSERT(inSuite, record2.Append(header, ResourceType::kAuthority, output));
131     NL_TEST_ASSERT(inSuite, header.GetAnswerCount() == 1);
132     NL_TEST_ASSERT(inSuite, header.GetAuthorityCount() == 1);
133     NL_TEST_ASSERT(inSuite, header.GetAdditionalCount() == 0);
134
135     NL_TEST_ASSERT(inSuite, record3.Append(header, ResourceType::kAdditional, output));
136     NL_TEST_ASSERT(inSuite, header.GetAnswerCount() == 1);
137     NL_TEST_ASSERT(inSuite, header.GetAuthorityCount() == 1);
138     NL_TEST_ASSERT(inSuite, header.GetAdditionalCount() == 1);
139
140     NL_TEST_ASSERT(inSuite, output.Needed() == sizeof(expectedOutput));
141     NL_TEST_ASSERT(inSuite, memcmp(dataBuffer, expectedOutput, sizeof(expectedOutput)) == 0);
142 }
143
144 void RecordOrderIsEnforced(nlTestSuite * inSuite, void * inContext)
145 {
146     uint8_t headerBuffer[HeaderRef::kSizeBytes];
147     uint8_t dataBuffer[128];
148
149     HeaderRef header(headerBuffer);
150
151     BufBound output(dataBuffer, sizeof(dataBuffer));
152     FakeResourceRecord record("somedata");
153
154     header.Clear();
155     header.SetAuthorityCount(1);
156     NL_TEST_ASSERT(inSuite, record.Append(header, ResourceType::kAnswer, output) == false);
157
158     header.Clear();
159     header.SetAdditionalCount(1);
160     NL_TEST_ASSERT(inSuite, record.Append(header, ResourceType::kAnswer, output) == false);
161     NL_TEST_ASSERT(inSuite, record.Append(header, ResourceType::kAuthority, output) == false);
162 }
163
164 void ErrorsOutOnSmallBuffers(nlTestSuite * inSuite, void * inContext)
165 {
166     uint8_t headerBuffer[HeaderRef::kSizeBytes];
167     uint8_t dataBuffer[123];
168
169     HeaderRef header(headerBuffer);
170
171     FakeResourceRecord record("somedata");
172
173     const uint8_t expectedOutput[] = {
174         //
175         3,   'f', 'o', 'o', // QNAME part: foo
176         3,   'b', 'a', 'r', // QNAME part: bar
177         0,                  // QNAME ends
178         0,   1,             // QClass IN
179         0,   255,           // QType ANY (totally fake)
180         0,   0,   0,   0,   // TTL
181         0,   8,             // data size
182         's', 'o', 'm', 'e', 'd', 'a', 't', 'a',
183     };
184
185     header.Clear();
186     uint8_t clearHeader[HeaderRef::kSizeBytes];
187
188     memcpy(clearHeader, headerBuffer, HeaderRef::kSizeBytes);
189
190     for (size_t i = 0; i < sizeof(expectedOutput); i++)
191     {
192         memset(dataBuffer, 0, sizeof(dataBuffer));
193         BufBound output(dataBuffer, i);
194
195         NL_TEST_ASSERT(inSuite, record.Append(header, ResourceType::kAnswer, output) == false);
196
197         // header untouched
198         NL_TEST_ASSERT(inSuite, memcmp(headerBuffer, clearHeader, HeaderRef::kSizeBytes) == 0);
199     }
200
201     memset(dataBuffer, 0, sizeof(dataBuffer));
202     BufBound output(dataBuffer, sizeof(expectedOutput));
203
204     NL_TEST_ASSERT(inSuite, record.Append(header, ResourceType::kAnswer, output));
205     NL_TEST_ASSERT(inSuite, output.Needed() == sizeof(expectedOutput));
206     NL_TEST_ASSERT(inSuite, memcmp(dataBuffer, expectedOutput, sizeof(expectedOutput)) == 0);
207     NL_TEST_ASSERT(inSuite, memcmp(headerBuffer, clearHeader, HeaderRef::kSizeBytes) != 0);
208 }
209
210 void RecordCount(nlTestSuite * inSuite, void * inContext)
211 {
212     constexpr int kAppendCount = 10;
213     uint8_t headerBuffer[HeaderRef::kSizeBytes];
214     uint8_t dataBuffer[123];
215
216     HeaderRef header(headerBuffer);
217     header.Clear();
218
219     FakeResourceRecord record("somedata");
220
221     for (int i = 0; i < kAppendCount; i++)
222     {
223         BufBound output(dataBuffer, sizeof(dataBuffer));
224         NL_TEST_ASSERT(inSuite, record.Append(header, ResourceType::kAnswer, output));
225         NL_TEST_ASSERT(inSuite, header.GetAnswerCount() == i + 1);
226         NL_TEST_ASSERT(inSuite, header.GetAuthorityCount() == 0);
227         NL_TEST_ASSERT(inSuite, header.GetAdditionalCount() == 0);
228     }
229
230     for (int i = 0; i < kAppendCount; i++)
231     {
232         BufBound output(dataBuffer, sizeof(dataBuffer));
233         NL_TEST_ASSERT(inSuite, record.Append(header, ResourceType::kAuthority, output));
234         NL_TEST_ASSERT(inSuite, header.GetAnswerCount() == kAppendCount);
235         NL_TEST_ASSERT(inSuite, header.GetAuthorityCount() == i + 1);
236         NL_TEST_ASSERT(inSuite, header.GetAdditionalCount() == 0);
237     }
238
239     for (int i = 0; i < kAppendCount; i++)
240     {
241         BufBound output(dataBuffer, sizeof(dataBuffer));
242         NL_TEST_ASSERT(inSuite, record.Append(header, ResourceType::kAdditional, output));
243         NL_TEST_ASSERT(inSuite, header.GetAnswerCount() == kAppendCount);
244         NL_TEST_ASSERT(inSuite, header.GetAuthorityCount() == kAppendCount);
245         NL_TEST_ASSERT(inSuite, header.GetAdditionalCount() == i + 1);
246     }
247 }
248
249 const nlTest sTests[] = {
250     NL_TEST_DEF("CanWriteSimpleRecord", CanWriteSimpleRecord),       //
251     NL_TEST_DEF("CanWriteMultipleRecords", CanWriteMultipleRecords), //
252     NL_TEST_DEF("RecordOrderIsEnforced", RecordOrderIsEnforced),     //
253     NL_TEST_DEF("ErrorsOutOnSmallBuffers", ErrorsOutOnSmallBuffers), //
254     NL_TEST_DEF("RecordCount", RecordCount),                         //
255     NL_TEST_SENTINEL()                                               //
256 };
257
258 } // namespace
259
260 int TestResourceRecord(void)
261 {
262     nlTestSuite theSuite = { "ResourceRecord", sTests, nullptr, nullptr };
263     nlTestRunner(&theSuite, nullptr);
264     return nlTestRunnerStats(&theSuite);
265 }
266
267 CHIP_REGISTER_TEST_SUITE(TestResourceRecord)