1 /** 2 * 3 * /home/tomas/workspace/mqtt-d/source/mqttd/tests.d 4 * 5 * Author: 6 * Tomáš Chaloupka <chalucha@gmail.com> 7 * 8 * Copyright (c) 2015 Tomáš Chaloupka 9 * 10 * Boost Software License 1.0 (BSL-1.0) 11 * 12 * Permission is hereby granted, free of charge, to any person or organization obtaining a copy 13 * of the software and accompanying documentation covered by this license (the "Software") to use, 14 * reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative 15 * works of the Software, and to permit third-parties to whom the Software is furnished to do so, 16 * all subject to the following: 17 * 18 * The copyright notices in the Software and this entire statement, including the above license 19 * grant, this restriction and the following disclaimer, must be included in all copies of the Software, 20 * in whole or in part, and all derivative works of the Software, unless such copies or derivative works 21 * are solely in the form of machine-executable object code generated by a source language processor. 22 * 23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 24 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 25 * PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE 26 * DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, 27 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 28 * OTHER DEALINGS IN THE SOFTWARE. 29 */ 30 module mqttd.tests; 31 32 version (unittest): 33 34 import std.array; 35 import std.stdio; 36 import mqttd; 37 import mqttd.serialization; 38 39 /// ubyte tests 40 unittest 41 { 42 ubyte id = 10; 43 auto wr = serializer(appender!(ubyte[])); 44 wr.write(id); 45 46 assert(wr.data.length == 1); 47 assert(wr.data[0] == 0x0A); 48 49 id = 0x2B; 50 wr.clear(); 51 wr.write(id); 52 53 assert(wr.data.length == 1); 54 assert(wr.data[0] == 0x2B); 55 56 id = deserializer([0x11]).read!ubyte(); 57 assert(id == 0x11); 58 59 id = [0x22].deserializer.read!ubyte(); 60 assert(id == 0x22); 61 } 62 63 /// ushort tests 64 unittest 65 { 66 ushort id = 1; 67 auto wr = serializer(appender!(ubyte[])); 68 wr.write(id); 69 70 assert(wr.data.length == 2); 71 assert(wr.data[0] == 0); 72 assert(wr.data[1] == 1); 73 74 id = 0x1A2B; 75 wr.clear(); 76 wr.write(id); 77 78 assert(wr.data.length == 2); 79 assert(wr.data[0] == 0x1A); 80 assert(wr.data[1] == 0x2B); 81 82 id = [0x11, 0x22].deserializer.read!ushort(); 83 assert(id == 0x1122); 84 } 85 86 /// string tests 87 unittest 88 { 89 import std..string : representation; 90 91 auto name = "test"; 92 auto wr = serializer(appender!(ubyte[])); 93 wr.write(name); 94 95 assert(wr.data.length == 6); 96 assert(wr.data[0] == 0); 97 assert(wr.data[1] == 4); 98 assert(wr.data[2..$] == "test".representation); 99 100 name = (cast(ubyte[])[0x00, 0x0A] ~ "randomname".representation).deserializer.read!string(); 101 assert(name == "randomname"); 102 } 103 104 /// Fixed header tests 105 unittest 106 { 107 assert(FixedHeader(PacketType.RESERVED1, true, QoSLevel.Reserved, true) == 0x0F); 108 109 FixedHeader header = 0x0F; 110 assert(header.type == PacketType.RESERVED1); 111 assert(header.dup); 112 assert(header.retain); 113 assert(header.qos == QoSLevel.Reserved); 114 115 header = FixedHeader(PacketType.CONNECT, 0x0F, 255); 116 117 auto wr = serializer(appender!(ubyte[])); 118 wr.write(header); 119 120 assert(wr.data.length == 3); 121 assert(wr.data[0] == 0x1F); 122 assert(wr.data[1] == 0xFF); 123 assert(wr.data[2] == 0x01); 124 125 header.length = 10; 126 wr.clear(); 127 wr.write(header); 128 assert(wr.data.length == 2); 129 assert(wr.data[0] == 0x1F); 130 assert(wr.data[1] == 0x0A); 131 132 header = [0x1F, 0x0A].deserializer.read!FixedHeader(); 133 assert(header.type == PacketType.CONNECT); 134 assert(header.flags == 0x1F); 135 assert(header.length == 10); 136 137 header = [0x20, 0x80, 0x02].deserializer.read!FixedHeader(); 138 assert(header.type == PacketType.CONNACK); 139 assert(header.flags == 0x20); 140 assert(header.length == 256); 141 } 142 143 /// ConnectFlags test 144 unittest 145 { 146 ConnectFlags flags = ConnectFlags(128); 147 148 auto wr = serializer(appender!(ubyte[])); 149 wr.write(flags); 150 151 assert(wr.data.length == 1); 152 assert(wr.data[0] == 128); 153 154 flags = [2].deserializer.read!ConnectFlags(); 155 assert(flags.cleanSession); 156 } 157 158 /// Connect message tests 159 unittest 160 { 161 ubyte[] data = [ 162 0x10, //fixed header 163 0x1c, // rest is 28 164 0x00, 0x04, //length of MQTT text 165 'M', 'Q', 'T', 'T', // MQTT 166 0x04, //protocol level 167 0x80, //just user name flag 168 0x00, 0x00, //zero keepalive 169 0x00, 0x0a, //length of client identifier 170 't', 'e', 's', 't', 'c', 'l', 'i', 'e', 'n', 't', //testclient text 171 0x00, 0x04, //username length 172 'u', 's', 'e', 'r' //user text 173 ]; 174 175 auto con = Connect(); 176 con.clientIdentifier = "testclient"; 177 con.flags.userName = true; 178 con.userName = "user"; 179 180 auto wr = appender!(ubyte[]); 181 wr.serialize(con); 182 183 assert(wr.data.length == 30); 184 185 //debug writefln("%(%.02x %)", wr.data); 186 assert(wr.data == data); 187 188 auto con2 = wr.data.deserialize!Connect(); 189 //auto con2 = deserialize!Connect(data); 190 assert(con == con2); 191 } 192 193 unittest 194 { 195 ubyte[] data = [ 196 0x20, //fixed header 197 0x02, //rest is 2 198 0x00, //flags 199 0x00 //return code 200 ]; 201 ubyte[] data2 = [ 202 0x20, //fixed header 203 0x02, //rest is 2 204 0x01, //flags 205 0x05 //return code 206 ]; 207 208 auto conack = ConnAck(); 209 210 auto wr = appender!(ubyte[]); 211 wr.serialize(conack); 212 213 assert(wr.data.length == 4); 214 215 //debug writefln("%(%.02x %)", wr.data); 216 assert(wr.data == data); 217 218 auto conack2 = wr.data.deserialize!ConnAck(); 219 220 // TODO: this for some reason fails.. 221 // writefln("%(%.02x %)", *(cast(byte[ConnAck.sizeof]*)(&conack))); 222 // writefln("%(%.02x %)", *(cast(byte[ConnAck.sizeof]*)(&conack2))); 223 // assert(conack == conack2); 224 assert(conack.header == conack2.header); 225 assert(conack.flags == conack2.flags); 226 assert(conack.returnCode == conack2.returnCode); 227 assert(conack.returnCode == ConnectReturnCode.ConnectionAccepted); 228 229 conack2.flags = 0x01; 230 conack2.returnCode = ConnectReturnCode.NotAuthorized; 231 wr.clear(); 232 233 wr.serialize(conack2); 234 235 assert(wr.data.length == 4); 236 assert(wr.data == data2); 237 } 238 239 unittest 240 { 241 ubyte[] data = [ 242 0x33, //fixed header 243 0x12, //rest is 18 244 0x00, 0x09, //topic length 245 '/', 'r', 'o', 'o', 't', '/', 's', 'e', 'c', //filter text 246 0xab, 0xcd, //packet id 247 0x01, 0x2, 0x3, 0x4, 0x5 //payload 248 ]; 249 250 auto pub = Publish(); 251 pub.header.qos = QoSLevel.QoS1; 252 pub.header.retain = true; 253 pub.packetId = 0xabcd; 254 pub.topic = "/root/sec"; 255 pub.payload = [1, 2, 3, 4, 5]; 256 257 auto wr = appender!(ubyte[]).serialize(pub); 258 259 // debug writefln("%(%.02x %)", wr.data); 260 assert(wr.data.length == 20); 261 262 assert(wr.data == data); 263 264 auto pub2 = wr.data.deserialize!Publish(); 265 assert(pub == pub2); 266 } 267 268 unittest 269 { 270 void testPubx(T)(ubyte header) 271 { 272 ubyte[] data = [ 273 header, //fixed header 274 0x02, //rest is 2 275 0x00, 0x00 //packet id 276 ]; 277 278 ubyte[] data2 = [ 279 header, //fixed header 280 0x02, //rest is 2 281 0xab, 0xcd //packet id 282 ]; 283 284 auto px = T(); 285 286 auto wr = appender!(ubyte[]); 287 wr.serialize(px); 288 289 assert(wr.data.length == 4); 290 291 //debug writefln("%(%.02x %)", wr.data); 292 assert(wr.data == data); 293 294 auto px2 = wr.data.deserialize!T(); 295 296 //TODO: Fails but are same 297 //assert(px == px2); 298 assert(px.header == px2.header); 299 assert(px.packetId == px2.packetId); 300 301 px2.packetId = 0xabcd; 302 wr.clear(); 303 304 wr.serialize(px2); 305 306 assert(wr.data.length == 4); 307 assert(wr.data == data2); 308 } 309 310 testPubx!PubAck(0x40); 311 testPubx!PubRec(0x50); 312 testPubx!PubRel(0x62); 313 testPubx!PubComp(0x70); 314 testPubx!UnsubAck(0xb0); 315 } 316 317 unittest 318 { 319 ubyte[] data = [ 320 0x82, //fixed header 321 0x0c, //rest is 12 322 0xab, 0xcd, //packet id 323 0x00, 0x07, //filter length 324 '/', 'r', 'o', 'o', 't', '/', '*', //filter text 325 0x02 //qos 326 ]; 327 328 auto sub = Subscribe(); 329 sub.packetId = 0xabcd; 330 sub.topics ~= Topic("/root/*", QoSLevel.QoS2); 331 332 auto wr = appender!(ubyte[]); 333 wr.serialize(sub); 334 335 assert(wr.data.length == 14); 336 337 //debug writefln("%(%.02x %)", wr.data); 338 assert(wr.data == data); 339 340 auto sub2 = wr.data.deserialize!Subscribe(); 341 assert(sub == sub2); 342 } 343 344 unittest 345 { 346 ubyte[] data = [ 347 0x90, //fixed header 348 0x06, //rest is 2 349 0xab, 0xcd, //packet id 350 0x00, 0x01, 0x02, 0x80 //ret codes 351 ]; 352 353 auto suback = SubAck(); 354 suback.packetId = 0xabcd; 355 suback.returnCodes ~= QoSLevel.QoS0; 356 suback.returnCodes ~= QoSLevel.QoS1; 357 suback.returnCodes ~= QoSLevel.QoS2; 358 suback.returnCodes ~= QoSLevel.Failure; 359 360 auto wr = appender!(ubyte[]); 361 wr.serialize(suback); 362 363 assert(wr.data.length == 8); 364 365 //debug writefln("%(%.02x %)", wr.data); 366 assert(wr.data == data); 367 368 auto suback2 = wr.data.deserialize!SubAck(); 369 assert(suback == suback2); 370 } 371 372 unittest 373 { 374 ubyte[] data = [ 375 0xa2, //fixed header 376 0x0b, //rest is 11 377 0xab, 0xcd, //packet id 378 0x00, 0x07, //filter length 379 '/', 'r', 'o', 'o', 't', '/', '*' //filter text 380 ]; 381 382 auto unsub = Unsubscribe(); 383 unsub.packetId = 0xabcd; 384 unsub.topics ~= "/root/*"; 385 386 auto wr = appender!(ubyte[]); 387 wr.serialize(unsub); 388 389 //debug writefln("%(%.02x %)", wr.data); 390 assert(wr.data.length == 13); 391 assert(wr.data == data); 392 393 auto unsub2 = wr.data.deserialize!Unsubscribe(); 394 assert(unsub == unsub2); 395 } 396 397 unittest 398 { 399 void testSimple(T)(ubyte header) 400 { 401 auto s = T(); 402 403 auto wr = appender!(ubyte[]); 404 wr.serialize(s); 405 406 assert(wr.data.length == 2); 407 408 //debug writefln("%(%.02x %)", wr.data); 409 assert(wr.data == cast(ubyte[])[header, 0x00]); 410 411 auto s2 = wr.data.deserialize!T(); 412 413 assert(s.header == s2.header); 414 415 wr.clear(); 416 wr.serialize(s2); 417 418 assert(wr.data.length == 2); 419 assert(wr.data == cast(ubyte[])[header, 0x00]); 420 } 421 422 testSimple!PingReq(0xc0); 423 testSimple!PingResp(0xd0); 424 testSimple!Disconnect(0xe0); 425 }