This commit is contained in:
Andrey Ivanov 2021-03-16 15:47:50 -04:00 committed by Andrey Ivanov
parent 8680c3a85c
commit a0b572be3a
21 changed files with 583 additions and 433 deletions

View File

@ -1,14 +1,5 @@
cdir = $(shell pwd) cdir = $(shell pwd)
build-all:
go build -o ./bin/calendar ./cmd/calendar/main.go
go build -o ./bin/scheduler ./cmd/scheduler/main.go
go build -o ./bin/sender ./cmd/sender/main.go
start: build-all rabbit-start calendar-start scheduler-start sender-start
stop: scheduler-stop sender-stop calendar-stop rabbit-stop
integration-test: integration-test:
go test -count 10 -race ./cmd/calendar/... --config ./../../configs/calendar.conf go test -count 10 -race ./cmd/calendar/... --config ./../../configs/calendar.conf
@ -25,35 +16,31 @@ generate:
protoc -I ./api/public --go_out=plugins=grpc:./pkg/api/public --grpc-gateway_out=logtostderr=true:./pkg/api/public ./api/public/public.proto protoc -I ./api/public --go_out=plugins=grpc:./pkg/api/public --grpc-gateway_out=logtostderr=true:./pkg/api/public ./api/public/public.proto
protoc -I ./api/private --go_out=plugins=grpc:./internal/api/private ./api/private/private.proto protoc -I ./api/private --go_out=plugins=grpc:./internal/api/private ./api/private/private.proto
compose-build: up: sup-up calendar-up sender-up sheduler-up
sudo -S docker-compose -f ./cicd/docker-compose.yml build
up: down: calendar-down sender-down sheduler-down sup-down clean
sudo -S docker-compose -f ./cicd/docker-compose.yml up -d --build
down: shutdown clean calendar-up:
docker-compose -f ./cicd/dc_calendar.yml up -d --build
calendar-down:
docker-compose -f ./cicd/dc_calendar.yml down
shutdown: sender-up:
sudo -S docker-compose -f ./cicd/docker-compose.yml down docker-compose -f ./cicd/dc_sender.yml up -d --build
sender-down:
docker-compose -f ./cicd/dc_sender.yml down
sheduler-up:
docker-compose -f ./cicd/dc_sheduler.yml up -d --build
sheduler-down:
docker-compose -f ./cicd/dc_sheduler.yml down
sup-up:
docker-compose -f ./cicd/dc_sup.yml up -d --build
sup-down:
docker-compose -f ./cicd/dc_sup.yml down
clean: clean:
sudo docker rmi $(sudo docker images | grep '<none>' | awk '{print $3}') sudo docker rmi $(sudo docker images | grep '<none>' | awk '{print $3}')
calendar-start:
nohup ./bin/calendar -config ./configs/calendar.conf > /dev/null 2>&1 &
calendar-stop:
kill -9 `pgrep calendar`
scheduler-start:
nohup ./bin/scheduler -config ./configs/scheduler.conf > /dev/null 2>&1 &
scheduler-stop:
kill -9 `pgrep scheduler`
sender-start:
nohup ./bin/sender -config ./configs/sender.conf > /dev/null 2>&1 &
sender-stop:
kill -9 `pgrep sender`
.PHONY: build run test lint .PHONY: build run test lint

View File

@ -6,20 +6,9 @@ RUN go get -d ./cmd/calendar/.
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o calendar ./cmd/calendar/. RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o calendar ./cmd/calendar/.
FROM alpine:latest FROM alpine:latest
ENV APP_GRPC_ADDRESS=0.0.0.0 ENV APP_GRPC_PORT $APP_GRPC_PORT
ENV APP_GRPC_PORT=50051 ENV APP_HTTP_PORT $APP_HTTP_PORT
ENV APP_HTTP_ADDRESS=0.0.0.0 ENV APP_API_PORT $APP_API_PORT
ENV APP_HTTP_PORT=8888
ENV APP_API_ADDRESS=0.0.0.0
ENV APP_API_PORT=50053
ENV APP_LOGGER_FILE=/logs/calendar.log
ENV APP_LOGGER_LEVEL=INFO
ENV APP_STORAGE_INMEMORY=false
ENV APP_STORAGE_SQLHOST=psql
ENV APP_STORAGE_SQLPORT=5432
ENV APP_STORAGE_SQLDBASE=calendar
ENV APP_STORAGE_SQLUSER=calendar
ENV APP_STORAGE_SQLPASS=12345678
WORKDIR / WORKDIR /
COPY --from=builder /app/calendar ./sbin COPY --from=builder /app/calendar ./sbin
EXPOSE ${APP_GRPC_PORT} EXPOSE ${APP_GRPC_PORT}

View File

@ -0,0 +1,29 @@
version: '3'
services:
calendar:
build:
context: ..
dockerfile: ./cicd/calendar/Dockerfile
volumes:
- ../logs:/logs
restart: on-failure
environment:
APP_GRPC_ADDRESS: 0.0.0.0
APP_GRPC_PORT: 50051
APP_HTTP_ADDRESS: 0.0.0.0
APP_HTTP_PORT: 8888
APP_API_ADDRESS: 0.0.0.0
APP_API_PORT: 50053
APP_LOGGER_FILE: /logs/calendar.log
APP_LOGGER_LEVEL: INFO
APP_STORAGE_INMEMORY: "false"
APP_STORAGE_SQLHOST: localhost
APP_STORAGE_SQLPORT: 5432
APP_STORAGE_SQLDBASE: calendar
APP_STORAGE_SQLUSER: calendar
APP_STORAGE_SQLPASS: 12345678
ports:
- 8888:8888
- 50051:50051
- 50053:50053
network_mode: host

View File

