diff --git a/Dockerfile b/Dockerfile index dc8f95418..c6826b904 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,18 @@ -FROM php:8.2 +FROM php:8.4 WORKDIR /tmp/cassandra-php-driver RUN apt update -y \ - && apt install python3 pip cmake unzip mlocate build-essential git libuv1-dev libssl-dev libgmp-dev openssl zlib1g-dev libpcre3-dev openjdk-11-jre openjdk-11-jdk -y \ - && pip install git+https://github.com/riptano/ccm.git@master + && apt install python3 pip cmake unzip plocate build-essential git libuv1-dev libssl-dev libgmp-dev openssl zlib1g-dev libpcre2-dev -y \ + && pip install --break-system-packages setuptools git+https://github.com/apache/cassandra-ccm \ + && apt-get install -y wget gnupg ca-certificates \ + && mkdir -p /etc/apt/keyrings \ + && wget -O /etc/apt/keyrings/adoptium.gpg https://packages.adoptium.net/artifactory/api/gpg/key/public \ + && echo "deb [signed-by=/etc/apt/keyrings/adoptium.gpg] https://packages.adoptium.net/artifactory/deb bookworm main" > /etc/apt/sources.list.d/adoptium.list \ + && apt-get update \ + && apt-get install -y temurin-11-jdk \ + && rm -rf /var/lib/apt/lists/* + +RUN mkdir -p ~/.ccm && echo '[repositories]\ncassandra = https://dlcdn.apache.org/cassandra' > ~/.ccm/config COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin RUN docker-php-source extract \ @@ -17,7 +26,7 @@ RUN cmake -DCMAKE_CXX_FLAGS="-fPIC" -DCASS_BUILD_STATIC=OFF -DCASS_BUILD_SHARED= RUN docker-php-source extract COPY ext ext -ENV NO_INTERACTION true +ENV NO_INTERACTION=true RUN cd ext \ && phpize \ && LDFLAGS="-L/usr/local/lib" LIBS="-lssl -lz -luv -lm -lgmp -lstdc++" ./configure --with-cassandra=/usr/local \ @@ -38,10 +47,9 @@ ENV CI=$CI COPY support support COPY tests tests COPY phpunit.xml . -ENV JAVA_HOME /usr/lib/jvm/java-11-openjdk-amd64/ +ENV JAVA_HOME=/usr RUN bin/phpunit --stop-on-error --stop-on-failure --testsuite unit -RUN bin/phpunit --stop-on-error --stop-on-failure --testsuite integration --exclude-group flaky -RUN bash -c "for i in {1..10}; do bin/phpunit --stop-on-error --stop-on-failure --testsuite integration --group flaky && exit 0 || sleep 1; done; exit 1;" +RUN bin/phpunit --stop-on-error --stop-on-failure --testsuite integration COPY features features COPY behat.yml . diff --git a/behat.yml b/behat.yml index 7dfd0e545..a6d9922c8 100644 --- a/behat.yml +++ b/behat.yml @@ -7,7 +7,7 @@ default: tags: "~@cassandra-version-less-2.1&&~@cassandra-version-only-2.0&&~@broken" contexts: - FeatureContext: - cassandra_version: "4.1.0" + cassandra_version: "4.1.10" cassandra-version-3.11: formatters: diff --git a/composer.json b/composer.json index aa21551dd..d98236557 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "datastax/php-driver", - "type": "library", + "type": "php-ext", "description": "DataStax PHP Driver for Apache Cassandra", "keywords": [ "cassandra", @@ -26,6 +26,9 @@ "require": { "php": ">=8.1" }, + "php-ext": { + "extension-name": "cassandra" + }, "require-dev": { "behat/behat": "^3.7", "phpunit/php-code-coverage": "^7.0", diff --git a/ext/doc/generate_doc.php b/ext/doc/generate_doc.php index a74c573c8..2b08c6325 100644 --- a/ext/doc/generate_doc.php +++ b/ext/doc/generate_doc.php @@ -66,8 +66,6 @@ function isAlreadyImplementedByBase($current, $implemented) { function replaceKeyword($string) { if ($string == "Function") { return "Function_"; - } else if ($string == "function") { - return "function_"; } else if ($string == "Float") { return "Float_"; } @@ -383,6 +381,7 @@ function writeMethod($doc, $file, $class, $method, &$singleEOL) { fwrite($file, "...\$params"); } else { $parameterType = parseDocMetadata($doc, $className, $methodName, $parameterName); + $defaultValue = NULL; if ($parameter->isOptional()) { $defaultValue = $parameter->isDefaultValueAvailable() ? $parameter->getDefaultValue() : null; if (empty($defaultValue)) { @@ -397,6 +396,10 @@ function writeMethod($doc, $file, $class, $method, &$singleEOL) { } $parameterName = "$parameterName = $defaultValue"; } + // https://php.watch/versions/8.4/implicitly-marking-parameter-type-nullable-deprecated + if ($parameterType && rtrim($parameterType) !== 'mixed' && $defaultValue === 'null') { + $parameterType = "?$parameterType"; + } fwrite($file, "$parameterType\$$parameterName"); } $first = false; diff --git a/ext/src/Column.yaml b/ext/src/Column.yaml index 5de05dbc9..226b77899 100644 --- a/ext/src/Column.yaml +++ b/ext/src/Column.yaml @@ -13,7 +13,10 @@ Column: comment: Type of the column type: \Cassandra\Type isReversed: - comment: Returns whether the column is in descending or ascending order. + comment: |- + Returns whether the column is in descending or ascending order. + + @deprecated return: comment: Whether the column is stored in descending order. type: bool @@ -28,12 +31,18 @@ Column: comment: Whether the column is frozen type: bool indexName: - comment: Returns name of the index if defined. + comment: |- + Returns name of the index if defined. + + @deprecated return: comment: Name of the index if defined or null type: string indexOptions: - comment: Returns index options if present. + comment: |- + Returns index options if present. + + @deprecated return: comment: Index options if present or null type: string diff --git a/ext/src/Keyspace.yaml b/ext/src/Keyspace.yaml index 62f2b6fcc..aeef4bf1f 100644 --- a/ext/src/Keyspace.yaml +++ b/ext/src/Keyspace.yaml @@ -30,7 +30,7 @@ Keyspace: type: string return: comment: Table instance or null - type: \Cassandra\Table|null + type: \Cassandra\DefaultTable|null tables: comment: Returns all tables defined in this keyspace return: diff --git a/ext/src/Schema.yaml b/ext/src/Schema.yaml index 9aa079fa1..3c376eaf6 100644 --- a/ext/src/Schema.yaml +++ b/ext/src/Schema.yaml @@ -10,7 +10,7 @@ Schema: type: string return: comment: Keyspace instance or null - type: \Cassandra\Keyspace + type: \Cassandra\DefaultKeyspace keyspaces: comment: Returns all keyspaces defined in the schema. return: diff --git a/ext/src/Session.yaml b/ext/src/Session.yaml index a767bf9ed..07b268348 100644 --- a/ext/src/Session.yaml +++ b/ext/src/Session.yaml @@ -104,7 +104,7 @@ Session: comment: Get a snapshot of the cluster's current schema. return: comment: A snapshot of the cluster's schema. - type: \Cassandra\Schema + type: \Cassandra\DefaultSchema metrics: comment: Get performance and diagnostic metrics. return: diff --git a/ext/util/hash.c b/ext/util/hash.c index 9ca91349d..d4f1bc015 100644 --- a/ext/util/hash.c +++ b/ext/util/hash.c @@ -136,7 +136,7 @@ php_driver_value_compare(zval* zvalue1, zval* zvalue2 TSRMLS_DC) { return 1; } -int php_driver_data_compare(const void* a, const void* b TSRMLS_DC) { +int php_driver_data_compare(Bucket* a, Bucket* b TSRMLS_DC) { Bucket *f, *s; zval *first, *second; diff --git a/ext/util/hash.h b/ext/util/hash.h index 7a6a54875..887504785 100644 --- a/ext/util/hash.h +++ b/ext/util/hash.h @@ -51,7 +51,7 @@ struct php_driver_set_entry_ { unsigned php_driver_value_hash(zval* zvalue TSRMLS_DC); int php_driver_value_compare(zval* zvalue1, zval* zvalue2 TSRMLS_DC); -int php_driver_data_compare(const void* a, const void* b TSRMLS_DC); +int php_driver_data_compare(Bucket* a, Bucket* b TSRMLS_DC); unsigned php_driver_mpz_hash(unsigned seed, mpz_t n); diff --git a/support/ccm.php b/support/ccm.php index 596318cdb..ccdcdb43f 100644 --- a/support/ccm.php +++ b/support/ccm.php @@ -22,7 +22,7 @@ class CCM { const DEFAULT_CLUSTER_PREFIX = "php-driver"; - const DEFAULT_CASSANDRA_VERSION = "4.1.0"; + const DEFAULT_CASSANDRA_VERSION = "4.1.10"; const PROCESS_TIMEOUT_IN_SECONDS = 480; private $clusterPrefix; private $isSilent; @@ -179,7 +179,7 @@ private function internalSetup($dataCenterOneNodes, $dataCenterTwoNodes) $this->run('create', '-v', 'binary:' . $this->version, '-b', $clusterName); $params = array( - 'updateconf', '--rt', '1000', 'read_request_timeout_in_ms: 1000', + 'updateconf', 'read_request_timeout_in_ms: 1000', 'write_request_timeout_in_ms: 1000', 'request_timeout_in_ms: 1000', 'phi_convict_threshold: 16', 'hinted_handoff_enabled: false', 'dynamic_snitch_update_interval_in_ms: 1000', @@ -212,15 +212,15 @@ private function internalSetup($dataCenterOneNodes, $dataCenterTwoNodes) } if (version_compare($this->version, "2.2.0", ">=")) { - $this->run('updateconf', 'enable_user_defined_functions: true'); + $params[] = 'enable_user_defined_functions: true'; } if (version_compare($this->version, "3.0.0", ">=")) { - $this->run('updateconf', 'enable_scripted_user_defined_functions: true'); + $params[] = 'enable_scripted_user_defined_functions: true'; } if (version_compare($this->version, "3.0.0", ">=")) { - $this->run('updateconf', 'enable_materialized_views: true'); + $params[] = 'enable_materialized_views: true'; } $params[] = 'key_cache_size_in_mb: 0'; @@ -228,6 +228,15 @@ private function internalSetup($dataCenterOneNodes, $dataCenterTwoNodes) $params[] = 'memtable_flush_writers: 1'; $params[] = 'max_hints_delivery_threads: 1'; + // https://cassandra.apache.org/_/blog/Apache-Cassandra-4.1-Configuration-Standardization.html + if (version_compare($this->version, '4.1.0', '>=')) { + $params = \preg_replace( + ['/_in_ms: (\d+)/m', '/_in_mb: (\d+)/m', '/_mb_per_sec: (\d+)/m', '/^enable_(\w+)/m'], + [': \1ms', ': \1MiB', ': \1MiB/s', '\1_enabled'], + $params + ); + } + call_user_func_array(array($this, 'run'), $params); $this->run('populate', '-n', $dataCenterOneNodes.':'.$dataCenterTwoNodes, '-i', '127.0.0.'); } diff --git a/tests/integration/Cassandra/BasicIntegrationTest.php b/tests/integration/Cassandra/BasicIntegrationTest.php index 7e9ac3382..1f91fd83a 100644 --- a/tests/integration/Cassandra/BasicIntegrationTest.php +++ b/tests/integration/Cassandra/BasicIntegrationTest.php @@ -119,7 +119,7 @@ abstract class BasicIntegrationTest extends TestCase { */ protected function setUp(): void { // Initialize the database and establish a connection - $this->integration = new Integration(get_class(), $this->getName(false), + $this->integration = new Integration(get_class($this), $this->getName(false), $this->numberDC1Nodes, $this->numberDC2Nodes, $this->replicationFactor, $this->isClientAuthentication, $this->isSSL, $this->isUserDefinedAggregatesFunctions); diff --git a/tests/integration/Cassandra/ConsistencyIntegrationTest.php b/tests/integration/Cassandra/ConsistencyIntegrationTest.php index 8d37af5e0..37ff28a41 100644 --- a/tests/integration/Cassandra/ConsistencyIntegrationTest.php +++ b/tests/integration/Cassandra/ConsistencyIntegrationTest.php @@ -40,6 +40,7 @@ class ConsistencyIntegrationTest extends BasicIntegrationTest { public function testDefaultConsistencyLevel() { // Create a new table $this->session->execute("CREATE TABLE {$this->tableNamePrefix} (key int PRIMARY KEY)"); + usleep(200000); // Enable tracing $this->ccm->enableTracing(true); diff --git a/tests/integration/Cassandra/SchemaMetadataIntegrationTest.php b/tests/integration/Cassandra/SchemaMetadataIntegrationTest.php index d24bee034..8bf6fa2e8 100644 --- a/tests/integration/Cassandra/SchemaMetadataIntegrationTest.php +++ b/tests/integration/Cassandra/SchemaMetadataIntegrationTest.php @@ -20,8 +20,6 @@ /** * Schema metadata integration tests. - * - * @group flaky */ class SchemaMetadataIntegrationTest extends BasicIntegrationTest { /** @@ -70,7 +68,8 @@ protected function createKeyspaceWithSchema($keyspaceName, $tableSchemas) { array_filter(array_keys($tableSchema), function ($columnName) { return strpos($columnName, "key") === 0; })) ); - $this->session->execute($query); + $this->session->execute($query)->count(); + usleep(200000); } } @@ -82,6 +81,7 @@ protected function createTableForSecondaryIndexes() { "CREATE TABLE {$this->tableNamePrefix} " . "(key1 text, value1 int, value2 map, PRIMARY KEY(key1))" ); + usleep(200000); } /** @@ -89,6 +89,7 @@ protected function createTableForSecondaryIndexes() { */ protected function createSimpleSecondaryIndex() { $this->session->execute("CREATE INDEX simple ON {$this->tableNamePrefix} (value1)"); + sleep(1); } /** @@ -96,6 +97,7 @@ protected function createSimpleSecondaryIndex() { */ protected function createCollectionSecondaryIndex() { $this->session->execute("CREATE INDEX collection ON {$this->tableNamePrefix} (KEYS(value2))"); + sleep(1); } /** @@ -134,6 +136,7 @@ protected function createTablesForMaterializedViews() { "CREATE TABLE {$this->tableNamePrefix}_2 " . "(key1 text, key2 int, value1 int, PRIMARY KEY(key1, key2))" ); + usleep(200000); } /** @@ -146,6 +149,7 @@ protected function createSimpleMaterializedView() { "SELECT $column FROM {$this->tableNamePrefix}_1 WHERE value1 IS NOT NULL AND key1 IS NOT NULL " . "PRIMARY KEY(value1, key1)" ); + usleep(200000); } /** @@ -506,6 +510,7 @@ public function testEnumerateKeyspaces() { if (strpos($keyspaceName, "system") === 0) continue; $this->createKeyspace($keyspaceName); } + usleep(200000); $count = 0; foreach ($this->session->schema()->keyspaces() as $keyspace) { @@ -631,6 +636,7 @@ public function testGetColumnIndexOptions() { "CREATE TABLE {$this->tableNamePrefix}_with_index " . "(key int PRIMARY KEY, value map>>)" ); + usleep(200000); $keyspace = $this->session->schema()->keyspace($this->keyspaceName); $this->assertNotNull($keyspace); @@ -644,7 +650,7 @@ public function testGetColumnIndexOptions() { $this->assertNull($indexOptions); $this->session->execute("CREATE INDEX ON {$this->tableNamePrefix}_with_index (value)"); - sleep(10); + sleep(1); $keyspace = $this->session->schema()->keyspace($this->keyspaceName); $this->assertNotNull($keyspace); @@ -676,6 +682,7 @@ public function testSchemaMetadataWithNullFields() { "CREATE TABLE {$this->tableNamePrefix}_null_comment " . "(key int PRIMARY KEY, value int)" ); + usleep(200000); $keyspace = $this->session->schema()->keyspace($this->keyspaceName); $table = $keyspace->table("{$this->tableNamePrefix}_null_comment"); @@ -714,6 +721,7 @@ public function testSchemaMetadataWithNestedColumnTypes() { "CREATE TABLE {$this->tableNamePrefix}_nested3 " . "(key int PRIMARY KEY, value list>>>>)" ); + usleep(200000); $keyspace = $this->session->schema()->keyspace($this->keyspaceName); @@ -1280,6 +1288,7 @@ public function testSingleQuoteCustomValue() { . "key TEXT PRIMARY KEY," . "value 'org.apache.cassandra.db.marshal.LexicalUUIDType')" ); + usleep(200000); // Get the schema from the session $schema = $this->session->schema(); diff --git a/tests/integration/Cassandra/UserTypeIntegrationTest.php b/tests/integration/Cassandra/UserTypeIntegrationTest.php index 1c66b45e6..0155efe36 100644 --- a/tests/integration/Cassandra/UserTypeIntegrationTest.php +++ b/tests/integration/Cassandra/UserTypeIntegrationTest.php @@ -128,7 +128,7 @@ public static function generateAddressValue() { * value * (DEFAULT: self::generateAddressValue()) */ - public static function assertAddressValue(UserTypeValue $address, UserTypeValue $expected = null) { + public static function assertAddressValue(UserTypeValue $address, ?UserTypeValue $expected = null) { // Determine if the expected value should be defaulted if (is_null($expected)) { $expected = self::generateAddressValue();