Files
gemini-grc/gopher/network_test.go
antanst a8173544e7 Update and refactor core functionality
- Update common package utilities
- Refactor network code for better error handling
- Remove deprecated files and functionality
- Enhance blacklist and filtering capabilities
- Improve snapshot handling and processing
2025-06-29 22:38:38 +03:00

299 lines
7.5 KiB
Go

package gopher
import (
"net"
"testing"
"gemini-grc/common/errors"
"gemini-grc/config"
"github.com/stretchr/testify/assert"
)
func TestConstructPayloadFromPath(t *testing.T) {
tests := []struct {
name string
input string
expected string
}{
{
name: "Path with Gopher item type",
input: "/1/path/to/resource",
expected: "/path/to/resource",
},
{
name: "Path with different item type",
input: "/0/another/path",
expected: "/another/path",
},
{
name: "Path without item type but with leading slash",
input: "/simple/path",
expected: "/simple/path",
},
{
name: "Path without item type and without leading slash",
input: "no/leading/slash",
expected: "/no/leading/slash",
},
{
name: "Empty path",
input: "",
expected: "/",
},
{
name: "Single character item type",
input: "/h/homepage",
expected: "/homepage",
},
{
name: "Single slash",
input: "/",
expected: "/",
},
{
name: "Item type-looking path",
input: "/1",
expected: "/1",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := constructPayloadFromPath(tt.input)
if result != tt.expected {
t.Errorf("constructPayloadFromPath(%q) = %q, want %q",
tt.input, result, tt.expected)
}
})
}
}
func TestParseLinks(t *testing.T) {
tests := []struct {
name string
currentURL string
input string
want int // number of expected links
wantErr bool
}{
{
name: "Empty input",
currentURL: "gopher://example.com:70",
input: "",
want: 0,
wantErr: false,
},
{
name: "Single directory link",
currentURL: "gopher://example.com:70",
input: "1About Us\t/about\texample.com",
want: 1,
wantErr: false,
},
{
name: "Single text file link",
currentURL: "gopher://example.com:70",
input: "0README\t/readme.txt\texample.com",
want: 1,
wantErr: false,
},
{
name: "Multiple links of different types",
currentURL: "gopher://example.com:70",
input: "1About Us\t/about\texample.com\n0README\t/readme.txt\texample.com\n1Contact\t/contact\texample.com",
want: 3,
wantErr: false,
},
{
name: "Ignore non-linkable types",
currentURL: "gopher://example.com:70",
input: "iInfo line\t/info\texample.com\n1Directory\t/dir\texample.com\n0Text\t/text.txt\texample.com",
want: 2,
wantErr: false,
},
{
name: "Malformed lines",
currentURL: "gopher://example.com:70",
input: "1Incomplete line\n0No tabs\n1Missing parts\t",
want: 0,
wantErr: false,
},
{
name: "Mixed valid and invalid lines",
currentURL: "gopher://example.com:70",
input: "1Valid link\t/valid\texample.com\n1Incomplete\t\n0Text file\t/text.txt\texample.com\n1Another valid\t/another\texample.com",
want: 3,
wantErr: false,
},
{
name: "Absolute URLs",
currentURL: "gopher://example.com:70",
input: "1External link\tgopher://external.com/path\texternal.com\n0Document\tgopher://other.com/doc.txt\tother.com",
want: 2,
wantErr: false,
},
{
name: "With whitespace",
currentURL: "gopher://example.com:70",
input: " 1Padded line \t/padded\texample.com\n0Text file \t/doc.txt\texample.com",
want: 2,
wantErr: false,
},
{
name: "Special characters in paths",
currentURL: "gopher://example.com:70",
input: "1Special chars\t/path with spaces\texample.com\n0Doc\t/über/päth.txt\texample.com",
want: 2,
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := getGopherPageLinks(tt.input)
assert.Equal(t, tt.want, len(got), "expected %d links, got %d", tt.want, len(got))
})
}
}
func TestCheckForError(t *testing.T) {
tests := []struct {
name string
input string
wantError bool
errorPrefix string
}{
{
name: "No error",
input: "1Directory\t/dir\texample.com\n0Text\t/text.txt\texample.com",
wantError: false,
errorPrefix: "",
},
{
name: "Simple error message",
input: "3Error: File not found\t\texample.com",
wantError: true,
errorPrefix: "gopher error: 3Error: File not found",
},
{
name: "Error with multiple tabs",
input: "3File not found\t/error\texample.com\t70",
wantError: true,
errorPrefix: "gopher error: 3File not found",
},
{
name: "Error among valid entries",
input: `1Welcome\t/welcome\texample.com
3Access denied\t\texample.com
0README\t/readme.txt\texample.com`,
wantError: false,
errorPrefix: "",
},
{
name: "Error with no tabs",
input: "3Server is down for maintenance",
wantError: true,
errorPrefix: "gopher error: 3Server is down for maintenance",
},
{
name: "Multiple errors (should return first)",
input: `3First error\t\texample.com
3Second error\t\texample.com`,
wantError: true,
errorPrefix: "gopher error: 3First error",
},
{
name: "Error with whitespace",
input: " 3 Error with spaces \t\texample.com",
wantError: true,
errorPrefix: "gopher error: 3 Error with spaces",
},
{
name: "Empty input",
input: "",
wantError: false,
errorPrefix: "",
},
{
name: "Just newlines",
input: "\n\n\n",
wantError: false,
errorPrefix: "",
},
{
name: "Error after empty lines",
input: `
3Error after empty lines\t\texample.com`,
wantError: true,
errorPrefix: "gopher error: 3Error after empty lines",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := checkForError(tt.input)
if !tt.wantError {
assert.NoError(t, err)
return
}
assert.Error(t, err)
assert.Contains(t, err.Error(), tt.errorPrefix)
})
}
}
func TestConnectAndGetDataTimeout(t *testing.T) {
// Start a test server that doesn't respond
listener, err := net.Listen("tcp", "localhost:0")
if err != nil {
t.Fatalf("Failed to start listener: %v", err)
}
defer listener.Close()
// Accept the connection but don't respond
go func() {
conn, err := listener.Accept()
if err != nil {
t.Logf("Failed to accept connection: %v", err)
return
}
defer conn.Close()
// Keep the connection open without sending any data to simulate a timeout
select {}
}()
// Construct the URL of our test server
address := listener.Addr().String()
testURL := "gopher://" + address + "/testpath"
// Save original config values
originalTimeout := config.CONFIG.ResponseTimeout
originalMaxSize := config.CONFIG.MaxResponseSize
// Set test config values
config.CONFIG.ResponseTimeout = 1 // Set a very short timeout for this test
config.CONFIG.MaxResponseSize = 1024 // Just for consistency, we won't reach this
// Test the function
_, err = connectAndGetData(testURL)
// Reset config values
config.CONFIG.ResponseTimeout = originalTimeout
config.CONFIG.MaxResponseSize = originalMaxSize
// Check if the error is due to timeout
if err == nil {
t.Error("Expected an error due to timeout, but got no error")
} else if !commonErrors.IsHostError(err) {
t.Errorf("Expected a HostError, but got: %v", err)
} else {
// Here you might want to check if the specific error message contains 'timeout'
// However, since we don't have the exact error string, we're checking the type
t.Logf("Successfully timed out: %v", err)
}
}