Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ make

> curl -X GET http://127.0.0.163:8000/spyfamily/character/Loid
"Character: Loid Forger"

> curl -X GET http://127.0.0.163:8000/onepiece/
"Hello Straw Hat Pirates!"

> curl -X POST http://127.0.0.163:8000/onepiece/crew \
-H "Content-Type: application/json" \
-d '{"name":"Jinbe"}'
"Jinbe has joined the Straw Hat crew!"
```

## Go Test
Expand Down
43 changes: 43 additions & 0 deletions internal/sbi/api_onepiece.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package sbi

import (
"fmt"
"net/http"

"github.com/gin-gonic/gin"
)

func (s *Server) getOnePieceRoute() []Route {
return []Route{
{
Name: "Hello Straw Hats",
Method: http.MethodGet,
Pattern: "/",
APIFunc: s.HTTPOnePieceGreeting,
},
{
Name: "Recruit Straw Hat",
Method: http.MethodPost,
Pattern: "/crew",
APIFunc: s.HTTPOnePieceRecruit,
},
}
}

func (s *Server) HTTPOnePieceGreeting(c *gin.Context) {
c.JSON(http.StatusOK, "Hello Straw Hat Pirates!")
}

func (s *Server) HTTPOnePieceRecruit(c *gin.Context) {
var request struct {
Name string `json:"name" binding:"required"`
}

if err := c.ShouldBindJSON(&request); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "name is required"})
return
}

message := fmt.Sprintf("%s has joined the Straw Hat crew!", request.Name)
c.JSON(http.StatusCreated, message)
}
111 changes: 111 additions & 0 deletions internal/sbi/processor/onepiece_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package processor_test

import (
"bytes"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"

"github.com/Alonza0314/nf-example/internal/sbi"
"github.com/Alonza0314/nf-example/pkg/factory"
"github.com/gin-gonic/gin"
"go.uber.org/mock/gomock"
)

func newTestServer(t *testing.T) *sbi.Server {
t.Helper()
gin.SetMode(gin.TestMode)
ctrl := gomock.NewController(t)
nfApp := sbi.NewMocknfApp(ctrl)
nfApp.EXPECT().Config().Return(&factory.Config{
Configuration: &factory.Configuration{
Sbi: &factory.Sbi{Port: 8000},
},
}).AnyTimes()
return sbi.NewServer(nfApp, "")
}

func Test_HTTPOnePieceGreeting(t *testing.T) {
server := newTestServer(t)
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
req, err := http.NewRequest(http.MethodGet, "/onepiece", nil)
if err != nil {
t.Fatalf("create request: %v", err)
}
ctx.Request = req

server.HTTPOnePieceGreeting(ctx)

if recorder.Code != http.StatusOK {
t.Fatalf("unexpected status: got %d want %d", recorder.Code, http.StatusOK)
}

var actual string
if err = json.Unmarshal(recorder.Body.Bytes(), &actual); err != nil {
t.Fatalf("decode response: %v", err)
}
const expected = "Hello Straw Hat Pirates!"
if actual != expected {
t.Fatalf("unexpected body: got %q want %q", actual, expected)
}
}

func Test_HTTPOnePieceRecruit(t *testing.T) {
server := newTestServer(t)

t.Run("Success", func(t *testing.T) {
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
body := bytes.NewBufferString(`{"name":"Jinbe"}`)
req, err := http.NewRequest(http.MethodPost, "/onepiece/crew", body)
if err != nil {
t.Fatalf("create request: %v", err)
}
req.Header.Set("Content-Type", "application/json")
ctx.Request = req

server.HTTPOnePieceRecruit(ctx)

if recorder.Code != http.StatusCreated {
t.Fatalf("unexpected status: got %d want %d", recorder.Code, http.StatusCreated)
}

var actual string
if err = json.Unmarshal(recorder.Body.Bytes(), &actual); err != nil {
t.Fatalf("decode response: %v", err)
}
const expected = "Jinbe has joined the Straw Hat crew!"
if actual != expected {
t.Fatalf("unexpected body: got %q want %q", actual, expected)
}
})

t.Run("MissingName", func(t *testing.T) {
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
body := bytes.NewBufferString(`{}`)
req, err := http.NewRequest(http.MethodPost, "/onepiece/crew", body)
if err != nil {
t.Fatalf("create request: %v", err)
}
req.Header.Set("Content-Type", "application/json")
ctx.Request = req

server.HTTPOnePieceRecruit(ctx)

if recorder.Code != http.StatusBadRequest {
t.Fatalf("unexpected status: got %d want %d", recorder.Code, http.StatusBadRequest)
}

var payload map[string]string
if err = json.Unmarshal(recorder.Body.Bytes(), &payload); err != nil {
t.Fatalf("decode error response: %v", err)
}
const expected = "name is required"
if payload["error"] != expected {
t.Fatalf("unexpected error message: got %q want %q", payload["error"], expected)
}
})
}
2 changes: 2 additions & 0 deletions internal/sbi/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ func newRouter(s *Server) *gin.Engine {
spyFamilyGroup := router.Group("/spyfamily")
applyRoutes(spyFamilyGroup, s.getSpyFamilyRoute())

onePieceGroup := router.Group("/onepiece")
applyRoutes(onePieceGroup, s.getOnePieceRoute())
attendanceGroup := router.Group("/attendance")
applyRoutes(attendanceGroup, s.getAttendanceRoute())
taskGroup := router.Group("/task")
Expand Down
Loading