[hw-3] loms service
262
docs/homework-3/README.md
Normal file
@@ -0,0 +1,262 @@
|
||||
# Домашнее задание по модулю "Межсервисное взаимодействие и основы эксплуатации"
|
||||
|
||||
Добавить сервис LOMS и организовать взаимодействие между cart и loms с использованием gRPC.
|
||||
|
||||
## Основное задание
|
||||
|
||||
Необходимо:
|
||||
- Имплементировать сервис, отвечающий за учет заказов и стоки по товарам. Логика работы методов и их контракты описаны ниже.
|
||||
- Реализовать взаимодействие сервисов cart и loms через gRPC.
|
||||
|
||||
Требование к решению:
|
||||
- Создать protobuf контракт сервиса loms.
|
||||
- В каждом проекте нужно добавить в Makefile команды для генерации .go файлов из proto файлов и установки нужных зависимостей (используем protoc).
|
||||
- Состояние храним в in-memory, персистентное хранилище на данный момент не требуется. 2 репозитория - Stock и Order.
|
||||
- Код должен быть покрыт тестами (тесты на методы репозитория - не требуются).
|
||||
- Добавить gRPC интерцептор, который будет валидировать запросы через proto-gen-validator (правила валидации указываются в *.proto).
|
||||
- Добавить HTTP-gateway. HTTP-запросы также должны проходить валидацию через добавленный выше gRPC интерцептор.
|
||||
|
||||
## Дополнительное задание
|
||||
- Добавить swagger-ui и возможность совершать запросы из swagger к сервису.
|
||||
- Написать end-to-end тесты на все новые методы .
|
||||
|
||||
## Спецификация LOMS (Logistics and Order Management System)
|
||||
|
||||
Сервис отвечает за учет заказов и стоки по товарам.
|
||||
|
||||
### OrderCreate
|
||||
|
||||
Создает новый заказ для пользователя из списка переданных товаров с резервированием нужного количества стоков:
|
||||
+ заказ получает статус "new"
|
||||
+ резервирует нужное количество единиц товара
|
||||
+ если удалось зарезервировать стоки, заказ получает статус "awaiting payment"
|
||||
+ если не удалось зарезервировать стоки, заказ получает статус "failed", изменение стоков не происходит
|
||||
|
||||
**Параметры ошибочных ответов:**
|
||||
|
||||
| Сценарий | gRPC код ошибки (HTTP) | Описание |
|
||||
|------------------------------------------------------------------------------|------------------------|---------------------------------------------------------------------------------|
|
||||
| Вызов с нулевым или отрицательным значением userId | 3 (400) | Идентификатор пользователя должен быть натуральным числом (больше нуля) |
|
||||
| Вызов c пустым списком товаров | 3 (400) | Идентификатор товара должен быть натуральным числом (больше нуля) |
|
||||
| Вызов с нулевыми или отрицательными значениями sku в списке | 3 (400) | Количество должно быть натуральным числом (больше нуля) |
|
||||
| Вызов с нулевыми или отрицательными значениями Count для любого sku в списке | 3 (400) | Count должен быть натуральным числом (больше нуля) |
|
||||
| Превышение стоков хотя бы у одного товара | 9 (400) | Для всех товаров сток должен быть больше или равен запрашиваемому |
|
||||
| Отсутствие информации по стокам в системе | 9 (400) | Невозможно создать заказ, если по хотя бы одному товару нет информации о стоках |
|
||||
| Все остальные случаи | 13 или 2 (500) | Проблемы из-за неисправностей в системе |
|
||||
|
||||

