From 9191af8b1d4c928d4c1510ccbd450f16d07feb76 Mon Sep 17 00:00:00 2001 From: Volodymyr Panivko Date: Thu, 26 Mar 2026 21:57:29 +0100 Subject: [PATCH 1/2] THRIFT-5757: finish PHP cross-test integration --- .github/workflows/build.yml | 47 ++++++++++- .../src/thrift/generate/t_php_generator.cc | 61 +++++++++----- lib/php/Makefile.am | 5 +- lib/php/lib/Protocol/TJSONProtocol.php | 2 +- lib/php/lib/Protocol/TSimpleJSONProtocol.php | 2 +- .../thrift_protocol/php_thrift_protocol.cpp | 81 ++++++++++++++++++- test/known_failures_Linux.json | 33 +------- test/php/Handler.php | 68 ++++++++++++++-- test/php/Makefile.am | 7 +- test/php/TestServer.php | 39 ++++++++- test/php/test_php.ini | 1 - test/py/TestClient.py | 2 +- test/py/TestServer.py | 2 +- test/tests.json | 6 ++ 14 files changed, 276 insertions(+), 80 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 293e5089cf1..6f77fa9d6ba 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -167,6 +167,26 @@ jobs: - name: Run Tests run: vendor/bin/phpunit -c lib/php/phpunit.xml + - name: Build PHP cross test extension + if: matrix.php-version == '8.3' + run: make -C lib/php src/ext/thrift_protocol/modules/thrift_protocol.so + + - name: Run make precross for php test + if: matrix.php-version == '8.3' + run: make -C test/php precross + + - name: Upload php precross artifacts + if: matrix.php-version == '8.3' + uses: actions/upload-artifact@v7 + with: + name: php-precross + if-no-files-found: error + path: | + lib/php/src/ext/thrift_protocol/modules/thrift_protocol.so + test/php/gen-php/ + test/php/gen-php-classmap/ + retention-days: 3 + lib-go: needs: compiler runs-on: ubuntu-24.04 @@ -839,6 +859,7 @@ jobs: cross-test: needs: + - lib-php - lib-java-kotlin #- lib-swift # currently broken and no maintainers around -> see THRIFT-5864 #- lib-rust # currently broken and no maintainers around -> see THRIFT-5917 @@ -853,9 +874,9 @@ jobs: # swift is currently broken and no maintainers around -> see THRIFT-5864 # rust currently broken and no maintainers around -> see THRIFT-5917 # kotlin cross test are failing -> see THRIFT-5879 - server_lang: ['java', 'go', 'cpp', 'py', 'rb', 'nodejs', 'nodets'] + server_lang: ['java', 'go', 'cpp', 'py', 'rb', 'php', 'nodejs', 'nodets'] # we always use comma join as many client langs as possible, to reduce the number of jobs - client_lang: ['java,kotlin', 'go,cpp,py,nodejs,nodets', 'rb'] + client_lang: ['java,kotlin', 'go,cpp,py,php,nodejs,nodets', 'rb'] fail-fast: false steps: - uses: actions/checkout@v6 @@ -869,6 +890,16 @@ jobs: python -m pip install --upgrade pip setuptools python -m pip install "tornado>=6.3.0" "twisted>=24.3.0" "zope.interface>=6.1" + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: "8.3" + extensions: mbstring, intl, xml, curl, sockets + ini-values: "error_reporting=E_ALL" + + - name: Install PHP dependencies + run: composer install --no-progress --prefer-dist + - uses: actions/setup-java@v5 with: distribution: temurin @@ -941,6 +972,18 @@ jobs: name: rb-precross path: . + - name: Download php precross artifacts + uses: actions/download-artifact@v8 + with: + name: php-precross + path: . + + - name: Prepare PHP cross test extensions + run: | + mkdir -p test/php/php_ext_dir + ln -sf ../../../lib/php/src/ext/thrift_protocol/modules/thrift_protocol.so test/php/php_ext_dir/ + ln -sf "$(php-config --extension-dir)/sockets.so" test/php/php_ext_dir/ + - name: Download nodejs and nodets precross artifacts uses: actions/download-artifact@v8 with: diff --git a/compiler/cpp/src/thrift/generate/t_php_generator.cc b/compiler/cpp/src/thrift/generate/t_php_generator.cc index d3f2f70e850..015077377c2 100644 --- a/compiler/cpp/src/thrift/generate/t_php_generator.cc +++ b/compiler/cpp/src/thrift/generate/t_php_generator.cc @@ -1550,11 +1550,10 @@ void t_php_generator::generate_process_function(std::ostream& out, t_service* ts out << indent() << "$result = new " << resultname << "();" << '\n'; } - // Try block for a function with exceptions - if (xceptions.size() > 0) { - out << indent() << "try {" << '\n'; - indent_up(); - } + // Wrap handler invocations so undeclared runtime failures become + // TApplicationException responses instead of crashing the PHP test server. + out << indent() << "try {" << '\n'; + indent_up(); // Generate the function call t_struct* arg_struct = tfunction->get_arglist(); @@ -1577,23 +1576,44 @@ void t_php_generator::generate_process_function(std::ostream& out, t_service* ts } out << ");" << '\n'; - if (!tfunction->is_oneway() && xceptions.size() > 0) { - indent_down(); - for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { - out << indent() << "} catch (" - << php_namespace(get_true_type((*x_iter)->get_type())->get_program()) - << (*x_iter)->get_type()->get_name() << " $" << (*x_iter)->get_name() << ") {" - << '\n'; - if (!tfunction->is_oneway()) { - indent_up(); - out << indent() << "$result->" << (*x_iter)->get_name() << " = $" - << (*x_iter)->get_name() << ";" << '\n'; - indent_down(); - out << indent(); - } + indent_down(); + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + out << indent() << "} catch (" + << php_namespace(get_true_type((*x_iter)->get_type())->get_program()) + << (*x_iter)->get_type()->get_name() << " $" << (*x_iter)->get_name() << ") {" + << '\n'; + if (!tfunction->is_oneway()) { + indent_up(); + out << indent() << "$result->" << (*x_iter)->get_name() << " = $" + << (*x_iter)->get_name() << ";" << '\n'; + indent_down(); } - out << "}" << '\n'; } + out << indent() << "} catch (TApplicationException $ex) {" << '\n'; + indent_up(); + if (!tfunction->is_oneway()) { + out << indent() << "$output->writeMessageBegin('" << tfunction->get_name() + << "', TMessageType::EXCEPTION, $seqid);" << '\n' + << indent() << "$ex->write($output);" << '\n' + << indent() << "$output->writeMessageEnd();" << '\n' + << indent() << "$output->getTransport()->flush();" << '\n'; + } + out << indent() << "return;" << '\n'; + indent_down(); + out << indent() << "} catch (\\Throwable $ex) {" << '\n'; + indent_up(); + if (!tfunction->is_oneway()) { + out << indent() << "$x = new TApplicationException($ex->getMessage(), " + << "TApplicationException::INTERNAL_ERROR);" << '\n' + << indent() << "$output->writeMessageBegin('" << tfunction->get_name() + << "', TMessageType::EXCEPTION, $seqid);" << '\n' + << indent() << "$x->write($output);" << '\n' + << indent() << "$output->writeMessageEnd();" << '\n' + << indent() << "$output->getTransport()->flush();" << '\n'; + } + out << indent() << "return;" << '\n'; + indent_down(); + out << indent() << "}" << '\n'; // Shortcut out here for oneway functions if (tfunction->is_oneway()) { @@ -2707,6 +2727,7 @@ string t_php_generator::declare_field(t_field* tfield, bool init, bool obj) { case t_base_type::TYPE_VOID: break; case t_base_type::TYPE_STRING: + case t_base_type::TYPE_UUID: result += " = ''"; break; case t_base_type::TYPE_BOOL: diff --git a/lib/php/Makefile.am b/lib/php/Makefile.am index ece8d244574..07c23ba1c7b 100644 --- a/lib/php/Makefile.am +++ b/lib/php/Makefile.am @@ -64,8 +64,8 @@ phpfactory_DATA = \ lib/Factory/TJSONProtocolFactory.php \ lib/Factory/TProtocolFactory.php \ lib/Factory/TStringFuncFactory.php \ - lib/Factory/TTransportFactoryInterface.php - lib/Factory/TTransportFactory.php + lib/Factory/TTransportFactoryInterface.php \ + lib/Factory/TTransportFactory.php \ lib/Factory/TFramedTransportFactory.php phpprotocoldir = $(phpdir)/Protocol @@ -158,4 +158,3 @@ EXTRA_DIST = \ MAINTAINERCLEANFILES = \ Makefile.in - diff --git a/lib/php/lib/Protocol/TJSONProtocol.php b/lib/php/lib/Protocol/TJSONProtocol.php index 1e8c3918578..28b7615fa83 100644 --- a/lib/php/lib/Protocol/TJSONProtocol.php +++ b/lib/php/lib/Protocol/TJSONProtocol.php @@ -210,7 +210,7 @@ private function writeJSONString($b) $this->trans_->write(self::QUOTE); } - $this->trans_->write(json_encode($b, JSON_UNESCAPED_UNICODE)); + $this->trans_->write(json_encode($b, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)); if (is_numeric($b) && $this->context_->escapeNum()) { $this->trans_->write(self::QUOTE); diff --git a/lib/php/lib/Protocol/TSimpleJSONProtocol.php b/lib/php/lib/Protocol/TSimpleJSONProtocol.php index 982bfd3e6c4..1927aad6d4a 100644 --- a/lib/php/lib/Protocol/TSimpleJSONProtocol.php +++ b/lib/php/lib/Protocol/TSimpleJSONProtocol.php @@ -85,7 +85,7 @@ private function writeJSONString($b) { $this->writeContext_->write(); - $this->trans_->write(json_encode((string)$b)); + $this->trans_->write(json_encode((string)$b, JSON_UNESCAPED_SLASHES)); } private function writeJSONInteger($num) diff --git a/lib/php/src/ext/thrift_protocol/php_thrift_protocol.cpp b/lib/php/src/ext/thrift_protocol/php_thrift_protocol.cpp index c016b070b6a..04dc1d2eb41 100644 --- a/lib/php/src/ext/thrift_protocol/php_thrift_protocol.cpp +++ b/lib/php/src/ext/thrift_protocol/php_thrift_protocol.cpp @@ -72,6 +72,7 @@ enum TType { T_MAP = 13, T_SET = 14, T_LIST = 15, + T_UUID = 16, T_UTF8 = 16, T_UTF16 = 17 }; @@ -85,6 +86,61 @@ const int8_t T_EXCEPTION = 3; const int INVALID_DATA = 1; const int BAD_VERSION = 4; +static inline int uuid_hex_nibble(char c) { + if (c >= '0' && c <= '9') { + return c - '0'; + } + if (c >= 'a' && c <= 'f') { + return 10 + (c - 'a'); + } + if (c >= 'A' && c <= 'F') { + return 10 + (c - 'A'); + } + return -1; +} + +static bool parse_uuid_string(const char* value, size_t len, uint8_t (&uuid)[16]) { + size_t nibble_index = 0; + int high_nibble = -1; + + for (size_t i = 0; i < len; ++i) { + const char c = value[i]; + if (c == '-' || c == '{' || c == '}') { + continue; + } + + const int nibble = uuid_hex_nibble(c); + if (nibble < 0) { + return false; + } + + if (high_nibble < 0) { + high_nibble = nibble; + } else { + if (nibble_index >= sizeof(uuid)) { + return false; + } + uuid[nibble_index++] = static_cast((high_nibble << 4) | nibble); + high_nibble = -1; + } + } + + return nibble_index == sizeof(uuid) && high_nibble < 0; +} + +static void format_uuid_string(const uint8_t (&uuid)[16], char (&buffer)[37]) { + static const char hex[] = "0123456789abcdef"; + size_t out = 0; + for (size_t i = 0; i < sizeof(uuid); ++i) { + if (i == 4 || i == 6 || i == 8 || i == 10) { + buffer[out++] = '-'; + } + buffer[out++] = hex[(uuid[i] >> 4) & 0x0f]; + buffer[out++] = hex[uuid[i] & 0x0f]; + } + buffer[out] = '\0'; +} + zend_module_entry thrift_protocol_module_entry = { STANDARD_MODULE_HEADER, "thrift_protocol", @@ -467,8 +523,10 @@ void skip_element(long thrift_typeID, PHPInputTransport& transport) { case T_DOUBLE: transport.skip(8); return; + case T_UUID: + transport.skip(16); + return; //case T_UTF7: // aliases T_STRING - case T_UTF8: case T_UTF16: case T_STRING: { uint32_t len = transport.readU32(); @@ -582,7 +640,6 @@ void binary_deserialize(int8_t thrift_typeID, PHPInputTransport& transport, zval RETURN_DOUBLE(a.d); } //case T_UTF7: // aliases T_STRING - case T_UTF8: case T_UTF16: case T_STRING: { uint32_t size = transport.readU32(); @@ -596,6 +653,14 @@ void binary_deserialize(int8_t thrift_typeID, PHPInputTransport& transport, zval } return; } + case T_UUID: { + uint8_t uuid[16]; + char strbuf[37]; + transport.readBytes(uuid, sizeof(uuid)); + format_uuid_string(uuid, strbuf); + ZVAL_STRINGL(return_value, strbuf, sizeof(strbuf) - 1); + return; + } case T_MAP: { // array of key -> value uint8_t types[2]; transport.readBytes(types, 2); @@ -673,7 +738,7 @@ void binary_deserialize(int8_t thrift_typeID, PHPInputTransport& transport, zval static void binary_serialize_hashtable_key(int8_t keytype, PHPOutputTransport& transport, HashTable* ht, HashPosition& ht_pos, HashTable* spec) { - bool keytype_is_numeric = (!((keytype == T_STRING) || (keytype == T_UTF8) || (keytype == T_UTF16))); + bool keytype_is_numeric = (!((keytype == T_STRING) || (keytype == T_UUID) || (keytype == T_UTF16))); zend_string* key; uint key_len; @@ -751,7 +816,15 @@ void binary_serialize(int8_t thrift_typeID, PHPOutputTransport& transport, zval* a.d = Z_DVAL_P(value); transport.writeI64(a.c); } return; - case T_UTF8: + case T_UUID: { + if (Z_TYPE_P(value) != IS_STRING) convert_to_string(value); + uint8_t uuid[16]; + if (!parse_uuid_string(Z_STRVAL_P(value), Z_STRLEN_P(value), uuid)) { + throw_tprotocolexception("Attempt to send an invalid UUID string", INVALID_DATA); + } + transport.write(reinterpret_cast(uuid), sizeof(uuid)); + return; + } case T_UTF16: case T_STRING: if (Z_TYPE_P(value) != IS_STRING) convert_to_string(value); diff --git a/test/known_failures_Linux.json b/test/known_failures_Linux.json index 3f00d7ac65e..1f4c18b2cdc 100644 --- a/test/known_failures_Linux.json +++ b/test/known_failures_Linux.json @@ -127,14 +127,6 @@ "cpp-nodejs_multij-json_http-ip", "cpp-nodejs_multij-json_http-ip-ssl", "cpp-nodejs_multij-json_websocket-domain", - "cpp-php_binary-accel_buffered-ip", - "cpp-php_binary-accel_framed-ip", - "cpp-php_json_buffered-ip", - "cpp-php_json_framed-ip", - "cpp-php_multi-accel_buffered-ip", - "cpp-php_multi-accel_framed-ip", - "cpp-php_multij-json_buffered-ip", - "cpp-php_multij-json_framed-ip", "cpp-py_binary-accel_http-domain", "cpp-py_binary-accel_http-ip", "cpp-py_binary-accel_http-ip-ssl", @@ -425,18 +417,6 @@ "java-netstd_multij-json_fastframed-framed-ip-ssl", "java-netstd_multij-json_framed-ip", "java-netstd_multij-json_framed-ip-ssl", - "java-php_binary-accel_buffered-ip", - "java-php_binary-accel_fastframed-framed-ip", - "java-php_binary-accel_framed-ip", - "java-php_json_buffered-ip", - "java-php_json_fastframed-framed-ip", - "java-php_json_framed-ip", - "java-php_multi-accel_buffered-ip", - "java-php_multi-accel_fastframed-framed-ip", - "java-php_multi-accel_framed-ip", - "java-php_multij-json_buffered-ip", - "java-php_multij-json_fastframed-framed-ip", - "java-php_multij-json_framed-ip", "kotlin-netstd_binary_framed-ip", "kotlin-netstd_compact_framed-ip", "kotlin-netstd_json_framed-ip", @@ -669,10 +649,6 @@ "nodejs-nodejs_compact_websocket-domain", "nodejs-nodejs_header_websocket-domain", "nodejs-nodejs_json_websocket-domain", - "nodejs-php_binary-accel_buffered-ip", - "nodejs-php_binary-accel_framed-ip", - "nodejs-php_json_buffered-ip", - "nodejs-php_json_framed-ip", "nodejs-py_binary-accel_http-domain", "nodejs-py_binary-accel_http-ip", "nodejs-py_binary-accel_http-ip-ssl", @@ -692,7 +668,6 @@ "nodejs-py_json_http-ip", "nodejs-py_json_http-ip-ssl", "nodets-netstd_binary_buffered-ip", - "nodets-php_binary-accel_buffered-ip", "perl-netstd_binary_buffered-ip", "perl-netstd_binary_buffered-ip-ssl", "perl-netstd_binary_framed-ip", @@ -993,12 +968,6 @@ "py-nodejs_compact_http-domain", "py-nodejs_header_http-domain", "py-nodejs_json_http-domain", - "py-php_accel_buffered-ip", - "py-php_accel_framed-ip", - "py-php_binary-accel_buffered-ip", - "py-php_binary-accel_framed-ip", - "py-php_json_buffered-ip", - "py-php_json_framed-ip", "py-rb_accel-binary_buffered-domain", "py-rb_accel-binary_buffered-ip", "py-rb_accel-binary_buffered-ip-ssl", @@ -1127,4 +1096,4 @@ "rs-netstd_multi-binary_framed-ip", "rs-netstd_multic-compact_buffered-ip", "rs-netstd_multic-compact_framed-ip" -] \ No newline at end of file +] diff --git a/test/php/Handler.php b/test/php/Handler.php index 3ea1f584f6b..a03554c4854 100644 --- a/test/php/Handler.php +++ b/test/php/Handler.php @@ -89,31 +89,87 @@ public function testTypedef($thing) public function testMapMap($hello) { - return $hello; + return [ + -4 => [ + -4 => -4, + -3 => -3, + -2 => -2, + -1 => -1, + ], + 4 => [ + 4 => 4, + 3 => 3, + 2 => 2, + 1 => 1, + ], + ]; } public function testInsanity(\ThriftTest\Insanity $argument) { - return $argument; + $looney = new \ThriftTest\Insanity(); + + return [ + 1 => [ + \ThriftTest\Numberz::TWO => $argument, + \ThriftTest\Numberz::THREE => $argument, + ], + 2 => [ + \ThriftTest\Numberz::SIX => $looney, + ], + ]; } public function testMulti($arg0, $arg1, $arg2, array $arg3, $arg4, $arg5) { - // TODO: Implement testMulti() method. + $result = new \ThriftTest\Xtruct(); + $result->string_thing = 'Hello2'; + $result->byte_thing = $arg0; + $result->i32_thing = $arg1; + $result->i64_thing = $arg2; + + return $result; } public function testException($arg) { - throw new \Exception($arg); + if ($arg === 'Xception') { + $exception = new \ThriftTest\Xception(); + $exception->errorCode = 1001; + $exception->message = $arg; + throw $exception; + } + + if ($arg === 'TException') { + throw new \Thrift\Exception\TException('This is a TException'); + } } public function testMultiException($arg0, $arg1) { - throw new \Exception($arg0, $arg1); + if ($arg0 === 'Xception') { + $exception = new \ThriftTest\Xception(); + $exception->errorCode = 1001; + $exception->message = 'This is an Xception'; + throw $exception; + } + + if ($arg0 === 'Xception2') { + $exception = new \ThriftTest\Xception2(); + $exception->errorCode = 2002; + $exception->struct_thing = new \ThriftTest\Xtruct(); + $exception->struct_thing->string_thing = 'This is an Xception2'; + throw $exception; + } + + $result = new \ThriftTest\Xtruct(); + $result->string_thing = $arg1; + + return $result; } public function testOneway($secondsToSleep) { - sleep($secondsToSleep); + usleep($secondsToSleep * 300000); } } diff --git a/test/php/Makefile.am b/test/php/Makefile.am index 60a63cf5d78..9aefa9d43b4 100644 --- a/test/php/Makefile.am +++ b/test/php/Makefile.am @@ -21,13 +21,12 @@ stubs: ../ThriftTest.thrift $(THRIFT) --gen php ../ThriftTest.thrift $(THRIFT) --gen php:inlined ../ThriftTest.thrift $(MKDIR_P) gen-php-classmap - $(THRIFT) -out gen-php-classmap --gen php:classmap ../ThriftTest.thrift + $(THRIFT) -out gen-php-classmap --gen php:classmap,server,rest ../ThriftTest.thrift php_ext_dir: mkdir -p php_ext_dir - ln -s ../../../lib/php/src/ext/thrift_protocol/modules/thrift_protocol.so php_ext_dir/ - ln -s "$$(php-config --extension-dir)/json.so" php_ext_dir/ - ln -s "$$(php-config --extension-dir)/sockets.so" php_ext_dir/ + ln -sf ../../../lib/php/src/ext/thrift_protocol/modules/thrift_protocol.so php_ext_dir/ + ln -sf "$$(php-config --extension-dir)/sockets.so" php_ext_dir/ precross: stubs php_ext_dir diff --git a/test/php/TestServer.php b/test/php/TestServer.php index 3b017523a3e..4afb5d0ff48 100644 --- a/test/php/TestServer.php +++ b/test/php/TestServer.php @@ -4,6 +4,14 @@ require_once __DIR__ . '/../../vendor/autoload.php'; +class TBinaryProtocolAcceleratedFactory implements \Thrift\Factory\TProtocolFactory +{ + public function getProtocol($trans) + { + return new \Thrift\Protocol\TBinaryProtocolAccelerated($trans, false, true); + } +} + $opts = getopt( 'h::', [ @@ -30,7 +38,7 @@ --server-type=arg (simple) type of server, "simple", "thread-pool", "threaded", or "nonblocking" --transport=arg (buffered) transport: buffered, framed, http, anonpipe, zlib - --protocol=arg (binary) protocol: binary, compact, header, json + --protocol=arg (binary) protocol: binary, compact, json, accel --multiplex Add TMultiplexedProtocol service name "ThriftTest" --abstract-namespace Create the domain socket in the Abstract Namespace (no connection with filesystem pathnames) @@ -45,10 +53,11 @@ $port = $opts['port'] ?? 9090; $transport = $opts['transport'] ?? 'buffered'; +$protocol = $opts['protocol'] ?? 'binary'; $loader = new Thrift\ClassLoader\ThriftClassLoader(); -$loader->registerDefinition('ThriftTest', __DIR__ . '/../../lib/php/test/Resources/packages/phpcm'); +$loader->registerDefinition('ThriftTest', __DIR__ . '/gen-php-classmap'); $loader->register(); $sslOptions = \stream_context_create( @@ -70,6 +79,28 @@ $serverTransportFactory = new \Thrift\Factory\TTransportFactory(); } +switch ($protocol) { + case 'binary': + $protocolFactory = new \Thrift\Factory\TBinaryProtocolFactory(false, true); + break; + case 'accel': + if (!function_exists('thrift_protocol_write_binary')) { + fwrite(STDERR, "Acceleration extension is not loaded\n"); + exit(1); + } + $protocolFactory = new TBinaryProtocolAcceleratedFactory(); + break; + case 'compact': + $protocolFactory = new \Thrift\Factory\TCompactProtocolFactory(); + break; + case 'json': + $protocolFactory = new \Thrift\Factory\TJSONProtocolFactory(); + break; + default: + fwrite(STDERR, "--protocol must be one of {binary|compact|json|accel}\n"); + exit(1); +} + $serverTransport = new \Thrift\Server\TServerSocket('localhost', $port); $handler = new Handler(); $processor = new ThriftTest\ThriftTestProcessor($handler); @@ -79,8 +110,8 @@ $serverTransport, $serverTransportFactory, $serverTransportFactory, - new \Thrift\Factory\TBinaryProtocolFactory(), - new \Thrift\Factory\TBinaryProtocolFactory() + $protocolFactory, + $protocolFactory ); echo "Starting the Test server...\n"; diff --git a/test/php/test_php.ini b/test/php/test_php.ini index 5eecb329618..b135e7462ab 100644 --- a/test/php/test_php.ini +++ b/test/php/test_php.ini @@ -1,3 +1,2 @@ ;extension=thrift_protocol.so -;extension=json.so ;extension=sockets.so diff --git a/test/py/TestClient.py b/test/py/TestClient.py index 07b39a0dc9c..316ff8840ba 100755 --- a/test/py/TestClient.py +++ b/test/py/TestClient.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # -*- coding: utf-8 -*- # # Licensed to the Apache Software Foundation (ASF) under one diff --git a/test/py/TestServer.py b/test/py/TestServer.py index 59a06ad2ada..dcc46d73c6e 100755 --- a/test/py/TestServer.py +++ b/test/py/TestServer.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # # Licensed to the Apache Software Foundation (ASF) under one diff --git a/test/tests.json b/test/tests.json index 3ebbaac5249..a62658ed1bd 100644 --- a/test/tests.json +++ b/test/tests.json @@ -286,6 +286,7 @@ "server": { "extra_args": ["TSimpleServer"], "command": [ + "python3", "TestServer.py", "--verbose", "--genpydir=gen-py" @@ -294,6 +295,7 @@ "client": { "timeout": 15, "command": [ + "python3", "TestClient.py", "--verbose", "--host=localhost", @@ -563,6 +565,8 @@ "command": [ "php", "-dextension_dir=php_ext_dir", + "-dextension=thrift_protocol.so", + "-dextension=sockets.so", "--php-ini=test_php.ini", "--no-php-ini", "-ddisplay_errors=stderr", @@ -589,6 +593,8 @@ "command": [ "php", "-dextension_dir=php_ext_dir", + "-dextension=thrift_protocol.so", + "-dextension=sockets.so", "--php-ini=test_php.ini", "--no-php-ini", "-ddisplay_errors=stderr", From 2c687f6b15f47e2a3ba46e53b251146aeac1e11b Mon Sep 17 00:00:00 2001 From: Volodymyr Panivko Date: Thu, 26 Mar 2026 23:25:37 +0100 Subject: [PATCH 2/2] THRIFT-5757: align Python cross-test launchers --- test/php/Handler.php | 2 ++ test/py/TestClient.py | 2 +- test/py/TestServer.py | 2 +- test/tests.json | 4 ++-- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/test/php/Handler.php b/test/php/Handler.php index a03554c4854..670720fe42e 100644 --- a/test/php/Handler.php +++ b/test/php/Handler.php @@ -170,6 +170,8 @@ public function testMultiException($arg0, $arg1) public function testOneway($secondsToSleep) { + // Keep the oneway test quick so the cross-test matrix measures fire-and-forget behavior, + // not a full second of handler blocking in the single-threaded PHP test server. usleep($secondsToSleep * 300000); } } diff --git a/test/py/TestClient.py b/test/py/TestClient.py index 316ff8840ba..07b39a0dc9c 100755 --- a/test/py/TestClient.py +++ b/test/py/TestClient.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python # -*- coding: utf-8 -*- # # Licensed to the Apache Software Foundation (ASF) under one diff --git a/test/py/TestServer.py b/test/py/TestServer.py index dcc46d73c6e..59a06ad2ada 100755 --- a/test/py/TestServer.py +++ b/test/py/TestServer.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one diff --git a/test/tests.json b/test/tests.json index a62658ed1bd..ac7e51f2e85 100644 --- a/test/tests.json +++ b/test/tests.json @@ -286,7 +286,7 @@ "server": { "extra_args": ["TSimpleServer"], "command": [ - "python3", + "python", "TestServer.py", "--verbose", "--genpydir=gen-py" @@ -295,7 +295,7 @@ "client": { "timeout": 15, "command": [ - "python3", + "python", "TestClient.py", "--verbose", "--host=localhost",