@ -0,0 +1,20 @@
version: '3'
services:
sender:
build:
context: ..
dockerfile: ./cicd/sender/Dockerfile
volumes:
- ../logs:/logs
restart: on-failure
environment:
APP_RABBITMQ_ADDRESS: localhost
APP_RABBITMQ_PORT: 5672
APP_RABBITMQ_LOGIN: rabbit
APP_RABBITMQ_PASS: rabbit
APP_RABBITMQ_EXCHANGE: calendar
APP_RABBITMQ_QUEUE: notifications
APP_RABBITMQ_KEY: events
APP_LOGGER_FILE: /logs/calendar.log
APP_LOGGER_LEVEL: INFO
network_mode: host

View File

@ -0,0 +1,22 @@
version: '3'
services:
scheduler:
build:
context: ..
dockerfile: ./cicd/scheduler/Dockerfile
volumes:
- ../logs:/logs
restart: on-failure
environment:
APP_RABBITMQ_ADDRESS: localhost
APP_RABBITMQ_PORT: 5672
APP_RABBITMQ_LOGIN: rabbit
APP_RABBITMQ_PASS: rabbit
APP_RABBITMQ_EXCHANGE: calendar
APP_RABBITMQ_QUEUE: notifications
APP_RABBITMQ_KEY: events
APP_API_ADDRESS: localhost
APP_API_PORT: 50053
APP_LOGGER_FILE: /logs/calendar.log
APP_LOGGER_LEVEL: INFO
network_mode: host

View File

@ -0,0 +1,39 @@
version: '3'
services:
goose:
build:
context: ..
dockerfile: ./cicd/goose/Dockerfile
restart: on-failure
environment:
GOOSE_DRIVER: "postgres"
GOOSE_DBSTRING: "host=localhost port=5432 user=calendar password=12345678 dbname=calendar sslmode=disable"
depends_on:
- psql
network_mode: host
psql:
image: postgres:11-alpine
hostname: "psql"
container_name: psql
environment:
POSTGRES_USER: calendar
POSTGRES_PASSWORD: 12345678
POSTGRES_DB: calendar
ports:
- 5432:5432
network_mode: host
rabbitmq:
image: rabbitmq:3-management-alpine
hostname: "rabbitmq"
container_name: rabbitmq
environment:
RABBITMQ_ERLANG_COOKIE: "SWQOKODSQALRPCLNMEQG"
RABBITMQ_DEFAULT_USER: "rabbit"
RABBITMQ_DEFAULT_PASS: "rabbit"
RABBITMQ_DEFAULT_VHOST: "/"
ports:
- 15672:15672
- 5672:5672
network_mode: host

View File

@ -1,80 +0,0 @@
version: '3'
services:
calendar:
build:
context: ..
dockerfile: ./cicd/calendar/Dockerfile
volumes:
- ../logs:/logs
ports:
- "8888:8888"
- "50051:50051"
- "50053:50053"
expose:
- 8888
- 50051
- 50053
depends_on:
- psql
- goose
scheduler:
build:
context: ..
dockerfile: ./cicd/scheduler/Dockerfile
volumes:
- ../logs:/logs
depends_on:
- rabbitmq
- calendar
restart: on-failure
sender:
build:
context: ..
dockerfile: ./cicd/sender/Dockerfile
volumes:
- ../logs:/logs
depends_on:
- rabbitmq
restart: on-failure
goose:
build:
context: ..
dockerfile: ./cicd/goose/Dockerfile
environment:
GOOSE_DRIVER: "postgres"
GOOSE_DBSTRING: "host=psql port=5432 user=calendar password=12345678 dbname=calendar sslmode=disable"
depends_on:
- psql
restart: on-failure
psql:
image: postgres:11-alpine
hostname: "psql"
container_name: psql
environment:
POSTGRES_USER: calendar
POSTGRES_PASSWORD: 12345678
POSTGRES_DB: calendar
ports:
- "5432:5432"
expose:
- 5432
rabbitmq:
image: rabbitmq:3-management-alpine
hostname: "rabbitmq"
container_name: rabbitmq
environment:
RABBITMQ_ERLANG_COOKIE: "SWQOKODSQALRPCLNMEQG"
RABBITMQ_DEFAULT_USER: "rabbit"
RABBITMQ_DEFAULT_PASS: "rabbit"
RABBITMQ_DEFAULT_VHOST: "/"
ports:
- "5672:5672"
- "15672:15672"
expose:
- 15672
- 5672

View File

@ -6,17 +6,6 @@ RUN go get -d ./cmd/scheduler/.
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o scheduler ./cmd/scheduler/. RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o scheduler ./cmd/scheduler/.
FROM alpine:latest FROM alpine:latest
ENV APP_RABBITMQ_ADDRESS=rabbitmq
ENV APP_RABBITMQ_PORT=5672
ENV APP_RABBITMQ_LOGIN=rabbit
ENV APP_RABBITMQ_PASS=rabbit
ENV APP_RABBITMQ_EXCHANGE=calendar
ENV APP_RABBITMQ_QUEUE=notifications
ENV APP_RABBITMQ_KEY=events
ENV APP_API_ADDRESS=calendar
ENV APP_API_PORT=50053
ENV APP_LOGGER_FILE=/logs/calendar.log
ENV APP_LOGGER_LEVEL=INFO
WORKDIR / WORKDIR /
COPY --from=builder /app/scheduler ./sbin COPY --from=builder /app/scheduler ./sbin
ENTRYPOINT ["scheduler"] ENTRYPOINT ["scheduler"]

View File

