Adds actions, changes time to pointers to make nillable.
All checks were successful
gitea-deepak/gogmagog/pipeline/head This commit looks good

This commit is contained in:
Deepak Mallubhotla 2021-01-01 11:49:22 -06:00
parent 95d945dda7
commit 70ddd91d6b
Signed by: deepak
GPG Key ID: 64BF53A3369104E7
7 changed files with 310 additions and 27 deletions

View File

@ -10,10 +10,10 @@ type Action struct {
ActionDescription string `json:"action_description"` ActionDescription string `json:"action_description"`
EstimatedChunks int `json:"estimated_chunks"` EstimatedChunks int `json:"estimated_chunks"`
CompletedChunks int `json:"completed_chunks"` CompletedChunks int `json:"completed_chunks"`
CompletedOn time.Time `json:"completed_on"` CompletedOn *time.Time `json:"completed_on,omitempty"`
PlanID int `json:"plan_id"` PlanID int `json:"plan_id"`
CreatedAt time.Time `json:"created_at"` CreatedAt *time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"` UpdatedAt *time.Time `json:"updated_at"`
} }
// Actions returns all actions from the model. // Actions returns all actions from the model.

View File

@ -7,7 +7,7 @@ import (
// Plan represents a single day's agenda of actions. // Plan represents a single day's agenda of actions.
type Plan struct { type Plan struct {
PlanID int64 `json:"plan_id"` PlanID int64 `json:"plan_id"`
PlanDate time.Time `json:"plan_date"` PlanDate *time.Time `json:"plan_date"`
} }
// Plans returns all plans in the model. // Plans returns all plans in the model.

54
routes/actions.go Normal file
View File

@ -0,0 +1,54 @@
package routes
import (
"encoding/json"
"gitea.deepak.science/deepak/gogmagog/models"
"github.com/go-chi/chi"
"net/http"
"strconv"
)
func newActionRouter(m *models.Model) http.Handler {
router := chi.NewRouter()
router.Get("/", getAllActionsFunc(m))
router.Get("/{actionid}", getActionByIDFunc(m))
return router
}
func getAllActionsFunc(m *models.Model) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
actions, err := m.Actions()
if err != nil {
serverError(w, err)
return
}
w.Header().Add("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(actions); err != nil {
serverError(w, err)
}
}
}
func getActionByIDFunc(m *models.Model) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
id, err := strconv.Atoi(chi.URLParam(r, "actionid"))
if err != nil {
notFoundHandler(w, r)
return
}
action, err := m.Action(id)
if err != nil {
if models.IsNotFoundError(err) {
notFoundHandler(w, r)
return
}
serverError(w, err)
return
}
w.Header().Add("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(action); err != nil {
serverError(w, err)
}
}
}

228
routes/actions_test.go Normal file
View File

