1<?php 2 3namespace test\php; 4 5/** @var \Composer\Autoload\ClassLoader $loader */ 6$loader = require __DIR__ . '/../../vendor/autoload.php'; 7 8use Thrift\ClassLoader\ThriftClassLoader; 9 10if (!isset($GEN_DIR)) { 11 $GEN_DIR = 'gen-php'; 12} 13if (!isset($MODE)) { 14 $MODE = 'normal'; 15} 16 17 18if ($GEN_DIR == 'gen-php') { 19 $loader->addPsr4('', $GEN_DIR); 20} else { 21 $loader = new ThriftClassLoader(); 22 $loader->registerDefinition('ThriftTest', $GEN_DIR); 23 $loader->register(); 24} 25 26/* 27 * Licensed to the Apache Software Foundation (ASF) under one 28 * or more contributor license agreements. See the NOTICE file 29 * distributed with this work for additional information 30 * regarding copyright ownership. The ASF licenses this file 31 * to you under the Apache License, Version 2.0 (the 32 * "License"); you may not use this file except in compliance 33 * with the License. You may obtain a copy of the License at 34 * 35 * http://www.apache.org/licenses/LICENSE-2.0 36 * 37 * Unless required by applicable law or agreed to in writing, 38 * software distributed under the License is distributed on an 39 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 40 * KIND, either express or implied. See the License for the 41 * specific language governing permissions and limitations 42 * under the License. 43 */ 44 45/** Include the Thrift base */ 46/** Include the protocols */ 47use Thrift\Protocol\TBinaryProtocol; 48use Thrift\Protocol\TBinaryProtocolAccelerated; 49use Thrift\Protocol\TCompactProtocol; 50use Thrift\Protocol\TJSONProtocol; 51 52/** Include the socket layer */ 53use Thrift\Transport\TSocket; 54use Thrift\Transport\TSocketPool; 55 56/** Include the socket layer */ 57use Thrift\Transport\TFramedTransport; 58use Thrift\Transport\TBufferedTransport; 59 60function makeProtocol($transport, $PROTO) 61{ 62 if ($PROTO == 'binary') { 63 return new TBinaryProtocol($transport); 64 } else if ($PROTO == 'compact') { 65 return new TCompactProtocol($transport); 66 } else if ($PROTO == 'json') { 67 return new TJSONProtocol($transport); 68 } else if ($PROTO == 'accel') { 69 if (!function_exists('thrift_protocol_write_binary')) { 70 echo "Acceleration extension is not loaded\n"; 71 exit(1); 72 } 73 return new TBinaryProtocolAccelerated($transport); 74 } 75 76 echo "--protocol must be one of {binary|compact|json|accel}\n"; 77 exit(1); 78} 79 80$host = 'localhost'; 81$port = 9090; 82 83if ($argc > 1) { 84 $host = $argv[0]; 85} 86 87if ($argc > 2) { 88 $host = $argv[1]; 89} 90 91foreach ($argv as $arg) { 92 if (substr($arg, 0, 7) == '--port=') { 93 $port = substr($arg, 7); 94 } else if (substr($arg, 0, 12) == '--transport=') { 95 $MODE = substr($arg, 12); 96 } else if (substr($arg, 0, 11) == '--protocol=') { 97 $PROTO = substr($arg, 11); 98 } 99} 100 101$hosts = array('localhost'); 102 103$socket = new TSocket($host, $port); 104$socket = new TSocketPool($hosts, $port); 105$socket->setDebug(TRUE); 106 107if ($MODE == 'inline') { 108 $transport = $socket; 109 $testClient = new \ThriftTest\ThriftTestClient($transport); 110} else if ($MODE == 'framed') { 111 $framedSocket = new TFramedTransport($socket); 112 $transport = $framedSocket; 113 $protocol = makeProtocol($transport, $PROTO); 114 $testClient = new \ThriftTest\ThriftTestClient($protocol); 115} else { 116 $bufferedSocket = new TBufferedTransport($socket, 1024, 1024); 117 $transport = $bufferedSocket; 118 $protocol = makeProtocol($transport, $PROTO); 119 $testClient = new \ThriftTest\ThriftTestClient($protocol); 120} 121 122$transport->open(); 123 124$start = microtime(true); 125 126define('ERR_BASETYPES', 1); 127define('ERR_STRUCTS', 2); 128define('ERR_CONTAINERS', 4); 129define('ERR_EXCEPTIONS', 8); 130define('ERR_UNKNOWN', 64); 131$exitcode = 0; 132/** 133 * VOID TEST 134 */ 135print_r("testVoid()"); 136$testClient->testVoid(); 137print_r(" = void\n"); 138 139function roundtrip($testClient, $method, $value) { 140 global $exitcode; 141 print_r("$method($value)"); 142 $ret = $testClient->$method($value); 143 print_r(" = \"$ret\"\n"); 144 if ($value !== $ret) { 145 print_r("*** FAILED ***\n"); 146 $exitcode |= ERR_BASETYPES; 147 } 148} 149 150/** 151 * STRING TEST 152 */ 153roundtrip($testClient, 'testString', "Test"); 154 155/** 156 * BOOL TEST 157 */ 158roundtrip($testClient, 'testBool', true); 159roundtrip($testClient, 'testBool', false); 160 161/** 162 * BYTE TEST 163 */ 164roundtrip($testClient, 'testByte', 1); 165roundtrip($testClient, 'testByte', -1); 166roundtrip($testClient, 'testByte', 127); 167roundtrip($testClient, 'testByte', -128); 168 169/** 170 * I32 TEST 171 */ 172roundtrip($testClient, 'testI32', -1); 173 174/** 175 * I64 TEST 176 */ 177roundtrip($testClient, 'testI64', 0); 178roundtrip($testClient, 'testI64', 1); 179roundtrip($testClient, 'testI64', -1); 180roundtrip($testClient, 'testI64', -34359738368); 181 182/** 183 * DOUBLE TEST 184 */ 185roundtrip($testClient, 'testDouble', -852.234234234); 186 187/** 188 * BINARY TEST -- TODO 189 */ 190 191/** 192 * STRUCT TEST 193 */ 194print_r("testStruct({\"Zero\", 1, -3, -5})"); 195$out = new \ThriftTest\Xtruct(); 196$out->string_thing = "Zero"; 197$out->byte_thing = 1; 198$out->i32_thing = -3; 199$out->i64_thing = -5; 200$in = $testClient->testStruct($out); 201print_r(" = {\"".$in->string_thing."\", ". 202 $in->byte_thing.", ". 203 $in->i32_thing.", ". 204 $in->i64_thing."}\n"); 205 206if ($in != $out) { 207 echo "**FAILED**\n"; 208 $exitcode |= ERR_STRUCTS; 209} 210 211/** 212 * NESTED STRUCT TEST 213 */ 214print_r("testNest({1, {\"Zero\", 1, -3, -5}), 5}"); 215$out2 = new \ThriftTest\Xtruct2(); 216$out2->byte_thing = 1; 217$out2->struct_thing = $out; 218$out2->i32_thing = 5; 219$in2 = $testClient->testNest($out2); 220$in = $in2->struct_thing; 221print_r(" = {".$in2->byte_thing.", {\"". 222 $in->string_thing."\", ". 223 $in->byte_thing.", ". 224 $in->i32_thing.", ". 225 $in->i64_thing."}, ". 226 $in2->i32_thing."}\n"); 227 228if ($in2 != $out2) { 229 echo "**FAILED**\n"; 230 $exitcode |= ERR_STRUCTS; 231} 232 233/** 234 * MAP TEST 235 */ 236$mapout = array(); 237for ($i = 0; $i < 5; ++$i) { 238 $mapout[$i] = $i-10; 239} 240print_r("testMap({"); 241$first = true; 242foreach ($mapout as $key => $val) { 243 if ($first) { 244 $first = false; 245 } else { 246 print_r(", "); 247 } 248 print_r("$key => $val"); 249} 250print_r("})"); 251 252$mapin = $testClient->testMap($mapout); 253print_r(" = {"); 254$first = true; 255foreach ($mapin as $key => $val) { 256 if ($first) { 257 $first = false; 258 } else { 259 print_r(", "); 260 } 261 print_r("$key => $val"); 262} 263print_r("}\n"); 264 265if ($mapin != $mapout) { 266 echo "**FAILED**\n"; 267 $exitcode |= ERR_CONTAINERS; 268} 269 270$mapout = array(); 271for ($i = 0; $i < 10; $i++) { 272 $mapout["key$i"] = "val$i"; 273} 274print_r('testStringMap({'); 275$first = true; 276foreach ($mapout as $key => $val) { 277 if ($first) { 278 $first = false; 279 } else { 280 print_r(", "); 281 } 282 print_r("\"$key\" => \"$val\""); 283} 284print_r("})"); 285$mapin = $testClient->testStringMap($mapout); 286print_r(" = {"); 287$first = true; 288foreach ($mapin as $key => $val) { 289 if ($first) { 290 $first = false; 291 } else { 292 print_r(", "); 293 } 294 print_r("\"$key\" => \"$val\""); 295} 296print_r("}\n"); 297ksort($mapin); 298if ($mapin != $mapout) { 299 echo "**FAILED**\n"; 300 $exitcode |= ERR_CONTAINERS; 301} 302 303/** 304 * SET TEST 305 */ 306$setout = array();; 307for ($i = -2; $i < 3; ++$i) { 308 $setout[$i]= true; 309} 310print_r("testSet({"); 311echo implode(',', array_keys($setout)); 312print_r("})"); 313$setin = $testClient->testSet($setout); 314print_r(" = {"); 315echo implode(', ', array_keys($setin)); 316print_r("}\n"); 317// Order of keys in set does not matter 318ksort($setin); 319if ($setout !== $setin) { 320 echo "**FAILED**\n"; 321 $exitcode |= ERR_CONTAINERS; 322} 323// Regression test for corrupted array 324if ($setin[2] !== $setout[2] || is_int($setin[2])) { 325 echo "**FAILED**\n"; 326 $exitcode |= ERR_CONTAINERS; 327} 328 329/** 330 * LIST TEST 331 */ 332$listout = array(); 333for ($i = -2; $i < 3; ++$i) { 334 $listout []= $i; 335} 336print_r("testList({"); 337$first = true; 338foreach ($listout as $val) { 339 if ($first) { 340 $first = false; 341 } else { 342 print_r(", "); 343 } 344 print_r($val); 345} 346print_r("})"); 347$listin = $testClient->testList($listout); 348print_r(" = {"); 349$first = true; 350foreach ($listin as $val) { 351 if ($first) { 352 $first = false; 353 } else { 354 print_r(", "); 355 } 356 print_r($val); 357} 358print_r("}\n"); 359if ($listin !== $listout) { 360 echo "**FAILED**\n"; 361 $exitcode |= ERR_CONTAINERS; 362} 363 364/** 365 * ENUM TEST 366 */ 367print_r("testEnum(ONE)"); 368$ret = $testClient->testEnum(\ThriftTest\Numberz::ONE); 369print_r(" = $ret\n"); 370if ($ret != \ThriftTest\Numberz::ONE) { 371 echo "**FAILED**\n"; 372 $exitcode |= ERR_STRUCTS; 373} 374 375print_r("testEnum(TWO)"); 376$ret = $testClient->testEnum(\ThriftTest\Numberz::TWO); 377print_r(" = $ret\n"); 378if ($ret != \ThriftTest\Numberz::TWO) { 379 echo "**FAILED**\n"; 380 $exitcode |= ERR_STRUCTS; 381} 382 383print_r("testEnum(THREE)"); 384$ret = $testClient->testEnum(\ThriftTest\Numberz::THREE); 385print_r(" = $ret\n"); 386if ($ret != \ThriftTest\Numberz::THREE) { 387 echo "**FAILED**\n"; 388 $exitcode |= ERR_STRUCTS; 389} 390 391print_r("testEnum(FIVE)"); 392$ret = $testClient->testEnum(\ThriftTest\Numberz::FIVE); 393print_r(" = $ret\n"); 394if ($ret != \ThriftTest\Numberz::FIVE) { 395 echo "**FAILED**\n"; 396 $exitcode |= ERR_STRUCTS; 397} 398 399print_r("testEnum(EIGHT)"); 400$ret = $testClient->testEnum(\ThriftTest\Numberz::EIGHT); 401print_r(" = $ret\n"); 402if ($ret != \ThriftTest\Numberz::EIGHT) { 403 echo "**FAILED**\n"; 404 $exitcode |= ERR_STRUCTS; 405} 406 407/** 408 * TYPEDEF TEST 409 */ 410print_r("testTypedef(309858235082523)"); 411$uid = $testClient->testTypedef(309858235082523); 412print_r(" = $uid\n"); 413if ($uid !== 309858235082523) { 414 echo "**FAILED**\n"; 415 $exitcode |= ERR_STRUCTS; 416} 417 418/** 419 * NESTED MAP TEST 420 */ 421print_r("testMapMap(1)"); 422$mm = $testClient->testMapMap(1); 423print_r(" = {"); 424foreach ($mm as $key => $val) { 425 print_r("$key => {"); 426 foreach ($val as $k2 => $v2) { 427 print_r("$k2 => $v2, "); 428 } 429 print_r("}, "); 430} 431print_r("}\n"); 432$expected_mm = [ 433 -4 => [-4 => -4, -3 => -3, -2 => -2, -1 => -1], 434 4 => [4 => 4, 3 => 3, 2 => 2, 1 => 1], 435]; 436if ($mm != $expected_mm) { 437 echo "**FAILED**\n"; 438 $exitcode |= ERR_CONTAINERS; 439} 440 441/** 442 * INSANITY TEST 443 */ 444$insane = new \ThriftTest\Insanity(); 445$insane->userMap[\ThriftTest\Numberz::FIVE] = 5000; 446$truck = new \ThriftTest\Xtruct(); 447$truck->string_thing = "Truck"; 448$truck->byte_thing = 8; 449$truck->i32_thing = 8; 450$truck->i64_thing = 8; 451$insane->xtructs []= $truck; 452print_r("testInsanity()"); 453$whoa = $testClient->testInsanity($insane); 454print_r(" = {"); 455foreach ($whoa as $key => $val) { 456 print_r("$key => {"); 457 foreach ($val as $k2 => $v2) { 458 print_r("$k2 => {"); 459 $userMap = $v2->userMap; 460 print_r("{"); 461 if (is_array($userMap)) { 462 foreach ($userMap as $k3 => $v3) { 463 print_r("$k3 => $v3, "); 464 } 465 } 466 print_r("}, "); 467 468 $xtructs = $v2->xtructs; 469 print_r("{"); 470 if (is_array($xtructs)) { 471 foreach ($xtructs as $x) { 472 print_r("{\"".$x->string_thing."\", ". 473 $x->byte_thing.", ".$x->i32_thing.", ".$x->i64_thing."}, "); 474 } 475 } 476 print_r("}"); 477 478 print_r("}, "); 479 } 480 print_r("}, "); 481} 482print_r("}\n"); 483 484/** 485 * EXCEPTION TEST 486 */ 487print_r("testException('Xception')"); 488try { 489 $testClient->testException('Xception'); 490 print_r(" void\nFAILURE\n"); 491 $exitcode |= ERR_EXCEPTIONS; 492} catch (\ThriftTest\Xception $x) { 493 print_r(' caught xception '.$x->errorCode.': '.$x->message."\n"); 494} 495 496// Regression test for THRIFT-4263 497print_r("testBinarySerializer_Deserialize('foo')"); 498try { 499 \Thrift\Serializer\TBinarySerializer::deserialize(base64_decode('foo'), \ThriftTest\Xtruct2::class); 500 echo "**FAILED**\n"; 501 $exitcode |= ERR_STRUCTS; 502} catch (\Thrift\Exception\TTransportException $happy_exception) { 503 // We expected this due to binary data of base64_decode('foo') is less then 4 504 // bytes and it tries to find thrift version number in the transport by 505 // reading i32() at the beginning. Casting to string validates that 506 // exception is still accessible in memory and not corrupted. Without patch, 507 // PHP will error log that the exception doesn't have any tostring method, 508 // which is a lie due to corrupted memory. 509 for($i=99; $i > 0; $i--) { 510 (string)$happy_exception; 511 } 512 print_r(" SUCCESS\n"); 513} 514 515/** 516 * Normal tests done. 517 */ 518 519$stop = microtime(true); 520$elp = round(1000*($stop - $start), 0); 521print_r("Total time: $elp ms\n"); 522 523/** 524 * Extraneous "I don't trust PHP to pack/unpack integer" tests 525 */ 526 527if ($protocol instanceof TBinaryProtocolAccelerated) { 528 // Regression check: check that method name is not double-freed 529 // Method name should not be an interned string. 530 $method_name = "Void"; 531 $method_name = "test$method_name"; 532 533 $seqid = 0; 534 $args = new \ThriftTest\ThriftTest_testVoid_args(); 535 thrift_protocol_write_binary($protocol, $method_name, \Thrift\Type\TMessageType::CALL, $args, $seqid, $protocol->isStrictWrite()); 536 $testClient->recv_testVoid(); 537 538} 539 540// Max I32 541$num = pow(2, 30) + (pow(2, 30) - 1); 542roundtrip($testClient, 'testI32', $num); 543 544// Min I32 545$num = 0 - pow(2, 31); 546roundtrip($testClient, 'testI32', $num); 547 548// Max I64 549$num = pow(2, 62) + (pow(2, 62) - 1); 550roundtrip($testClient, 'testI64', $num); 551 552// Min I64 553$num = 0 - pow(2, 62) - pow(2, 62); 554roundtrip($testClient, 'testI64', $num); 555 556$transport->close(); 557exit($exitcode); 558