Skip to content

Commit 7015110

Browse files
authored
Add /kills command with save state functionality (#4)
* Add /kills command with save state functionality CHANGELOG: - Kills state it's loaded at session start, if doesn't exists set to 0. - Kills state it's saved on the file kills.txt - Kills state it's saved after each ban, to ensure being saved. - If /kills it's called will report the current kills state. * Add unit tests * Improve test coverage on edge cases: fix some behaviors too Important fix: os.O_TRUNC should be set as flag in os.OpenFile to overwrite the kills.txt file properly. Otherwise, ff the kills.txt had initially "random-fuckups", writing 10 will turn out in: "10ndom-fuckups". This is not the intended behavior. * Separate main function in main.go and mark as !test This will make more easier to control the unit tests, since main is not possible to test.
1 parent fd460de commit 7015110

File tree

5 files changed

+149
-38
lines changed

5 files changed

+149
-38
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ jobs:
4747
- name: Calc coverage
4848
run: |
4949
export PATH=$PATH:$(go env GOPATH)/bin
50-
go test -v -covermode=count -coverprofile=coverage.out
50+
go test -v -covermode=count -tags test -coverprofile=coverage.out
5151
- name: Convert coverage to lcov
5252
uses: jandelgado/gcov2lcov-action@v1.0.0
5353
with:

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@
1717
/troll-shield
1818

1919
*.log
20+
/kills.txt

main.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
//+build !test
2+
// Copyright 2020 the commonlispbr authors. All rights reserved
3+
// Use of this source code is governed by a BSD-style
4+
// license that can be found in the LICENSE file.
5+
6+
package main
7+
8+
import (
9+
"strings"
10+
)
11+
12+
func main() {
13+
setupLogging()
14+
bot, botHidden, err := setupBots()
15+
if err != nil {
16+
log.Fatal(err.Error())
17+
}
18+
kills := loadKills(killsFile)
19+
log.Printf("Currently kill state: %v", kills)
20+
21+
for update := range getUpdates(bot) {
22+
if messageEvent(&update) {
23+
if update.Message.Text == "/lelerax" {
24+
reply(bot, &update, "Estou vivo.")
25+
}
26+
27+
if update.Message.Text == "/kills" {
28+
reportKills(bot, &update, kills)
29+
}
30+
31+
// Exit automatically from group after the bot receive a message from it
32+
for _, trollGroup := range trollGroups {
33+
if fromChatEvent(&update, strings.TrimLeft(trollGroup, "@")) {
34+
leaveChat(bot, &update, trollGroup)
35+
}
36+
}
37+
}
38+
39+
if newChatMemberEvent(&update) {
40+
for _, member := range *update.Message.NewChatMembers {
41+
if trollHouse := findTrollHouses(botHidden, member.ID); trollHouse != "" {
42+
err := kickTroll(bot, &update, member, trollHouse)
43+
if err == nil {
44+
kills++
45+
if err := saveKills(killsFile, kills); err != nil {
46+
log.Printf("saving kills failed: %v", err)
47+
}
48+
}
49+
} else if fromChatEvent(&update, "commonlispbr") && !member.IsBot {
50+
welcomeMessage(bot, &update, member)
51+
}
52+
53+
// Exit automatically from groups when I'm joining it
54+
for _, trollGroup := range trollGroups {
55+
if fromChatEvent(&update, strings.TrimLeft(trollGroup, "@")) && member.UserName == bot.Self.UserName {
56+
leaveChat(bot, &update, trollGroup)
57+
}
58+
}
59+
60+
}
61+
}
62+
}
63+
}

troll_shield.go

Lines changed: 32 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ package main
77
import (
88
"fmt"
99
"io"
10+
"io/ioutil"
1011
logger "log"
1112
"os"
13+
"strconv"
1214
"strings"
1315
"sync"
1416

@@ -38,6 +40,7 @@ var trollGroups = []string{
3840
}
3941

4042
const logfile = "troll-shield.log"
43+
const killsFile = "kills.txt"
4144

4245
var log = logger.New(os.Stderr, "", logger.LstdFlags)
4346

@@ -139,7 +142,7 @@ func findTrollHouses(bot TrollShieldBot, userID int) string {
139142
}
140143

141144
// kickTroll ban the troll and send a message about where we can found the trolls
142-
func kickTroll(bot TrollShieldBot, update *telegram.Update, user telegram.User, trollHouse string) {
145+
func kickTroll(bot TrollShieldBot, update *telegram.Update, user telegram.User, trollHouse string) error {
143146
chatMember := telegram.ChatMemberConfig{
144147
ChatID: update.Message.Chat.ID,
145148
UserID: user.ID,
@@ -161,6 +164,8 @@ func kickTroll(bot TrollShieldBot, update *telegram.Update, user telegram.User,
161164
)
162165
reply(bot, update, text)
163166
}
167+
168+
return err
164169
}
165170

166171
func setupLogging() {
@@ -229,43 +234,35 @@ func leaveChat(bot TrollShieldBot, update *telegram.Update, trollGroup string) {
229234
}
230235
}
231236

232-
func main() {
233-
setupLogging()
234-
bot, botHidden, err := setupBots()
235-
if err != nil {
236-
log.Fatal(err.Error())
237+
func loadKills(fpath string) int64 {
238+
dat, err := ioutil.ReadFile(fpath)
239+
if err == nil {
240+
i, err := strconv.Atoi(strings.TrimSpace(string(dat)))
241+
if err != nil {
242+
log.Printf("Parsing %q go bad, got error: %v", fpath, err)
243+
} else {
244+
return int64(i)
245+
}
237246
}
238247

239-
for update := range getUpdates(bot) {
240-
if messageEvent(&update) {
241-
if update.Message.Text == "/lelerax" {
242-
reply(bot, &update, "Estou vivo.")
243-
}
244-
245-
// Exit automatically from group after the bot receive a message from it
246-
for _, trollGroup := range trollGroups {
247-
if fromChatEvent(&update, strings.TrimLeft(trollGroup, "@")) {
248-
leaveChat(bot, &update, trollGroup)
249-
}
250-
}
251-
}
248+
return 0
249+
}
252250

253-
if newChatMemberEvent(&update) {
254-
for _, member := range *update.Message.NewChatMembers {
255-
if trollHouse := findTrollHouses(botHidden, member.ID); trollHouse != "" {
256-
kickTroll(bot, &update, member, trollHouse)
257-
} else if fromChatEvent(&update, "commonlispbr") && !member.IsBot {
258-
welcomeMessage(bot, &update, member)
259-
}
260-
261-
// Exit automatically from groups when I'm joining it
262-
for _, trollGroup := range trollGroups {
263-
if fromChatEvent(&update, strings.TrimLeft(trollGroup, "@")) && member.UserName == bot.Self.UserName {
264-
leaveChat(bot, &update, trollGroup)
265-
}
266-
}
251+
func saveKills(fpath string, kills int64) error {
252+
f, err := os.OpenFile(fpath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666)
253+
if err == nil {
254+
_, err = f.WriteString(strconv.FormatInt(kills, 10))
255+
}
256+
if e := f.Close(); e != nil {
257+
err = e
258+
}
259+
return err
260+
}
267261

268-
}
269-
}
262+
func reportKills(bot TrollShieldBot, update *telegram.Update, kills int64) {
263+
txt := fmt.Sprintf("%v foram sacrificados.", kills)
264+
if kills%2 == 0 {
265+
txt = fmt.Sprintf("Já taquei o pau em %v trolls!", kills)
270266
}
267+
reply(bot, update, txt)
271268
}

troll_shield_test.go

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package main
22

33
import (
44
"errors"
5+
"io/ioutil"
56
"os"
67
"testing"
78

@@ -142,9 +143,13 @@ func TestKickTroll(t *testing.T) {
142143
message.Chat = &chat
143144
update.Message = &message
144145
user := telegram.User{}
145-
kickTroll(&botnilson, &update, user, "@trollhouse")
146+
if err := kickTroll(&botnilson, &update, user, "@trollhouse"); err != nil {
147+
t.Errorf("kickTroll error: %v", err)
148+
}
146149
user.ID = 1
147-
kickTroll(&botnilson, &update, user, "@trollhouse")
150+
if err := kickTroll(&botnilson, &update, user, "@trollhouse"); err == nil {
151+
t.Errorf("kickTroll should fail, but got: %v", err)
152+
}
148153
}
149154

150155
func TestWelcomeMessage(t *testing.T) {
@@ -202,3 +207,48 @@ func TestGetUpdates(t *testing.T) {
202207
bot := BotMockup{}
203208
getUpdates(&bot)
204209
}
210+
211+
func TestSaveLoadKills(t *testing.T) {
212+
tmpfile, err := ioutil.TempFile("", "kills.txt")
213+
if err != nil {
214+
t.Fatal(err)
215+
}
216+
content := []byte("isso-nao-eh-um-numero")
217+
if _, err := tmpfile.Write(content); err != nil {
218+
t.Fatal(err)
219+
}
220+
221+
if kills := loadKills(tmpfile.Name()); kills != 0 {
222+
t.Errorf("loadKills should return 0 when there is a invalid number, got: %v", kills)
223+
}
224+
225+
// write 10
226+
if err := saveKills(tmpfile.Name(), 10); err != nil {
227+
t.Errorf("saveKills failed: %v", err)
228+
}
229+
230+
// read 10
231+
if kills := loadKills(tmpfile.Name()); kills != 10 {
232+
t.Errorf("Save/Load of KillCounter didn't worked, expected 10, got %v", kills)
233+
}
234+
235+
if err := tmpfile.Close(); err != nil {
236+
t.Fatal(err)
237+
}
238+
239+
if err := os.Remove(tmpfile.Name()); err != nil {
240+
t.Fatal(err)
241+
}
242+
243+
}
244+
245+
func TestReportKills(t *testing.T) {
246+
bot := BotMockup{}
247+
update := telegram.Update{}
248+
message := telegram.Message{}
249+
chat := telegram.Chat{}
250+
message.Chat = &chat
251+
update.Message = &message
252+
reportKills(&bot, &update, int64(11))
253+
reportKills(&bot, &update, int64(10))
254+
}

0 commit comments

Comments
 (0)