From 6061731030b51c92fc79ce2d86ed21e0be98d0bc Mon Sep 17 00:00:00 2001 From: Uiseop Eom Date: Tue, 12 Jul 2022 01:46:51 +0900 Subject: [PATCH] chore: Add test code for input validation --- .../BatchSizeLimitExceededException.php | 4 +- src/ZaiClient/Requests/CartaddEvent.php | 4 + src/ZaiClient/Requests/CustomEvent.php | 5 +- src/ZaiClient/Requests/EventInBatch.php | 2 +- src/ZaiClient/Requests/LikeEvent.php | 4 + src/ZaiClient/Requests/PurchaseEvent.php | 2 +- src/ZaiClient/Requests/RateEvent.php | 4 + .../RelatedItemsRecommendationRequest.php | 12 +- .../RerankingRecommendationRequest.php | 11 +- .../Requests/UserRecommendationRequest.php | 11 +- src/ZaiClient/Requests/ViewEvent.php | 4 + tests/EventLogTest.php | 59 ++++++++++ tests/RecommendationTest.php | 111 +++++++++++++++++- tests/TestUtils.php | 11 ++ 14 files changed, 219 insertions(+), 25 deletions(-) create mode 100644 tests/TestUtils.php diff --git a/src/ZaiClient/Exceptions/BatchSizeLimitExceededException.php b/src/ZaiClient/Exceptions/BatchSizeLimitExceededException.php index 536ef7d..1aef51c 100644 --- a/src/ZaiClient/Exceptions/BatchSizeLimitExceededException.php +++ b/src/ZaiClient/Exceptions/BatchSizeLimitExceededException.php @@ -15,9 +15,9 @@ */ class BatchSizeLimitExceededException extends \Exception { - public function __construct() + public function __construct($records_num) { - $message = sprintf("Number of total records cannot exceed 50, but your Event holds %d."); + $message = sprintf("Number of total records cannot exceed 50, but your Event holds %d.", $records_num); parent::__construct($message, 2); } diff --git a/src/ZaiClient/Requests/CartaddEvent.php b/src/ZaiClient/Requests/CartaddEvent.php index 81b8a86..ba664e6 100644 --- a/src/ZaiClient/Requests/CartaddEvent.php +++ b/src/ZaiClient/Requests/CartaddEvent.php @@ -11,6 +11,7 @@ use ZaiKorea\ZaiClient\Requests\BaseEvent; use ZaiKorea\ZaiClient\Requests\EventInBatch; use ZaiKorea\ZaiClient\Configs\Config; +use ZaiKorea\ZaiClient\Exceptions\BatchSizeLimitExceededException; /** * @final @@ -79,6 +80,9 @@ public function __construct($customer_id, $item_ids, $options = array()) $tmp_timestamp += Config::EPSILON; } + if (count($events) > 50) + throw new BatchSizeLimitExceededException(count($events)); + if (count($events) == 1) $this->setPayload($events[0]); else diff --git a/src/ZaiClient/Requests/CustomEvent.php b/src/ZaiClient/Requests/CustomEvent.php index 70fa8e2..fcfc46a 100644 --- a/src/ZaiClient/Requests/CustomEvent.php +++ b/src/ZaiClient/Requests/CustomEvent.php @@ -11,6 +11,7 @@ use ZaiKorea\ZaiClient\Requests\BaseEvent; use ZaiKorea\ZaiClient\Requests\EventInBatch; use ZaiKorea\ZaiClient\Configs\Config; +use ZaiKorea\ZaiClient\Exceptions\BatchSizeLimitExceededException; /** * @final @@ -107,7 +108,6 @@ public function __construct( ) ); } - array_push($events, new EventInBatch( $customer_id, $custom_action['item_id'], @@ -118,6 +118,9 @@ public function __construct( $tmp_timestamp += Config::EPSILON; } + if (count($events) > 50) + throw new BatchSizeLimitExceededException(count($events)); + if (count($events) == 1) $this->setPayload($events[0]); else diff --git a/src/ZaiClient/Requests/EventInBatch.php b/src/ZaiClient/Requests/EventInBatch.php index f270ea0..917c7a5 100644 --- a/src/ZaiClient/Requests/EventInBatch.php +++ b/src/ZaiClient/Requests/EventInBatch.php @@ -35,7 +35,7 @@ public function __construct($user_id, $item_id, $timestamp, $event_type, $event_ throw new \InvalidArgumentException('Length of user id must be between 1 and 100.'); if (!(strlen($this->item_id) > 0 && strlen($this->item_id) <= 100)) - throw new \InvalidArgumentException('Length of user id must be between 1 and 100.'); + throw new \InvalidArgumentException('Length of item id must be between 1 and 100.'); if (!(strlen($this->event_type) > 0 && strlen($this->event_type) <= 100)) throw new \InvalidArgumentException('Length of event type must be between 1 and 100.'); diff --git a/src/ZaiClient/Requests/LikeEvent.php b/src/ZaiClient/Requests/LikeEvent.php index f9142da..ef91d3a 100644 --- a/src/ZaiClient/Requests/LikeEvent.php +++ b/src/ZaiClient/Requests/LikeEvent.php @@ -11,6 +11,7 @@ use ZaiKorea\ZaiClient\Requests\BaseEvent; use ZaiKorea\ZaiClient\Requests\EventInBatch; use ZaiKorea\ZaiClient\Configs\Config; +use ZaiKorea\ZaiClient\Exceptions\BatchSizeLimitExceededException; /** * @final @@ -80,6 +81,9 @@ public function __construct($customer_id, $item_ids, $options = array()) $tmp_timestamp += Config::EPSILON; } + if (count($events) > 50) + throw new BatchSizeLimitExceededException(count($events)); + if (count($events) == 1) $this->setPayload($events[0]); else diff --git a/src/ZaiClient/Requests/PurchaseEvent.php b/src/ZaiClient/Requests/PurchaseEvent.php index 7d6a6bf..453ecd0 100644 --- a/src/ZaiClient/Requests/PurchaseEvent.php +++ b/src/ZaiClient/Requests/PurchaseEvent.php @@ -113,7 +113,7 @@ public function __construct($customer_id, $orders = array(), $options = array()) } if (count($events) > 50) - throw new BatchSizeLimitExceededException(); + throw new BatchSizeLimitExceededException(count($events)); if (count($events) == 1) $this->setPayload($events[0]); diff --git a/src/ZaiClient/Requests/RateEvent.php b/src/ZaiClient/Requests/RateEvent.php index bef7e5d..71003e7 100644 --- a/src/ZaiClient/Requests/RateEvent.php +++ b/src/ZaiClient/Requests/RateEvent.php @@ -11,6 +11,7 @@ use ZaiKorea\ZaiClient\Requests\BaseEvent; use ZaiKorea\ZaiClient\Requests\EventInBatch; use ZaiKorea\ZaiClient\Configs\Config; +use ZaiKorea\ZaiClient\Exceptions\BatchSizeLimitExceededException; /** * @final @@ -97,6 +98,9 @@ public function __construct($customer_id, $rate_actions = array(), $options = ar $tmp_timestamp += Config::EPSILON; } + if (count($events) > 50) + throw new BatchSizeLimitExceededException(count($events)); + if (count($events) == 1) $this->setPayload($events[0]); else diff --git a/src/ZaiClient/Requests/RelatedItemsRecommendationRequest.php b/src/ZaiClient/Requests/RelatedItemsRecommendationRequest.php index 24d9a25..f11cbd3 100644 --- a/src/ZaiClient/Requests/RelatedItemsRecommendationRequest.php +++ b/src/ZaiClient/Requests/RelatedItemsRecommendationRequest.php @@ -17,27 +17,27 @@ class RelatedItemsRecommendationRequest extends RecommendationRequest public function __construct($item_id, $limit, $options = array()) { - if (!(is_null(null) || strlen($item_id) > 0 && strlen($item_id) <= 100)) + if (is_null($item_id) || !(strlen($item_id) > 0 && strlen($item_id) <= 100)) throw new \InvalidArgumentException('Length of item id must be between 1 and 100.'); if (!(0 < $limit && $limit <= 1000000)) throw new \InvalidArgumentException('Limit must be between 1 and 1000,000.'); + if (!is_array($options)) + throw new \InvalidArgumentException("Options must be given as an array."); if (isset($options['offset'])) { + if (!(0 <= $options['offset'] && $options['offset'] <= 1000000)) throw new \InvalidArgumentException('Offset must be between 0 and 1000,000.'); } - if (isset($options['recommendation_type'])) { - if ($options['recommendation_type'] == null || !(0 < strlen($options['recommendation_type'] && strlen($options['recommendation_type']) <= 100))) + if (isset($options['recommendation_type'])) { // php tip! isset() returns false if the value of $options['recommendation_type'] is null + if (!(0 < strlen($options['recommendation_type'] && strlen($options['recommendation_type']) <= 100))) throw new \InvalidArgumentException('Length of recommendation type must be between 1 and 100.'); } $this->item_id = $item_id; $this->limit = $limit; - if (!is_array($options)) - throw new \InvalidArgumentException("options must be given as an array."); - $this->recommendation_type = isset($options['recommendation_type']) ? $options['recommendation_type'] : self::DEFAULT_RECOMMENDATION_TYPE; $this->offset = isset($options['offset']) ? $options['offset'] : self::DEFAULT_OFFSET; } diff --git a/src/ZaiClient/Requests/RerankingRecommendationRequest.php b/src/ZaiClient/Requests/RerankingRecommendationRequest.php index cce6673..00d111a 100644 --- a/src/ZaiClient/Requests/RerankingRecommendationRequest.php +++ b/src/ZaiClient/Requests/RerankingRecommendationRequest.php @@ -40,12 +40,16 @@ public function __construct($user_id, $item_ids, $limit, $options = array()) if (!(is_null(null) || (0 < $limit && $limit <= 1000000))) throw new \InvalidArgumentException('Limit must be null or between 1 and 1000,000.'); + if (!is_array($options)) + throw new \InvalidArgumentException("Options must be given as an array."); + if (isset($options['offset'])) { if (!(0 <= $options['offset'] && $options['offset'] <= 1000000)) throw new \InvalidArgumentException('Offset must be between 0 and 1000,000.'); } - if (isset($options['recommendation_type'])) { - if ($options['recommendation_type'] == null || !(0 < strlen($options['recommendation_type'] && strlen($options['recommendation_type']) <= 100))) + + if (isset($options['recommendation_type'])) { // php tip! isset() returns false if the value of $options['recommendation_type'] is null + if (!(0 < strlen($options['recommendation_type'] && strlen($options['recommendation_type']) <= 100))) throw new \InvalidArgumentException('Length of recommendation type must be between 1 and 100.'); } @@ -53,9 +57,6 @@ public function __construct($user_id, $item_ids, $limit, $options = array()) $this->item_ids = $item_ids; // This should be an array $this->limit = $limit; - if (!is_array($options)) - throw new \InvalidArgumentException("options must be given as an array."); - $this->recommendation_type = isset($options['recommendation_type']) ? $options['recommendation_type'] : self::DEFAULT_RECOMMENDATION_TYPE; $this->offset = isset($options['offset']) ? $options['offset'] : self::DEFAULT_OFFSET; } diff --git a/src/ZaiClient/Requests/UserRecommendationRequest.php b/src/ZaiClient/Requests/UserRecommendationRequest.php index f52c510..2180a97 100644 --- a/src/ZaiClient/Requests/UserRecommendationRequest.php +++ b/src/ZaiClient/Requests/UserRecommendationRequest.php @@ -24,21 +24,22 @@ public function __construct($user_id, $limit, $options = array()) if (!(0 < $limit && $limit <= 1000000)) throw new \InvalidArgumentException('Limit must be between 1 and 1000,000.'); + if (!is_array($options)) + throw new \InvalidArgumentException('Options must be given as an array.'); + if (isset($options['offset'])) { if (!(0 <= $options['offset'] && $options['offset'] <= 1000000)) throw new \InvalidArgumentException('Offset must be between 0 and 1000,000.'); } - if (isset($options['recommendation_type'])) { - if ($options['recommendation_type'] == null || !(0 < strlen($options['recommendation_type'] && strlen($options['recommendation_type']) <= 100))) + + if (isset($options['recommendation_type'])) { // php tip! isset() returns false if the value of $options['recommendation_type'] is null + if (!(0 < strlen($options['recommendation_type'] && strlen($options['recommendation_type']) <= 100))) throw new \InvalidArgumentException('Length of recommendation type must be between 1 and 100.'); } $this->user_id = $user_id; $this->limit = $limit; - if (!is_array($options)) - throw new \InvalidArgumentException('options must be givent as an array. $options given instead.'); - $this->recommendation_type = isset($options['recommendation_type']) ? $options['recommendation_type'] : self::DEFAULT_RECOMMENDATION_TYPE; $this->offset = isset($options['offset']) ? $options['offset'] : self::DEFAULT_OFFSET; } diff --git a/src/ZaiClient/Requests/ViewEvent.php b/src/ZaiClient/Requests/ViewEvent.php index 3182a0a..b459acc 100644 --- a/src/ZaiClient/Requests/ViewEvent.php +++ b/src/ZaiClient/Requests/ViewEvent.php @@ -11,6 +11,7 @@ use ZaiKorea\ZaiClient\Requests\BaseEvent; use ZaiKorea\ZaiClient\Requests\EventInBatch; use ZaiKorea\ZaiClient\Configs\Config; +use ZaiKorea\ZaiClient\Exceptions\BatchSizeLimitExceededException; class ViewEvent extends BaseEvent { @@ -77,6 +78,9 @@ public function __construct($customer_id, $item_ids, $options = array()) $tmp_timestamp += Config::EPSILON; } + if (count($events) > 50) + throw new BatchSizeLimitExceededException(count($events)); + if (count($events) == 1) $this->setPayload($events[0]); else diff --git a/tests/EventLogTest.php b/tests/EventLogTest.php index 67fb284..68716c1 100644 --- a/tests/EventLogTest.php +++ b/tests/EventLogTest.php @@ -16,10 +16,13 @@ use ZaiKorea\ZaiClient\Requests\RateEvent; use ZaiKorea\ZaiClient\Requests\CustomEvent; use ZaiKorea\ZaiClient\Exceptions\ZaiClientException; +use ZaiKorea\ZaiClient\Exceptions\BatchSizeLimitExceededException; use ZaiKorea\ZaiClient\Configs\Config; define('SECRET', getenv('ZAI_TEST')); +require_once 'TestUtils.php'; + class EventLogTest extends TestCase { private $client_id = 'test'; @@ -471,4 +474,60 @@ public function testBadOrdersTypeOnPurchaseEventWithEmptyArray() $purchase_event = new PurchaseEvent($customer_id, $orders); $client->addEventLog($purchase_event); } + + public function testBadCustomerIdOnViewEvent() + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Length of user id must be between 1 and 100.'); + + $client = new ZaiClient($this->client_id, SECRET); + $customer_id = generateRandomString(101); + + $item_id = ['P12345']; + $view_event = new ViewEvent($customer_id, $item_id); + $client->addEventLog($view_event); + } + + public function testBadItemIdOnViewEvent() + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Length of item id must be between 1 and 100.'); + + $client = new ZaiClient($this->client_id, SECRET); + $customer_id = 'php-raise-error'; + + $item_id = [generateRandomString(101)]; + $view_event = new ViewEvent($customer_id, $item_id); + $client->addEventLog($view_event); + } + + public function testBadEventTypeCustomerEvent() + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Length of event type must be between 1 and 100.'); + + $client = new ZaiClient($this->client_id, SECRET); + $customer_id = 'php-raise-error'; + + $custom_event_type = generateRandomString(102); + $custom_action = ['item_id' => 'P99999', 'value' => 9]; + $custom_event = new CustomEvent($customer_id, $custom_event_type, $custom_action); + $client->addEventLog($custom_event); + } + + public function testBatchLimiteExceededException() + { + $this->expectException(BatchSizeLimitExceededException::class); + $this->expectExceptionMessage(sprintf("Number of total records cannot exceed 50, but your Event holds %d.", 55)); + + $client = new ZaiClient($this->client_id, SECRET); + $customer_id = 'php-raise-error'; + + $orders = array( + ['item_id' => 'P1234567', 'price' => 11000, 'count' => 52], + ['item_id' => 'P5678901', 'price' => 11000, 'count' => 3] + ); + $purchase_event = new PurchaseEvent($customer_id, $orders); + $client->addEventLog($purchase_event); + } } diff --git a/tests/RecommendationTest.php b/tests/RecommendationTest.php index 6930c94..6b0df8d 100644 --- a/tests/RecommendationTest.php +++ b/tests/RecommendationTest.php @@ -9,16 +9,17 @@ define('SECRET', getenv('ZAI_TEST')); +require_once 'TestUtils.php'; + class RecommendationTest extends TestCase { private $client_id = 'test'; - private $client_secret = 'KVPzvdHTPWnt0xaEGc2ix-eqPXFCdEV5zcqolBr_h1k'; // secret key for testing public function testGetRecommendationsWithUserRecommendationRequest() { $client = new ZaiClient($this->client_id, SECRET); - $user_id = 'ZaiTest_User_id'; - $limit = 10; + $user_id = 'user'; + $limit = 3; $options = [ 'recommendation_type' => 'homepage', 'offset' => 0 @@ -28,6 +29,7 @@ public function testGetRecommendationsWithUserRecommendationRequest() $response = $client->getRecommendations($request); self::assertNotNull($response->getItems(), "items in response is null"); + self::assertEquals($response->getItems(), ['user_homepage_ITEM_ID_0', 'user_homepage_ITEM_ID_1', 'user_homepage_ITEM_ID_2']); self::assertSame($response->getCount(), $limit, "items count don't match"); self::assertTrue(time() - $response->getTimestamp() < 0.5); } @@ -36,7 +38,7 @@ public function testGetRecommendationsWithUserRecommendationRequestWithNull() { $client = new ZaiClient($this->client_id, SECRET); $user_id = null; - $limit = 10; + $limit = 3; $options = [ 'recommendation_type' => 'homepage', 'offset' => 0 @@ -46,6 +48,7 @@ public function testGetRecommendationsWithUserRecommendationRequestWithNull() $response = $client->getRecommendations($request); self::assertNotNull($response->getItems(), "items in response is null"); + self::assertEquals($response->getItems(), ['None_homepage_ITEM_ID_0', 'None_homepage_ITEM_ID_1', 'None_homepage_ITEM_ID_2']); self::assertSame($response->getCount(), $limit, "items count don't match"); self::assertTrue(time() - $response->getTimestamp() < 0.5); } @@ -105,4 +108,104 @@ public function testGetRecommendationsWithRerankingRecommendationRequest() self::assertSame($response->getCount(), $limit, "items count don't match"); self::assertTrue(time() - $response->getTimestamp() < 0.5); } + + /* ------------------- Test Errors --------------------- */ + public function testUserRecommendationWithNullLimit() + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Limit must be between 1 and 1000,000.'); + + $user_id = "ZaiTest_User_id"; + $limit = null; + + $options = [ + 'recommendation_type' => 'homepage', + 'offset' => 0 + ]; + $request = new UserRecommendationRequest($user_id, $limit, $options); + $client = new ZaiClient($this->client_id, SECRET); + $response = $client->getRecommendations($request); + } + + public function testRelatedItemsRecommendationWithNullLimit() + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Limit must be between 1 and 1000,000.'); + + $user_id = "ZaiTest_User_id"; + $limit = null; + + $options = [ + 'recommendation_type' => 'homepage', + 'offset' => 0 + ]; + $request = new RelatedItemsRecommendationRequest($user_id, $limit, $options); + $client = new ZaiClient($this->client_id, SECRET); + $response = $client->getRecommendations($request); + } + + public function testRelatedRecommendationWithNullItemId() + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Length of item id must be between 1 and 100.'); + + $item_id = null; + $limit = 10; + + $options = [ + 'recommendation_type' => 'homepage', + 'offset' => 0 + ]; + $request = new RelatedItemsRecommendationRequest($item_id, $limit, $options); + $client = new ZaiClient($this->client_id, SECRET); + $response = $client->getRecommendations($request); + } + + public function testRerankingRecommendationWithEmptyItemIds() + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Length of item_ids must be between 1 and 1000,000.'); + + $client = new ZaiClient($this->client_id, SECRET); + $user_id = "ZaiTest_User_id"; + $item_ids = []; + $limit = 3; + $options = [ + 'recommendation_type' => 'all_products_page', + 'offset' => 0 + ]; + + $request = new RerankingRecommendationRequest($user_id, $item_ids, $limit, $options); + $response = $client->getRecommendations($request); + } + + public function testUserRecommendationWithNullRecommendationType() + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Length of recommendation type must be between 1 and 100.'); + + $user_id = "LongRecommendationType"; + $limit = 3; + + $options = [ + 'recommendation_type' => generateRandomString(101), + ]; + $request = new UserRecommendationRequest($user_id, $limit, $options); + $client = new ZaiClient($this->client_id, SECRET); + $response = $client->getRecommendations($request); + } + + public function testUserRecommendationWithNoneArrayOptions() + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Options must be given as an array.'); + + $user_id = "ZaiTest_User_id"; + $limit = 3; + + $options = 'homepage'; + $request = new UserRecommendationRequest($user_id, $limit, $options); + $client = new ZaiClient($this->client_id, SECRET); + $response = $client->getRecommendations($request); + } } diff --git a/tests/TestUtils.php b/tests/TestUtils.php new file mode 100644 index 0000000..388de90 --- /dev/null +++ b/tests/TestUtils.php @@ -0,0 +1,11 @@ +