From 6531916ce9823eb309b344e0210e6e693342e0a0 Mon Sep 17 00:00:00 2001 From: Martin/Geno Date: Sat, 1 Jun 2019 19:26:03 +0200 Subject: [PATCH] [TEST] review threema bot component : WIP --- component/main_test.go | 22 ++++++- component/threema/account.go | 5 ++ component/threema/bot.go | 110 ++++++++++++++++++++++----------- component/threema/bot_test.go | 98 +++++++++++++++++++++++++++++ component/threema/main.go | 10 ++- component/threema/main_test.go | 8 ++- 6 files changed, 212 insertions(+), 41 deletions(-) create mode 100644 component/threema/bot_test.go diff --git a/component/main_test.go b/component/main_test.go index a64619e..8fcf9d4 100644 --- a/component/main_test.go +++ b/component/main_test.go @@ -1,6 +1,7 @@ package component import ( + "errors" "testing" "github.com/stretchr/testify/assert" @@ -16,10 +17,27 @@ func TestAddComponent(t *testing.T) { } func TestLoad(t *testing.T) { - AddComponent("a", func(config map[string]interface{}) (Component, error) { return nil, nil }) + assert := assert.New(t) + AddComponent("error", func(config map[string]interface{}) (Component, error) { + return nil, errors.New("dummy") + }) + // load correct Load([]Config{ {}, - // {Type: "a", Connection: "[::1]:10001"}, + }) + + // error on component + assert.Panics(func() { + Load([]Config{ + {Type: "error", Connection: "[::1]:10001"}, + }) + }) + + // error on connect + assert.Panics(func() { + Load([]Config{ + {Type: "a", Connection: "[::1]:10001"}, + }) }) } diff --git a/component/threema/account.go b/component/threema/account.go index cf3b51d..12cf0e5 100644 --- a/component/threema/account.go +++ b/component/threema/account.go @@ -1,6 +1,7 @@ package threema import ( + "errors" "strconv" "github.com/bdlm/log" @@ -27,6 +28,10 @@ func (t *Threema) getAccount(jid *models.JID) (*Account, error) { } account := models.AccountThreema{} + if database.Read == nil { + return nil, errors.New("no database connection") + } + database.Read.Where("xmpp_id = (?)", database.Read.Table(jid.TableName()).Select("id").Where(map[string]interface{}{ "local": jid.Local, diff --git a/component/threema/bot.go b/component/threema/bot.go index 6bd9ddc..03d01fa 100644 --- a/component/threema/bot.go +++ b/component/threema/bot.go @@ -11,51 +11,91 @@ import ( "dev.sum7.eu/genofire/thrempp/models" ) -func (t *Threema) Bot(from *models.JID, request string) string { - server := o3.ThreemaRest{} - logger := log.WithFields(map[string]interface{}{ - "type": "threema", - "jid": from.String(), - }) +type Bot struct { + jid *models.JID + threema *Threema + server o3.ThreemaRest + logger *log.Entry +} +func (t *Threema) getBot(jid *models.JID) *Bot { + jidStr := jid.String() + if bot, ok := t.bot[jidStr]; ok { + return bot + } + if db := database.Read; db != nil && db.DB().Ping() == nil { + if err := db.Where(jid).First(jid); err.RecordNotFound() { + database.Write.Create(jid) + } else if err != nil { + log.Errorf("error getting jid %s from datatbase: %s", jid.String(), err.Error) + } + } + bot := &Bot{ + jid: jid, + threema: t, + server: o3.ThreemaRest{}, + logger: log.WithFields(map[string]interface{}{ + "type": "threema", + "jid": jidStr, + }), + } + t.bot[jidStr] = bot + return bot +} +func (b *Bot) getAccount() (*Account, error) { + return b.threema.getAccount(b.jid) +} + +func (b *Bot) Handle(request string) string { switch request { case "generate": + return b.cmdGenerate() + case "help": + return b.cmdHelp() + } + return fmt.Sprintf("command not found\n%s", b.cmdHelp()) +} - // test if account already exists - account, err := t.getAccount(from) - if err == nil { - return fmt.Sprintf("you already has the threema account with id: %s", string(account.TID)) - } +func (b *Bot) cmdHelp() string { + return ` + generate : generate a threema id (if not exists) + ` +} - // create account - id, err := server.CreateIdentity() - if err != nil { - logger.Warnf("failed to generate: %s", err) - return fmt.Sprintf("failed to create a threema account: %s", err) - } - //TODO works it - if err := database.Read.Where(from).First(from); err != nil { - database.Write.Create(from) - } +func (b *Bot) cmdGenerate() string { + logger := b.logger.WithField("bot", "generate") + // test if account already exists + account, err := b.getAccount() + if err == nil { + return fmt.Sprintf("you already has the threema account with id: %s", string(account.TID)) + } - // store account - a := models.AccountThreema{} - a.XMPPID = from.ID - a.TID = make([]byte, len(id.ID)) - a.LSK = make([]byte, len(id.LSK)) - copy(a.TID, id.ID[:]) - copy(a.LSK, id.LSK[:]) - database.Write.Create(&a) + // create account + id, err := b.server.CreateIdentity() + if err != nil { + logger.Warnf("failed to generate: %s", err) + return fmt.Sprintf("failed to create a threema account: %s", err) + } - // fetch account and connect - account, err = t.getAccount(from) - tid := string(account.TID) - if tid != "" { + // store account + a := models.AccountThreema{} + a.XMPPID = b.jid.ID + a.TID = make([]byte, len(id.ID)) + a.LSK = make([]byte, len(id.LSK)) + copy(a.TID, id.ID[:]) + copy(a.LSK, id.LSK[:]) + database.Write.Create(&a) + + // fetch account and connect + account, err = b.getAccount() + if err != nil { + logger.Warnf("failed to generate: %s", err) + } else { + if tid := string(account.TID); tid != "" { logger.WithField("threema", tid).Info("generate") return fmt.Sprintf("threema account with id: %s", tid) } logger.Warn("failed to generate") - return "failed to create a threema account" } - return "command not supported" + return "failed to create a threema account" } diff --git a/component/threema/bot_test.go b/component/threema/bot_test.go new file mode 100644 index 0000000..0ca7e78 --- /dev/null +++ b/component/threema/bot_test.go @@ -0,0 +1,98 @@ +package threema + +import ( + "testing" + + "dev.sum7.eu/genofire/golang-lib/database" + "github.com/stretchr/testify/assert" + + "dev.sum7.eu/genofire/thrempp/models" +) + +func TestBot(t *testing.T) { + assert := assert.New(t) + + b := Bot{ + jid: &models.JID{}, + threema: &Threema{ + bot: make(map[string]*Bot), + }, + } + + msg := b.Handle("help") + assert.NotEqual("", msg) + + // getAccount + a, err := b.getAccount() + assert.Error(err) + assert.Nil(a) +} + +func TestGetBot(t *testing.T) { + assert := assert.New(t) + + tr := Threema{ + bot: make(map[string]*Bot), + } + jid := &models.JID{ + Local: "a", + Domain: "example.org", + } + // + b := tr.getBot(jid) + assert.NotNil(b) + + // getBot from cache + b = tr.getBot(jid) + assert.NotNil(b) + + // reset cache + test jid db + tr.bot = make(map[string]*Bot) + database.Open(database.Config{ + Type: "sqlite3", + Connection: "file::memory:?mode=memory", + }) + defer database.Close() + b = tr.getBot(jid) + assert.NotNil(b) +} +func TestBotGenerate(t *testing.T) { + assert := assert.New(t) + + threema := &Threema{ + bot: make(map[string]*Bot), + accountJID: make(map[string]*Account), + } + + b := threema.getBot(&models.JID{ + Local: "generate", + Domain: "example.org", + }) + + // failed to generate without db + msg := b.Handle("generate") + assert.Equal("failed to create a threema account", msg) + + database.Open(database.Config{ + Type: "sqlite3", + Connection: "file::memory:?mode=memory", + }) + threema = &Threema{ + bot: make(map[string]*Bot), + accountJID: make(map[string]*Account), + } + b = threema.getBot(&models.JID{ + Local: "generate", + Domain: "example.org", + }) + + // generate + msg = b.Handle("generate") + assert.Contains(msg, "threema account with id") + + // alread generated + msg = b.Handle("generate") + assert.Contains(msg, "threema account with id") + + database.Close() +} diff --git a/component/threema/main.go b/component/threema/main.go index 8996748..5a549ce 100644 --- a/component/threema/main.go +++ b/component/threema/main.go @@ -16,12 +16,14 @@ type Threema struct { component.Component out chan xmpp.Packet accountJID map[string]*Account + bot map[string]*Bot } func NewThreema(config map[string]interface{}) (component.Component, error) { return &Threema{ out: make(chan xmpp.Packet), accountJID: make(map[string]*Account), + bot: make(map[string]*Bot), }, nil } @@ -52,8 +54,12 @@ func (t *Threema) send(packet xmpp.Packet) xmpp.Packet { to := models.ParseJID(p.PacketAttrs.To) if to.IsDomain() { + if from == nil { + log.Warn("recieve message without sender") + return nil + } msg := xmpp.NewMessage("chat", "", from.String(), "", "en") - msg.Body = t.Bot(from, p.Body) + msg.Body = t.getBot(from).Handle(p.Body) return msg } @@ -71,7 +77,7 @@ func (t *Threema) send(packet xmpp.Packet) xmpp.Packet { return msg } default: - log.Warnf("unkown package%v", p) + log.Warnf("unkown package: %v", p) } return nil } diff --git a/component/threema/main_test.go b/component/threema/main_test.go index 322abcb..0773f6e 100644 --- a/component/threema/main_test.go +++ b/component/threema/main_test.go @@ -58,6 +58,7 @@ func TestSend(t *testing.T) { tr := Threema{ out: out, accountJID: make(map[string]*Account), + bot: make(map[string]*Bot), } go func() { tr.Send(xmpp.Message{ @@ -76,11 +77,14 @@ func TestSend(t *testing.T) { // chat with bot p = tr.send(xmpp.Message{ - PacketAttrs: xmpp.PacketAttrs{To: "example.org"}, + PacketAttrs: xmpp.PacketAttrs{ + From: "a@example.com", + To: "example.org", + }, }) assert.NotNil(p) msg = p.(xmpp.Message) - assert.Equal("command not supported", msg.Body) + assert.Contains(msg.Body, "command not found") // chat with delivier error database.Open(database.Config{