@ -6,15 +6,6 @@ RUN go get -d ./cmd/sender/.
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o sender ./cmd/sender/. RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o sender ./cmd/sender/.
FROM alpine:latest FROM alpine:latest
ENV APP_RABBITMQ_ADDRESS=rabbitmq
ENV APP_RABBITMQ_PORT=5672
ENV APP_RABBITMQ_LOGIN=rabbit
ENV APP_RABBITMQ_PASS=rabbit
ENV APP_RABBITMQ_EXCHANGE=calendar
ENV APP_RABBITMQ_QUEUE=notifications
ENV APP_RABBITMQ_KEY=events
ENV APP_LOGGER_FILE=/logs/calendar.log
ENV APP_LOGGER_LEVEL=INFO
WORKDIR / WORKDIR /
COPY --from=builder /app/sender ./sbin COPY --from=builder /app/sender ./sbin
ENTRYPOINT ["sender"] ENTRYPOINT ["sender"]

View File

@ -15,7 +15,7 @@ File = "./logs/calendar.log"
Level = "INFO" Level = "INFO"
[Storage] [Storage]
inMemory = true inMemory = false
SQLHost = "localhost" SQLHost = "localhost"
SQLPort = "5432" SQLPort = "5432"
SQLDbase = "calendar" SQLDbase = "calendar"

View File

