Expand smsglobal

This commit is contained in:
Adrian Gallagher
2017-09-14 13:07:08 +10:00
parent 04d1de9e22
commit 4a67edac99
6 changed files with 295 additions and 112 deletions

View File

@@ -14,6 +14,7 @@ import (
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/currency"
"github.com/thrasher-/gocryptotrader/portfolio"
"github.com/thrasher-/gocryptotrader/smsglobal"
)
// Constants declared here are filename strings and test strings
@@ -66,11 +67,7 @@ type SMSGlobalConfig struct {
Enabled bool
Username string
Password string
Contacts []struct {
Name string
Number string
Enabled bool
}
Contacts []smsglobal.Contact
}
// Post holds the bot configuration data

View File

@@ -3,11 +3,31 @@ package events
import (
"testing"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
"github.com/thrasher-/gocryptotrader/smsglobal"
)
var (
loaded = false
)
func testSetup(t *testing.T) {
if !loaded {
cfg := config.GetConfig()
err := cfg.LoadConfig("")
if err != nil {
t.Fatalf("Test failed. Failed to load config %s", err)
}
smsglobal.New(cfg.SMS.Username, cfg.SMS.Password, cfg.Name, cfg.SMS.Contacts)
loaded = true
}
}
func TestAddEvent(t *testing.T) {
testSetup(t)
pair := pair.NewCurrencyPair("BTC", "USD")
eventID, err := AddEvent("ANX", "price", ">,==", pair, "SPOT", actionTest)
if err != nil && eventID != 0 {
@@ -36,6 +56,8 @@ func TestAddEvent(t *testing.T) {
}
func TestRemoveEvent(t *testing.T) {
testSetup(t)
pair := pair.NewCurrencyPair("BTC", "USD")
eventID, err := AddEvent("ANX", "price", ">,==", pair, "SPOT", actionTest)
if err != nil && eventID != 0 {
@@ -50,6 +72,8 @@ func TestRemoveEvent(t *testing.T) {
}
func TestGetEventCounter(t *testing.T) {
testSetup(t)
pair := pair.NewCurrencyPair("BTC", "USD")
one, err := AddEvent("ANX", "price", ">,==", pair, "SPOT", actionTest)
if err != nil {
@@ -87,6 +111,8 @@ func TestGetEventCounter(t *testing.T) {
}
func TestExecuteAction(t *testing.T) {
testSetup(t)
pair := pair.NewCurrencyPair("BTC", "USD")
one, err := AddEvent("ANX", "price", ">,==", pair, "SPOT", actionTest)
if err != nil {
@@ -127,11 +153,12 @@ func TestExecuteAction(t *testing.T) {
if !RemoveEvent(one) {
t.Error("Test Failed. ExecuteAction: Error, error removing event")
}
// More tests when ExecuteAction is expanded
}
func TestEventToString(t *testing.T) {
testSetup(t)
pair := pair.NewCurrencyPair("BTC", "USD")
one, err := AddEvent("ANX", "price", ">,==", pair, "SPOT", actionTest)
if err != nil {
@@ -149,6 +176,8 @@ func TestEventToString(t *testing.T) {
}
func TestCheckCondition(t *testing.T) {
testSetup(t)
// Test invalid currency pair
newPair := pair.NewCurrencyPair("A", "B")
one, err := AddEvent("ANX", "price", ">=,10", newPair, "SPOT", actionTest)
@@ -219,6 +248,8 @@ func TestCheckCondition(t *testing.T) {
}
func TestIsValidEvent(t *testing.T) {
testSetup(t)
err := IsValidEvent("ANX", "price", ">,==", actionTest)
if err != nil {
t.Errorf("Test Failed. IsValidEvent: %s", err)
@@ -253,6 +284,8 @@ func TestIsValidEvent(t *testing.T) {
}
func TestCheckEvents(t *testing.T) {
testSetup(t)
pair := pair.NewCurrencyPair("BTC", "USD")
_, err := AddEvent("ANX", "price", ">=,10", pair, "SPOT", actionTest)
if err != nil {
@@ -263,17 +296,21 @@ func TestCheckEvents(t *testing.T) {
}
func TestIsValidExchange(t *testing.T) {
boolean := IsValidExchange("ANX", configPathTest)
testSetup(t)
boolean := IsValidExchange("ANX")
if !boolean {
t.Error("Test Failed. IsValidExchange: Error, incorrect Exchange")
}
boolean = IsValidExchange("OBTUSE", configPathTest)
boolean = IsValidExchange("OBTUSE")
if boolean {
t.Error("Test Failed. IsValidExchange: Error, incorrect return")
}
}
func TestIsValidCondition(t *testing.T) {
testSetup(t)
boolean := IsValidCondition(">")
if !boolean {
t.Error("Test Failed. IsValidCondition: Error, incorrect Condition")
@@ -301,6 +338,8 @@ func TestIsValidCondition(t *testing.T) {
}
func TestIsValidAction(t *testing.T) {
testSetup(t)
boolean := IsValidAction("sms")
if !boolean {
t.Error("Test Failed. IsValidAction: Error, incorrect Action")
@@ -316,6 +355,8 @@ func TestIsValidAction(t *testing.T) {
}
func TestIsValidItem(t *testing.T) {
testSetup(t)
boolean := IsValidItem("price")
if !boolean {
t.Error("Test Failed. IsValidItem: Error, incorrect Item")

View File

@@ -23,7 +23,6 @@ const (
actionSMSNotify = "SMS"
actionConsolePrint = "CONSOLE_PRINT"
actionTest = "ACTION_TEST"
configPathTest = config.ConfigTestFile
)
var (
@@ -107,12 +106,12 @@ func (e *Event) ExecuteAction() bool {
action := common.SplitStrings(e.Action, ",")
if action[0] == actionSMSNotify {
message := fmt.Sprintf("Event triggered: %s", e.String())
s := smsglobal.SMSGlobal
if action[1] == "ALL" {
smsglobal.SMSSendToAll(message, config.Cfg)
s.SendMessageToAll(message)
} else {
smsglobal.SMSNotify(smsglobal.SMSGetNumberByName(action[1],
config.Cfg.SMS), message, config.Cfg,
)
contact, _ := s.GetContactByName(action[1])
s.SendMessage(contact.Number, message)
}
}
} else {
@@ -188,12 +187,7 @@ func IsValidEvent(Exchange, Item, Condition, Action string) error {
Item = common.StringToUpper(Item)
Action = common.StringToUpper(Action)
configPath := ""
if Action == actionTest {
configPath = configPathTest
}
if !IsValidExchange(Exchange, configPath) {
if !IsValidExchange(Exchange) {
return errExchangeDisabled
}
@@ -218,10 +212,12 @@ func IsValidEvent(Exchange, Item, Condition, Action string) error {
return errInvalidAction
}
cfg := config.GetConfig()
if action[1] != "ALL" && smsglobal.SMSGetNumberByName(
action[1], cfg.SMS) == smsglobal.ErrSMSContactNotFound {
return errInvalidAction
if action[1] != "ALL" {
s := smsglobal.SMSGlobal
_, err := s.GetContactByName(action[1])
if err != nil {
return errInvalidAction
}
}
} else {
if Action != actionConsolePrint && Action != actionTest {
@@ -254,14 +250,9 @@ func CheckEvents() {
}
// IsValidExchange validates the exchange
func IsValidExchange(Exchange, configPath string) bool {
func IsValidExchange(Exchange string) bool {
Exchange = common.StringToUpper(Exchange)
cfg := config.GetConfig()
if len(cfg.Exchanges) == 0 {
cfg.LoadConfig(configPath)
}
for _, x := range cfg.Exchanges {
if x.Name == Exchange && x.Enabled {
return true

View File

@@ -64,6 +64,7 @@ type ExchangeMain struct {
// overarching type across this code base.
type Bot struct {
config *config.Config
smsglobal *smsglobal.Base
portfolio *portfolio.Base
exchange ExchangeMain
exchanges []exchange.IBotExchange
@@ -115,14 +116,16 @@ func main() {
log.Fatal(err)
}
AdjustGoMaxProcs()
log.Printf("Bot '%s' started.\n", bot.config.Name)
log.Printf("Fiat display currency: %s.", bot.config.FiatDisplayCurrency)
AdjustGoMaxProcs()
if bot.config.SMS.Enabled {
bot.smsglobal = smsglobal.New(bot.config.SMS.Username, bot.config.SMS.Password,
bot.config.Name, bot.config.SMS.Contacts)
log.Printf(
"SMS support enabled. Number of SMS contacts %d.\n",
smsglobal.GetEnabledSMSContacts(bot.config.SMS),
bot.smsglobal.GetEnabledContacts(),
)
} else {
log.Println("SMS support disabled.")

View File

@@ -3,66 +3,150 @@ package smsglobal
import (
"errors"
"flag"
"log"
"net/url"
"strings"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
)
const (
smsGlobalAPIURL = "http://www.smsglobal.com/http-api.php"
smsGlobalAPIURL = "https://www.smsglobal.com/http-api.php"
// ErrSMSContactNotFound is a general error code for "SMS Contact not found."
ErrSMSContactNotFound = "SMS Contact not found."
errSMSNotSent = "SMS message not sent."
)
// GetEnabledSMSContacts returns how many SMS contacts are enabled in the
// contacts list.
func GetEnabledSMSContacts(smsCfg config.SMSGlobalConfig) int {
// vars for the SMS global package
var (
SMSGlobal *Base
)
// Contact struct stores information related to a SMSGlobal contact
type Contact struct {
Name string `json:"name"`
Number string `json:"number"`
Enabled bool `json:"enabled"`
}
// Base struct stores information related to the SMSGlobal package
type Base struct {
Contacts []Contact `json:"contacts"`
Username string `json:"username"`
Password string `json:"password"`
SendFrom string `json:"send_from"`
}
// New initalises the SMSGlobal var
func New(username, password, sendFrom string, contacts []Contact) *Base {
if username == "" || password == "" || sendFrom == "" || len(contacts) == 0 {
return nil
}
var goodContacts []Contact
for x := range contacts {
if contacts[x].Name != "" || contacts[x].Number != "" {
goodContacts = append(goodContacts, contacts[x])
}
}
SMSGlobal = &Base{
Contacts: goodContacts,
Username: username,
Password: password,
SendFrom: sendFrom,
}
return SMSGlobal
}
// GetEnabledContacts returns how many SMS contacts are enabled in the
// contact list
func (s *Base) GetEnabledContacts() int {
counter := 0
for _, contact := range smsCfg.Contacts {
if contact.Enabled {
for x := range s.Contacts {
if s.Contacts[x].Enabled {
counter++
}
}
return counter
}
// SMSSendToAll sends a message to all enabled contacts in cfg
func SMSSendToAll(message string, cfg config.Config) {
for _, contact := range cfg.SMS.Contacts {
if contact.Enabled && len(contact.Number) == 10 {
err := SMSNotify(contact.Number, message, cfg)
if err != nil {
log.Printf("Unable to send SMS to %s.\n", contact.Name)
}
// GetContactByNumber returns a contact with supplied number
func (s *Base) GetContactByNumber(number string) (Contact, error) {
for x := range s.Contacts {
if s.Contacts[x].Number == number {
return s.Contacts[x], nil
}
}
return Contact{}, errors.New(ErrSMSContactNotFound)
}
// GetContactByName returns a contact with supplied name
func (s *Base) GetContactByName(name string) (Contact, error) {
for x := range s.Contacts {
if common.StringToLower(s.Contacts[x].Name) == common.StringToLower(name) {
return s.Contacts[x], nil
}
}
return Contact{}, errors.New(ErrSMSContactNotFound)
}
// AddContact checks to see if a contact exists and adds them if it doesn't
func (s *Base) AddContact(contact Contact) {
if contact.Name == "" || contact.Number == "" {
return
}
if s.ContactExists(contact) {
return
}
s.Contacts = append(s.Contacts, contact)
}
// ContactExists checks to see if a contact exists
func (s *Base) ContactExists(contact Contact) bool {
for x := range s.Contacts {
if s.Contacts[x].Number == contact.Number && common.StringToLower(s.Contacts[x].Name) == common.StringToLower(contact.Name) {
return true
}
}
return false
}
// RemoveContact removes a contact if it exists
func (s *Base) RemoveContact(contact Contact) {
if !s.ContactExists(contact) {
return
}
for x := range s.Contacts {
if s.Contacts[x].Name == contact.Name && s.Contacts[x].Number == contact.Number {
s.Contacts = append(s.Contacts[:x], s.Contacts[x+1:]...)
return
}
}
}
// SMSGetNumberByName returns contact number by supplied name
func SMSGetNumberByName(name string, smsCfg config.SMSGlobalConfig) string {
for _, contact := range smsCfg.Contacts {
if common.StringToUpper(contact.Name) == common.StringToUpper(name) {
return contact.Number
// SendMessageToAll sends a message to all enabled contacts in cfg
func (s *Base) SendMessageToAll(message string) {
for x := range s.Contacts {
if s.Contacts[x].Enabled {
s.SendMessage(s.Contacts[x].Name, message)
}
}
return ErrSMSContactNotFound
}
// SMSNotify sends a message to an individual contact
func SMSNotify(to, message string, cfg config.Config) error {
// SendMessage sends a message to an individual contact
func (s *Base) SendMessage(to, message string) error {
if flag.Lookup("test.v") != nil {
return nil
}
values := url.Values{}
values.Set("action", "sendsms")
values.Set("user", cfg.SMS.Username)
values.Set("password", cfg.SMS.Password)
values.Set("from", cfg.Name)
values.Set("user", s.Username)
values.Set("password", s.Password)
values.Set("from", s.SendFrom)
values.Set("to", to)
values.Set("text", message)

View File

@@ -1,71 +1,138 @@
package smsglobal
import (
"log"
"testing"
"github.com/thrasher-/gocryptotrader/config"
)
func TestGetEnabledSMSContacts(t *testing.T) {
cfg := config.GetConfig()
err := cfg.LoadConfig(config.ConfigTestFile)
if err != nil {
t.Errorf(
"Test Failed. GetEnabledSMSContacts: Function return is incorrect with, %s.",
err,
)
func TestNew(t *testing.T) {
result := New("", "", "", nil)
if result != nil {
t.Error("Test failed. New: Expected nil result")
}
numberOfContacts := GetEnabledSMSContacts(cfg.SMS)
if numberOfContacts != len(cfg.SMS.Contacts) {
t.Errorf(
"Test Failed. GetEnabledSMSContacts: Function return is incorrect with, %d.",
numberOfContacts,
)
contact := Contact{Name: "bob", Number: "1234", Enabled: true}
var contacts []Contact
contacts = append(contacts, contact)
result = New("bob", "pw", "Skynet", contacts)
if !result.ContactExists(contact) {
t.Error("Test failed. New: Expected contact not found")
}
}
func TestSMSSendToAll(t *testing.T) {
cfg := config.GetConfig()
err := cfg.LoadConfig(config.ConfigTestFile)
if err != nil {
t.Errorf(
"Test Failed. SMSSendToAll: \nFunction return is incorrect with, %s.",
err,
)
}
SMSSendToAll("SMSGLOBAL Test - SMSSENDTOALL", *cfg)
}
func TestGetEnabledContacts(t *testing.T) {
contact := Contact{Name: "bob", Number: "1234", Enabled: true}
var contacts []Contact
contacts = append(contacts, contact)
result := New("bob", "pw", "Skynet", contacts)
func TestSMSGetNumberByName(t *testing.T) {
cfg := config.GetConfig()
err := cfg.LoadConfig(config.ConfigTestFile)
if err != nil {
t.Errorf(
"Test Failed. SMSGetNumberByName: Function return is incorrect with, %s.",
err,
)
}
number := SMSGetNumberByName("StyleGherkin", cfg.SMS)
if number == "" {
t.Error("Test Failed. SMSNotify Error: No number, name not found.")
}
number = SMSGetNumberByName("testy", cfg.SMS)
if number == "" {
t.Error("Test Failed. SMSNotify Error: No number, name not found.")
expected := 1
actual := result.GetEnabledContacts()
if expected != actual {
t.Errorf("Test failed. TestGetEnabledContacts expected %d, got %d",
expected, actual)
}
}
func TestSMSNotify(t *testing.T) {
cfg := config.GetConfig()
err := cfg.LoadConfig(config.ConfigTestFile)
func TestGetContactByNumber(t *testing.T) {
contact := Contact{Name: "bob", Number: "1234", Enabled: true}
var contacts []Contact
contacts = append(contacts, contact)
result := New("bob", "pw", "Skynet", contacts)
actual, err := result.GetContactByNumber(contact.Number)
if err != nil {
t.Errorf(
"Test Failed. SMSNotify: \nFunction return is incorrect with, %s.",
err,
)
t.Fatalf("Test failed. TestGetContactByNumber: %s", err)
}
if actual.Name != contact.Name && actual.Number != contact.Number && actual.Enabled != contact.Enabled {
t.Fatal("Test failed. TestGetContactByNumber: Incorrect values")
}
_, err = result.GetContactByNumber("ASDASDASD")
if err == nil {
t.Fatal("Test failed. TestGetContactByNumber: Returned nil err on non-existant number")
}
// err2 := SMSNotify("+61312112718", "teststring", *cfg)
// if err2 != nil {
// t.Error("Test Failed. SMSNotify: \nError: ", err2)
// }
}
func TestGetContactByName(t *testing.T) {
contact := Contact{Name: "bob", Number: "1234", Enabled: true}
var contacts []Contact
contacts = append(contacts, contact)
result := New("bob", "pw", "Skynet", contacts)
actual, err := result.GetContactByName(contact.Name)
if err != nil {
t.Fatalf("Test failed. TestGetContactByName: %s", err)
}
if actual.Name != contact.Name && actual.Number != contact.Number && actual.Enabled != contact.Enabled {
t.Fatal("Test failed. TestGetContactByName: Incorrect values")
}
_, err = result.GetContactByName("ASDASDASD")
if err == nil {
t.Fatal("Test failed. TestGetContactByName: Returned nil err on non-existant number")
}
}
func TestAddContact(t *testing.T) {
contact := Contact{Name: "bob", Number: "1234", Enabled: true}
var contacts []Contact
contacts = append(contacts, contact)
result := New("bob", "pw", "Skynet", contacts)
// Test adding same contact
result.AddContact(contact)
if result.GetEnabledContacts() > 1 {
t.Fatal("Test failed. TestAddContact: Incorrect values")
}
invalidContact := Contact{Name: "", Number: "", Enabled: true}
result.AddContact(invalidContact)
if result.GetEnabledContacts() > 1 {
t.Fatal("Test failed. TestAddContact: Incorrect values")
}
newContact := Contact{Name: "newContact", Number: "12345", Enabled: true}
result.AddContact(newContact)
if result.GetEnabledContacts() != 2 {
t.Fatal("Test failed. TestAddContact: Incorrect values")
}
}
func TestRemoveContact(t *testing.T) {
contact := Contact{Name: "bob", Number: "1234", Enabled: true}
var contacts []Contact
contacts = append(contacts, contact)
result := New("bob", "pw", "Skynet", contacts)
result.RemoveContact(Contact{Name: "blah", Number: "1234"})
if result.GetEnabledContacts() != 1 {
t.Fatal("Test failed. TestRemoveContact: Incorrect values")
}
result.RemoveContact(contact)
if result.GetEnabledContacts() != 0 {
t.Fatal("Test failed. TestRemoveContact: Incorrect values")
}
}
func TestSendMessageToAll(t *testing.T) {
contact := Contact{Name: "bob", Number: "1234", Enabled: true}
var contacts []Contact
contacts = append(contacts, contact)
result := New("bob", "pw", "Skynet", contacts)
result.SendMessageToAll("hello world")
}
func TestSendMessage(t *testing.T) {
contact := Contact{Name: "bob", Number: "1234", Enabled: true}
var contacts []Contact
contacts = append(contacts, contact)
result := New("bob", "pw", "Skynet", contacts)
err := result.SendMessage(contact.Number, "hello world")
log.Println(err)
t.Log(err)
}