Merge branch 'release-http' into 'master'
Release http. See merge request slon/shad-go-private!63
This commit is contained in:
commit
af4632b443
5 changed files with 93 additions and 11 deletions
|
@ -1,3 +1,18 @@
|
||||||
|
- group: HTTP
|
||||||
|
start: 23-03-2022 18:00
|
||||||
|
deadline: 10-04-2022 23:59
|
||||||
|
tasks:
|
||||||
|
- task: urlshortener
|
||||||
|
score: 100
|
||||||
|
- task: digitalclock
|
||||||
|
score: 100
|
||||||
|
- task: olympics
|
||||||
|
score: 200
|
||||||
|
- task: firewall
|
||||||
|
score: 200
|
||||||
|
- task: coverme
|
||||||
|
score: 300
|
||||||
|
|
||||||
- group: Concurrency with shared memory
|
- group: Concurrency with shared memory
|
||||||
start: 17-03-2022 23:59
|
start: 17-03-2022 23:59
|
||||||
deadline: 03-04-2022 23:59
|
deadline: 03-04-2022 23:59
|
||||||
|
|
|
@ -16,12 +16,18 @@ Package main можно не тестировать.
|
||||||
Coverage 100% говорит ровно о том, что все строки кода выполнялись.
|
Coverage 100% говорит ровно о том, что все строки кода выполнялись.
|
||||||
Хорошие тесты, в первую очередь, тестируют функциональность.
|
Хорошие тесты, в первую очередь, тестируют функциональность.
|
||||||
|
|
||||||
Как посмотреть coverage:
|
Как посмотреть общий coverage:
|
||||||
```
|
```
|
||||||
go test -v -cover ./coverme/...
|
go test -v -cover ./coverme/...
|
||||||
```
|
```
|
||||||
|
|
||||||
Coverage можно выводить в html (см. ссылки), и эта функциональность поддерживается в Goland.
|
Как посмотреть coverage пакета в html:
|
||||||
|
```
|
||||||
|
go test -v -coverprofile=/tmp/coverage.out ./coverme/models/...
|
||||||
|
go tool cover -html=/tmp/coverage.out
|
||||||
|
```
|
||||||
|
Аналогичная функциональность поддерживается в Goland.
|
||||||
|
Также рекомендуем ознакомиться с рассказом о cover в блоге (см. ссылки).
|
||||||
|
|
||||||
## Ссылки
|
## Ссылки
|
||||||
|
|
||||||
|
@ -44,7 +50,7 @@ Todo-app с минимальной функциональностью + client.
|
||||||
|
|
||||||
Health check:
|
Health check:
|
||||||
```
|
```
|
||||||
✗ curl -i -X GET localhost:6029/
|
✗ curl -i -X GET localhost:6029/
|
||||||
HTTP/1.1 200 OK
|
HTTP/1.1 200 OK
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
Date: Thu, 19 Mar 2020 21:46:02 GMT
|
Date: Thu, 19 Mar 2020 21:46:02 GMT
|
||||||
|
@ -66,7 +72,7 @@ Content-Length: 51
|
||||||
|
|
||||||
Получить todo по id:
|
Получить todo по id:
|
||||||
```
|
```
|
||||||
✗ curl -i localhost:6029/todo/0
|
✗ curl -i localhost:6029/todo/0
|
||||||
HTTP/1.1 200 OK
|
HTTP/1.1 200 OK
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
Date: Thu, 19 Mar 2020 21:44:17 GMT
|
Date: Thu, 19 Mar 2020 21:44:17 GMT
|
||||||
|
@ -77,7 +83,7 @@ Content-Length: 51
|
||||||
|
|
||||||
Получить все todo:
|
Получить все todo:
|
||||||
```
|
```
|
||||||
✗ curl -i -X GET localhost:6029/todo
|
✗ curl -i -X GET localhost:6029/todo
|
||||||
HTTP/1.1 200 OK
|
HTTP/1.1 200 OK
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
Date: Thu, 19 Mar 2020 21:44:37 GMT
|
Date: Thu, 19 Mar 2020 21:44:37 GMT
|
||||||
|
@ -85,3 +91,19 @@ Content-Length: 53
|
||||||
|
|
||||||
[{"id":0,"title":"A","content":"a","finished":false}]
|
[{"id":0,"title":"A","content":"a","finished":false}]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Завершить todo:
|
||||||
|
```
|
||||||
|
✗ curl -i -X POST localhost:6029/todo/0/finish
|
||||||
|
HTTP/1.1 200 OK
|
||||||
|
Date: Thu, 24 Mar 2022 15:40:49 GMT
|
||||||
|
Content-Length: 0
|
||||||
|
|
||||||
|
✗ curl -i -X GET localhost:6029/todo
|
||||||
|
HTTP/1.1 200 OK
|
||||||
|
Content-Type: application/json
|
||||||
|
Date: Thu, 24 Mar 2022 15:41:04 GMT
|
||||||
|
Content-Length: 52
|
||||||
|
|
||||||
|
[{"id":0,"title":"A","content":"a","finished":true}]%
|
||||||
|
```
|
||||||
|
|
|
@ -9,7 +9,6 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/gorilla/handlers"
|
"github.com/gorilla/handlers"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
@ -34,10 +33,11 @@ func (app *App) Start(port int) {
|
||||||
|
|
||||||
func (app *App) initRoutes() {
|
func (app *App) initRoutes() {
|
||||||
app.router = mux.NewRouter()
|
app.router = mux.NewRouter()
|
||||||
app.router.HandleFunc("/", app.status).Methods("Get")
|
app.router.HandleFunc("/", app.status).Methods("GET")
|
||||||
app.router.HandleFunc("/todo", app.list).Methods("Get")
|
app.router.HandleFunc("/todo", app.list).Methods("GET")
|
||||||
app.router.HandleFunc("/todo/{id:[0-9]+}", app.getTodo).Methods("Get")
|
app.router.HandleFunc("/todo/{id:[0-9]+}", app.getTodo).Methods("GET")
|
||||||
app.router.HandleFunc("/todo/create", app.addTodo).Methods("Post")
|
app.router.HandleFunc("/todo/{id:[0-9]+}/finish", app.finishTodo).Methods("POST")
|
||||||
|
app.router.HandleFunc("/todo/create", app.addTodo).Methods("POST")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (app *App) run(addr string) {
|
func (app *App) run(addr string) {
|
||||||
|
@ -80,7 +80,7 @@ func (app *App) addTodo(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (app *App) getTodo(w http.ResponseWriter, r *http.Request) {
|
func (app *App) getTodo(w http.ResponseWriter, r *http.Request) {
|
||||||
id, err := strconv.Atoi(strings.TrimPrefix(r.URL.Path, "/todo/"))
|
id, err := strconv.Atoi(mux.Vars(r)["id"])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.BadRequest(w, "ID must be an int")
|
utils.BadRequest(w, "ID must be an int")
|
||||||
return
|
return
|
||||||
|
@ -95,6 +95,21 @@ func (app *App) getTodo(w http.ResponseWriter, r *http.Request) {
|
||||||
_ = utils.RespondJSON(w, http.StatusOK, todo)
|
_ = utils.RespondJSON(w, http.StatusOK, todo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (app *App) finishTodo(w http.ResponseWriter, r *http.Request) {
|
||||||
|
id, err := strconv.Atoi(mux.Vars(r)["id"])
|
||||||
|
if err != nil {
|
||||||
|
utils.BadRequest(w, "ID must be an int")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := app.db.FinishTodo(models.ID(id)); err != nil {
|
||||||
|
utils.ServerError(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
func (app *App) status(w http.ResponseWriter, r *http.Request) {
|
func (app *App) status(w http.ResponseWriter, r *http.Request) {
|
||||||
_ = utils.RespondJSON(w, http.StatusOK, "API is up and working!")
|
_ = utils.RespondJSON(w, http.StatusOK, "API is up and working!")
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,3 +69,19 @@ func (c *Client) List() ([]*models.Todo, error) {
|
||||||
err = json.NewDecoder(resp.Body).Decode(&todos)
|
err = json.NewDecoder(resp.Body).Decode(&todos)
|
||||||
return todos, err
|
return todos, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) Finish(id models.ID) error {
|
||||||
|
u := fmt.Sprintf("%s/todo/%d/finish", c.addr, id)
|
||||||
|
|
||||||
|
resp, err := http.Post(u, "application/json", nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer func() { _ = resp.Body.Close() }()
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return fmt.Errorf("unexpected status code %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ type Storage interface {
|
||||||
AddTodo(string, string) (*Todo, error)
|
AddTodo(string, string) (*Todo, error)
|
||||||
GetTodo(ID) (*Todo, error)
|
GetTodo(ID) (*Todo, error)
|
||||||
GetAll() ([]*Todo, error)
|
GetAll() ([]*Todo, error)
|
||||||
|
FinishTodo(ID) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type InMemoryStorage struct {
|
type InMemoryStorage struct {
|
||||||
|
@ -69,3 +70,16 @@ func (s *InMemoryStorage) GetAll() ([]*Todo, error) {
|
||||||
|
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *InMemoryStorage) FinishTodo(id ID) error {
|
||||||
|
s.mu.Lock()
|
||||||
|
defer s.mu.Unlock()
|
||||||
|
|
||||||
|
todo, ok := s.todos[id]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("todo %d not found", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
todo.MarkFinished()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue