def test_update_prod_info(self): """ Update a product information. """ test_prod_id = 111 test_prod_name = "ab" prod_info = ProductInformation(prod_id=test_prod_id, prod_name=test_prod_name) prod_info.save() # update test_new_qty = 10 test_used_qty = 30 test_open_boxed_qty = 40 test_restock_level = 20 test_restock_amt = 66 prod_info.new_qty = test_new_qty prod_info.used_qty = test_used_qty prod_info.open_boxed_qty = test_open_boxed_qty prod_info.restock_level = test_restock_level prod_info.restock_amt = test_restock_amt prod_infos = ProductInformation.list_all() self.assertEqual(1, len(prod_infos)) self.assertIsNotNone(prod_infos[0]) self.assert_fields_equal(prod_infos[0], test_prod_id, test_prod_name, test_new_qty, test_used_qty, test_open_boxed_qty, test_restock_level, test_restock_amt)
def test_construct_prod_info(self): """ Construct a product information and assert it exists. """ # Test with only mandatory fields. test_prod_id = 1 test_prod_name = "asdf" prod_info = ProductInformation(prod_id=test_prod_id, prod_name=test_prod_name) self.assertIsNotNone(prod_info) self.assert_fields_equal(prod_info, test_prod_id, test_prod_name, None, None, None, None, None) # Test with all fields. test_prod_id = 10 test_prod_name = "zxcv" test_new_qty = 2 test_used_qty = 3 test_open_boxed_qty = 4 test_restock_level = 5 test_restock_amt = 6 prod_info = ProductInformation(prod_id=test_prod_id, prod_name=test_prod_name, new_qty=test_new_qty, used_qty=test_used_qty, open_boxed_qty=test_open_boxed_qty, restock_level=test_restock_level, restock_amt=test_restock_amt) self.assertIsNotNone(prod_info) self.assert_fields_equal(prod_info, test_prod_id, test_prod_name, test_new_qty, test_used_qty, test_open_boxed_qty, test_restock_level, test_restock_amt)
def test_query_by_quantity(self): """ Query by the total quantity """ ProductInformation(prod_id=88, new_qty=1, used_qty=1, open_boxed_qty=1, restock_level=0).save() ProductInformation(prod_id=99, new_qty=2, used_qty=2, open_boxed_qty=2, restock_level=0).save() response = self.app.get(PATH_INVENTORY_QUERY_BY_QUANTITY.format(3)) self.assertEqual(status.HTTP_200_OK, response.status_code) data = json.loads(response.data) self.assertEqual(88, data[0]['prod_id']) response = self.app.get(PATH_INVENTORY_QUERY_BY_QUANTITY.format(6)) self.assertEqual(status.HTTP_200_OK, response.status_code) data = json.loads(response.data) self.assertEqual(99, data[0]['prod_id']) response = self.app.get(PATH_INVENTORY_QUERY_BY_QUANTITY.format(5)) self.assertEqual(status.HTTP_200_OK, response.status_code) self.assertEqual(json.loads(response.data), [])
def test_automatic_restock(self): """ Test automatic restocking functionality """ prod_info = ProductInformation(prod_id=1, prod_name='Storm Trooper', \ new_qty=20, used_qty=30, open_boxed_qty=40, \ restock_level=1000, restock_amt=100) prod_info.save() retrived_prod_info = ProductInformation.find(prod_id=1) self.assertIsNotNone(retrived_prod_info) total_qty = retrived_prod_info.new_qty + retrived_prod_info.used_qty \ + retrived_prod_info.open_boxed_qty self.assertEqual(total_qty, 1090)
def test_deserialize_prod_info(self): """ Test deserialization of a product information. """ test_prod_id = 119 test_prod_name = "fire" data = {PROD_ID: test_prod_id, PROD_NAME: test_prod_name} prod_info = ProductInformation() prod_info.deserialize(data) self.assertIsNotNone(prod_info) self.assert_fields_equal(prod_info, test_prod_id, test_prod_name, DEFAULT_NEW_QTY, DEFAULT_USED_QTY, DEFAULT_OPEN_BOXED_QTY, DEFAULT_RESTOCK_LEVEL, DEFALUT_RESTOCK_AMT)
def test_find_by_name(self): """ Test find by the product name """ ProductInformation(prod_id=1234, prod_name="foo").save() ProductInformation(prod_id=4321, prod_name="bar").save() result = ProductInformation.find_by_name("foo") self.assertEqual(1, len(result)) self.assertEqual(1234, result[0].prod_id) ProductInformation(prod_id=5678, prod_name="foo").save() result = ProductInformation.find_by_name("foo") self.assertEqual(2, len(result))
def test_delete_prod_info(self): """ Delete a product information """ prod_info = ProductInformation(prod_id=110, prod_name="qwe") prod_info.save() self.assertEqual(1, len(ProductInformation.list_all())) prod_info.delete() self.assertEqual(0, len(ProductInformation.list_all()))
def test_automatic_restock_exception(self): """ Test automatic_restock() when property is not initialized. """ # Missing 'restock_level' prod_info = ProductInformation(prod_id=1, prod_name='Storm Trooper', \ new_qty=20, used_qty=30, open_boxed_qty=40, \ restock_amt=100) self.assertRaises(DataValidationError, prod_info.automatic_restock)
def get_prod_info(prod_id): """ Return ProductInformation identified by prod_id. --- tags: - Inventory produces: - application/json parameters: - name: prod_id in: path description: ID of Inventory entry to retrieve type: integer required: true responses: 200: description: Inventory entry returned schema: $ref: '#/definitions/Product' 404: description: Inventory entry not found """ app.logger.info("GET received, retrieve id {}.".format(prod_id)) prod_info = ProductInformation.find(prod_id) if not prod_info: raise NotFound(NOT_FOUND_MSG.format(prod_id)) return jsonify(prod_info.serialize()), status.HTTP_200_OK
def test_restock(self): """ Test manual restocking function. """ prod_info = ProductInformation() # when new_qty is None. test_restock_amt = 19 self.assertRaises(DataValidationError, prod_info.restock, test_restock_amt) # wwhen new_qty is not None. test_new_qty = 3 prod_info.new_qty = test_new_qty prod_info.restock(test_restock_amt) self.assertIsNotNone(prod_info) self.assert_fields_equal(prod_info, None, None, test_new_qty + test_restock_amt, None, None, None, None)
def test_deserialize_bad_data(self): """ Test deserialization of bad data. """ prod_info = ProductInformation() # Input data is not of JSON format. data = "this is not a dictionary" self.assertRaises(DataValidationError, prod_info.deserialize, data) # Optional fields contain values smaller than defaults. prod_info = ProductInformation(prod_id=1, prod_name="ert", new_qty=-1, used_qty=-1, open_boxed_qty=-1, restock_level=-2, restock_amt=-1) self.assertRaises(DataValidationError, prod_info.deserialize, data)
def setUp(self): """ Runs before each test """ server.init_db() db.drop_all() db.create_all() # automatic restock will be triggered when the 2 products are saved to database. ProductInformation(prod_id=1, prod_name='a', new_qty=1, used_qty=1, open_boxed_qty=1, restock_level=10, restock_amt=10).save() ProductInformation(prod_id=2, prod_name='b', new_qty=2, used_qty=2, open_boxed_qty=2, restock_level=20, restock_amt=20).save() self.app = server.app.test_client()
def test_find_by_condition(self): """ Test find by the product condition """ ProductInformation(prod_id=1234, new_qty=1, used_qty=0, open_boxed_qty=0).save() ProductInformation(prod_id=4321, new_qty=0, used_qty=2, open_boxed_qty=0).save() ProductInformation(prod_id=5678, new_qty=1, used_qty=0, open_boxed_qty=3).save() result = ProductInformation.find_by_condition("new") self.assertEqual(2, len(result)) result = ProductInformation.find_by_condition("used") self.assertEqual(1, len(result)) self.assertEqual(4321, result[0].prod_id) result = ProductInformation.find_by_condition("open-boxed") self.assertEqual(1, len(result)) self.assertEqual(5678, result[0].prod_id)
def restock_action(prod_id): """ Restock new quantity. This endpoint will update the number of new_qty of the given prod_id. --- tags: - Inventory consumes: - application/json definitions: Restock_Amount: type: object properties: restock_amt: type: integer minimum: 0 description: Amount to be added to the product's new_amt field. parameters: - name: prod_id in: path description: ID of product. type: integer required: true - in: body name: body required: true schema: id: data $ref: '#/definitions/Restock_Amount' responses: 200: description: Product restocked successfully. 400: description: Bad Request (invalid input data) """ check_content_type(JSON) app.logger.info("PUT received, restock id {} with {}.".format( prod_id, request.get_json())) prod_info = ProductInformation.find(prod_id) if not prod_info: raise NotFound(NOT_FOUND_MSG.format(prod_id)) data = request.get_json() add_amt = data.get('restock_amt') if (len(list(data.keys())) != 1) or (add_amt is None) or (add_amt < 0): raise BadRequest("Please only give 'restock_amt' as input.") prod_info.restock(add_amt) prod_info.save() return make_response(jsonify(prod_info.serialize()), status.HTTP_200_OK)
def test_serialize_prod_info(self): """ Test serialize() function """ test_prod_id = 911 test_prod_name = "nebula" prod_info = ProductInformation(prod_id=test_prod_id, prod_name=test_prod_name) data = prod_info.serialize() self.assertIsNotNone(data) self.assertIn(PROD_ID, data) self.assertEqual(test_prod_id, data[PROD_ID]) self.assertIn(PROD_NAME, data) self.assertEqual(test_prod_name, data[PROD_NAME]) self.assertIn(NEW_QTY, data) self.assertIsNone(data[NEW_QTY]) self.assertIn(USED_QTY, data) self.assertIsNone(data[USED_QTY]) self.assertIn(OPEN_BOXED_QTY, data) self.assertIsNone(data[OPEN_BOXED_QTY]) self.assertIn(RESTOCK_LEVEL, data) self.assertIsNone(data[RESTOCK_LEVEL]) self.assertIn(RESTOCK_AMT, data) self.assertIsNone(data[RESTOCK_AMT])
def test_deserialize_update_prod_info(self): """ Test deserialization while updating product information. """ #create entry in order check deserialization test_prod_id = 1 test_prod_name = "asdf" prod_info = ProductInformation(prod_id=test_prod_id, prod_name=test_prod_name) self.assertIsNotNone(prod_info) self.assert_fields_equal(prod_info, test_prod_id, test_prod_name, None, None, None, None, None) #test deserialize_update when test_prod_name = "fire" data = {PROD_NAME: test_prod_name, RESTOCK_AMT: 5} prod_info.deserialize_update(data) self.assertIsNotNone(prod_info) self.assert_fields_equal(prod_info, test_prod_id, test_prod_name, None, None, None, None, 5) #test deserilaize_update when prod_id is provided update_prod_id = 3 test_prod_name = "fire" data = { PROD_ID: update_prod_id, PROD_NAME: test_prod_name, RESTOCK_AMT: 5 } prod_info = ProductInformation() self.assertRaises(DataValidationError, prod_info.deserialize_update, data) # Optional fields contain values smaller than defaults. prod_info = ProductInformation(prod_name="ert", new_qty=-1, used_qty=-1, open_boxed_qty=-1, restock_level=-2, restock_amt=-1) self.assertRaises(DataValidationError, prod_info.deserialize_update, data)
def update_prod_info(prod_id): """ Update ProdcutInformation This endpoint will update product inventory information (by id) based on data posted in the body --- tags: - Inventory consumes: - application/json produces: - application/json parameters: - name: prod_id in: path description: ID of product information to be updated type: integer required: true - in: body name: body schema: id: data $ref: '#/definitions/Product' responses: 200: description: Inventory information Updated schema: $ref: '#/definitions/Product' 400: description: Bad Request (the posted data was not valid) """ check_content_type(JSON) app.logger.info("PUT received, update id {} with payload {}.".format( prod_id, request.get_json())) prod_info = ProductInformation.find(prod_id) if not prod_info: raise NotFound(NOT_FOUND_MSG.format(prod_id)) prod_info.deserialize_update(request.get_json()) prod_info.save() return make_response(jsonify(prod_info.serialize()), status.HTTP_200_OK)
def test_create_prod_info(self): """ Create a new prodct information and add it to the data table """ prod_infos = ProductInformation.list_all() self.assertEqual(prod_infos, []) test_prod_id = 11 test_prod_name = "a" prod_info = ProductInformation(prod_id=test_prod_id, prod_name=test_prod_name) prod_info.save() prod_infos = ProductInformation.list_all() self.assertEqual(1, len(prod_infos)) self.assertIsNotNone(prod_infos[0]) self.assert_fields_equal(prod_infos[0], test_prod_id, test_prod_name, None, None, None, None, None)
def delete_prod_info(prod_id): """ Deletes a ProductInformation This endpoint will delete a ProductInformation based on the prod_id specified in the path. Should always return 200 OK. --- tags: - Inventory parameters: - in: path name: prod_id type: integer required: true description: prod_id of the product information to be deleted. responses: 200: description: Product information deleted. """ app.logger.info("DELETE received, delete id {}.".format(prod_id)) prod_info = ProductInformation.find(prod_id) if prod_info: prod_info.delete() return make_response('', status.HTTP_200_OK)
def test_find_by_quantity(self): """ Test find by the product quantity """ ProductInformation(prod_id=1234, new_qty=1, used_qty=2, open_boxed_qty=3).save() ProductInformation(prod_id=4321, new_qty=5, used_qty=1, open_boxed_qty=2).save() result = ProductInformation.find_by_quantity(1) self.assertEqual(0, len(result)) result = ProductInformation.find_by_quantity(6) self.assertEqual(1, len(result)) self.assertEqual(1234, result[0].prod_id) result = ProductInformation.find_by_quantity(8) self.assertEqual(1, len(result)) self.assertEqual(4321, result[0].prod_id) result = ProductInformation.find_by_quantity(-1) self.assertEqual(0, len(result))
def init_db(): """ Initialies the SQLAlchemy app """ ProductInformation.init_db()
def query_prod_info(): """ Retrieve a list of all the products in the inventory & query specific entries in the Inventory system This endpoint will return all the details of the products in the inventory unless a query parameter is specificed --- tags: - Inventory description: The inventory endpoint allows you to query the inventory parameters: - name: prod_name in: query description: the name of the product you are looking for required: false type: string - name: quantity in: query description: if you want to check how many products have a specfic quantity required: false type: integer - name: condition in: query description: if you want to find all the products of a certain condition (e.g. new, used, open_boxed) required: false type: string enum: - new - used - open_boxed responses: 400: description: Bad Request (invalid posted data) 200: description: An array of all the products schema: type: array items: schema: $ref: '#/definitions/Product' """ if request.args: app.logger.info("GET received, List all that satisfy {}.".format( request.args.to_dict())) else: app.logger.info("GET received, List all.") all_prod_info = [] if request.args.get('prod_name'): prod_name = request.args.get('prod_name') all_prod_info = ProductInformation.find_by_name(prod_name) elif request.args.get('quantity'): quantity = request.args.get('quantity') try: quantity = int(quantity) all_prod_info = ProductInformation.find_by_quantity(quantity) except ValueError: abort(status.HTTP_400_BAD_REQUEST, INVALID_PARAMETER_MSG) elif request.args.get('condition'): condition = request.args.get('condition') if condition in ['new', 'used', 'open-boxed']: all_prod_info = ProductInformation.find_by_condition(condition) else: abort(status.HTTP_400_BAD_REQUEST, INVALID_PARAMETER_MSG) elif not request.args: all_prod_info = ProductInformation.list_all() else: abort(status.HTTP_400_BAD_REQUEST, INVALID_PARAMETER_MSG) results = [prod_info.serialize() for prod_info in all_prod_info] return jsonify(results), status.HTTP_200_OK
def create_prod_info(): """ Creates a ProductInformation This endpoint will create a ProductInformation based the data in the body that is posted --- tags: - Inventory consumes: - application/json produces: - application/json definitions: Product: type: object properties: prod_id: type: integer description: Unique ID of the product. prod_name: type: string description: Name for the product. new_qty: type: integer description: Quantity of condition "new". used_qty: type: integer description: Quantity of condition "used". open_boxed_qty: type: integer description: Quantity of condition "open boxed". restock_level: type: integer minimum: -1 description: Bottom line of a product's quantity with condition "new". restock_amt: type: integer description: Quantity to be added to a product's quantity with condition "new". parameters: - in: body name: body required: true schema: id: data required: - prod_id - prod_name $ref: '#/definitions/Product' responses: 201: description: Product information created schema: $ref: '#/definitions/Product' 400: description: Bad Request (invalid posted data) """ check_content_type(JSON) app.logger.info("POST received, create with payload {}.".format( request.get_json())) prod_info = ProductInformation() prod_info.deserialize(request.get_json()) if ProductInformation.find(prod_info.prod_id): raise BadRequest(CANNOT_CREATE_MSG.format(prod_info.prod_id)) prod_info.save() message = prod_info.serialize() location_url = url_for(GET_PROD_INFO, prod_id=prod_info.prod_id, _external=True) return make_response(jsonify(message), status.HTTP_201_CREATED, {LOCATION: location_url})