From 4213243744e7d960fbb1b98a3ad5a68cee95c68e Mon Sep 17 00:00:00 2001 From: cws Date: Mon, 5 Jun 2017 21:20:08 -0400 Subject: [PATCH] stats: Add a day categorization above all others --- plugins/stats/stats.go | 49 +++++++++++++++++++++++-------- plugins/stats/stats_test.go | 57 ++++++++++++++++--------------------- 2 files changed, 62 insertions(+), 44 deletions(-) diff --git a/plugins/stats/stats.go b/plugins/stats/stats.go index 01cabcf..58d652c 100644 --- a/plugins/stats/stats.go +++ b/plugins/stats/stats.go @@ -31,9 +31,17 @@ func New(bot bot.Bot) *StatsPlugin { } type stat struct { + // date formatted: "2006-01-02" + day string + // category bucket string - key string - val value + // specific unique individual + key string + val value +} + +func mkDay() string { + return time.Now().Format("2006-01-02") } // The value type is here in the future growth case that we might want to put a @@ -53,13 +61,16 @@ func valueFromBytes(b []byte) (value, error) { type stats []stat -func mkStat(bucket, key, val []byte) (stat, error) { +// mkStat converts raw data to a stat struct +// Expected a string representation of the date formatted: "2006-01-02" +func mkStat(day string, bucket, key, val []byte) (stat, error) { v, err := valueFromBytes(val) if err != nil { log.Printf("mkStat: error getting value from bytes: %s", err) return stat{}, err } return stat{ + day: day, bucket: string(bucket), key: string(key), val: v, @@ -71,7 +82,9 @@ func (v value) add(other value) value { return v + other } -func statFromDB(path, bucket, key string) (stat, error) { +// statFromDB takes a location specification and returns the data at that path +// Expected a string representation of the date formatted: "2006-01-02" +func statFromDB(path, day, bucket, key string) (stat, error) { db, err := bolt.Open(path, 0600, &bolt.Options{ Timeout: 1 * time.Second, }) @@ -90,11 +103,17 @@ func statFromDB(path, bucket, key string) (stat, error) { } defer tx.Rollback() - b, err := tx.CreateBucketIfNotExists(buk) + d, err := tx.CreateBucketIfNotExists([]byte(day)) if err != nil { log.Println("statFromDB: Error creating the bucket") return stat{}, err } + b, err := d.CreateBucketIfNotExists(buk) + if err != nil { + log.Println("statFromDB: Error creating the bucket") + return stat{}, err + } + v := b.Get(k) if err := tx.Commit(); err != nil { @@ -103,12 +122,13 @@ func statFromDB(path, bucket, key string) (stat, error) { } if v == nil { - return stat{bucket, key, 0}, nil + return stat{day, bucket, key, 0}, nil } - return mkStat(buk, k, v) + return mkStat(day, buk, k, v) } +// toDB takes a stat and records it, adding to the value in the DB if necessary func (s stats) toDB(path string) error { db, err := bolt.Open(path, 0600, &bolt.Options{Timeout: 1 * time.Second}) if err != nil { @@ -119,7 +139,12 @@ func (s stats) toDB(path string) error { for _, stat := range s { err = db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucketIfNotExists([]byte(stat.bucket)) + d, err := tx.CreateBucketIfNotExists([]byte(stat.day)) + if err != nil { + log.Println("toDB: Error creating bucket") + return err + } + b, err := d.CreateBucketIfNotExists([]byte(stat.bucket)) if err != nil { log.Println("toDB: Error creating bucket") return err @@ -192,24 +217,24 @@ func (p *StatsPlugin) RegisterWeb() *string { } func (p *StatsPlugin) mkUserStat(message msg.Message) stats { - return stats{stat{"user", message.User.Name, 1}} + return stats{stat{mkDay(), "user", message.User.Name, 1}} } func (p *StatsPlugin) mkHourStat(message msg.Message) stats { hr := time.Now().Hour() - return stats{stat{"user", string(hr), 1}} + return stats{stat{mkDay(), "user", string(hr), 1}} } func (p *StatsPlugin) mkSightingStat(message msg.Message) stats { stats := stats{} for _, name := range p.bot.Config().Stats.Sightings { if strings.Contains(message.Body, name+" sighting") { - stats = append(stats, stat{"sighting", name, 1}) + stats = append(stats, stat{mkDay(), "sighting", name, 1}) } } return stats } func (p *StatsPlugin) mkChannelStat(message msg.Message) stats { - return stats{stat{"channel", message.Channel, 1}} + return stats{stat{mkDay(), "channel", message.Channel, 1}} } diff --git a/plugins/stats/stats_test.go b/plugins/stats/stats_test.go index 2c95bf4..d5597f4 100644 --- a/plugins/stats/stats_test.go +++ b/plugins/stats/stats_test.go @@ -47,10 +47,12 @@ func TestWithDB(t *testing.T) { rmDB(t) t.Run("TestDBReadWrite", func(t *testing.T) { + day := mkDay() bucket := "testBucket" key := "testKey" expected := stats{stat{ + day, bucket, key, 1, @@ -59,7 +61,7 @@ func TestWithDB(t *testing.T) { err := expected.toDB(dbPath) assert.Nil(t, err) - actual, err := statFromDB(dbPath, bucket, key) + actual, err := statFromDB(dbPath, day, bucket, key) assert.Nil(t, err) assert.Equal(t, actual, expected[0]) @@ -69,11 +71,13 @@ func TestWithDB(t *testing.T) { rmDB(t) t.Run("TestDBAddStatInLoop", func(t *testing.T) { + day := mkDay() bucket := "testBucket" key := "testKey" expected := value(25) statPack := stats{stat{ + day, bucket, key, 5, @@ -84,7 +88,7 @@ func TestWithDB(t *testing.T) { assert.Nil(t, err) } - actual, err := statFromDB(dbPath, bucket, key) + actual, err := statFromDB(dbPath, day, bucket, key) assert.Nil(t, err) assert.Equal(t, actual.val, expected) @@ -93,42 +97,25 @@ func TestWithDB(t *testing.T) { rmDB(t) t.Run("TestDBAddStats", func(t *testing.T) { + day := mkDay() bucket := "testBucket" key := "testKey" expected := value(5) - statPack := stats{ - stat{ + statPack := stats{} + for i := 0; i < 5; i++ { + statPack = append(statPack, stat{ + day, bucket, key, 1, - }, - stat{ - bucket, - key, - 1, - }, - stat{ - bucket, - key, - 1, - }, - stat{ - bucket, - key, - 1, - }, - stat{ - bucket, - key, - 1, - }, + }) } err := statPack.toDB(dbPath) assert.Nil(t, err) - actual, err := statFromDB(dbPath, bucket, key) + actual, err := statFromDB(dbPath, day, bucket, key) assert.Nil(t, err) assert.Equal(t, actual.val, expected) @@ -151,6 +138,7 @@ func makeMessage(payload string) msg.Message { } func testUserCounter(t *testing.T, count int) { + day := mkDay() expected := value(count) mb := bot.NewMockBot() mb.Cfg.Stats.DBPath = dbPath @@ -164,7 +152,7 @@ func testUserCounter(t *testing.T, count int) { _, err := os.Stat(dbPath) assert.Nil(t, err) - stat, err := statFromDB(mb.Config().Stats.DBPath, "user", "tester") + stat, err := statFromDB(mb.Config().Stats.DBPath, day, "user", "tester") assert.Nil(t, err) actual := stat.val assert.Equal(t, actual, expected) @@ -175,6 +163,7 @@ func TestMessages(t *testing.T) { assert.NotNil(t, err) t.Run("TestOneUserCounter", func(t *testing.T) { + day := mkDay() count := 5 expected := value(count) mb := bot.NewMockBot() @@ -189,7 +178,7 @@ func TestMessages(t *testing.T) { _, err := os.Stat(dbPath) assert.Nil(t, err) - stat, err := statFromDB(mb.Config().Stats.DBPath, "user", "tester") + stat, err := statFromDB(mb.Config().Stats.DBPath, day, "user", "tester") assert.Nil(t, err) actual := stat.val assert.Equal(t, actual, expected) @@ -198,6 +187,7 @@ func TestMessages(t *testing.T) { rmDB(t) t.Run("TestTenUserCounter", func(t *testing.T) { + day := mkDay() count := 5 expected := value(count) mb := bot.NewMockBot() @@ -212,7 +202,7 @@ func TestMessages(t *testing.T) { _, err := os.Stat(dbPath) assert.Nil(t, err) - stat, err := statFromDB(mb.Config().Stats.DBPath, "user", "tester") + stat, err := statFromDB(mb.Config().Stats.DBPath, day, "user", "tester") assert.Nil(t, err) actual := stat.val assert.Equal(t, actual, expected) @@ -221,6 +211,7 @@ func TestMessages(t *testing.T) { rmDB(t) t.Run("TestChannelCounter", func(t *testing.T) { + day := mkDay() count := 5 expected := value(count) mb := bot.NewMockBot() @@ -235,7 +226,7 @@ func TestMessages(t *testing.T) { _, err := os.Stat(dbPath) assert.Nil(t, err) - stat, err := statFromDB(mb.Config().Stats.DBPath, "channel", "test") + stat, err := statFromDB(mb.Config().Stats.DBPath, day, "channel", "test") assert.Nil(t, err) actual := stat.val assert.Equal(t, actual, expected) @@ -244,6 +235,7 @@ func TestMessages(t *testing.T) { rmDB(t) t.Run("TestSightingCounter", func(t *testing.T) { + day := mkDay() count := 5 expected := value(count) mb := bot.NewMockBot() @@ -261,7 +253,7 @@ func TestMessages(t *testing.T) { _, err := os.Stat(dbPath) assert.Nil(t, err) - stat, err := statFromDB(mb.Config().Stats.DBPath, "sighting", "user") + stat, err := statFromDB(mb.Config().Stats.DBPath, day, "sighting", "user") assert.Nil(t, err) actual := stat.val assert.Equal(t, actual, expected) @@ -270,6 +262,7 @@ func TestMessages(t *testing.T) { rmDB(t) t.Run("TestSightingCounterNoResults", func(t *testing.T) { + day := mkDay() count := 5 expected := value(0) mb := bot.NewMockBot() @@ -287,7 +280,7 @@ func TestMessages(t *testing.T) { _, err := os.Stat(dbPath) assert.Nil(t, err) - stat, err := statFromDB(mb.Config().Stats.DBPath, "sighting", "user") + stat, err := statFromDB(mb.Config().Stats.DBPath, day, "sighting", "user") assert.Nil(t, err) actual := stat.val assert.Equal(t, actual, expected)