def test_find_by_id_type(self):
        """ Test find_by_id_type function """
        test_recommendation = self._create_one_recommendation(by_id=1,
                                                              by_rel_id=2,
                                                              by_type=1)
        find_result = Recommendation.find_by_id_type(
            by_id=test_recommendation.product_id,
            by_type=test_recommendation.type_id)

        self.assertEqual(len(find_result.all()), 1)
        self.assertEqual(find_result.first(), test_recommendation)

        test_recommendation = self._create_one_recommendation(by_id=1,
                                                              by_rel_id=3,
                                                              by_type=1)
        find_result = Recommendation.find_by_id_type(
            by_id=test_recommendation.product_id,
            by_type=test_recommendation.type_id)

        self.assertEqual(len(find_result.all()), 2)

        self.assertRaises(TypeError, Recommendation.find_by_id_type, "not_int",
                          2)
        self.assertRaises(TypeError, Recommendation.find_by_id_type, 1,
                          "not_int")
        self.assertRaises(DataValidationError, Recommendation.find_by_id_type,
                          1, 5)
 def setUpClass(cls):
     """ These run once before Test suite """
     app.debug = False
     # Set up the test database
     app.config["SQLALCHEMY_DATABASE_URI"] = DATABASE_URI
     app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
     Recommendation.init_db(app)
    def get(self, product_id, related_product_id):
        """
        Retrieve a single recommendation

        This endpoint will return a Recommendation based on it's product id and related product id.
        """
        app.logger.info(
            "Querying Recommendation for product id: %s and related product id: %s",
            product_id,
            related_product_id,
        )
        recommendation = (Recommendation.find_recommendation(
            product_id, related_product_id).first()
                          or Recommendation.find_recommendation(
                              product_id, related_product_id, False).first())

        if not recommendation:
            api.abort(
                status.HTTP_404_NOT_FOUND,
                "404 Not Found: Recommendation for product id {} with related product id {} not found"
                .format(product_id, related_product_id),
            )

        app.logger.info(
            "Returning Recommendation for product id: %s and related product id: %s",
            product_id,
            related_product_id,
        )

        return recommendation.serialize(), status.HTTP_200_OK
    def test_find_by_id_status(self):
        """ Test find_by_id_status function """
        test_recommendation = self._create_one_recommendation(by_id=1,
                                                              by_rel_id=2,
                                                              by_type=1)
        find_result = Recommendation.find_by_id_status(
            by_id=test_recommendation.product_id,
            by_status=test_recommendation.status)

        self.assertEqual(len(find_result.all()), 1)
        self.assertEqual(find_result.first(), test_recommendation)

        test_recommendation = self._create_one_recommendation(by_id=1,
                                                              by_rel_id=3,
                                                              by_type=2)
        find_result = Recommendation.find_by_id_status(
            by_id=test_recommendation.product_id,
            by_status=test_recommendation.status)

        self.assertEqual(len(find_result.all()), 2)

        self.assertRaises(TypeError, Recommendation.find_by_id_status,
                          "not_int", False)
        self.assertRaises(TypeError, Recommendation.find_by_id_status, 1,
                          "not_bool")
 def _create_one_recommendation(self,
                                by_id,
                                by_rel_id,
                                by_type,
                                by_status=True):
     """ Create one specific recommendation for testing """
     test_recommendation = Recommendation(
         product_id=by_id,
         related_product_id=by_rel_id,
         type_id=by_type,
         status=by_status,
     )
     test_recommendation.create()
     return test_recommendation
    def test_get_all_recommendations_by_relid(self):
        """ Get all recommendations by related product id functions"""
        recommendation1 = self._create_one_recommendation(1, 2, 1)[0]
        recommendation2 = self._create_one_recommendation(3, 2, 3, by_status=False)[0]

        # Test Case 1
        # Test search by related product id only
        resp = self.app.get(BASE_URL + "?related-product-id={}".format(2))
        self.assertEqual(resp.status_code, status.HTTP_200_OK)
        self.assertEqual(len(resp.get_json()), 2)

        result1 = Recommendation().deserialize(resp.get_json()[0])
        result2 = Recommendation().deserialize(resp.get_json()[1])
        self.assertEqual(result1, recommendation1)
        self.assertEqual(result2, recommendation2)

        # Test Case 2
        # Test search by related product id and type id
        resp = self.app.get(BASE_URL + "?related-product-id={}&type-id={}".format(2,1))
        self.assertEqual(resp.status_code, status.HTTP_200_OK)
        self.assertEqual(len(resp.get_json()), 1)

        result = Recommendation().deserialize(resp.get_json()[0])
        self.assertEqual(result, recommendation1)

        # if the type-id is invalid
        resp = self.app.get(BASE_URL + "?related-product-id={}&type-id={}".format(2,10))
        self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST)
        
        # Test Case 3
        # Test search by related product id and status
        resp = self.app.get(BASE_URL + "?related-product-id={}&status={}".format(2,False))
        self.assertEqual(resp.status_code, status.HTTP_200_OK)
        self.assertEqual(len(resp.get_json()), 1)

        result = Recommendation().deserialize(resp.get_json()[0])
        self.assertEqual(result, recommendation2)

        # Test Case 4
        # Test search by related product id with type id and status
        resp = self.app.get(BASE_URL + "?related-product-id={}&type-id={}&status={}".format(2,3,False))
        self.assertEqual(resp.status_code, status.HTTP_200_OK)
        self.assertEqual(len(resp.get_json()), 1)

        result = Recommendation().deserialize(resp.get_json()[0])
        self.assertEqual(result, recommendation2)

        # if the type-id is invalid
        resp = self.app.get(BASE_URL + "?related-product-id={}&type-id={}&status={}".format(2,10,False))
        self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST)
