[TEST] review threema bot component : WIP
This commit is contained in:
		
							parent
							
								
									bd87c4ac86
								
							
						
					
					
						commit
						6531916ce9
					
				| 
						 | 
				
			
			@ -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"},
 | 
			
		||||
		})
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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"
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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()
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Reference in New Issue