Skip to content
Closed
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
9 changes: 8 additions & 1 deletion .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,14 @@ linters:
goconst:
min-len: 5
min-occurrences: 3
ignore-strings-values: get|post|put|delete|patch|options|head
ignore-string-values:
- get
- post
- put
- delete
- patch
- options
- head
gocritic:
disabled-checks:
- regexpMust
Expand Down
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ require (
github.com/gin-gonic/gin v1.10.0
github.com/google/uuid v1.6.0
github.com/sirupsen/logrus v1.9.3
github.com/stretchr/testify v1.9.0
github.com/urfave/cli v1.22.15
go.uber.org/mock v0.4.0
gopkg.in/yaml.v2 v2.4.0
Expand All @@ -20,6 +21,7 @@ require (
github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
Expand All @@ -35,6 +37,7 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/tim-ywliu/nested-logrus-formatter v1.3.2 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
Expand Down
18 changes: 18 additions & 0 deletions internal/context/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package context

import (
"os"
"sync"

"github.com/Alonza0314/nf-example/internal/logger"
"github.com/Alonza0314/nf-example/pkg/factory"
Expand All @@ -10,6 +11,11 @@ import (
"github.com/free5gc/openapi/models"
)

type Task struct {
ID int `json:"id"`
Name string `json:"name"`
}

type NFContext struct {
NfId string
Name string
Expand All @@ -18,6 +24,13 @@ type NFContext struct {
SBIPort int

SpyFamilyData map[string]string

MessageRecord []string
MessageMu sync.Mutex

Tasks []Task
TaskMutex sync.RWMutex
NextTaskID uint64
}

var nfContext = NFContext{}
Expand Down Expand Up @@ -57,6 +70,11 @@ func InitNfContext() {
"Henry": "Henderson",
"Martha": "Marriott",
}

nfContext.MessageRecord = []string{}

nfContext.Tasks = make([]Task, 0)
nfContext.NextTaskID = 0
}

func GetSelf() *NFContext {
Expand Down
54 changes: 54 additions & 0 deletions internal/sbi/api_message.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package sbi

import (
"net/http"

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

func (s *Server) myPutGetMessageRoute() []Route {
return []Route{
{
Name: "get messages",
Method: http.MethodGet,
Pattern: "/",
APIFunc: s.HTTPGetMessageRecord,
// Use
// curl -X GET http://127.0.0.163:8000/message/ -w "\n"
// return all added message
},
{
Name: "add message",
Method: http.MethodPut,
Pattern: "/:Message",
APIFunc: s.HTTPAddNewMessage,
// Use
// curl -X PUT http://127.0.0.163:8000/message/yourmessage -w "\n"
// add "yourmessage" to message record
},
{
// empty input handle, will not accept
Name: "empty input",
Method: http.MethodPut,
Pattern: "/",
APIFunc: s.noMessageHandler,
},
}
}

func (s *Server) HTTPAddNewMessage(c *gin.Context) {
newMessage := c.Param("Message")
if newMessage == "" {
s.noMessageHandler(c)
return
}
s.Processor().AddNewMessage(c, newMessage)
}

func (s *Server) noMessageHandler(c *gin.Context) {
c.String(http.StatusBadRequest, "No message provided")
}

func (s *Server) HTTPGetMessageRecord(c *gin.Context) {
s.Processor().GetMessageRecord(c)
}
52 changes: 52 additions & 0 deletions internal/sbi/api_message_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package sbi_test

import (
"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 Test_PUTWithEmptyInput(t *testing.T) {
gin.SetMode(gin.TestMode)

mockCtrl := gomock.NewController(t)
nfApp := sbi.NewMocknfApp(mockCtrl)
nfApp.EXPECT().Config().Return(&factory.Config{
Configuration: &factory.Configuration{
Sbi: &factory.Sbi{
Port: 8000,
},
},
}).AnyTimes()
server := sbi.NewServer(nfApp, "")

t.Run("Add Message That Empty", func(t *testing.T) {
const EXPECTED_STATUS = 400
const EXPECTED_BODY = "No message provided"

httpRecorder := httptest.NewRecorder()
ginCtx, _ := gin.CreateTestContext(httpRecorder)

var err error
ginCtx.Request, err = http.NewRequest("PUT", "/message/", nil)
if err != nil {
t.Errorf("Failed to create request: %s", err)
return
}

server.HTTPAddNewMessage(ginCtx)

if httpRecorder.Code != EXPECTED_STATUS {
t.Errorf("Expected status code %d, got %d", EXPECTED_STATUS, httpRecorder.Code)
}

if httpRecorder.Body.String() != EXPECTED_BODY {
t.Errorf("Expected body %s, got %s", EXPECTED_BODY, httpRecorder.Body.String())
}
})
}
32 changes: 32 additions & 0 deletions internal/sbi/api_task.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package sbi

import (
"net/http"

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

func (s *Server) HTTPCreateNewTask(c *gin.Context) {
s.Processor().CreateNewTask(c)
}

func (s *Server) HTTPGetAllTasks(c *gin.Context) {
s.Processor().GetAllTasks(c)
}

func (s *Server) getTaskRoute() []Route {
return []Route{
{
Name: "Get All Tasks",
Method: http.MethodGet,
Pattern: "/tasks",
APIFunc: s.HTTPGetAllTasks,
},
{
Name: "Create New Task",
Method: http.MethodPost,
Pattern: "/tasks",
APIFunc: s.HTTPCreateNewTask,
},
}
}
33 changes: 33 additions & 0 deletions internal/sbi/processor/message.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package processor

import (
"fmt"
"net/http"

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

func (p *Processor) AddNewMessage(c *gin.Context, newMessage string) {
p.Context().MessageMu.Lock()
defer p.Context().MessageMu.Unlock()
// add message
p.Context().MessageRecord = append(p.Context().MessageRecord, newMessage)
c.String(http.StatusOK, "add a new message!")
}

func (p *Processor) GetMessageRecord(c *gin.Context) {
p.Context().MessageMu.Lock()
defer p.Context().MessageMu.Unlock()

// no content
if len(p.Context().MessageRecord) == 0 {
c.String(http.StatusOK, "no message now, add some messagess!")
return
}
// get record
Record := ""
for _, s := range p.Context().MessageRecord {
Record += fmt.Sprintf("%s\n", s)
}
c.String(http.StatusOK, Record)
}
113 changes: 113 additions & 0 deletions internal/sbi/processor/message_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package processor_test

import (
"net/http/httptest"
"testing"

nf_context "github.com/Alonza0314/nf-example/internal/context"
"github.com/Alonza0314/nf-example/internal/sbi/processor"
"github.com/gin-gonic/gin"
gomock "go.uber.org/mock/gomock"
)

func Test_AddNewMessage(t *testing.T) {
gin.SetMode(gin.TestMode)

mockCtrl := gomock.NewController(t)
processorNf := processor.NewMockProcessorNf(mockCtrl)
processor, err := processor.NewProcessor(processorNf)
if err != nil {
t.Errorf("Failed to create processor: %s", err)
return
}

t.Run("Add Message That Not Empty", func(t *testing.T) {
const INPUT_MESSAGE = "ABC"
const EXPECTED_STATUS = 200
const EXPECTED_BODY = "add a new message!"

processorNf.EXPECT().Context().Return(&nf_context.NFContext{
MessageRecord: []string{},
}).AnyTimes()

httpRecorder := httptest.NewRecorder()
ginCtx, _ := gin.CreateTestContext(httpRecorder)
processor.AddNewMessage(ginCtx, INPUT_MESSAGE)

if httpRecorder.Code != EXPECTED_STATUS {
t.Errorf("Expected status code %d, got %d", EXPECTED_STATUS, httpRecorder.Code)
}

if httpRecorder.Body.String() != EXPECTED_BODY {
t.Errorf("Expected body %s, got %s", EXPECTED_BODY, httpRecorder.Body.String())
}
})
}

func Test_GetMessageNotEmpty(t *testing.T) {
gin.SetMode(gin.TestMode)

mockCtrl := gomock.NewController(t)
processorNf := processor.NewMockProcessorNf(mockCtrl)
processor, err := processor.NewProcessor(processorNf)
if err != nil {
t.Errorf("Failed to create processor: %s", err)
return
}

t.Run("Get Message That Not Empty", func(t *testing.T) {
const EXPECTED_STATUS = 200
const EXPECTED_BODY = "ABC\n123\n"

processorNf.EXPECT().Context().Return(&nf_context.NFContext{
MessageRecord: []string{
"ABC",
"123",
},
}).AnyTimes()

httpRecorder := httptest.NewRecorder()
ginCtx, _ := gin.CreateTestContext(httpRecorder)
processor.GetMessageRecord(ginCtx)

if httpRecorder.Code != EXPECTED_STATUS {
t.Errorf("Expected status code %d, got %d", EXPECTED_STATUS, httpRecorder.Code)
}

if httpRecorder.Body.String() != EXPECTED_BODY {
t.Errorf("Expected body %s, got %s", EXPECTED_BODY, httpRecorder.Body.String())
}
})
}

func Test_GetMessageEmpty(t *testing.T) {
gin.SetMode(gin.TestMode)

mockCtrl := gomock.NewController(t)
processorNf := processor.NewMockProcessorNf(mockCtrl)
processor, err := processor.NewProcessor(processorNf)
if err != nil {
t.Errorf("Failed to create processor: %s", err)
return
}
t.Run("Get Message That Empty", func(t *testing.T) {
const EXPECTED_STATUS = 200
const EXPECTED_BODY = "no message now, add some messagess!"

processorNf.EXPECT().Context().Return(&nf_context.NFContext{
MessageRecord: []string{},
}).AnyTimes()

httpRecorder := httptest.NewRecorder()
ginCtx, _ := gin.CreateTestContext(httpRecorder)
processor.GetMessageRecord(ginCtx)

if httpRecorder.Code != EXPECTED_STATUS {
t.Errorf("Expected status code %d, got %d", EXPECTED_STATUS, httpRecorder.Code)
}

if httpRecorder.Body.String() != EXPECTED_BODY {
t.Errorf("Expected body %s, got %s", EXPECTED_BODY, httpRecorder.Body.String())
}
})
}
Loading
Loading