def data_load(payload):
    """ Loads a Recommendation into the database """
    recommendation = Recommendation()
    recommendation.product_id = payload["product-id"]
    recommendation.related_product_id = payload["related-product-id"]
    recommendation.type_id = payload["type-id"]
    recommendation.status = payload["status"]
    recommendation.create()
 def _create_one_recommendation(self, by_id, by_rel_id, by_type, by_status=True):
     """ Create one specific recommendation for testing """
     test_recommendation = Recommendation(
         product_id=by_id,
         related_product_id=by_rel_id,
         type_id=by_type,
         status=by_status,
     )
     location_url = BASE_URL
     resp = self.app.post(
         location_url,
         json=test_recommendation.serialize(),
         content_type="application/json",
     )
     return [test_recommendation, resp.headers.get("Location", None)]
    def delete(self, product_id, related_product_id):
        """
        Delete a recommendation
        This endpoint will delete one unique recommendation based on
        the product id and related product id provided in the URI
        """
        app.logger.info(
            "Request to delete a recommendation by product id and related product id"
        )

        find_result = Recommendation.find_by_id_relid(product_id,
                                                      related_product_id)

        if not find_result.first():
            return "", status.HTTP_204_NO_CONTENT

        recommendation = find_result.first()
        app.logger.info(
            "Deleting recommendation with product id %s and related product id %s ...",
            recommendation.product_id,
            recommendation.related_product_id,
        )
        recommendation.delete()
        app.logger.info(
            "Deleted recommendation with product id %s and related product id %s ...",
            recommendation.product_id,
            recommendation.related_product_id,
        )

        return "", status.HTTP_204_NO_CONTENT
    def test_find_recommendation(self):
        """ Test find recommendation function """
        valid_recommendation = self._create_recommendations(count=1)[0]
        recommendation = Recommendation.find_recommendation(
            valid_recommendation.product_id,
            valid_recommendation.related_product_id,
            valid_recommendation.status,
        )

        self.assertEqual(recommendation.first(), valid_recommendation)

        valid_recommendation = self._create_recommendations(count=1,
                                                            by_status=False)[0]
        recommendation = Recommendation.find_recommendation(
            valid_recommendation.product_id,
            valid_recommendation.related_product_id,
            valid_recommendation.status,
        )

        self.assertEqual(recommendation.first(), valid_recommendation)

        valid_recommendation = self._create_recommendations(count=1,
                                                            by_status=False)[0]

        self.assertRaises(
            TypeError,
            Recommendation.find_recommendation,
            "abcd",
            valid_recommendation.related_product_id,
            valid_recommendation.status,
        )

        self.assertRaises(
            TypeError,
            Recommendation.find_recommendation,
            valid_recommendation.product_id,
            "efgh",
            valid_recommendation.status,
        )

        self.assertRaises(
            TypeError,
            Recommendation.find_recommendation,
            valid_recommendation.product_id,
            valid_recommendation.related_product_id,
            "notbool",
        )
    def post(self):
        """
        Creates a recommendation
        This endpoint will create a Recommendation based the data that is posted

        """
        app.logger.info(
            "Request for create a new recommendation in the database")

        app.logger.debug('Payload = %s', api.payload)
        recommendation = Recommendation()
        try:
            recommendation.deserialize(api.payload)
        except DataValidationError as error:
            raise BadRequest("Bad Request invalid data payload")

        if recommendation.product_id == recommendation.related_product_id:
            raise BadRequest(
                "product_id cannot be the same as related_product_id")

        existing_recommendation = (Recommendation.find_recommendation(
            recommendation.product_id,
            recommendation.related_product_id).first()
                                   or Recommendation.find_recommendation(
                                       recommendation.product_id,
                                       recommendation.related_product_id,
                                       by_status=False,
                                   ).first())

        if existing_recommendation:
            raise BadRequest(
                "Recommendation with given product id and related product id already exists"
            )

        recommendation.create()
        location_url = api.url_for(
            RecommendationResource,
            product_id=recommendation.product_id,
            related_product_id=recommendation.related_product_id,
            _external=True)

        app.logger.info(
            "recommendation from product ID [%s] to related product ID [%s] created.",
            recommendation.product_id,
            recommendation.related_product_id,
        )
        return (recommendation.serialize(), status.HTTP_201_CREATED, {
            "location": location_url
        })
    def test_find_by_status(self):
        """ Test find by status function """
        recommendation = self._create_one_recommendation(by_id=1,
                                                         by_rel_id=2,
                                                         by_type=1)
        result = Recommendation.find_by_status(by_status=True)

        self.assertEqual(len(result.all()), 1)
        self.assertEqual(result.first(), recommendation)

        self.assertRaises(TypeError, Recommendation.find_by_status, "not bool")
    def test_find_by_id_relid(self):
        """ Test find by product_id and related_product_id function """
        test_recommendation = self._create_one_recommendation(by_id=1,
                                                              by_rel_id=2,
                                                              by_type=1)
        find_result = Recommendation.find_by_id_relid(
            by_id=test_recommendation.product_id,
            by_rel_id=test_recommendation.related_product_id,
        )

        self.assertEqual(len(find_result.all()), 1)
        self.assertEqual(find_result.first(), test_recommendation)

        find_result_empty = Recommendation.find_by_id_relid(
            by_id=test_recommendation.product_id, by_rel_id=3)
        self.assertEqual(len(find_result_empty.all()), 0)

        self.assertRaises(TypeError, Recommendation.find_by_id_relid, 1,
                          "not_int")
        self.assertRaises(TypeError, Recommendation.find_by_id_relid,
                          "not_int", 1)
    def test_find_by_relid_status(self):
        """ Test find by related_product_id and status"""
        recommendation1 = self._create_one_recommendation(1, 2, 1)
        recommendation2 = self._create_one_recommendation(3,
                                                          2,
                                                          3,
                                                          by_status=False)
        result = Recommendation.find_by_relid_status(2, False)
        self.assertEqual(len(result.all()), 1)
        self.assertEqual(result.first(), recommendation2)

        self.assertRaises(TypeError, Recommendation.find_by_relid_status, 2, 1)
        self.assertRaises(TypeError, Recommendation.find_by_relid_status,
                          "String", True)
    def test_find_by_type_id(self):
        """ Test find by type_id function """
        recommendation = self._create_one_recommendation(by_id=1,
                                                         by_rel_id=2,
                                                         by_type=1)
        result = Recommendation.find_by_type_id(
            by_type_id=recommendation.type_id)

        self.assertEqual(len(result.all()), 1)
        self.assertEqual(result.first(), recommendation)

        self.assertRaises(TypeError, Recommendation.find_by_type_id, "not int")
        self.assertRaises(DataValidationError, Recommendation.find_by_type_id,
                          4)
    def test_create(self):
        """ Test Recommendation Create function """
        recommendation = Recommendation()
        recommendation.product_id = 10
        recommendation.related_product_id = 20
        recommendation.type_id = 20
        recommendation.status = True

        self.assertRaises(DataValidationError, recommendation.create)
    def test_get_recommendation(self):
        """ Get Recommendation Tests"""
        recommendation = self._create_recommendations(1)[0][0]

        # Test Case 1
        resp = self.app.get(
            BASE_URL
            + "/"
            + str(recommendation.product_id)
            + "/"
            + str(recommendation.related_product_id)
        )

        returned_recommendation = Recommendation()
        returned_recommendation.deserialize(resp.get_json())

        self.assertEqual(resp.status_code, status.HTTP_200_OK)
        self.assertEqual(recommendation, returned_recommendation)

        # Test Case 2
        resp = self.app.get(
            BASE_URL + "/" + str(recommendation.product_id) + "/" + str(99999)
        )

        self.assertEqual(resp.status_code, status.HTTP_404_NOT_FOUND)

        # Test Case 3
        resp = self.app.get(
            BASE_URL + "/" + str(recommendation.product_id) + "/" + str(-99999)
        )

        self.assertEqual(resp.status_code, status.HTTP_404_NOT_FOUND)

        # Test Case 4
        resp = self.app.get(BASE_URL + "/" + str(recommendation.product_id) + "/abcd")

        self.assertEqual(resp.status_code, status.HTTP_404_NOT_FOUND)
    def test_find_by_relid_type(self):
        """ Test find by related_product_id and type_id"""
        recommendation1 = self._create_one_recommendation(1, 2, 3)
        recommendation2 = self._create_one_recommendation(3,
                                                          2,
                                                          3,
                                                          by_status=False)
        result = Recommendation.find_by_relid_type(2, 3)
        self.assertEqual(len(result.all()), 2)

        self.assertRaises(TypeError, Recommendation.find_by_relid_type, 1,
                          "I'm everything but not int")
        self.assertRaises(TypeError, Recommendation.find_by_relid_type,
                          "I'm everything but not int", 1)
        self.assertRaises(DataValidationError,
                          Recommendation.find_by_relid_type, 5, 999999)
    def test_find_by_relid_type_status(self):
        """ Test find by related product id with type id and status"""
        recommendation1 = self._create_one_recommendation(1, 2, 3)
        recommendation2 = self._create_one_recommendation(3,
                                                          2,
                                                          3,
                                                          by_status=False)
        result = Recommendation.find_by_relid_type_status(2, 3, False)
        self.assertEqual(len(result.all()), 1)
        self.assertEqual(result.first(), recommendation2)

        self.assertRaises(TypeError, Recommendation.find_by_relid_type_status,
                          "rel_id not int", 2, False)
        self.assertRaises(TypeError, Recommendation.find_by_relid_type_status,
                          1, "type id not int", True)
        self.assertRaises(TypeError, Recommendation.find_by_relid_type_status,
                          1, 3, "status not bool")
        self.assertRaises(DataValidationError,
                          Recommendation.find_by_relid_type_status, 1,
                          509090909, False)
    def test_find_by_id_type_status(self):
        """ Test find_by_id_type_status function """
        recommendation = self._create_one_recommendation(by_id=1,
                                                         by_rel_id=2,
                                                         by_type=3)

        result = Recommendation.find_by_id_type_status(
            by_id=recommendation.product_id,
            by_type=recommendation.type_id,
            by_status=recommendation.status,
        )

        self.assertEqual(len(result.all()), 1)
        self.assertEqual(result.first(), recommendation)

        self.assertRaises(TypeError, Recommendation.find_by_id_type_status,
                          "not int", 2, 2)
        self.assertRaises(TypeError, Recommendation.find_by_id_type_status, 1,
                          "not int", 2)
        self.assertRaises(TypeError, Recommendation.find_by_id_type_status, 1,
                          2, "not bool")
        self.assertRaises(DataValidationError,
                          Recommendation.find_by_id_type_status, 1, 5, True)
    def delete(self, product_id):
        """
        Deletes all recommendations
        This endpoint will delete all the recommendations based on
        the product id provided in the URI
        """
        app.logger.info("Request to delete recommendations by product id")
        recommendations = Recommendation.find(product_id)

        if not recommendations.first():
            return "", status.HTTP_204_NO_CONTENT

        for recommendation in recommendations:
            app.logger.info(
                "Deleting all related products for product %s",
                recommendation.product_id,
            )
            recommendation.delete()
            app.logger.info(
                "Deleted all related products for product %s",
                recommendation.product_id,
            )

        return "", status.HTTP_204_NO_CONTENT
    def get(self):
        """
            Search recommendation based on query parameters

            This endpoint will return recommendation based on it's product id, related product id, type, and status.
        """

        args = recommendation_args.parse_args()
        product_id = args["product-id"]
        related_product_id = args["related-product-id"]
        type_id = args["type-id"]
        by_status = args["status"]

        if product_id == related_product_id and product_id is not None:
            raise BadRequest(
                "product_id cannot be the same as related_product_id")

        app.logger.info("Request for all recommendations in the database")

        try:
            if product_id and related_product_id:
                recommendations = Recommendation.find_by_id_relid(
                    product_id, related_product_id)
            elif product_id:
                if type_id and by_status is not None:
                    recommendations = Recommendation.find_by_id_type_status(
                        product_id, type_id, by_status)
                elif type_id:
                    recommendations = Recommendation.find_by_id_type(
                        product_id, type_id)
                elif by_status is not None:
                    recommendations = Recommendation.find_by_id_status(
                        product_id, by_status)
                else:
                    recommendations = Recommendation.find(product_id)
            elif related_product_id:
                if type_id and by_status is not None:
                    recommendations = Recommendation.find_by_relid_type_status(
                        related_product_id, type_id, by_status)
                elif type_id:
                    recommendations = Recommendation.find_by_relid_type(
                        related_product_id, type_id)
                elif by_status is not None:
                    recommendations = Recommendation.find_by_relid_status(
                        related_product_id, by_status)
                else:
                    recommendations = Recommendation.find_by_rel_id(
                        related_product_id)
            elif type_id and by_status is not None:
                recommendations = Recommendation.find_by_type_id_status(
                    type_id, by_status)
            elif type_id:
                recommendations = Recommendation.find_by_type_id(type_id)
            elif by_status is not None:
                recommendations = Recommendation.find_by_status(by_status)
            else:
                recommendations = Recommendation.all()
        except DataValidationError as error:
            raise BadRequest(str(error))
        except ValueError as error:
            raise BadRequest(str(error))

        result = []
        for rec in recommendations:
            record = rec.serialize()
            result.append(record)

        return result, status.HTTP_200_OK
    def test_toggle_recommendation_between_products(self):
        """ Toggle Recommendations Tests """
        recommendation = self._create_recommendations(count=1, by_status=True)[0][0]
        # Test Case 1
        resp = self.app.put(
            BASE_URL
            + "/{}/{}/toggle".format(
                recommendation.product_id, recommendation.related_product_id
            )
        )
        resp_message = resp.get_json()

        self.assertEqual(resp.status_code, status.HTTP_200_OK)
        self.assertIsNotNone(resp_message)
        self.assertEqual(not recommendation.status, resp_message["status"])

        resp = self.app.get(
            BASE_URL
            + "/{}/{}".format(
                recommendation.product_id, recommendation.related_product_id
            )
        )
        returned_recommendation = Recommendation()
        returned_recommendation.deserialize(resp.get_json())

        self.assertEqual(resp.status_code, status.HTTP_200_OK)
        self.assertEqual(not recommendation.status, returned_recommendation.status)

        # Test Case 2
        resp = self.app.put(
            BASE_URL
            + "/{}/{}/toggle".format(
                recommendation.product_id, recommendation.related_product_id
            )
        )
        resp_message = resp.get_json()

        self.assertEqual(resp.status_code, status.HTTP_200_OK)
        self.assertIsNotNone(resp_message)
        self.assertEqual(recommendation.status, resp_message["status"])

        resp = self.app.get(
            BASE_URL
            + "/{}/{}".format(
                recommendation.product_id, recommendation.related_product_id
            )
        )
        returned_recommendation = Recommendation()
        returned_recommendation.deserialize(resp.get_json())

        self.assertEqual(resp.status_code, status.HTTP_200_OK)
        self.assertEqual(recommendation.status, returned_recommendation.status)

        # Test Case 3
        resp = self.app.put(
            BASE_URL
            + "/{}/{}/toggle".format(recommendation.product_id, 99999)
        )

        self.assertEqual(resp.status_code, status.HTTP_404_NOT_FOUND)

        # Test Case 4
        resp = self.app.put(
            BASE_URL
            + "/{}/{}/toggle".format(recommendation.product_id, -99999)
        )

        self.assertEqual(resp.status_code, status.HTTP_404_NOT_FOUND)

        # Test Case 5
        resp = self.app.put(
            BASE_URL
            + "/{}/{}/toggle".format(recommendation.product_id, "abcd")
        )

        self.assertEqual(resp.status_code, status.HTTP_404_NOT_FOUND)
    def test_update_recommendation(self):
        """ Update Recommendations Tests """
        recommendations = self._create_recommendations(count=2, by_status=True)
        new_typeid = {1: 2, 2: 3, 3: 1}

        old_recommendation = recommendations[0][0]

        new_recommendation = Recommendation()
        new_recommendation.product_id = old_recommendation.product_id
        new_recommendation.related_product_id = old_recommendation.related_product_id
        new_recommendation.type_id = new_typeid[old_recommendation.type_id]
        new_recommendation.status = True

        update_url = (
           BASE_URL + "/"
            + str(new_recommendation.product_id)
            + "/"
            + str(new_recommendation.related_product_id)
        )
        get_url = (
           BASE_URL + "/"
            + str(old_recommendation.product_id)
            + "/"
            + str(new_recommendation.related_product_id)
        )

        update_resp = self.app.put(
            update_url,
            json=new_recommendation.serialize(),
            content_type="application/json",
        )
        self.assertEqual(update_resp.status_code, status.HTTP_200_OK)
        self.assertNotEqual(len(update_resp.data), 0)

        resp = self.app.get(
            get_url
        )

        self.assertEqual(len(resp.data), len(update_resp.data))
        updated_recommendation = Recommendation()
        updated_recommendation.deserialize(resp.get_json())
        self.assertEqual(
            updated_recommendation,
            new_recommendation,
            "recommendation updated successfully",
        )

        resp = self.app.put(
            update_url, json=new_recommendation.serialize(), content_type="not/json"
        )
        self.assertEqual(resp.status_code, status.HTTP_415_UNSUPPORTED_MEDIA_TYPE)


        old_recommendation = recommendations[1][0]

        # Test invalid product_id
        invalid_recommendation = {
            "product-id": "invalid_id",
            "related-product-id": old_recommendation.related_product_id,
            "type-id": new_typeid[old_recommendation.type_id],
            "status": True,
        }

        update_url = (
           BASE_URL + "/"
            + str(invalid_recommendation["product-id"])
            + "/"
            + str(invalid_recommendation["related-product-id"])
        )
        get_url = (
           BASE_URL + "/"
            + str(old_recommendation.product_id)
            + "/"
            + str(old_recommendation.related_product_id)
        )

        resp = self.app.put(
            update_url, json=invalid_recommendation, content_type="application/json"
        )
        self.assertEqual(resp.status_code, status.HTTP_404_NOT_FOUND)

        resp = self.app.get(
            get_url
        )
        updated_recommendation = Recommendation()
        updated_recommendation.deserialize(resp.get_json())

        self.assertEqual(
            updated_recommendation,
            old_recommendation,
            "recommendation should not be updated",
        )

        # Test invalid related_product_id
        invalid_recommendation = {
            "product-id": old_recommendation.product_id,
            "related-product-id": "invalid_related_product_id",
            "type-id": new_typeid[old_recommendation.type_id],
            "status": True,
        }

        update_url = (
           BASE_URL + "/"
            + str(invalid_recommendation["product-id"])
            + "/"
            + str(invalid_recommendation["related-product-id"])
        )

        resp = self.app.put(
            update_url, json=invalid_recommendation, content_type="application/json"
        )
        self.assertEqual(resp.status_code, status.HTTP_404_NOT_FOUND)

        # Test invalid type
        invalid_recommendation = {
            "product-id": old_recommendation.product_id,
            "related-product-id": old_recommendation.related_product_id,
            "type-id": 10,
            "status": True,
        }

        update_url = (
           BASE_URL + "/"
            + str(invalid_recommendation["product-id"])
            + "/"
            + str(invalid_recommendation["related-product-id"])
        )

        resp = self.app.put(
            update_url, json=invalid_recommendation, content_type="application/json"
        )
        self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST)

        # Test non-existe product_id
        non_exist_recommendation = {
            "product-id": 50000,
            "related-product-id": old_recommendation.related_product_id,
            "type-id": 2,
            "status": True,
        }

        update_url = (
           BASE_URL + "/"
            + str(non_exist_recommendation["product-id"])
            + "/"
            + str(non_exist_recommendation["related-product-id"])
        )

        resp = self.app.put(
            update_url, json=non_exist_recommendation, content_type="application/json"
        )
        self.assertEqual(resp.status_code, status.HTTP_404_NOT_FOUND)
 def test_find_by_rel_id(self):
     """ Test find by related_product_id"""
     recommendation = self._create_one_recommendation(1, 2, 1)
     result = Recommendation.find_by_rel_id(
         recommendation.related_product_id)
     self.assertEqual(result.first(), recommendation)
    def test_get_all_recommendations(self):
        """ Get all recommendations tests"""
        # Test Case 1
        # Test for empty database
        resp = self.app.get(BASE_URL)
        self.assertEqual(resp.status_code, status.HTTP_200_OK)

        # Test Case 2
        # Test for non-empty database
        recommendation = self._create_one_recommendation(
            by_id=1, by_rel_id=2, by_type=1
        )[0]

        resp = self.app.get(BASE_URL)
        self.assertEqual(resp.status_code, status.HTTP_200_OK)
        self.assertTrue(len(resp.get_json()) > 0)

        # Test for the accuracy
        resp = resp.get_json()
        returned_recommendation = Recommendation()
        returned_recommendation.deserialize(resp[0])
        self.assertEqual(recommendation, returned_recommendation)

        # Test Case 3
        resp = self.app.get(
            BASE_URL + "?product-id={}&related-product-id={}".format(
                recommendation.product_id, recommendation.related_product_id
            )
        )
        resp = resp.get_json()[0]

        returned_recommendation = Recommendation()
        returned_recommendation.deserialize(resp)
        self.assertEqual(recommendation, returned_recommendation)

        # Test Case 4
        resp = self.app.get(
            BASE_URL + "?product-id={}".format(recommendation.product_id)
        )
        resp = resp.get_json()[0]

        returned_recommendation = Recommendation()
        returned_recommendation.deserialize(resp)
        self.assertEqual(recommendation, returned_recommendation)

        # Test Case 5
        resp = self.app.get(
            BASE_URL + "?product-id={}".format("test")
        )
        self.assertEqual(status.HTTP_400_BAD_REQUEST, resp.status_code)

        # Test Case 6
        resp = self.app.get(
            BASE_URL + "?product-id={}&type-id={}".format(
                recommendation.product_id, recommendation.type_id
            )
        )
        resp = resp.get_json()[0]
        
        returned_recommendation = Recommendation()
        returned_recommendation.deserialize(resp)
        self.assertEqual(recommendation, returned_recommendation)

        
        # if the type-id is invalid
        resp = self.app.get(BASE_URL + "?product-id={}&type-id={}".format(recommendation.product_id,10))
        self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST)
        

        # Test Case 6 
        resp = self.app.get(
            BASE_URL + "?product-id={}&status={}".format(
                recommendation.product_id, recommendation.status
            )
        )
        resp = resp.get_json()[0]

        returned_recommendation = Recommendation()
        returned_recommendation.deserialize(resp)
        self.assertEqual(recommendation, returned_recommendation)

        # Test Case 7
        resp = self.app.get(
            BASE_URL + "?product-id={}&type-id={}&status={}".format(
                recommendation.product_id, recommendation.type_id, recommendation.status
            )
        )
        resp = resp.get_json()[0]

        returned_recommendation = Recommendation()
        returned_recommendation.deserialize(resp)
        self.assertEqual(recommendation, returned_recommendation)


        # if the type-id is invalid
        resp = self.app.get(BASE_URL + "?product-id={}&type-id={}&status={}".format(
            recommendation.product_id,10, recommendation.status))
        self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST)
        

        # Test Case 8
        resp = self.app.get(
            BASE_URL + "?type-id={}&status={}".format(
                recommendation.type_id, recommendation.status
            )
        )
        resp = resp.get_json()[0]

        returned_recommendation = Recommendation()
        returned_recommendation.deserialize(resp)
        self.assertEqual(recommendation, returned_recommendation)

        # if the type-id is invalid
        resp = self.app.get(BASE_URL + "?type-id={}&status={}".format(
            10, recommendation.status))
        self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST)
        

        # Test Case 9
        resp = self.app.get(
            BASE_URL + "?type-id={}".format(recommendation.type_id)
        )
        resp = resp.get_json()[0]

        returned_recommendation = Recommendation()
        returned_recommendation.deserialize(resp)
        self.assertEqual(recommendation, returned_recommendation)

        # if the type-id is invalid
        resp = self.app.get(BASE_URL + "?type-id={}".format(10))
        self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST)
        


        # Test Case 10
        resp = self.app.get(
            BASE_URL + "?status={}".format(recommendation.status))
        
        resp = resp.get_json()[0]

        returned_recommendation = Recommendation()
        returned_recommendation.deserialize(resp)
        self.assertEqual(recommendation, returned_recommendation)

        # Test Case 11
        resp = self.app.get(
            BASE_URL + "?product-id={}&type-id={}&status={}".format(
                "invalid_product_id", recommendation.type_id, recommendation.status
            )
        )
        self.assertEqual(status.HTTP_400_BAD_REQUEST, resp.status_code)

        # Test Case 12
        resp = self.app.get(
            BASE_URL + "?product-id={}&type-id={}&status={}".format(
                recommendation.product_id, 5, recommendation.status
            )
        )
        self.assertEqual(status.HTTP_400_BAD_REQUEST, resp.status_code)

        # Test Case 13
        resp = self.app.get(
            BASE_URL + "?product-id={}&related-product-id={}".format(1,1)
        )
        self.assertEqual(status.HTTP_400_BAD_REQUEST, resp.status_code)
    def test_create_recommendation(self):
        """ Create Recommendation Tests """

        # Test Case 1
        recommendation = Recommendation(
            product_id=10, related_product_id=20, type_id=1, status=True
        )

        resp = self.app.post(
            BASE_URL,
            json=recommendation.serialize(),
            content_type="application/json",
        )
        resp_message = resp.get_json()

        self.assertEqual(status.HTTP_201_CREATED, resp.status_code)
        self.assertTrue(
            resp.headers.get("Location", None).endswith(
                "/recommendations/{}/{}".format(
                    recommendation.product_id, recommendation.related_product_id
                )
            )
        )
        self.assertEqual(recommendation.serialize(), resp_message)

        # Test Case 2
        recommendation = Recommendation(
            product_id=10, related_product_id=20, type_id=1, status=True
        )

        resp = self.app.post(
            BASE_URL,
            json=recommendation.serialize(),
            content_type="application/json",
        )

        self.assertEqual(status.HTTP_400_BAD_REQUEST, resp.status_code)

        # Test Case 3
        recommendation = Recommendation(
            product_id=10, related_product_id=20, type_id=10, status=True
        )

        resp = self.app.post(
            BASE_URL,
            json=recommendation.serialize(),
            content_type="application/json",
        )

        self.assertEqual(status.HTTP_400_BAD_REQUEST, resp.status_code)

        # Test Case 4
        recommendation = Recommendation(
            product_id=10, related_product_id=-20, type_id=1, status=True
        )

        resp = self.app.post(
            BASE_URL,
            json=recommendation.serialize(),
            content_type="application/json",
        )

        self.assertEqual(status.HTTP_201_CREATED, resp.status_code)

        # Test Case 5
        recommendation = Recommendation(
            product_id=1000, related_product_id=1000, type_id=1, status=True
        )

        resp = self.app.post(
            BASE_URL,
            json=recommendation.serialize(),
            content_type="application/json",
        )
        self.assertEqual(status.HTTP_400_BAD_REQUEST, resp.status_code)
        resp = self.app.post(
            BASE_URL,
            json=recommendation.serialize(),
            content_type="application/json",
        )
        self.assertEqual(status.HTTP_400_BAD_REQUEST, resp.status_code)
