Skip to content

Commit

Permalink
build: output test coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
danroc committed Nov 1, 2024
1 parent 2cd23fe commit 3f66cfe
Show file tree
Hide file tree
Showing 9 changed files with 227 additions and 6 deletions.
1 change: 1 addition & 0 deletions .github/workflows/build-test-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ jobs:
go install mvdan.cc/[email protected]
go install github.com/securego/gosec/v2/cmd/[email protected]
go install github.com/mgechev/[email protected]
go install github.com/boumenot/[email protected]
- name: Build
run: make build
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
/dist/
coverage.out
coverage.xml
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ build: ## Build the binary
go build -ldflags="-s -w" -o ./dist/geoblock ./cmd/geoblock/

test:
go test ./...
go test -coverprofile=coverage.out ./...
gocover-cobertura < coverage.out > coverage.xml

docker: ## Build docker image
docker build -t geoblock .
4 changes: 2 additions & 2 deletions pkg/database/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@ func parseRecords(records [][]string) ([]Entry, error) {
)

if startIP == nil {
return nil, &utils.InvalidIPError{Address: record[0]}
return nil, &utils.ErrInvalidIP{Address: record[0]}
}

if endIP == nil {
return nil, &utils.InvalidIPError{Address: record[1]}
return nil, &utils.ErrInvalidIP{Address: record[1]}
}

entries = append(entries, Entry{
Expand Down
48 changes: 48 additions & 0 deletions pkg/rules/engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,22 @@ func TestEngine_Authorize(t *testing.T) {
},
want: false,
},
{
name: "deny unknown domain",
config: &schema.AccessControl{
Rules: []schema.AccessControlRule{
{
Domains: []string{"example.org"},
Policy: schema.PolicyAllow,
},
},
DefaultPolicy: schema.PolicyDeny,
},
query: &Query{
RequestedDomain: "example.com",
},
want: false,
},
{
name: "allow by network",
config: &schema.AccessControl{
Expand Down Expand Up @@ -150,6 +166,22 @@ func TestEngine_Authorize(t *testing.T) {
},
want: false,
},
{
name: "deny unknown country",
config: &schema.AccessControl{
Rules: []schema.AccessControlRule{
{
Countries: []string{"FR", "US"},
Policy: schema.PolicyAllow,
},
},
DefaultPolicy: schema.PolicyDeny,
},
query: &Query{
SourceCountry: "DE",
},
want: false,
},
{
name: "allow by ASN",
config: &schema.AccessControl{
Expand Down Expand Up @@ -182,6 +214,22 @@ func TestEngine_Authorize(t *testing.T) {
},
want: false,
},
{
name: "deny unknown ASN",
config: &schema.AccessControl{
Rules: []schema.AccessControlRule{
{
AutonomousSystems: []uint32{1111, 2222},
Policy: schema.PolicyAllow,
},
},
DefaultPolicy: schema.PolicyDeny,
},
query: &Query{
SourceASN: 3333,
},
want: false,
},
{
name: "allow by domain, network, country, and ASN",
config: &schema.AccessControl{
Expand Down
1 change: 1 addition & 0 deletions pkg/utils/duration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ func TestParseDuration(t *testing.T) {
"1m 30",
"1m x",
"1m s",
"",
}

for _, input := range invalidDurations {
Expand Down
73 changes: 73 additions & 0 deletions pkg/utils/helpers_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package utils_test

import (
"testing"

"github.com/danroc/geoblock/pkg/utils"
)

func TestAny(t *testing.T) {
tests := []struct {
name string
values []int
f func(int) bool
want bool
}{
{"empty slice", []int{}, func(v int) bool { return v > 0 }, false},
{"no match", []int{1, 2, 3}, func(v int) bool { return v > 3 }, false},
{"one match", []int{1, 2, 3}, func(v int) bool { return v == 2 }, true},
{"all match", []int{1, 2, 3}, func(v int) bool { return v > 0 }, true},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := utils.Any(tt.values, tt.f); got != tt.want {
t.Errorf("Any() = %v, want %v", got, tt.want)
}
})
}
}

func TestAll(t *testing.T) {
tests := []struct {
name string
values []int
f func(int) bool
want bool
}{
{"empty slice", []int{}, func(v int) bool { return v > 0 }, true},
{"no match", []int{1, 2, 3}, func(v int) bool { return v > 3 }, false},
{"one match", []int{1, 2, 3}, func(v int) bool { return v == 2 }, false},
{"all match", []int{1, 2, 3}, func(v int) bool { return v > 0 }, true},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := utils.All(tt.values, tt.f); got != tt.want {
t.Errorf("All() = %v, want %v", got, tt.want)
}
})
}
}

func TestNone(t *testing.T) {
tests := []struct {
name string
values []int
f func(int) bool
want bool
}{
{"empty slice", []int{}, func(v int) bool { return v > 0 }, true},
{"no match", []int{1, 2, 3}, func(v int) bool { return v > 3 }, true},
{"one match", []int{1, 2, 3}, func(v int) bool { return v == 2 }, false},
{"all match", []int{1, 2, 3}, func(v int) bool { return v > 0 }, false},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := utils.None(tt.values, tt.f); got != tt.want {
t.Errorf("None() = %v, want %v", got, tt.want)
}
})
}
}
6 changes: 3 additions & 3 deletions pkg/utils/ip.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ func CompareIP(a net.IP, b net.IP) int {
return bytes.Compare(a, b)
}