@ -0,0 +1,228 @@
package routes_test
import (
"gitea.deepak.science/deepak/gogmagog/models"
"gitea.deepak.science/deepak/gogmagog/routes"
"github.com/stretchr/testify/assert"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
)
func TestEmptyActions(t *testing.T) {
// set up
assert := assert.New(t)
m := getEmptyModel()
router := routes.NewRouter(m)
req, _ := http.NewRequest("GET", "/actions", nil)
rr := httptest.NewRecorder()
// function under test
router.ServeHTTP(rr, req)
// check results
status := rr.Code
assert.Equal(http.StatusOK, status)
expected := `[]`
assert.JSONEq(expected, rr.Body.String())
contentType := rr.Header().Get("Content-Type")
assert.Equal("application/json", contentType)
}
func TestOneAction(t *testing.T) {
// set up
assert := assert.New(t)
createdDate, _ := time.Parse("2006-01-02", "2021-01-01")
updatedDate, _ := time.Parse("2006-01-02", "2021-01-02")
completedDate, _ := time.Parse("2006-01-02", "2021-01-03")
a1 := &models.Action{ActionID: 3, ActionDescription: "testing", CompletedChunks: 1, CompletedOn: &completedDate, CreatedAt: &createdDate, UpdatedAt: &updatedDate, EstimatedChunks: 3, PlanID: 0}
m := getModel([]*models.Plan{}, []*models.Action{a1})
router := routes.NewRouter(m)
req, _ := http.NewRequest("GET", "/actions", nil)
rr := httptest.NewRecorder()
// function under test
router.ServeHTTP(rr, req)
// check results
status := rr.Code
assert.Equal(http.StatusOK, status)
// We pass in the date as a time.time so it makes sense that it comes back with a midnight timestamp.
expected := `[
{
"action_id": 3,
"action_description": "testing",
"estimated_chunks": 3,
"completed_chunks": 1,
"completed_on": "2021-01-03T00:00:00Z",
"updated_at": "2021-01-02T00:00:00Z",
"created_at": "2021-01-01T00:00:00Z",
"plan_id": 0
}
]`
assert.JSONEq(expected, rr.Body.String())
contentType := rr.Header().Get("Content-Type")
assert.Equal("application/json", contentType)
}
func TestErrorAction(t *testing.T) {
// set up
assert := assert.New(t)
m := getErrorModel("Model always errors")
router := routes.NewRouter(m)
req, _ := http.NewRequest("GET", "/actions", nil)
rr := httptest.NewRecorder()
// function under test
router.ServeHTTP(rr, req)
// check results
status := rr.Code
assert.Equal(http.StatusInternalServerError, status)
// We pass in the date as a time.time so it makes sense that it comes back with a midnight timestamp.
expected := `Internal Server Error`
assert.Equal(expected, strings.TrimSpace(rr.Body.String()))
}
func TestEmptyActionErrorWriter(t *testing.T) {
// set up
assert := assert.New(t)
m := getEmptyModel()
router := routes.NewRouter(m)
req, _ := http.NewRequest("GET", "/actions", nil)
rr := NewBadWriter()
// function under test
router.ServeHTTP(rr, req)
// check results
status := rr.Code
assert.Equal(http.StatusInternalServerError, status)
}
func TestOneActionByID(t *testing.T) {
// set up
assert := assert.New(t)
createdDate, _ := time.Parse("2006-01-02", "2021-01-01")
updatedDate, _ := time.Parse("2006-01-02", "2021-01-02")
a := &models.Action{ActionID: 6, ActionDescription: "howdy", CompletedOn: nil, CreatedAt: &createdDate, UpdatedAt: &updatedDate, CompletedChunks: 0, EstimatedChunks: 54, PlanID: 3}
m := getModel([]*models.Plan{}, []*models.Action{a})
router := routes.NewRouter(m)
req, _ := http.NewRequest("GET", "/actions/6", nil)
rr := httptest.NewRecorder()
// function under test
router.ServeHTTP(rr, req)
// check results
status := rr.Code
assert.Equal(http.StatusOK, status)
// We pass in the date as a time.time so it makes sense that it comes back with a midnight timestamp.
expected := `{
"action_id": 6,
"action_description": "howdy",
"estimated_chunks": 54,
"completed_chunks": 0,
"updated_at": "2021-01-02T00:00:00Z",
"created_at": "2021-01-01T00:00:00Z",
"plan_id": 3
}`
assert.JSONEq(expected, rr.Body.String())
contentType := rr.Header().Get("Content-Type")
assert.Equal("application/json", contentType)
}
func TestErrorActionByID(t *testing.T) {
// set up
assert := assert.New(t)
m := getErrorModel("Model always errors")
router := routes.NewRouter(m)
req, _ := http.NewRequest("GET", "/actions/5", nil)
rr := httptest.NewRecorder()
// function under test
router.ServeHTTP(rr, req)
// check results
status := rr.Code
assert.Equal(http.StatusInternalServerError, status)
// We pass in the date as a time.time so it makes sense that it comes back with a midnight timestamp.
expected := `Internal Server Error`
assert.Equal(expected, strings.TrimSpace(rr.Body.String()))
}
func TestEmptyActionErrorWriterByID(t *testing.T) {
// set up
assert := assert.New(t)
a := &models.Action{ActionID: 6}
m := getModel([]*models.Plan{}, []*models.Action{a})
router := routes.NewRouter(m)
req, _ := http.NewRequest("GET", "/actions/6", nil)
rr := NewBadWriter()
// function under test
router.ServeHTTP(rr, req)
// check results
status := rr.Code
assert.Equal(http.StatusInternalServerError, status)
}
func TestNotFoundActionByIDText(t *testing.T) {
// set up
assert := assert.New(t)
m := getEmptyModel()
router := routes.NewRouter(m)
req, _ := http.NewRequest("GET", "/actions/wo", nil)
rr := httptest.NewRecorder()
// function under test
router.ServeHTTP(rr, req)
// check results
status := rr.Code
assert.Equal(http.StatusNotFound, status)
}
func TestNotFoundActionByIDEmpty(t *testing.T) {
// set up
assert := assert.New(t)
m := getEmptyModel()
router := routes.NewRouter(m)
req, _ := http.NewRequest("GET", "/actions/1", nil)
rr := httptest.NewRecorder()
// function under test
router.ServeHTTP(rr, req)
// check results
status := rr.Code
assert.Equal(http.StatusNotFound, status)
}

