Skip to content

Commit e758473

Browse files
authored
Upgrade libs and add tests (#53)
* chore: add unit tests for helper, cache, geolocation, and modules packages * chore: add end-to-end tests and update Taskfile with e2e targets * chore: add GitHub Actions CI workflow for build and test * chore: add GitHub Actions CI workflow for build and test
1 parent b903eff commit e758473

24 files changed

Lines changed: 2493 additions & 34 deletions

.github/workflows/ci.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [ "**" ]
6+
pull_request:
7+
branches: [ "**" ]
8+
9+
jobs:
10+
ci:
11+
name: Build & Test
12+
runs-on: ubuntu-latest
13+
14+
steps:
15+
- uses: actions/checkout@v6
16+
17+
- name: Set up Go
18+
uses: actions/setup-go@v6
19+
with:
20+
go-version-file: go.mod
21+
22+
- name: Download dependencies
23+
run: go mod download
24+
25+
- name: Build
26+
run: go build ./...
27+
28+
- name: Unit tests
29+
run: go test $(go list ./... | grep -v '/e2e')
30+
31+
- name: E2E tests
32+
run: go test ./e2e/...

README.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,3 @@ No special flags.
110110
./endlessh_analyzer analyze --target=analyze.txt # Generate analysis
111111
./endlessh_analyzer export json --start-date=2021-07-16 --end-date=2021-07-18 --target=export.json # Exports a given data range to json format
112112
```
113-
114-
## Known issues
115-
116-
Tests missing O_o

Taskfile.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,18 @@ tasks:
1010
desc: Build the binary
1111
cmd: go build .
1212

13+
test:
14+
desc: Run unit tests (excludes e2e)
15+
cmd: go test $(go list ./... | grep -v '/e2e')
16+
17+
e2e:
18+
desc: Run end-to-end tests only
19+
cmd: go test ./e2e/...
20+
21+
test:all:
22+
desc: Run all tests (unit + e2e)
23+
cmd: go test ./...
24+
1325
clean:
1426
desc: Cleanup dependencies
1527
cmd: go mod tidy

analyze/statistics/attackTimeStatistics.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,16 +76,15 @@ func GetAttackTimeStatistics(db *database.DbData, start *time2.Time, end *time2.
7676
builder := new(strings.Builder)
7777

7878
table := tablewriter.NewWriter(builder)
79-
table.SetHeader([]string{mode.label, "Attacks"})
80-
table.SetAutoWrapText(false)
79+
table.Header(mode.label, "Attacks")
8180

8281
p := message.NewPrinter(language.English)
8382
for _, item := range dataRows {
8483
line := []string{item[0], p.Sprint(item[1])}
85-
table.Append(line)
84+
_ = table.Append(line)
8685
}
8786

88-
table.Render()
87+
_ = table.Render()
8988

9089
return " " + strings.ToUpper(mode.label) + " ATTACKER STATISTICS\n" + builder.String(), nil
9190
}

analyze/statistics/headStatistics.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package statistics
33
import (
44
"github.com/hako/durafmt"
55
"github.com/olekukonko/tablewriter"
6+
"github.com/olekukonko/tablewriter/tw"
67
"golang.org/x/text/language"
78
"golang.org/x/text/message"
89
"strconv"
@@ -52,11 +53,12 @@ func GetHeadStatistics(db *database.DbData, start *time2.Time, end *time2.Time,
5253
builder := new(strings.Builder)
5354

5455
table := tablewriter.NewWriter(builder)
55-
table.SetHeader([]string{"Attack", ""})
56-
table.SetAutoWrapText(false)
57-
table.SetAlignment(tablewriter.ALIGN_LEFT)
58-
table.AppendBulk(data)
59-
table.Render()
56+
table.Header("Attack", "")
57+
table.Configure(func(cfg *tablewriter.Config) {
58+
cfg.Row.Alignment.Global = tw.AlignLeft
59+
})
60+
_ = table.Bulk(data)
61+
_ = table.Render()
6062

6163
return " GLOBAL STATISTICS\n" + builder.String()
6264
}
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
package statistics
2+
3+
import (
4+
"strconv"
5+
"testing"
6+
)
7+
8+
// --- weekdays slice ---
9+
10+
func TestWeekdays_HasSevenEntries(t *testing.T) {
11+
if len(weekdays) != 7 {
12+
t.Errorf("expected 7 weekdays, got %d", len(weekdays))
13+
}
14+
}
15+
16+
func TestWeekdays_StartsWithSunday(t *testing.T) {
17+
// SQLite strftime('%w') returns 0 for Sunday
18+
if weekdays[0] != "Sunday" {
19+
t.Errorf("expected weekdays[0]='Sunday', got '%s'", weekdays[0])
20+
}
21+
}
22+
23+
func TestWeekdays_EndsWithSaturday(t *testing.T) {
24+
if weekdays[6] != "Saturday" {
25+
t.Errorf("expected weekdays[6]='Saturday', got '%s'", weekdays[6])
26+
}
27+
}
28+
29+
func TestWeekdays_AllDaysPresent(t *testing.T) {
30+
expected := []string{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}
31+
for i, want := range expected {
32+
if weekdays[i] != want {
33+
t.Errorf("weekdays[%d]: expected '%s', got '%s'", i, want, weekdays[i])
34+
}
35+
}
36+
}
37+
38+
// --- months slice ---
39+
40+
func TestMonths_HasTwelveEntries(t *testing.T) {
41+
if len(months) != 12 {
42+
t.Errorf("expected 12 months, got %d", len(months))
43+
}
44+
}
45+
46+
func TestMonths_StartsWithJanuary(t *testing.T) {
47+
// SQLite strftime('%m') returns "01" for January → index months[0]
48+
if months[0] != "January" {
49+
t.Errorf("expected months[0]='January', got '%s'", months[0])
50+
}
51+
}
52+
53+
func TestMonths_EndsWithDecember(t *testing.T) {
54+
if months[11] != "December" {
55+
t.Errorf("expected months[11]='December', got '%s'", months[11])
56+
}
57+
}
58+
59+
func TestMonths_AllMonthsPresent(t *testing.T) {
60+
expected := []string{
61+
"January", "February", "March", "April", "May", "June",
62+
"July", "August", "September", "October", "November", "December",
63+
}
64+
for i, want := range expected {
65+
if months[i] != want {
66+
t.Errorf("months[%d]: expected '%s', got '%s'", i, want, months[i])
67+
}
68+
}
69+
}
70+
71+
// --- Month index mapping (strftime returns 1-based "01".."12") ---
72+
73+
func TestMonths_IndexMapping_StrftimeValue01_IsJanuary(t *testing.T) {
74+
// Simulates the code: val, _ := strconv.Atoi("01"); months[val-1]
75+
val, _ := strconv.Atoi("01")
76+
if months[val-1] != "January" {
77+
t.Errorf("strftime '01' → expected 'January', got '%s'", months[val-1])
78+
}
79+
}
80+
81+
func TestMonths_IndexMapping_StrftimeValue12_IsDecember(t *testing.T) {
82+
val, _ := strconv.Atoi("12")
83+
if months[val-1] != "December" {
84+
t.Errorf("strftime '12' → expected 'December', got '%s'", months[val-1])
85+
}
86+
}
87+
88+
func TestMonths_IndexMapping_StrftimeValue06_IsJune(t *testing.T) {
89+
val, _ := strconv.Atoi("06")
90+
if months[val-1] != "June" {
91+
t.Errorf("strftime '06' → expected 'June', got '%s'", months[val-1])
92+
}
93+
}
94+
95+
// --- TimeStatistic structs (DAY, MONTH, YEAR) ---
96+
97+
func TestTimeStatistic_DAY_HasCorrectLabel(t *testing.T) {
98+
if DAY.label != "Weekday" {
99+
t.Errorf("expected DAY.label='Weekday', got '%s'", DAY.label)
100+
}
101+
}
102+
103+
func TestTimeStatistic_DAY_HasCorrectFormat(t *testing.T) {
104+
if DAY.format != "%w" {
105+
t.Errorf("expected DAY.format='%%w', got '%s'", DAY.format)
106+
}
107+
}
108+
109+
func TestTimeStatistic_MONTH_HasCorrectLabel(t *testing.T) {
110+
if MONTH.label != "Month" {
111+
t.Errorf("expected MONTH.label='Month', got '%s'", MONTH.label)
112+
}
113+
}
114+
115+
func TestTimeStatistic_MONTH_HasCorrectFormat(t *testing.T) {
116+
if MONTH.format != "%m %Y" {
117+
t.Errorf("expected MONTH.format='%%m %%Y', got '%s'", MONTH.format)
118+
}
119+
}
120+
121+
func TestTimeStatistic_YEAR_HasCorrectLabel(t *testing.T) {
122+
if YEAR.label != "Year" {
123+
t.Errorf("expected YEAR.label='Year', got '%s'", YEAR.label)
124+
}
125+
}
126+
127+
func TestTimeStatistic_YEAR_HasCorrectFormat(t *testing.T) {
128+
if YEAR.format != "%Y" {
129+
t.Errorf("expected YEAR.format='%%Y', got '%s'", YEAR.format)
130+
}
131+
}
132+
133+
// --- Weekday index mapping (strftime '%w' returns "0".."6") ---
134+
135+
func TestWeekdays_IndexMapping_StrftimeValue0_IsSunday(t *testing.T) {
136+
val, _ := strconv.Atoi("0")
137+
if weekdays[val] != "Sunday" {
138+
t.Errorf("strftime '0' → expected 'Sunday', got '%s'", weekdays[val])
139+
}
140+
}
141+
142+
func TestWeekdays_IndexMapping_StrftimeValue6_IsSaturday(t *testing.T) {
143+
val, _ := strconv.Atoi("6")
144+
if weekdays[val] != "Saturday" {
145+
t.Errorf("strftime '6' → expected 'Saturday', got '%s'", weekdays[val])
146+
}
147+
}
148+
149+
func TestWeekdays_IndexMapping_StrftimeValue3_IsWednesday(t *testing.T) {
150+
val, _ := strconv.Atoi("3")
151+
if weekdays[val] != "Wednesday" {
152+
t.Errorf("strftime '3' → expected 'Wednesday', got '%s'", weekdays[val])
153+
}
154+
}

analyze/statistics/topStatistics.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,7 @@ func GetTopStatistics(db *database.DbData, start *time2.Time, end *time2.Time, d
4242
builder := new(strings.Builder)
4343

4444
table := tablewriter.NewWriter(builder)
45-
table.SetHeader([]string{"Rank", "Country", "Attacks", "Sum attack time", "Avg attack time"})
46-
table.SetAutoWrapText(false)
45+
table.Header("Rank", "Country", "Attacks", "Sum attack time", "Avg attack time")
4746

4847
p := message.NewPrinter(language.English)
4948
for idx, item := range dataRows {
@@ -54,10 +53,10 @@ func GetTopStatistics(db *database.DbData, start *time2.Time, end *time2.Time, d
5453
avgTFormat, _ := durafmt.ParseString(avgT.String())
5554

5655
line := []string{strconv.Itoa(idx + 1), item[0], p.Sprint(item[1]), sumTFormat.String(), avgTFormat.String()}
57-
table.Append(line)
56+
_ = table.Append(line)
5857
}
5958

60-
table.Render()
59+
_ = table.Render()
6160

6261
return " TOP 5 ATTACKER COUNTRY STATISTICS\n" + builder.String(), nil
6362
}

0 commit comments

Comments
 (0)