// InvalidIPError is used when a give IP address is invalid.
type InvalidIPError struct {
// ErrInvalidIP is used when a give IP address is invalid.
type ErrInvalidIP struct {
Address string
}

// Error returns the error message.
func (e *InvalidIPError) Error() string {
func (e *ErrInvalidIP) Error() string {
return fmt.Sprintf("invalid IP address: %s", e.Address)
}

Expand Down
95 changes: 95 additions & 0 deletions pkg/utils/ip_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package utils_test

import (
"net"
"testing"

"github.com/danroc/geoblock/pkg/utils"
)

func TestCompareIP(t *testing.T) {
tests := []struct {
a, b string
result int
}{
{"192.168.1.1", "192.168.1.1", 0},
{"192.168.1.1", "192.168.1.2", -1},
{"192.168.1.2", "192.168.1.1", 1},
{"::1", "::1", 0},
{"::1", "::2", -1},
{"::2", "::1", 1},
}

for _, test := range tests {
ipA := net.ParseIP(test.a)
ipB := net.ParseIP(test.b)
if ipA == nil || ipB == nil {
t.Fatalf("Invalid IP address in test case: %s, %s", test.a, test.b)
}

result := utils.CompareIP(ipA, ipB)
if result != test.result {
t.Errorf(
"CompareIP(%s, %s) = %d; want %d",
test.a,
test.b,
result,
test.result,
)
}
}
}

func TestIsIPv4(t *testing.T) {
tests := []struct {
ip string
result bool
}{
{"192.168.1.1", true},
{"255.255.255.255", true},
{"0.0.0.0", true},
{"::1", false},
{"2001:db8::68", false},
{"", false},
}

for _, test := range tests {
ip := net.ParseIP(test.ip)
if ip == nil && test.ip != "" {
t.Fatalf("Invalid IP address in test case: %s", test.ip)
}

result := utils.IsIPv4(ip)
if result != test.result {
t.Errorf(
"IsIPv4(%s) = %t; want %t",
test.ip,
result,
test.result,
)
}
}
}

func TestErrInvalidIP(t *testing.T) {
tests := []struct {
address string
message string
}{
{"256.256.256.256", "invalid IP address: 256.256.256.256"},
{"invalid-ip", "invalid IP address: invalid-ip"},
{"", "invalid IP address: "},
}

for _, test := range tests {
err := &utils.ErrInvalidIP{Address: test.address}
if err.Error() != test.message {
t.Errorf(
"ErrInvalidIP(%s).Error() = %s; want %s",
test.address,
err.Error(),
test.message,
)
}
}
}

0 comments on commit 3f66cfe

Please sign in to comment.