|
||||
|
||||
Request
|
||||
```
|
||||
{
|
||||
userId int64
|
||||
items []{
|
||||
sku int64
|
||||
count uint32
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Response
|
||||
```
|
||||
{
|
||||
orderId int64
|
||||
}
|
||||
```
|
||||
|
||||
### OrderInfo
|
||||
|
||||
Показывает информацию по заказу. Товары в ответе должны быть отсортированы по SKU в порядке возрастания.
|
||||
|
||||
**Параметры ошибочных ответов:**
|
||||
|
||||
| Сценарий | gRPC код ошибки (HTTP) | Описание |
|
||||
|-----------------------------------------------------|------------------------|---------------------------------------------------------------------|
|
||||
| Вызов с нулевым или отрицательным значением orderId | 3 (400) | Идентификатор заказа должен быть натуральным числом (больше нуля) |
|
||||
| Заказ с указанным orderId отсутствует в системе | 5 (404) | Можно получить информацию только для существующего в системе заказа |
|
||||
| Все остальные случаи | 13 или 2 (500) | Проблемы из-за неисправностей в системе |
|
||||
|
||||
|
||||

|
||||
|
||||
Request
|
||||
```
|
||||
{
|
||||
orderId int64
|
||||
}
|
||||
```
|
||||
|
||||
Response
|
||||
```
|
||||
{
|
||||
status string // (new | awaiting payment | failed | payed | cancelled)
|
||||
userId int64
|
||||
items []{
|
||||
sku int64
|
||||
count uint32
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### OrderPay
|
||||
|
||||
Помечает заказ оплаченным. Зарезервированные товары должны перейти в статус купленных.
|
||||
+ удаляем зарезервированные стоки на товаре
|
||||
+ заказ получает статус "payed"
|
||||
|
||||
**Параметры ошибочных ответов:**
|
||||
|
||||
| Сценарий | gRPC код ошибки (HTTP) | Описание |
|
||||
|-----------------------------------------------------|------------------------|-------------------------------------------------------------------|
|
||||
| Вызов с нулевым или отрицательным значением orderId | 3 (400) | Идентификатор заказа должен быть натуральным числом (больше нуля) |
|
||||
| Оплата несуществующего заказа | 5 (404) | Можно оплачивать только существующий заказ |
|
||||
| Оплата оплаченного заказа | 0 (200) | Оплата оплаченного заказа разрешается |
|
||||
| Оплата заказа в статусе != "awaiting payment" | 9 (400) | Оплата заказа в невалидном статусе невозможна |
|
||||
| Все остальные случаи | 13 или 2 (500) | Проблемы из-за неисправностей в системе |
|
||||
|
||||

|
||||
|
||||
Request
|
||||
```
|
||||
{
|
||||
orderId int64
|
||||
}
|
||||
```
|
||||
|
||||
Response
|
||||
```
|
||||
{}
|
||||
```
|
||||
|
||||
### OrderCancel
|
||||
|
||||
Отменяет заказ, снимает резерв со всех товаров в заказе.
|
||||
+ зарезервированные стоки на товаре становятся свободными стоками
|
||||
+ заказ получает статус "cancelled"
|
||||
|
||||
**Параметры ошибочных ответов:**
|
||||
|
||||
| Сценарий | gRPC код ошибки (HTTP) | Описание |
|
||||
|-----------------------------------------------------|------------------------|-------------------------------------------------------------------|
|
||||
| Вызов с нулевым или отрицательным значением orderId | 3 (400) | Идентификатор заказа должен быть натуральным числом (больше нуля) |
|
||||
| Отмена несуществующего заказа | 5 (404) | Можно отменять только существующий заказ |
|
||||
| Отмена отмененного заказа | 0 (200) | Отмена отмененного заказа разрешается (идемпотентность) |
|
||||
| Отмена заказа в статусе == "payed" или "failed" | 9 (400) | Невозможность отменить неудавшийся заказ, а также оплаченный |
|
||||
| Все остальные случаи | 13 или 2 (500) | Проблемы из-за неисправностей в системе |
|
||||
|
||||

|
||||
|
||||
Request
|
||||
```
|
||||
{
|
||||
orderId int64
|
||||
}
|
||||
```
|
||||
|
||||
Response
|
||||
```
|
||||
{}
|
||||
```
|
||||
|
||||
### StocksInfo
|
||||
|
||||
Возвращает количество товаров, которые можно купить. Если товар был зарезервирован у кого-то в заказе и ждет оплаты, его купить нельзя.
|
||||
- данные по товарам берутся из stock-data.json (embed)
|
||||
- структура stock:
|
||||
- sku - товар
|
||||
- total_count - всего товаров
|
||||
- reserved - количество зарезервированных
|
||||
|
||||
**Параметры ошибочных ответов:**
|
||||
|
||||
| Сценарий | gRPC код ошибки (HTTP) | Описание |
|
||||
|--------------------------------------------------|------------------------|--------------------------------------------------------------------|
|
||||
| Вызов с нулевым или отрицательным значением sku | 3 (400) | Идентификатор товара должен быть натуральным числом (больше нуля) |
|
||||
| Товара в запросе нет в базе стоков | 5 (404) | Можно получить информацию по стокам, если она есть в бд |
|
||||
| Все остальные случаи | 13 или 2 (500) | Проблемы из-за неисправностей в системе |
|
||||
|
||||

|
||||
|
||||
Request
|
||||
```
|
||||
{
|
||||
sku int64
|
||||
}
|
||||
```
|
||||
|
||||
Response
|
||||
```
|
||||
{
|
||||
count uint32
|
||||
}
|
||||
```
|
||||
|
||||
## Доработки сервиса cart
|
||||
|
||||
### POST /checkout/<user_id>
|
||||
|
||||
Требуется добавить метод checkout - оформить заказ по всем товарам корзины. Вызывает loms.OrderCreate.
|
||||
Сервис cart имеет HTTP-интерфейс. Взаимодействие с LOMS - через gRPC.
|
||||
|
||||
**Параметры ошибочных ответов:**
|
||||
|
||||
| Сценарий | HTTP код ошибки | Описание |
|
||||
|-----------------------------------------------------|-----------------|-------------------------------------------------------------------------|
|
||||
| Вызов с нулевым или отрицательным значением user_id | 400 | Идентификатор пользователя должен быть натуральным числом (больше нуля) |
|
||||
| Вызов для пустой корзины | 404 | Невозможно оформить заказ для пустой корзины |
|
||||
| Все остальные случаи | 500 | Проблемы из-за неисправностей в системе |
|
||||
|
||||

|
||||
|
||||
Request
|
||||
```
|
||||
POST /checkout/<user_id> (user_id - int64)
|
||||
```
|
||||
|
||||
Response
|
||||
```
|
||||
{
|
||||
order_id int64
|
||||
}
|
||||
```
|
||||
|
||||
### POST /user/<user_id>/cart/<sku_id>
|
||||
|
||||
Требуется добавить запрос в метод добавления товаров в корзину на проверку наличия стоков с помощью вызова gRPC метода loms.StocksInfo.
|
||||
|
||||
**Параметры ошибочных ответов:**
|
||||
Сценарии из прошлых домашних заданий без изменений.
|
||||
|
||||
| Сценарий | HTTP код ошибки | Описание |
|
||||
|-----------------------------------------|-----------------|--------------------------------------------------------------------|
|
||||
| Превышение стоков при добавлении товара | 412 | Невозможно добавить товара по количеству больше, чем есть в стоках |
|
||||
| Все остальные случаи | 500 | Проблемы из-за неисправностей в системе |
|
||||
|
||||

|
||||
|
||||
# Путь покупки товаров:
|
||||
|
||||
- <cart_host>/user/{user_id}/cart/{sku_id} - Добавляем товар в корзину с проверкой на наличие стоков.
|
||||
- <cart_host>/user/{user_id}/cart || <cart_host>/user/{user_id}/cart/{sku_id} - Можем удалять товары из корзины.
|
||||
- <cart_host>/user/{user_id}/cart - Можем получить состав корзины.
|
||||
- <cart_host>/checkout/{user_id} - Создаем заказ по товарам из корзины.
|
||||
- <order_host>/order/pay with body { "orderId": {order_id} } - Оплачиваем заказ.
|
||||
- <order_host>/order/cancel with body { "orderId": {order_id} } - Можем отменить заказ до оплаты.
|
||||
|
||||
### Примечания
|
||||
* e2e тесты проверяют HTTP коды ошибок, однако gRPC коды должны быть те, что указаны в требованиях. Например, могут быть проблемы с codes.FailedPrecondition, подробнее [тут](https://github.com/grpc-ecosystem/grpc-gateway/blob/main/runtime/errors.go).
|
||||
* Запросы из cart.http, loms.http & loms.grpc основаны на данных, что лежат в stock-data.json
|
||||
|
||||
## Автоматические проверки
|
||||
|
||||
Ваше решение должно проходить автоматические проверки:
|
||||
|
||||
- Компиляция
|
||||
- Линтер
|
||||
- Unit-тесты (если есть)
|
||||
- Автотесты
|
||||
|
||||
Прохождение автоматических проверок влияет на итоговую оценку за домашнюю работу.
|
||||
|
||||
### Дедлайны сдачи и проверки задания:
|
||||
- 7 июня 23:59 (сдача) / 10 июня, 23:59 (проверка)
|
||||
69
docs/homework-3/cart.http
Normal file
@@ -0,0 +1,69 @@
|
||||
### check cart state, expect empty cart
|
||||
GET http://localhost:8080/user/31337/cart
|
||||
Content-Type: application/json
|
||||
|
||||
### expected: 404 (Not Found) {}
|
||||
|
||||
|
||||
### add item to cart, see available stocks in loms db
|
||||
POST http://localhost:8080/user/31337/cart/1076963
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"count": 1
|
||||
}
|
||||
### expected: 200 (OK) {}
|
||||
|
||||
|
||||
### check cart state, expect single sku in cart
|
||||
GET http://localhost:8080/user/31337/cart
|
||||
|
||||
### expected: 200 (OK) {"items":[{"sku":1076963,"count":1,"name":"Теория нравственных чувств | Смит Адам","price":3379}],"totalPrice":3379}
|
||||
|
||||
|
||||
#########################
|
||||
### checkout cart
|
||||
POST http://localhost:8080/checkout/31337
|
||||
Content-Type: application/json
|
||||
|
||||
### expected: 200 (OK) {"order_id":1}
|
||||
|
||||
|
||||
### check orderID in LOMS
|
||||
GET http://localhost:8084/order/info?orderId=1
|
||||
Content-Type: application/json
|
||||
### expected: 200 (OK) {"status":"awaiting payment","user":31337,"Items":[{"sku":1076963,"count":1}]}
|
||||
|
||||
|
||||
### check cart, expect empty
|
||||
GET http://localhost:8080/user/31337/cart
|
||||
Content-Type: application/json
|
||||
|
||||
### expected: 404 (Not Found) {}
|
||||
|
||||
|
||||
### add unknown item, expect error
|
||||
POST http://localhost:8080/user/31337/cart/404
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"count": 1
|
||||
}
|
||||
### expected: 412 (Precondition Failed) {}
|
||||
|
||||
|
||||
### add item out of stock, expect error
|
||||
POST http://localhost:8080/user/31337/cart/135937324
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"count": 65534
|
||||
}
|
||||
### expected: 412 (Precondition Failed) {}
|
||||
|
||||
|
||||
### checkout empty cart, expect error
|
||||
POST http://localhost:8080/checkout/31337
|
||||
Content-Type: application/json
|
||||
|
||||
### expected: 404 (Not Found) {}
|
||||
18
docs/homework-3/img/cart-cart-checkout.plantuml
Normal file
@@ -0,0 +1,18 @@
|
||||
@startuml
|
||||
|
||||
actor User as u
|
||||
collections Cart as c
|
||||
database CartStorage as cs
|
||||
collections Order as o
|
||||
|
||||
u -> c : POST /checkout/<user_id>
|
||||
activate c
|
||||
c -> cs : cart.GetItemsByUserID
|
||||
c -> o : gRPC Loms.OrderCreate\n\t- user\n\t- []item
|
||||
c -> cs : cart.DeleteItemsByUserID
|
||||
|
||||
c -> u : Response: 200 OK
|
||||
|
||||
deactivate c
|
||||
|
||||
@enduml
|
||||
BIN
docs/homework-3/img/cart-cart-checkout.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
32
docs/homework-3/img/cart-cart-item-add.plantuml
Normal file
@@ -0,0 +1,32 @@
|
||||
@startuml
|
||||
|
||||
actor User as u
|
||||
collections Cart as c
|
||||
database CartStorage as cs
|
||||
collections ProductService as p
|
||||
collections Order as o
|
||||
|
||||
u -> c : POST /user/<user_id>/cart/<sku_id>\n\t- count
|
||||
activate c
|
||||
loop for each item in request
|
||||
c -> p : /get_product\n\t- sku\n\t- token
|
||||
activate p
|
||||
p -> c : \nResponse:\n\t- name\n\t- price
|
||||
deactivate p
|
||||
c -> c : validate product exists
|
||||
|
||||
c -> o : gRPC Loms.StocksInfo\n\t- sku
|
||||
activate o
|
||||
o -> c : Response:\n\t- count
|
||||
deactivate o
|
||||
c -> c : validate stocks
|
||||
alt stocks enough
|
||||
c -> cs : cart.AddItem()
|
||||
c -> u : 200 OK
|
||||
else
|
||||
c -> u : 412 Failed Precondition (insufficient stocks)
|
||||
end
|
||||
end
|
||||
deactivate c
|
||||
|
||||
@enduml
|
||||
BIN
docs/homework-3/img/cart-cart-item-add.png
Normal file
|
After Width: | Height: | Size: 48 KiB |
18
docs/homework-3/img/loms-order-cancel.plantuml
Normal file
@@ -0,0 +1,18 @@
|
||||
@startuml
|
||||
|
||||
actor User as u
|
||||
collections LOMS as l
|
||||
database OrdersStorage as os
|
||||
database StocksStorage as ss
|
||||
|
||||
u -> l : gRPC Loms.OrderCancel\n\t- orderID
|
||||
activate l
|
||||
|
||||
l -> os : order.GetByOrderID()
|
||||
l -> ss : stocks.ReserveCancel()
|
||||
l -> os : order.SetStatus(cancelled)
|
||||
deactivate l
|
||||
|
||||
l -> u : Response: OK (code_id=0)
|
||||
|
||||
@enduml
|
||||
BIN
docs/homework-3/img/loms-order-cancel.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
22
docs/homework-3/img/loms-order-create.plantuml
Normal file
@@ -0,0 +1,22 @@
|
||||
@startuml
|
||||
|
||||
actor User as u
|
||||
collections LOMS as l
|
||||
database OrdersStorage as os
|
||||
database StocksStorage as ss
|
||||
|
||||
u -> l : gRPC Loms.OrderCreate\n\t- user\n\t- items: []item{\n\t\t- sku\n\t\t- count\n\t }
|
||||
activate l
|
||||
l -> os : order.Create()\n\tstatus=new
|
||||
l -> ss : stocks.Reserve()
|
||||
|
||||
alt Reserve success
|
||||
l -> os : order.SetStatus(awaiting payment)
|
||||
l -> u : Response: OK (code_id=0)\n\t- orderID
|
||||
else
|
||||
l -> os : order.SetStatus(failed)
|
||||
l -> u : Failed Precondition (code_id 9)
|
||||
end
|
||||
deactivate l
|
||||
|
||||
@enduml
|
||||
BIN
docs/homework-3/img/loms-order-create.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
19
docs/homework-3/img/loms-order-info.plantuml
Normal file
@@ -0,0 +1,19 @@
|
||||
@startuml
|
||||
|
||||
actor User as u
|
||||
collections LOMS as l
|
||||
database OrdersStorage as os
|
||||
|
||||
u -> l : gRPC Loms.OrderInfo\n\t- orderID int64
|
||||
activate l
|
||||
|
||||
l -> os : order.GetByID()
|
||||
alt order exists
|
||||
l -> u : Response: OK (code_id=0)\n\t- status\n\t- user\n\t- []items{}
|
||||
else
|
||||
l -> u : Response: Not Found (code_id=5)
|
||||
end
|
||||
|
||||
deactivate l
|
||||
|
||||
@enduml
|
||||
BIN
docs/homework-3/img/loms-order-info.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
17
docs/homework-3/img/loms-order-pay.plantuml
Normal file
@@ -0,0 +1,17 @@
|
||||
@startuml
|
||||
|
||||
actor User as u
|
||||
collections LOMS as l
|
||||
database OrdersStorage as os
|
||||
database StocksStorage as ss
|
||||
|
||||
u -> l : gRPC Loms.OrderPay\n\t- orderID
|
||||
activate l
|
||||
l -> ss : stocks.ReserveRemove()
|
||||
l -> os : order.SetStatus(payed)
|
||||
|
||||
l -> u : Response: OK (code_id=0)
|
||||
|
||||
deactivate l
|
||||
|
||||
@enduml
|
||||
BIN
docs/homework-3/img/loms-order-pay.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
15
docs/homework-3/img/loms-stok-info.plantuml
Normal file
@@ -0,0 +1,15 @@
|
||||
@startuml
|
||||
|
||||
actor User as u
|
||||
collections LOMS as l
|
||||
database StocksStorage as ss
|
||||
|
||||
u -> l : gRPC Loms.StocksInfo\n\t- sku
|
||||
activate l
|
||||
|
||||
l -> ss : stocks.GetBySKU()
|
||||
|
||||
l -> u : Response: OK (code_id=0)\n- count
|
||||
deactivate l
|
||||
|
||||
@enduml
|
||||
BIN
docs/homework-3/img/loms-stok-info.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
189
docs/homework-3/loms.grpc
Normal file
@@ -0,0 +1,189 @@
|
||||
### create normal order
|
||||
grpcurl -plaintext -d @ localhost:8083 loms.Loms.OrderCreate <<EOM
|
||||
{
|
||||
"userId": 31337,
|
||||
"items": [
|
||||
{
|
||||
"sku": 1076963,
|
||||
"count": 3
|
||||
},
|
||||
{
|
||||
"sku": 135717466,
|
||||
"count": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
EOM
|
||||
### expected: {"orderId":1}
|
||||
|
||||
|
||||
### get info, assert status="awaiting payment"
|
||||
grpcurl -plaintext -d @ localhost:8083 loms.Loms.OrderInfo <<EOM
|
||||
{
|
||||
"orderId": 1
|
||||
}
|
||||
EOM
|
||||
### expected: {"status":"awaiting payment","userId":31337,"Items":[{"sku":1076963,"count":3},{"sku":135717466,"count":2}]}
|
||||
|
||||
|
||||
### pay order
|
||||
grpcurl -plaintext -d @ localhost:8083 loms.Loms.OrderPay <<EOM
|
||||
{
|
||||
"orderId": 1
|
||||
}
|
||||
EOM
|
||||
### expected: {}
|
||||
|
||||
|
||||
### check actual status is "payed"
|
||||
grpcurl -plaintext -d @ localhost:8083 loms.Loms.OrderInfo <<EOM
|
||||
{
|
||||
"orderId": 1
|
||||
}
|
||||
EOM
|
||||
### expected: {"status":"payed","userId":31337,"Items":[{"sku":1076963,"count":3},{"sku":135717466,"count":2}]}
|
||||
|
||||
|
||||
### unable to cancel payed order
|
||||
grpcurl -plaintext -d @ localhost:8083 loms.Loms.OrderCancel <<EOM
|
||||
{
|
||||
"orderId": 1
|
||||
}
|
||||
EOM
|
||||
### expected: Code: FailedPrecondition ...
|
||||
|
||||
|
||||
### get unknown order
|
||||
grpcurl -plaintext -d @ localhost:8083 loms.Loms.OrderInfo <<EOM
|
||||
{
|
||||
"orderId": 404
|
||||
}
|
||||
EOM
|
||||
### expected: Code: NotFound
|
||||
|
||||
|
||||
### cancel order not exists
|
||||
grpcurl -plaintext -d @ localhost:8083 loms.Loms.OrderCancel <<EOM
|
||||
{
|
||||
"orderId": 404
|
||||
}
|
||||
EOM
|
||||
### expected: Code: NotFound
|
||||
|
||||
|
||||
### create order with item that has no stocks info
|
||||
grpcurl -plaintext -d @ localhost:8083 loms.Loms.OrderCreate <<EOM
|
||||
{
|
||||
"userId": 31337,
|
||||
"items": [
|
||||
{
|
||||
"sku": 404,
|
||||
"count": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
EOM
|
||||
### expected: Code: FailedPrecondition
|
||||
|
||||
|
||||
### check order status is failed (not necessary, because no orderId after creation if any fails)
|
||||
grpcurl -plaintext -d @ localhost:8083 loms.Loms.OrderInfo <<EOM
|
||||
{
|
||||
"orderId": 2
|
||||
}
|
||||
EOM
|
||||
### expected: {"status":"failed","userId":31337,"Items":[{"sku":404,"count":3}]}
|
||||
|
||||
|
||||
### cancel failed order
|
||||
grpcurl -plaintext -d @ localhost:8083 loms.Loms.OrderCancel <<EOM
|
||||
{
|
||||
"orderId": 2
|
||||
}
|
||||
EOM
|
||||
### expected: Code: FailedPrecondition
|
||||
|
||||
|
||||
|
||||
### stock info for unknown sku
|
||||
grpcurl -plaintext -d @ localhost:8083 loms.Loms.StocksInfo <<EOM
|
||||
{
|
||||
"sku": 404
|
||||
}
|
||||
EOM
|
||||
### expected: Code: NotFound
|
||||
|
||||
|
||||
### stock info for normal sku
|
||||
grpcurl -plaintext -d @ localhost:8083 loms.Loms.StocksInfo <<EOM
|
||||
{
|
||||
"sku": 135717466
|
||||
}
|
||||
EOM
|
||||
### expected: {"count":78}
|
||||
|
||||
|
||||
### create order with count for sku more than stock
|
||||
grpcurl -plaintext -d @ localhost:8083 loms.Loms.OrderCreate <<EOM
|
||||
{
|
||||
"userId": 31337,
|
||||
"items": [
|
||||
{
|
||||
"sku": 135717466,
|
||||
"count": 79
|
||||
}
|
||||
]
|
||||
}
|
||||
EOM
|
||||
### expected: Code: FailedPrecondition
|
||||
|
||||
|
||||
### no change in stock info after failed order creation
|
||||
grpcurl -plaintext -d @ localhost:8083 loms.Loms.StocksInfo <<EOM
|
||||
{
|
||||
"sku": 135717466
|
||||
}
|
||||
EOM
|
||||
### expected: {"count":500}; 200 OK
|
||||
|
||||
|
||||
### create normal order for cancellation
|
||||
grpcurl -plaintext -d @ localhost:8083 loms.Loms.OrderCreate <<EOM
|
||||
{
|
||||
"userId": 31337,
|
||||
"items": [
|
||||
{
|
||||
"sku": 135717466,
|
||||
"count": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
EOM
|
||||
### expected: {"orderId":4}
|
||||
|
||||
|
||||
### cancel order
|
||||
grpcurl -plaintext -d @ localhost:8083 loms.Loms.OrderCancel <<EOM
|
||||
{
|
||||
"orderId": 4
|
||||
}
|
||||
EOM
|
||||
### expected: {}
|
||||
|
||||
|
||||
### check canceled order status
|
||||
grpcurl -plaintext -d @ localhost:8083 loms.Loms.OrderInfo <<EOM
|
||||
{
|
||||
"orderId": 4
|
||||
}
|
||||
EOM
|
||||
### expected: {"status":"cancelled","userId":31337,"Items":[{"sku":1076963,"count":2}]}
|
||||
|
||||
|
||||
### check stocks returns
|
||||
grpcurl -plaintext -d @ localhost:8083 loms.Loms.StocksInfo <<EOM
|
||||
{
|
||||
"sku": 135717466
|
||||
}
|
||||
EOM
|
||||
### expected: {"count":78}
|
||||
176
docs/homework-3/loms.http
Normal file
@@ -0,0 +1,176 @@
|
||||
### create normal order
|
||||
POST http://localhost:8084/order/create
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"userId": 31337,
|
||||
"items": [
|
||||
{
|
||||
"sku": 1076963,
|
||||
"count": 3
|
||||
},
|
||||
{
|
||||
"sku": 135717466,
|
||||
"count": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
### expected: 200 (OK) {"orderId":1}
|
||||
|
||||
|
||||
### get info, assert status="awaiting payment"
|
||||
GET http://localhost:8084/order/info?orderId=1
|
||||
Content-Type: application/json
|
||||
|
||||
### expected: 200 (OK) {"status":"awaiting payment","user":31337,"Items":[{"sku":1076963,"count":3},{"sku":135717466,"count":2}]}
|
||||
|
||||
|
||||
### pay order
|
||||
POST http://localhost:8084/order/pay
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"orderId": 1
|
||||
}
|
||||
### expected: 200 (OK) {}
|
||||
|
||||
|
||||
### check actual status is "payed"
|
||||
GET http://localhost:8084/order/info?orderId=1
|
||||
Content-Type: application/json
|
||||
|
||||
### expected: 200 (OK) {"status":"payed","user":31337,"Items":[{"sku":1076963,"count":3},{"sku":135717466,"count":2}]}
|
||||
|
||||
|
||||
### unable to cancel payed order
|
||||
POST http://localhost:8084/order/cancel
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"orderId": 1
|
||||
}
|
||||
### expected: 400 (Bad Request) {"code":9, ... }
|
||||
|
||||
|
||||
### get unknown order
|
||||
GET http://localhost:8084/order/info?orderId=404
|
||||
Content-Type: application/json
|
||||
|
||||
### expected: 404 (Not Found) {"code": 5, ... }
|
||||
|
||||
|
||||
### cancel order not exists
|
||||
POST http://localhost:8084/order/cancel
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"orderId": 404
|
||||
}
|
||||
### expected: 404 (Not Found) {"code": 5, ... }
|
||||
|
||||
|
||||
### create order with item that has no stocks info
|
||||
POST http://localhost:8084/order/create
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"userId": 31337,
|
||||
"items": [
|
||||
{
|
||||
"sku": 404,
|
||||
"count": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
### expected: 400 (Bad Request) {"code":9, ... }
|
||||
|
||||
|
||||
### check order status is failed (not necessary, because no orderId after creation if any fails)
|
||||
GET http://localhost:8084/order/info?orderId=2
|
||||
Content-Type: application/json
|
||||
|
||||
### expected: 200 (OK) {"status":"failed","userId":31337,"Items":[{"sku":404,"count":3}]}
|
||||
|
||||
### cancel failed order
|
||||
POST http://localhost:8084/order/cancel
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"orderId": 2
|
||||
}
|
||||
### expected: 400 (Bad Request) {"code":9, ... }
|
||||
|
||||
|
||||
### stock info for unknown sku
|
||||
GET http://localhost:8084/stock/info?sku=404
|
||||
Content-Type: application/json
|
||||
|
||||
### expected: 404 Not Found {"code":5, ... }
|
||||
|
||||
|
||||
### stock info for normal sku
|
||||
GET http://localhost:8084/stock/info?sku=135717466
|
||||
Content-Type: application/json
|
||||
|
||||
### expected: 200 (OK) {"count":78}
|
||||
|
||||
|
||||
### create order with count for sku more than stock
|
||||
POST http://localhost:8084/order/create
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"userId": 31337,
|
||||
"items": [
|
||||
{
|
||||
"sku": 135717466,
|
||||
"count": 79
|
||||
}
|
||||
]
|
||||
}
|
||||
### expected: 400 (Bad Request) {"code":9, ... }
|
||||
|
||||
### no change in stock info after failed order creation
|
||||
GET http://localhost:8084/stock/info?sku=135717466
|
||||
Content-Type: application/json
|
||||
|
||||
### expected: 200 (OK) {"count":78}
|
||||
|
||||
### create normal order for cancellation
|
||||
POST http://localhost:8084/order/create
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"userId": 31337,
|
||||
"items": [
|
||||
{
|
||||
"sku": 135717466,
|
||||
"count": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
### expected: 200 (OK) {"orderId":4}
|
||||
|
||||
|
||||
### cancel order
|
||||
POST http://localhost:8084/order/cancel
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"orderId": 4
|
||||
}
|
||||
### expected: 200 (OK)
|
||||
|
||||
|
||||
### check canceled order status
|
||||
GET http://localhost:8084/order/info?orderId=4
|
||||
Content-Type: application/json
|
||||
|
||||
### expected: {"status":"cancelled","user":31337,"Items":[{"sku":1076963,"count":2}]}
|
||||
|
||||
|
||||
### check stocks returns
|
||||
GET http://localhost:8084/stock/info?sku=135717466
|
||||
Content-Type: application/json
|
||||
|
||||
### expected: {"count":78}; 200 OK
|
||||
37
docs/homework-3/stock-data.json
Normal file
@@ -0,0 +1,37 @@
|
||||
[
|
||||
{
|
||||
"sku": 139275865,
|
||||
"total_count": 65534,
|
||||
"reserved": 0
|
||||
},
|
||||
{
|
||||
"sku": 2956315,
|
||||
"total_count": 100,
|
||||
"reserved": 30
|
||||
},
|
||||
{
|
||||
"sku": 1076963,
|
||||
"total_count": 100,
|
||||
"reserved": 35
|
||||
},
|
||||
{
|
||||
"sku": 135717466,
|
||||
"total_count": 100,
|
||||
"reserved": 20
|
||||
},
|
||||
{
|
||||
"sku": 135937324,
|
||||
"total_count": 100,
|
||||
"reserved": 30
|
||||
},
|
||||
{
|
||||
"sku": 1625903,
|
||||
"total_count": 10000,
|
||||
"reserved": 0
|
||||
},
|
||||
{
|
||||
"sku": 1148162,
|
||||
"total_count": 100,
|
||||
"reserved": 0
|
||||
}
|
||||
]
|
||||