def init_db():
    """ Initialies the SQLAlchemy app """
    global app
    Recommendation.init_db(app)
    def delete(self, product_id):
        """
        Deletes recommendations based on product id and query parameters
        This endpoint will delete all the recommendations based on
        the product id and the parameter type and stauts
        """
        args = status_type_args.parse_args()
        type_id = args["type-id"]
        recommendation_status = args["status"]
        app.logger.info(type_id)
        app.logger.info(recommendation_status)
        if type_id is None and recommendation_status is None:
            raise BadRequest(
                "Bad Request must provide at least 1 parameter : a valid type id or a valid status"
            )

        if (not (type_id is None)) and type_id not in [1, 2, 3]:
            raise BadRequest("Bad Request invalid type id provided")

        if (not (type_id is None)) and (not (recommendation_status is None)):
            app.logger.info(
                "Request to delete recommendations by type_id and status")

            recommendations = Recommendation.find_by_id_type_status(
                product_id, type_id, recommendation_status)

            for recommendation in recommendations:
                app.logger.info(
                    "Deleting all related products for product %s in type %s with status %r",
                    recommendation.product_id,
                    recommendation.type_id,
                    recommendation.status,
                )
                recommendation.delete()
                app.logger.info(
                    "Deleted all related products for product %s in type %s with status %r",
                    recommendation.product_id,
                    recommendation.type_id,
                    recommendation.status,
                )

            return "", status.HTTP_204_NO_CONTENT

        elif (not (type_id is None)):
            app.logger.info("Request to delete recommendations by type_id")
            recommendations = Recommendation.find_by_id_type(
                product_id, type_id)

            for recommendation in recommendations:
                app.logger.info(
                    "Deleting all related products for product %s in type %s with ",
                    recommendation.product_id,
                    recommendation.type_id,
                )
                recommendation.delete()
                app.logger.info(
                    "Deleted all related products for product %s in type %s with ",
                    recommendation.product_id,
                    recommendation.type_id,
                )

            return "", status.HTTP_204_NO_CONTENT

        elif (not (recommendation_status is None)):
            app.logger.info("Request to delete recommendations by status")
            recommendations = Recommendation.find_by_id_status(
                product_id, recommendation_status)

            for recommendation in recommendations:
                app.logger.info(
                    "Deleting all related products for product %s in status %r",
                    recommendation.product_id,
                    recommendation.status,
                )
                recommendation.delete()
                app.logger.info(
                    "Deleted all related products for product %s in status %r",
                    recommendation.product_id,
                    recommendation.status,
                )

            return "", status.HTTP_204_NO_CONTENT
    def test_deserialize(self):
        """ Test Recommendation deserialize function """
        invalid_recommendation = {
            "product-id": "abc",
            "related-product-id": "-10",
            "type-id": 20,
            "status": True,
        }

        recommendation = Recommendation()
        self.assertRaises(DataValidationError, recommendation.deserialize,
                          invalid_recommendation)

        invalid_recommendation = {
            "product-id": 10,
            "related-product-id": 5,
            "type-id": "not int",
            "status": True,
        }

        recommendation = Recommendation()
        self.assertRaises(DataValidationError, recommendation.deserialize,
                          invalid_recommendation)

        invalid_recommendation = {
            "product-id": "abc",
            "related-product-id": "-10",
            "type-id": 2,
            "status": True,
        }

        self.assertRaises(DataValidationError, recommendation.deserialize,
                          invalid_recommendation)

        invalid_recommendation = {
            "product-id": 10,
            "related-product-id": 20,
            "type-id": 2,
        }

        self.assertRaises(DataValidationError, recommendation.deserialize,
                          invalid_recommendation)

        invalid_recommendation = {
            "product-id": 10,
            "related-product-id": 20,
            "type-id": 2,
            "status": 10,
        }

        self.assertRaises(DataValidationError, recommendation.deserialize,
                          invalid_recommendation)

        invalid_recommendation = {
            "product-id": 1,
            "related-product-id": "invalid",
            "type-id": 2,
            "status": True,
        }

        self.assertRaises(DataValidationError, recommendation.deserialize,
                          invalid_recommendation)