View File

@ -37,7 +37,7 @@ func TestOnePlan(t *testing.T) {
// set up // set up
assert := assert.New(t) assert := assert.New(t)
planDate, _ := time.Parse("2006-01-02", "2021-01-01") planDate, _ := time.Parse("2006-01-02", "2021-01-01")
p := &models.Plan{PlanID: 6, PlanDate: planDate} p := &models.Plan{PlanID: 6, PlanDate: &planDate}
m := getModel([]*models.Plan{p}, []*models.Action{}) m := getModel([]*models.Plan{p}, []*models.Action{})
router := routes.NewRouter(m) router := routes.NewRouter(m)
req, _ := http.NewRequest("GET", "/plans", nil) req, _ := http.NewRequest("GET", "/plans", nil)
@ -108,7 +108,7 @@ func TestOnePlanByID(t *testing.T) {
// set up // set up
assert := assert.New(t) assert := assert.New(t)
planDate, _ := time.Parse("2006-01-02", "2021-01-01") planDate, _ := time.Parse("2006-01-02", "2021-01-01")
p := &models.Plan{PlanID: 6, PlanDate: planDate} p := &models.Plan{PlanID: 6, PlanDate: &planDate}
m := getModel([]*models.Plan{p}, []*models.Action{}) m := getModel([]*models.Plan{p}, []*models.Action{})
router := routes.NewRouter(m) router := routes.NewRouter(m)
req, _ := http.NewRequest("GET", "/plans/6", nil) req, _ := http.NewRequest("GET", "/plans/6", nil)
@ -158,7 +158,7 @@ func TestEmptyPlanErrorWriterByID(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
planDate, _ := time.Parse("2006-01-02", "2021-01-01") planDate, _ := time.Parse("2006-01-02", "2021-01-01")
p := &models.Plan{PlanID: 6, PlanDate: planDate} p := &models.Plan{PlanID: 6, PlanDate: &planDate}
m := getModel([]*models.Plan{p}, []*models.Action{}) m := getModel([]*models.Plan{p}, []*models.Action{})
router := routes.NewRouter(m) router := routes.NewRouter(m)

View File

@ -13,6 +13,7 @@ func NewRouter(m *models.Model) http.Handler {
router.MethodNotAllowed(methodNotAllowedHandler) router.MethodNotAllowed(methodNotAllowedHandler)
router.NotFound(notFoundHandler) router.NotFound(notFoundHandler)
router.Mount("/plans", newPlanRouter(m)) router.Mount("/plans", newPlanRouter(m))
router.Mount("/actions", newActionRouter(m))
router.Mount("/health", newHealthRouter(m)) router.Mount("/health", newHealthRouter(m))
router.Get("/ping", ping) router.Get("/ping", ping)
return router return router

View File

@ -40,7 +40,7 @@ func TestSelectPlans(t *testing.T) {
assert.Equal(1, len(plans)) assert.Equal(1, len(plans))
plan := plans[0] plan := plans[0]
assert.EqualValues(idToUse, plan.PlanID) assert.EqualValues(idToUse, plan.PlanID)
assert.Equal(currentTime, plan.PlanDate) assert.Equal(currentTime, *plan.PlanDate)
if err := mock.ExpectationsWereMet(); err != nil { if err := mock.ExpectationsWereMet(); err != nil {
t.Errorf("unfulfilled expectations: %s", err) t.Errorf("unfulfilled expectations: %s", err)
@ -61,7 +61,7 @@ func TestSelectPlanByID(t *testing.T) {
plan, err := str.SelectPlanByID(idToUse) plan, err := str.SelectPlanByID(idToUse)
assert.Nil(err) assert.Nil(err)
assert.EqualValues(idToUse, plan.PlanID) assert.EqualValues(idToUse, plan.PlanID)
assert.Equal(currentTime, plan.PlanDate) assert.Equal(currentTime, *plan.PlanDate)
if err := mock.ExpectationsWereMet(); err != nil { if err := mock.ExpectationsWereMet(); err != nil {
t.Errorf("unfulfilled expectations: %s", err) t.Errorf("unfulfilled expectations: %s", err)
@ -74,7 +74,7 @@ func TestInsertPlan(t *testing.T) {
str, mock := getDbMock(t) str, mock := getDbMock(t)
planDate, _ := time.Parse("2006-01-02", "2021-01-01") planDate, _ := time.Parse("2006-01-02", "2021-01-01")
plan := &models.Plan{PlanDate: planDate} plan := &models.Plan{PlanDate: &planDate}
idToUse := 8 idToUse := 8
@ -103,7 +103,7 @@ func TestInsertPlanErr(t *testing.T) {
str, mock := getDbMock(t) str, mock := getDbMock(t)
planDate, _ := time.Parse("2006-01-02", "2021-01-01") planDate, _ := time.Parse("2006-01-02", "2021-01-01")
plan := &models.Plan{PlanDate: planDate} plan := &models.Plan{PlanDate: &planDate}
mock.ExpectBegin() mock.ExpectBegin()
mock.ExpectQuery("^INSERT INTO plans \\(plan_date\\) VALUES \\(\\$1\\) RETURNING plan_id$"). mock.ExpectQuery("^INSERT INTO plans \\(plan_date\\) VALUES \\(\\$1\\) RETURNING plan_id$").
@ -127,7 +127,7 @@ func TestInsertPlanCommitErr(t *testing.T) {
str, mock := getDbMock(t) str, mock := getDbMock(t)
planDate, _ := time.Parse("2006-01-02", "2021-01-01") planDate, _ := time.Parse("2006-01-02", "2021-01-01")
plan := &models.Plan{PlanDate: planDate} plan := &models.Plan{PlanDate: &planDate}
idToUse := 8 idToUse := 8
@ -205,9 +205,9 @@ func TestSelectActions(t *testing.T) {
assert.Equal(desc, action.ActionDescription) assert.Equal(desc, action.ActionDescription)
assert.Equal(estChunks, action.EstimatedChunks) assert.Equal(estChunks, action.EstimatedChunks)
assert.Equal(compChunks, action.CompletedChunks) assert.Equal(compChunks, action.CompletedChunks)
assert.Equal(completeTime, action.CompletedOn) assert.Equal(completeTime, *action.CompletedOn)
assert.Equal(createTime, action.CreatedAt) assert.Equal(createTime, *action.CreatedAt)
assert.Equal(updateTime, action.UpdatedAt) assert.Equal(updateTime, *action.UpdatedAt)
assert.Equal(idToUse, action.PlanID) assert.Equal(idToUse, action.PlanID)
if err := mock.ExpectationsWereMet(); err != nil { if err := mock.ExpectationsWereMet(); err != nil {
@ -255,9 +255,9 @@ func TestSelectActionsByPlanID(t *testing.T) {
assert.Equal(desc, action.ActionDescription) assert.Equal(desc, action.ActionDescription)
assert.Equal(estChunks, action.EstimatedChunks) assert.Equal(estChunks, action.EstimatedChunks)
assert.Equal(compChunks, action.CompletedChunks) assert.Equal(compChunks, action.CompletedChunks)
assert.Equal(completeTime, action.CompletedOn) assert.Equal(completeTime, *action.CompletedOn)
assert.Equal(createTime, action.CreatedAt) assert.Equal(createTime, *action.CreatedAt)
assert.Equal(updateTime, action.UpdatedAt) assert.Equal(updateTime, *action.UpdatedAt)
assert.Equal(idToUse, action.PlanID) assert.Equal(idToUse, action.PlanID)
if err := mock.ExpectationsWereMet(); err != nil { if err := mock.ExpectationsWereMet(); err != nil {
@ -328,9 +328,9 @@ func TestSelectActionById(t *testing.T) {
assert.Equal(desc, action.ActionDescription) assert.Equal(desc, action.ActionDescription)
assert.Equal(estChunks, action.EstimatedChunks) assert.Equal(estChunks, action.EstimatedChunks)
assert.Equal(compChunks, action.CompletedChunks) assert.Equal(compChunks, action.CompletedChunks)
assert.Equal(completeTime, action.CompletedOn) assert.Equal(completeTime, *action.CompletedOn)
assert.Equal(createTime, action.CreatedAt) assert.Equal(createTime, *action.CreatedAt)
assert.Equal(updateTime, action.UpdatedAt) assert.Equal(updateTime, *action.UpdatedAt)
assert.Equal(idToUse, action.PlanID) assert.Equal(idToUse, action.PlanID)
if err := mock.ExpectationsWereMet(); err != nil { if err := mock.ExpectationsWereMet(); err != nil {