Skip to content
Permalink
Browse files
IGNITE-10022: JS, PHP thin clients: a more meaningful exception when
ENUM type is not registered

This closes #5187
  • Loading branch information
ekaterina-nbl authored and isapego committed Oct 29, 2018
1 parent 3dbff1d commit b09f264194c56180caf5228087fa21ea0a7d7f2e
Showing 3 changed files with 146 additions and 12 deletions.
@@ -265,8 +265,10 @@ private function readEnum(MessageBuffer $buffer): EnumItem
$ordinal = $buffer->readInteger();
$enumItem->setOrdinal($ordinal);
$type = $this->typeStorage->getType($enumItem->getTypeId());
if (!$type->isEnum() || !$type->getEnumValues() || count($type->getEnumValues()) <= $ordinal) {
BinaryUtils::serializationError(false, 'EnumItem can not be deserialized: type mismatch');
if (!$type || !$type->isEnum()) {
BinaryUtils::enumSerializationError(false, sprintf('enum type id "%d" is not registered', $enumItem->getTypeId()));
} elseif (!$type->getEnumValues() || count($type->getEnumValues()) <= $ordinal) {
BinaryUtils::enumSerializationError(false, 'type mismatch');
}
$enumValues = $type->getEnumValues();
$enumItem->setName($enumValues[$ordinal][0]);
@@ -396,21 +398,22 @@ private function writeUUID(MessageBuffer $buffer, array $value): void

private function writeEnum(MessageBuffer $buffer, EnumItem $enumValue): void
{
$type = $this->typeStorage->getType($enumValue->getTypeId());
if (!$type || !$type->isEnum()) {
BinaryUtils::enumSerializationError(true, sprintf('enum type id "%d" is not registered', $enumValue->getTypeId()));
}
$buffer->writeInteger($enumValue->getTypeId());
if ($enumValue->getOrdinal() !== null) {
$buffer->writeInteger($enumValue->getOrdinal());
return;
} elseif ($enumValue->getName() !== null || $enumValue->getValue() !== null) {
$type = $this->typeStorage->getType($enumValue->getTypeId());
if ($type && $type->isEnum()) {
$enumValues = $type->getEnumValues();
if ($enumValues) {
for ($i = 0; $i < count($enumValues); $i++) {
if ($enumValue->getName() === $enumValues[$i][0] ||
$enumValue->getValue() === $enumValues[$i][1]) {
$buffer->writeInteger($i);
return;
}
$enumValues = $type->getEnumValues();
if ($enumValues) {
for ($i = 0; $i < count($enumValues); $i++) {
if ($enumValue->getName() === $enumValues[$i][0] ||
$enumValue->getValue() === $enumValues[$i][1]) {
$buffer->writeInteger($i);
return;
}
}
}
@@ -203,6 +203,9 @@ public static function checkTypesCompatibility($expectedType, int $actualTypeCod
$actualTypeCode === ObjectType::BINARY_OBJECT &&
$expectedTypeCode === ObjectType::COMPLEX_OBJECT) {
return;
} elseif ($expectedTypeCode === ObjectType::ENUM &&
$actualTypeCode === ObjectType::BINARY_ENUM) {
return;
} elseif ($actualTypeCode !== $expectedTypeCode) {
BinaryUtils::typeCastError($actualTypeCode, $expectedTypeCode);
}
@@ -419,6 +422,15 @@ public static function serializationError(bool $serialize, string $message = nul
throw new ClientException($msg);
}

public static function enumSerializationError(bool $serialize, string $message = null): void
{
$msg = $serialize ? 'Enum item can not be serialized' : 'Enum item can not be deserialized';
if ($message) {
$msg = $msg . ': ' . $message;
}
throw new ClientException($msg);
}

public static function typeCastError($fromType, $toType): void
{
throw new ClientException(sprintf('Type "%s" can not be cast to %s',
@@ -18,14 +18,20 @@

namespace Apache\Ignite\Tests;

use \DateTime;
use Ds\Map;
use Ds\Set;
use PHPUnit\Framework\TestCase;
use Apache\Ignite\Type\ObjectType;
use Apache\Ignite\Type\MapObjectType;
use Apache\Ignite\Type\CollectionObjectType;
use Apache\Ignite\Type\ObjectArrayType;
use Apache\Ignite\Type\ComplexObjectType;
use Apache\Ignite\Data\BinaryObject;
use Apache\Ignite\Data\Date;
use Apache\Ignite\Data\Timestamp;
use Apache\Ignite\Data\EnumItem;
use Apache\Ignite\Exception\ClientException;

class TstComplObjectWithPrimitiveFields
{
@@ -490,6 +496,119 @@ public function testPutGetObjectArrayOfObjectArraysOfComplexObjectsWithDefaultFi
$this->putGetObjectArrays(new ObjectArrayType(new ObjectArrayType(new ComplexObjectType())), $array);
}

public function testPutGetDateTime(): void
{
$this->putGetDate("Y-m-d H:i:s", "2018-10-19 18:31:13", 0);
$this->putGetDate("Y-m-d H:i:s", "2018-10-19 18:31:13", 29726);
$this->putGetDate("Y-m-d H:i:s", "2018-10-19 18:31:13", 999999);

$this->putGetTimestamp("Y-m-d H:i:s", "2018-10-19 18:31:13", 0);
$this->putGetTimestamp("Y-m-d H:i:s", "2018-10-19 18:31:13", 29726000);
$this->putGetTimestamp("Y-m-d H:i:s", "2018-10-19 18:31:13", 999999999);

$this->putGetTimestampFromDateTime("Y-m-d H:i:s", "2018-10-19 18:31:13", 0);
$this->putGetTimestampFromDateTime("Y-m-d H:i:s", "2018-10-19 18:31:13", 29726);
$this->putGetTimestampFromDateTime("Y-m-d H:i:s", "2018-10-19 18:31:13", 999999);
}

public function testPutEnumItems(): void
{
$fakeTypeId = 12345;
$enumItem1 = new EnumItem($fakeTypeId);
$enumItem1->setOrdinal(1);
$this->putEnumItem($enumItem1, null);
$this->putEnumItem($enumItem1, ObjectType::ENUM);
$enumItem2 = new EnumItem($fakeTypeId);
$enumItem2->setName('name');
$this->putEnumItem($enumItem2, null);
$this->putEnumItem($enumItem2, ObjectType::ENUM);
$enumItem3 = new EnumItem($fakeTypeId);
$enumItem3->setOrdinal(2);
$this->putEnumItem($enumItem3, null);
$this->putEnumItem($enumItem3, ObjectType::ENUM);
}

private function putEnumItem($value, $valueType): void
{
$key = microtime();
self::$cache->
setKeyType(null)->
setValueType($valueType);
// Enums registration is not supported by the client, therefore put EnumItem must throw ClientException
try {
self::$cache->put($key, $value);
$this->fail('put EnumItem must throw ClientException');
} catch (ClientException $e) {
$this->assertContains('Enum item can not be serialized', $e->getMessage());
} finally {
self::$cache->removeAll();
}
}

private function putGetDate(string $format, string $dateString, int $micros): void
{
$key = microtime();
self::$cache->
setKeyType(null)->
setValueType(ObjectType::DATE);
try {
$dt = DateTime::createFromFormat("$format.u", sprintf("%s.%06d", $dateString, $micros));
$iDate = Date::fromDateTime($dt);
self::$cache->put($key, $iDate);
$result = self::$cache->get($key);

$this->assertEquals(sprintf("%06d", intval($micros / 1000) * 1000), $result->toDateTime()->format('u'));
$this->assertEquals($dateString, $result->toDateTime()->format($format));
} finally {
self::$cache->removeAll();
}
}

private function putGetTimestamp(string $format, string $dateString, int $nanos): void
{
$key = microtime();
self::$cache->
setKeyType(null)->
setValueType(ObjectType::TIMESTAMP);

try {
$millis = intval($nanos / 1000000);
$nanosInMillis = $nanos % 1000000;
self::$cache->put($key,
new Timestamp(
DateTime::createFromFormat($format, $dateString)->getTimestamp() * 1000 + $millis,
$nanosInMillis
)
);
$result = self::$cache->get($key);

$this->assertEquals($nanos % 1000000, $result->getNanos());
$this->assertEquals($dateString, $result->toDateTime()->format($format));
} finally {
self::$cache->removeAll();
}
}

private function putGetTimestampFromDateTime(string $format, string $dateString, $micros): void
{
$key = microtime();
self::$cache->
setKeyType(null)->
setValueType(ObjectType::TIMESTAMP);

try {
self::$cache->put($key, Timestamp::fromDateTime(
DateTime::createFromFormat("$format.u", sprintf("%s.%06d", $dateString, $micros))
));
$result = self::$cache->get($key);

$this->assertEquals(intval($micros / 1000) * 1000, $result->toDateTime()->format('u'));
$this->assertEquals($dateString, $result->toDateTime()->format($format));
} finally {
self::$cache->removeAll();
}
}

private function putGetObjectArrays(?ObjectArrayType $arrayType, array $value): void
{
$key = microtime();

0 comments on commit b09f264

Please sign in to comment.