Skip to content

Commit

Permalink
Merge pull request #12 from claustra01/feat/linebot_test
Browse files Browse the repository at this point in the history
LineBotのテストコードの作成
  • Loading branch information
claustra01 authored Apr 6, 2024
2 parents 96c5e49 + 19b94c9 commit a35cc2b
Show file tree
Hide file tree
Showing 10 changed files with 340 additions and 42 deletions.
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ up:
down:
docker-compose down

test:
cd bot && make test

lint:
cd bot && make lint
cd web && npm run check
Expand Down
3 changes: 3 additions & 0 deletions bot/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ env:
go mod tidy
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest

test:
go test ./...

lint:
$$(go env GOPATH)/bin/golangci-lint run ./...

Expand Down
53 changes: 53 additions & 0 deletions bot/handler/callback.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package handler

import (
"errors"
"log"
"net/http"

"github.com/claustra01/calendeye/linebot"
"github.com/claustra01/calendeye/webhook"
)

func Callback(w http.ResponseWriter, req *http.Request, bot *linebot.LineBot, channelSecret string) {
log.Println("/callback called...")

cb, err := webhook.ParseRequest(channelSecret, req)
if err != nil {
log.Printf("Cannot parse request: %+v\n", err)
if errors.Is(err, webhook.ErrInvalidSignature) {
w.WriteHeader(http.StatusBadRequest)
} else {
w.WriteHeader(http.StatusInternalServerError)
}
return
}

log.Println("Handling events...")
for _, event := range cb.Events {
log.Printf("/callback called%+v...\n", event)

switch e := event.(type) {
case webhook.MessageEvent:
switch message := e.Message.(type) {
case webhook.TextMessageContent:
if _, err = bot.ReplyMessage(
&linebot.ReplyMessageRequest{
ReplyToken: e.ReplyToken,
Messages: []linebot.MessageInterface{
linebot.NewTextMessage(message.Text),
},
},
); err != nil {
log.Print(err)
} else {
log.Println("Sent text reply.")
}
default:
log.Printf("Unsupported message content: %T\n", e.Message)
}
default:
log.Printf("Unsupported message: %T\n", event)
}
}
}
9 changes: 9 additions & 0 deletions bot/linebot/bot.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@ package linebot

import (
"context"
"errors"
"net/http"
"net/url"
"path"
)

var (
ErrNoChannelToken = errors.New("channelToken is required")
)

type LineBot struct {
httpClient *http.Client
endpoint *url.URL
Expand All @@ -15,6 +20,10 @@ type LineBot struct {
}

func NewBot(channelToken string) (*LineBot, error) {
if channelToken == "" {
return nil, ErrNoChannelToken
}

c := &LineBot{
httpClient: http.DefaultClient,
channelToken: channelToken,
Expand Down
66 changes: 66 additions & 0 deletions bot/linebot/bot_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package linebot_test

import (
"testing"

. "github.com/claustra01/calendeye/linebot"
)

func TestNewBot(t *testing.T) {
tests := []struct {
name string
channelToken string
wantErr error
}{
{
name: "Valid channel token",
channelToken: "token",
wantErr: nil,
},
{
name: "Empty channel token",
channelToken: "",
wantErr: ErrNoChannelToken,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_, err := NewBot(tt.channelToken)

if err != tt.wantErr {
t.Errorf("got error %v; want %v", err, tt.wantErr)
}
})
}
}

func TestUrl(t *testing.T) {
tests := []struct {
name string
path string
expected string
}{
{
name: "Valid path",
path: "/v2/bot/message/reply",
expected: "https://api.line.me/v2/bot/message/reply",
},
{
name: "Empty path",
path: "",
expected: "https://api.line.me",
},
}

bot, _ := NewBot("token")
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
url := bot.Url(tt.path)

if url != tt.expected {
t.Errorf("got %s; want %s", url, tt.expected)
}
})
}
}
33 changes: 33 additions & 0 deletions bot/linebot/message_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package linebot_test

import (
"testing"

. "github.com/claustra01/calendeye/linebot"
)

func TestNewTextMessage(t *testing.T) {
test := []struct {
name string
text string
}{
{
name: "Valid text",
text: "Hello, world!",
},
}

for _, tt := range test {
t.Run(tt.name, func(t *testing.T) {
msg := NewTextMessage(tt.text)

if msg.Type != "text" {
t.Errorf("got %s; want text", msg.Type)
}

if msg.Text != tt.text {
t.Errorf("got %s; want %s", msg.Text, tt.text)
}
})
}
}
44 changes: 2 additions & 42 deletions bot/server.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
package main