@ -9,16 +9,12 @@ require (
github.com/golang/protobuf v1.4.2 github.com/golang/protobuf v1.4.2
github.com/grpc-ecosystem/grpc-gateway v1.15.0 github.com/grpc-ecosystem/grpc-gateway v1.15.0
github.com/kr/text v0.2.0 // indirect github.com/kr/text v0.2.0 // indirect
github.com/lib/pq v1.8.0 // indirect github.com/lib/pq v1.10.0
github.com/mattn/go-sqlite3 v1.14.5 // indirect
github.com/mxschmitt/golang-env-struct v0.0.0-20181017075525-0c54aeca8397
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1 // indirect
github.com/pressly/goose v2.6.0+incompatible // indirect
github.com/sirupsen/logrus v1.4.2 // indirect github.com/sirupsen/logrus v1.4.2 // indirect
github.com/streadway/amqp v1.0.0 github.com/streadway/amqp v1.0.0
github.com/stretchr/testify v1.6.1 github.com/stretchr/testify v1.6.1
github.com/ziutek/mymysql v1.5.4 // indirect
go.uber.org/zap v1.15.0 // indirect go.uber.org/zap v1.15.0 // indirect
golang.org/x/net v0.0.0-20200625001655-4c5254603344 golang.org/x/net v0.0.0-20200625001655-4c5254603344
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009 // indirect golang.org/x/sys v0.0.0-20200909081042-eff7692f9009 // indirect

View File

@ -54,12 +54,8 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lib/pq v1.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg= github.com/lib/pq v1.10.0 h1:Zx5DJFEYQXio93kgXnQ09fXNiUKsqv4OUEu2UtGcB1E=
github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mattn/go-sqlite3 v1.14.5 h1:1IdxlwTNazvbKJQSxoJ5/9ECbEeaTTyeU7sEAZ5KKTQ=
github.com/mattn/go-sqlite3 v1.14.5/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI=
github.com/mxschmitt/golang-env-struct v0.0.0-20181017075525-0c54aeca8397 h1:fbcg7+DIrrjxSsS78ARgJu/qZOO928w4mCj1KBEO7xM=
github.com/mxschmitt/golang-env-struct v0.0.0-20181017075525-0c54aeca8397/go.mod h1:BvJngicNxsNmAUzt7zXpaoWKwuBiyxnD7DxzxfrrPyY=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
@ -68,8 +64,6 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pressly/goose v2.6.0+incompatible h1:3f8zIQ8rfgP9tyI0Hmcs2YNAqUCL1c+diLe3iU8Qd/k=
github.com/pressly/goose v2.6.0+incompatible/go.mod h1:m+QHWCqxR3k8D9l7qfzuC/djtlfzxr34mozWDYEu1z8=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk= github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk=
@ -90,8 +84,6 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=

View File

@ -24,11 +24,6 @@ func New(logger logger.Interface, storage store.StorageInterface) *App {
return &App{Logger: logger, Storage: storage} return &App{Logger: logger, Storage: storage}
} }
func (a *App) Handler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
_, _ = w.Write([]byte("Hello! I'm calendar app!"))
}
func (a *App) LoggingMiddleware(next http.HandlerFunc) http.HandlerFunc { func (a *App) LoggingMiddleware(next http.HandlerFunc) http.HandlerFunc {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now() start := time.Now()

View File

@ -3,11 +3,11 @@
CREATE TABLE events ( CREATE TABLE events (
id serial NOT NULL, id serial NOT NULL,
title varchar(255) NOT NULL, title varchar(255) NOT NULL,
date timestamptz NOT NULL, date timestamp NOT NULL,
latency int8 NOT NULL, latency int8 NOT NULL,
note text NULL, note text NULL,
userID int8 NOT NULL, userID int8 NOT NULL,
notifyTime timestamptz NULL, notifyTime int8 NULL,
notified bool notified bool
); );
-- +goose StatementEnd -- +goose StatementEnd

View File

@ -3,12 +3,15 @@ package sql
import ( import (
"database/sql" "database/sql"
"fmt" "fmt"
"log"
"time" "time"
_ "github.com/lib/pq"
"github.com/tiburon-777/HW_OTUS/hw12_13_14_15_calendar/pkg/storage/event" "github.com/tiburon-777/HW_OTUS/hw12_13_14_15_calendar/pkg/storage/event"
) )
const dateTimeLayout = "2006-01-02 15:04:00 -0700" const dateTimeLayout = "2006-01-02T15:04:00Z"
type Config struct { type Config struct {
User string User string
@ -22,17 +25,12 @@ type Storage struct {
db *sql.DB db *sql.DB
} }
func New(conf Config) *Storage { func New(config Config) *Storage {
return &Storage{} db, err := sql.Open("postgres", "user="+config.User+" password="+config.Pass+" host="+config.Host+" port="+config.Port+" dbname="+config.Dbase+" sslmode=disable")
}
func (s *Storage) Connect(config Config) error {
var err error
s.db, err = sql.Open("mysql", config.User+":"+config.Pass+"@tcp("+config.Host+":"+config.Port+")/"+config.Dbase)
if err != nil { if err != nil {
return fmt.Errorf("can't connect to SQL server: %w", err) log.Fatalf("can't connect to db: %s",err.Error())
} }
return nil return &Storage{db: db}
} }
func (s *Storage) Close() error { func (s *Storage) Close() error {
@ -40,25 +38,21 @@ func (s *Storage) Close() error {
} }
func (s *Storage) Create(ev event.Event) (event.ID, error) { func (s *Storage) Create(ev event.Event) (event.ID, error) {
res, err := s.db.Exec( lastInsertId := -1
if err := s.db.QueryRow(
`INSERT INTO events `INSERT INTO events
(title, date, latency, note, userID, notifyTime) VALUES (title, date, latency, note, userID, notifyTime) VALUES
($1, $2, $3, $4, $5, $6)`, ($1, $2, $3, $4, $5, $6) RETURNING id`,
ev.Title, ev.Title,
ev.Date.Format(dateTimeLayout), ev.Date.Format(dateTimeLayout),
ev.Latency, ev.Latency,
ev.Note, ev.Note,
ev.UserID, ev.UserID,
ev.NotifyTime, ev.NotifyTime,
) ).Scan(&lastInsertId); err != nil {
if err != nil {
return -1, fmt.Errorf("can't create event in SQL DB: %w", err) return -1, fmt.Errorf("can't create event in SQL DB: %w", err)
} }
idint64, err := res.LastInsertId() return event.ID(lastInsertId), nil
if err != nil {
return -1, fmt.Errorf("can't get LastInsertId from SQL DB: %w", err)
}
return event.ID(idint64), err
} }
func (s *Storage) Update(id event.ID, event event.Event) error { func (s *Storage) Update(id event.ID, event event.Event) error {
@ -93,7 +87,7 @@ func (s *Storage) Delete(id event.ID) error {
func (s *Storage) List() (map[event.ID]event.Event, error) { func (s *Storage) List() (map[event.ID]event.Event, error) {
res := make(map[event.ID]event.Event) res := make(map[event.ID]event.Event)
results, err := s.db.Query(`SELECT (id,title,date,latency,note,userID,notifyTime) from events ORDER BY id`) results, err := s.db.Query(`SELECT id,title,date,latency,note,userID,notifyTime from events ORDER BY id`)
if err != nil { if err != nil {
return nil, fmt.Errorf("can't get list of events from SQL DB: %w", err) return nil, fmt.Errorf("can't get list of events from SQL DB: %w", err)
} }
@ -122,7 +116,7 @@ func (s *Storage) GetByID(id event.ID) (event.Event, bool) {
var res event.Event var res event.Event
var dateRaw string var dateRaw string
err := s.db.QueryRow( err := s.db.QueryRow(
`SELECT (id,title,date,latency,note,userID,notifyTime) from events where id=$1`, id).Scan(res.Title, dateRaw, res.Latency, res.Note, res.UserID, res.NotifyTime) `SELECT title,date,latency,note,userID,notifyTime from events where id=$1`, id).Scan(&res.Title, &dateRaw, &res.Latency, &res.Note, &res.UserID, &res.NotifyTime)
if err != nil { if err != nil {
return res, false return res, false
} }
@ -136,15 +130,16 @@ func (s *Storage) GetByID(id event.ID) (event.Event, bool) {
func (s *Storage) GetByDate(startDate time.Time, rng string) (map[event.ID]event.Event, error) { func (s *Storage) GetByDate(startDate time.Time, rng string) (map[event.ID]event.Event, error) {
res := make(map[event.ID]event.Event) res := make(map[event.ID]event.Event)
endDate := getEndDate(startDate, rng)
results, err := s.db.Query( results, err := s.db.Query(
`SELECT (id,title,date,latency,note,userID,notifyTime) `SELECT id,title,date,latency,note,userID,notifyTime
from events from events
where (date>$1 AND date<$2) OR where (date>=$1 AND date<=$2)
(date+latency>$1 AND date+latency<$2) OR
(date<$1 AND date+latency>$2)
ORDER BY id`, ORDER BY id`,
startDate, startDate.Format(dateTimeLayout),
getEndDate(startDate, rng)) endDate.Format(dateTimeLayout))
if err != nil { if err != nil {
return nil, fmt.Errorf("can't get list of events from SQL DB: %w", err) return nil, fmt.Errorf("can't get list of events from SQL DB: %w", err)
} }

View File

@ -0,0 +1,97 @@
package client
import (
"context"
"github.com/golang/protobuf/ptypes/empty"
"github.com/tiburon-777/HW_OTUS/hw12_13_14_15_calendar/pkg/api/public"
"time"
)
type GRPCAPI struct{
Name string
Ctx context.Context
Host string
Port string
}
func (h GRPCAPI) GetName() string {
return h.Name
}
func (h GRPCAPI) Create(req *public.CreateReq) (*public.CreateRsp, error) {
ctx, cliGRPC, err := getCli(h)
if err != nil{
return nil, err
}
resp, err := cliGRPC.Create(ctx, req)
if err != nil{
return nil, err
}
return resp, nil
}
func (h GRPCAPI) Update(req *public.UpdateReq) error {
ctx, cliGRPC, err := getCli(h)
if err != nil{
return err
}
_, err = cliGRPC.Update(ctx, req)
if err != nil{
return err
}
return nil
}
func (h GRPCAPI) Delete(req *public.DeleteReq) error {
ctx, cliGRPC, err := getCli(h)
if err != nil{
return err
}
_, err = cliGRPC.Delete(ctx, req)
if err != nil{
return err
}
return nil
}
func (h GRPCAPI) GetByID(req *public.GetByIDReq) (*public.GetByIDResp, error) {
ctx, cliGRPC, err := getCli(h)
if err != nil{
return nil, err
}
resp, err := cliGRPC.GetByID(ctx, req)
if err != nil{
return nil, err
}
return resp, nil
}
func (h GRPCAPI) List() (*public.ListResp, error) {
ctx, cliGRPC, err := getCli(h)
if err != nil{
return nil, err
}
resp, err := cliGRPC.List(ctx, &empty.Empty{})
if err != nil{
return nil, err
}
return resp, nil
}
func (h GRPCAPI) GetByDate(req *public.GetByDateReq) (*public.GetByDateResp, error) {
ctx, cliGRPC, err := getCli(h)
if err != nil{
return nil, err
}
resp, err := cliGRPC.GetByDate(ctx, req)
if err != nil{
return nil, err
}
return resp, nil
}
func getCli(h GRPCAPI) (context.Context, public.GrpcClient, error) {
ctx,_ := context.WithTimeout(h.Ctx, 15*time.Second)
cliGRPC, err := public.NewClient(ctx,h.Host, h.Port)
return ctx, cliGRPC, err
}

View File

@ -0,0 +1,150 @@
package client
import (
"bytes"
"encoding/json"
"fmt"
"github.com/tiburon-777/HW_OTUS/hw12_13_14_15_calendar/pkg/api/public"
"io/ioutil"
"net"
"net/http"
"strconv"
"time"
)
type HTTPAPI struct{
Name string
BaseURL string
}
func (h HTTPAPI) GetName() string {
return h.Name
}
func (h HTTPAPI) Create(req *public.CreateReq) (*public.CreateRsp, error) {
jreq,err:= json.Marshal(req)
if err != nil {
return &public.CreateRsp{}, err
}
res, body, err := apiCall("POST",h.BaseURL+"/events", jreq)
if err != nil {
return &public.CreateRsp{}, err
}
if res.StatusCode!=201 {
return &public.CreateRsp{}, fmt.Errorf("unexpected status code %d",res.StatusCode)
}
var createRsp public.CreateRsp
err = json.Unmarshal(body,&createRsp)
if err != nil {
return &public.CreateRsp{}, err
}
return &createRsp, nil
}
func (h HTTPAPI) Update(req *public.UpdateReq) error {
jreq, err:= json.Marshal(req)
if err != nil {
return err
}
res, _, err := apiCall("PUT",h.BaseURL+"/events/"+strconv.Itoa(int(req.ID)), jreq)
if err != nil {
return err
}
if res.StatusCode!=201 {
return fmt.Errorf("unexpected status code %d",res.StatusCode)
}
return nil
}
func (h HTTPAPI) Delete(req *public.DeleteReq) error {
jreq, err:= json.Marshal(req)
if err != nil {
return err
}
res, _, err := apiCall("DELETE",h.BaseURL+"/events/"+strconv.Itoa(int(req.ID)), jreq)
if err != nil {
return err
}
if res.StatusCode!=201 {
return fmt.Errorf("unexpected status code %d",res.StatusCode)
}
return nil
}
func (h HTTPAPI) GetByID(req *public.GetByIDReq) ( *public.GetByIDResp, error) {
jreq, err:= json.Marshal(req)
if err != nil {
return &public.GetByIDResp{}, err
}
res, body, err := apiCall("GET",h.BaseURL+"/events/"+strconv.Itoa(int(req.ID)), jreq)
if err != nil {
return &public.GetByIDResp{}, err
}
if res.StatusCode!=201 {
return &public.GetByIDResp{}, fmt.Errorf("unexpected status code %d",res.StatusCode)
}
var getByIDResp public.GetByIDResp
err = json.Unmarshal(body,&getByIDResp)
if err != nil {
return &public.GetByIDResp{}, err
}
return &getByIDResp, nil
}
func (h HTTPAPI) List() ( *public.ListResp, error) {
res, body, err := apiCall("GET",h.BaseURL+"/events", nil)
if err != nil {
return &public.ListResp{}, err
}
if res.StatusCode!=200 {
return &public.ListResp{}, fmt.Errorf("unexpected status code %d",res.StatusCode)
}
var listResp public.ListResp
err = json.Unmarshal(body,&listResp)
if err != nil {
return &public.ListResp{}, err
}
return &listResp, nil
}
func (h HTTPAPI) GetByDate(req *public.GetByDateReq) ( *public.GetByDateResp, error) {
jreq, err:= json.Marshal(req)
if err != nil {
return &public.GetByDateResp{}, err
}
res, body, err := apiCall("GET",h.BaseURL+"/events/"+string(req.Range)+"/"+req.Date.String(), jreq)
if err != nil {
return &public.GetByDateResp{}, err
}
if res.StatusCode!=201 {
return &public.GetByDateResp{}, fmt.Errorf("unexpected status code %d",res.StatusCode)
}
var getByDateResp public.GetByDateResp
err = json.Unmarshal(body,&getByDateResp)
if err != nil {
return &public.GetByDateResp{}, err
}
return &getByDateResp, nil
}
func apiCall(method string, url string, payload []byte) (*http.Response, []byte, error) {
client := &http.Client{Transport: &http.Transport{ DialContext: (&net.Dialer{ Timeout: 15*time.Second}).DialContext }}
req, err := http.NewRequest(method, url, bytes.NewBuffer(payload))
if err != nil {
return nil, nil, err
}
req.Header.Add("Content-Type", "application/json")
req.Close = true
res, err := client.Do(req)
if err != nil {
return nil, nil, err
}
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, nil, err
}
if err = res.Body.Close(); err != nil {
return nil, nil, err
}
return res, body, nil
}

View File

@ -0,0 +1,13 @@
package client
import "github.com/tiburon-777/HW_OTUS/hw12_13_14_15_calendar/pkg/api/public"
type Interface interface {
GetName() string
Create(req *public.CreateReq) (*public.CreateRsp, error)
Update(req *public.UpdateReq) error
Delete(req *public.DeleteReq) error
GetByID(req *public.GetByIDReq) (*public.GetByIDResp, error)
List() (*public.ListResp, error)
GetByDate(req *public.GetByDateReq) (*public.GetByDateResp, error)
}

View File

@ -1,244 +1,10 @@
package main package main
import ( import (
"context"
"fmt"
"github.com/golang/protobuf/ptypes"
"github.com/golang/protobuf/ptypes/duration"
"github.com/golang/protobuf/ptypes/empty"
"github.com/golang/protobuf/ptypes/timestamp"
"github.com/stretchr/testify/require"
"github.com/tiburon-777/HW_OTUS/hw12_13_14_15_calendar/pkg/api/public"
"log" "log"
"sync"
"testing"
"time"
) )
var testEvent01 = public.CreateReq{
Title: "Test event 01",
Date: time2pbtimestamp(time.Now().Add(30 * time.Second)),
Latency: dur2pbduration(24 * time.Hour),
Note: "Note of test event 01",
NotifyTime: dur2pbduration(5 * time.Minute),
UserID: 1111,
}
var testEvent02 = public.CreateReq{
Title: "Test event 02",
Date: time2pbtimestamp(time.Now().Add(60 * time.Second)),
Latency: dur2pbduration(2 * 24 * time.Hour),
Note: "Note of test event 02",
NotifyTime: dur2pbduration(5 * time.Minute),
UserID: 2222,
}
func main() { func main() {
if err := TestPublicAPIEndpoint(); err != nil { log.Fatalln("Nothing to do")
log.Fatalf("TestPublicAPIEndpoint FAIL: %w", err)
}
if err := TestPublicGRPCEndpoint(); err != nil {
log.Fatalf("TestPublicGRPCEndpoint FAIL: %w", err)
}
}
func TestPublicGRPCEndpoint() error {
wg := sync.WaitGroup{}
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
publicAPI, err := public.NewClient(ctx, "localhost", "50051")
if err != nil {
return err
}
wg.Add(5)
// Реализовать тесты логики приложения:
t.Run("test public GRPC.Create and GRPC.GetById", func(t *testing.T) {
defer wg.Done()
resp1, err := publicAPI.Create(ctx, &testEvent01)
require.NoError(t, err)
require.Greater(t, resp1.ID, int64(0))
resp2, err := publicAPI.GetByID(ctx, &public.GetByIDReq{ID: resp1.ID})
require.NoError(t, err)
require.Equal(t, 1, len(resp2.Events))
require.Equal(t, testEvent01.Title, resp2.Events[0].Title)
require.Equal(t, testEvent01.UserID, resp2.Events[0].UserID)
require.Equal(t, testEvent01.Date.Seconds, resp2.Events[0].Date.Seconds)
require.Equal(t, testEvent01.Note, resp2.Events[0].Note)
})
t.Run("test public GRPC.Create, GRPC.Update and GRPC.GetById", func(t *testing.T) {
defer wg.Done()
resp1, err := publicAPI.Create(ctx, &testEvent01)
require.NoError(t, err)
require.Greater(t, resp1.ID, int64(0))
_, err = publicAPI.Update(ctx, &public.UpdateReq{ID: resp1.ID, Event: &public.Event{ID: resp1.ID, Title: testEvent02.Title, Date: testEvent02.Date, Latency: testEvent02.Latency, Note: testEvent02.Note, UserID: testEvent02.UserID, NotifyTime: testEvent02.NotifyTime}})
require.NoError(t, err)
resp2, err := publicAPI.GetByID(ctx, &public.GetByIDReq{ID: resp1.ID})
require.NoError(t, err)
require.Equal(t, 1, len(resp2.Events))
require.Equal(t, testEvent02.Title, resp2.Events[0].Title)
require.Equal(t, testEvent02.UserID, resp2.Events[0].UserID)
require.Equal(t, testEvent02.Date.Seconds, resp2.Events[0].Date.Seconds)
require.Equal(t, testEvent02.Note, resp2.Events[0].Note)
})
t.Run("test public GRPC.Create, GRPC.Delete and GRPC.GetById", func(t *testing.T) {
defer wg.Done()
resp1, err := publicAPI.Create(ctx, &testEvent01)
require.NoError(t, err)
require.Greater(t, resp1.ID, int64(0))
_, err = publicAPI.Delete(ctx, &public.DeleteReq{ID: resp1.ID})
require.NoError(t, err)
resp2, err := publicAPI.GetByID(ctx, &public.GetByIDReq{ID: resp1.ID})
require.Error(t, err)
require.Nil(t, resp2)
})
t.Run("test public GRPC.Create and GRPC.List", func(t *testing.T) {
defer wg.Done()
resp1, err := publicAPI.Create(ctx, &testEvent01)
require.NoError(t, err)
resp2, err := publicAPI.Create(ctx, &testEvent02)
require.NoError(t, err)
require.NotEqual(t, resp1.ID, resp2.ID)
list, err := publicAPI.List(ctx, &empty.Empty{})
require.NoError(t, err)
require.GreaterOrEqual(t, len(list.Events), 2)
var e1, e2 bool
for _, v := range list.Events {
if v.ID == resp1.ID {
e1 = true
}
if v.ID == resp2.ID {
e2 = true
}
}
require.True(t, e1)
require.True(t, e2)
})
t.Run("test public GRPC.Create and GRPC.GetByDate", func(t *testing.T) {
defer wg.Done()
resp1, err := publicAPI.Create(ctx, &testEvent01)
require.NoError(t, err)
list, err := publicAPI.GetByDate(ctx, &public.GetByDateReq{Date: testEvent01.Date, Range: public.QueryRange_DAY})
require.NoError(t, err)
require.GreaterOrEqual(t, len(list.Events), 2)
var e1 bool
for _, v := range list.Events {
if v.ID == resp1.ID {
e1 = true
}
}
require.True(t, e1)
})
wg.Wait()
}
func TestPublicAPIEndpoint() error {
wg := sync.WaitGroup{}
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
publicAPI, err := public.NewClient(ctx, "localhost", "50051")
require.NoError(t, err)
wg.Add(5)
// Реализовать тесты логики приложения:
t.Run("test public GRPC.Create and GRPC.GetById", func(t *testing.T) {
defer wg.Done()
resp1, err := publicAPI.Create(ctx, &testEvent01)
require.NoError(t, err)
require.Greater(t, resp1.ID, int64(0))
resp2, err := publicAPI.GetByID(ctx, &public.GetByIDReq{ID: resp1.ID})
require.NoError(t, err)
require.Equal(t, 1, len(resp2.Events))
require.Equal(t, testEvent01.Title, resp2.Events[0].Title)
require.Equal(t, testEvent01.UserID, resp2.Events[0].UserID)
require.Equal(t, testEvent01.Date.Seconds, resp2.Events[0].Date.Seconds)
require.Equal(t, testEvent01.Note, resp2.Events[0].Note)
})
t.Run("test public GRPC.Create, GRPC.Update and GRPC.GetById", func(t *testing.T) {
defer wg.Done()
resp1, err := publicAPI.Create(ctx, &testEvent01)
require.NoError(t, err)
require.Greater(t, resp1.ID, int64(0))
_, err = publicAPI.Update(ctx, &public.UpdateReq{ID: resp1.ID, Event: &public.Event{ID: resp1.ID, Title: testEvent02.Title, Date: testEvent02.Date, Latency: testEvent02.Latency, Note: testEvent02.Note, UserID: testEvent02.UserID, NotifyTime: testEvent02.NotifyTime}})
require.NoError(t, err)
resp2, err := publicAPI.GetByID(ctx, &public.GetByIDReq{ID: resp1.ID})
require.NoError(t, err)
require.Equal(t, 1, len(resp2.Events))
require.Equal(t, testEvent02.Title, resp2.Events[0].Title)
require.Equal(t, testEvent02.UserID, resp2.Events[0].UserID)
require.Equal(t, testEvent02.Date.Seconds, resp2.Events[0].Date.Seconds)
require.Equal(t, testEvent02.Note, resp2.Events[0].Note)
})
t.Run("test public GRPC.Create, GRPC.Delete and GRPC.GetById", func(t *testing.T) {
defer wg.Done()
resp1, err := publicAPI.Create(ctx, &testEvent01)
require.NoError(t, err)
require.Greater(t, resp1.ID, int64(0))
_, err = publicAPI.Delete(ctx, &public.DeleteReq{ID: resp1.ID})
require.NoError(t, err)
resp2, err := publicAPI.GetByID(ctx, &public.GetByIDReq{ID: resp1.ID})
require.Error(t, err)
require.Nil(t, resp2)
})
t.Run("test public GRPC.Create and GRPC.List", func(t *testing.T) {
defer wg.Done()
resp1, err := publicAPI.Create(ctx, &testEvent01)
require.NoError(t, err)
resp2, err := publicAPI.Create(ctx, &testEvent02)
require.NoError(t, err)
require.NotEqual(t, resp1.ID, resp2.ID)
list, err := publicAPI.List(ctx, &empty.Empty{})
require.NoError(t, err)
require.GreaterOrEqual(t, len(list.Events), 2)
var e1, e2 bool
for _, v := range list.Events {
if v.ID == resp1.ID {
e1 = true
}
if v.ID == resp2.ID {
e2 = true
}
}
require.True(t, e1)
require.True(t, e2)
})
t.Run("test public GRPC.Create and GRPC.GetByDate", func(t *testing.T) {
defer wg.Done()
resp1, err := publicAPI.Create(ctx, &testEvent01)
require.NoError(t, err)
list, err := publicAPI.GetByDate(ctx, &public.GetByDateReq{Date: testEvent01.Date, Range: public.QueryRange_DAY})
require.NoError(t, err)
require.GreaterOrEqual(t, len(list.Events), 2)
var e1 bool
for _, v := range list.Events {
if v.ID == resp1.ID {
e1 = true
}
}
require.True(t, e1)
})
wg.Wait()
}
func time2pbtimestamp(t time.Time) *timestamp.Timestamp {
r, err := ptypes.TimestampProto(t)
if err != nil {
log.Fatalf("cant convert Time to Timestamp: %s", err.Error())
}
return r
}
func dur2pbduration(t time.Duration) *duration.Duration {
return ptypes.DurationProto(t)
} }

View File

@ -0,0 +1,120 @@
package main
import (
"context"
"github.com/stretchr/testify/require"
"github.com/tiburon-777/HW_OTUS/hw12_13_14_15_calendar/pkg/api/public"
"github.com/tiburon-777/HW_OTUS/hw12_13_14_15_calendar/test/client"
"github.com/tiburon-777/HW_OTUS/hw12_13_14_15_calendar/test/misc"
"sync"
"testing"
)
func TestPublicAPIEndpoints(t *testing.T) {
cli := []client.Interface{
client.GRPCAPI{Ctx: context.Background(), Host: "localhost", Port:"50051", Name: "GRPC API"},
client.HTTPAPI{BaseURL: "http://localhost:50052", Name: "HTTP REST API"},
}
wg := sync.WaitGroup{}
wg.Add(len(cli)*5)
for _,c := range cli {
t.Run("test "+c.GetName()+" for Create and GetById", func(t *testing.T) {
defer wg.Done()
resp1, err := c.Create(&misc.TestEvent01)
require.NoError(t, err)
require.Greater(t, resp1.ID, int64(0))
resp2,err := c.GetByID(&public.GetByIDReq{ID:resp1.ID})
require.NoError(t, err)
require.Equal(t,1, len(resp2.Events))
require.Equal(t, misc.TestEvent01.Title, resp2.Events[0].Title)
require.Equal(t, misc.TestEvent01.UserID, resp2.Events[0].UserID)
require.Equal(t, misc.TestEvent01.Note, resp2.Events[0].Note)
})
t.Run("test "+c.GetName()+" for Create, Update and GetById", func(t *testing.T) {
defer wg.Done()
resp1, err := c.Create(&misc.TestEvent01)
require.NoError(t, err)
require.Greater(t, resp1.ID, int64(0))
err = c.Update(&public.UpdateReq{ID:resp1.ID, Event: &public.Event{ ID: resp1.ID, Title: misc.TestEvent02.Title, Date: misc.TestEvent02.Date, Latency: misc.TestEvent02.Latency, Note: misc.TestEvent02.Note, UserID: misc.TestEvent02.UserID, NotifyTime: misc.TestEvent02.NotifyTime }})
require.NoError(t, err)
resp2,err := c.GetByID(&public.GetByIDReq{ID:resp1.ID})
require.NoError(t, err)
require.Equal(t,1, len(resp2.Events))
require.Equal(t, misc.TestEvent02.Title, resp2.Events[0].Title)
require.Equal(t, misc.TestEvent02.UserID, resp2.Events[0].UserID)
require.Equal(t, misc.TestEvent02.Note, resp2.Events[0].Note)
})
t.Run("test "+c.GetName()+" for Create, Delete and GetById", func(t *testing.T) {
defer wg.Done()
resp1, err := c.Create(&misc.TestEvent01)
require.NoError(t, err)
require.Greater(t, resp1.ID, int64(0))
err = c.Delete(&public.DeleteReq{ ID: resp1.ID })
require.NoError(t, err)
resp2,err := c.GetByID(&public.GetByIDReq{ID:resp1.ID})
require.Error(t, err)
require.Nil(t, resp2)
})
t.Run("test "+c.GetName()+" for Create and List", func(t *testing.T) {
defer wg.Done()
resp1, err := c.Create(&misc.TestEvent01)
require.NoError(t, err)
require.Greater(t, resp1.ID, int64(0))
resp2, err := c.Create(&misc.TestEvent02)
require.NoError(t, err)
require.Greater(t, resp2.ID, int64(0))
resp3, err := c.List()
require.NoError(t, err)
require.GreaterOrEqual(t, len(resp3.Events), 2)
var e1, e2 bool
for _, v := range resp3.Events {
if v.ID == resp1.ID {
e1 = true
}
if v.ID == resp2.ID {
e2 = true
}
}
require.True(t, e1)
require.True(t, e2)
})
t.Run("test "+c.GetName()+" for Create and GetByDate", func(t *testing.T) {
defer wg.Done()
resp1, err := c.Create(&misc.TestEvent01)
require.NoError(t, err)
require.Greater(t, resp1.ID, int64(0))
resp2, err := c.Create(&misc.TestEvent02)
require.NoError(t, err)
require.Greater(t, resp2.ID, int64(0))
resp3,err := c.GetByDate(&public.GetByDateReq{Date: misc.TestEvent01.Date, Range: public.QueryRange_DAY})
require.NoError(t, err)
require.GreaterOrEqual(t, len(resp3.Events), 1)
var e1 bool
for _, v := range resp3.Events {
if v.ID == resp1.ID {
e1 = true
}
}
require.True(t, e1)
})
}
}

View File

@ -0,0 +1,40 @@
package misc
import (
"github.com/golang/protobuf/ptypes"
"github.com/golang/protobuf/ptypes/duration"
"github.com/golang/protobuf/ptypes/timestamp"
"github.com/tiburon-777/HW_OTUS/hw12_13_14_15_calendar/pkg/api/public"
"log"
"time"
)
var TestEvent01 = public.CreateReq{
Title: "Test event 01",
Date: Time2pbtimestamp(time.Now().Add(30 * time.Second)),
Latency: Dur2pbduration(24 * time.Hour),
Note: "Note of test event 01",
NotifyTime: Dur2pbduration(5 * time.Minute),
UserID: 1111,
}
var TestEvent02 = public.CreateReq{
Title: "Test event 02",
Date: Time2pbtimestamp(time.Now().Add(60 * time.Second)),
Latency: Dur2pbduration(2 * 24 * time.Hour),
Note: "Note of test event 02",
NotifyTime: Dur2pbduration(5 * time.Minute),
UserID: 2222,
}
func Time2pbtimestamp(t time.Time) *timestamp.Timestamp {
r, err := ptypes.TimestampProto(t)
if err != nil {
log.Fatalf("cant convert Time to Timestamp: %s", err.Error())
}
return r
}
func Dur2pbduration(t time.Duration) *duration.Duration {
return ptypes.DurationProto(t)
}