import (
"errors"
"log"
"net/http"
"os"

"github.com/claustra01/calendeye/handler"
"github.com/claustra01/calendeye/linebot"
"github.com/claustra01/calendeye/webhook"
"github.com/joho/godotenv"
)

Expand All @@ -32,46 +31,7 @@ func main() {

// Setup HTTP Server for receiving requests from LINE platform
http.HandleFunc("/callback", func(w http.ResponseWriter, req *http.Request) {
log.Println("/callback called...")

cb, err := webhook.ParseRequest(channelSecret, req)
if err != nil {
log.Printf("Cannot parse request: %+v\n", err)
if errors.Is(err, webhook.ErrInvalidSignature) {
w.WriteHeader(http.StatusBadRequest)
} else {
w.WriteHeader(http.StatusInternalServerError)
}
return
}

log.Println("Handling events...")
for _, event := range cb.Events {
log.Printf("/callback called%+v...\n", event)

switch e := event.(type) {
case webhook.MessageEvent:
switch message := e.Message.(type) {
case webhook.TextMessageContent:
if _, err = bot.ReplyMessage(
&linebot.ReplyMessageRequest{
ReplyToken: e.ReplyToken,
Messages: []linebot.MessageInterface{
linebot.NewTextMessage(message.Text),
},
},
); err != nil {
log.Print(err)
} else {
log.Println("Sent text reply.")
}
default:
log.Printf("Unsupported message content: %T\n", e.Message)
}
default:
log.Printf("Unsupported message: %T\n", event)
}
}
handler.Callback(w, req, bot, channelSecret)
})

// This is just sample code.
Expand Down
45 changes: 45 additions & 0 deletions bot/webhook/event_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package webhook_test

import (
"reflect"
"testing"

. "github.com/claustra01/calendeye/webhook"
)

func TestUnmarshalEvent(t *testing.T) {
tests := []struct {
name string
data []byte
expected EventInterface
wantErr bool
}{
{
name: "Invalid type field",
data: []byte(`{"mode":"unknown","timestamp":123456789}`),
expected: nil,
wantErr: true,
},
{
name: "Invalid JSON",
data: []byte(`invalid json`),
expected: nil,
wantErr: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := UnmarshalEvent(tt.data)

if (err != nil) != tt.wantErr {
t.Errorf("UnmarshalEvent() error = %v, wantErr %v", err, tt.wantErr)
return
}

if !reflect.DeepEqual(got, tt.expected) {
t.Errorf("UnmarshalEvent() got = %v, want %v", got, tt.expected)
}
})
}
}
57 changes: 57 additions & 0 deletions bot/webhook/message_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package webhook_test

import (
"reflect"
"testing"

. "github.com/claustra01/calendeye/webhook"
)

func TestMessageEvent_UnmarshalJSON(t *testing.T) {
tests := []struct {
name string
data []byte
expected MessageEvent
wantErr bool
}{
{
name: "Valid text message",
data: []byte(`{"type":"message","mode":"test_mode","timestamp":123456789,"source":{"type":"user","userId":"123"},"webhookEventId":"event_id","deliveryContext":{"isRedelivery":true},"message":{"type":"text","id":"message_id"},"replyToken":"reply_token"}`),
expected: MessageEvent{
Event: Event{
Type: "message",
Mode: "test_mode",
Timestamp: 123456789,
Source: UserSource{Source: Source{Type: "user"}, UserId: "123"},
WebhookEventId: "event_id",
DeliveryContext: DeliveryContext{IsRedelivery: true},
},
ReplyToken: "reply_token",
Message: TextMessageContent{MessageContent: MessageContent{Type: "text", Id: "message_id"}},
},
wantErr: false,
},
{
name: "Invalid JSON",
data: []byte(`invalid json`),
expected: MessageEvent{},
wantErr: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var cr MessageEvent
err := cr.UnmarshalJSON(tt.data)

if (err != nil) != tt.wantErr {
t.Errorf("MessageEvent.UnmarshalJSON() error = %v, wantErr %v", err, tt.wantErr)
return
}

if !reflect.DeepEqual(cr, tt.expected) {
t.Errorf("MessageEvent.UnmarshalJSON() got = %v, want %v", cr, tt.expected)
}
})
}
}
Loading

0 comments on commit a35cc2b

Please sign in to comment.