Skip to content

Commit 1dd2b55

Browse files
committed
add comprehensive tests for server response handling and gzip compression
1 parent 6c25242 commit 1dd2b55

File tree

6 files changed

+219
-2
lines changed

6 files changed

+219
-2
lines changed

sitemap_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1558,7 +1558,7 @@ func TestS_parseURLSet(t *testing.T) {
15581558
}
15591559
}
15601560

1561-
func Test_unzip(t *testing.T) {
1561+
func TestUnzip(t *testing.T) {
15621562
tests := []struct {
15631563
name string
15641564
input []byte

test/corrupted.gz

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
�corrupted data

test/test.gz

36 Bytes
Binary file not shown.

test/test.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Hello HOST

test_server.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import (
1111
"strings"
1212
)
1313

14+
var zipFunc = zip
15+
1416
// testServer creates a test server with a custom request handler that serves static files and dynamically replaces
1517
// the "HOST" string in the response with the value of the request's Host header. The server handles the following routes:
1618
// - "/" returns a 404 Not Found response.
@@ -48,7 +50,7 @@ func testServer() *httptest.Server {
4850
}
4951
strRes = strings.Replace(string(resUncompressed), "HOST", r.Host, -1)
5052

51-
resCompressed, err := zip([]byte(strRes), nil)
53+
resCompressed, err := zipFunc([]byte(strRes), nil)
5254
if err != nil {
5355
_, _ = fmt.Fprintf(w, "error: %v\n", err)
5456
return

test_server_test.go

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
package sitemap
2+
3+
import (
4+
"bytes"
5+
"compress/gzip"
6+
"fmt"
7+
"io"
8+
"net/http"
9+
"strings"
10+
"testing"
11+
)
12+
13+
// failingWriter is a mock io.Writer for testing error paths.
14+
type failingWriter struct {
15+
failOnNthWrite int
16+
writeCount int
17+
buffer bytes.Buffer
18+
}
19+
20+
func (fw *failingWriter) Write(p []byte) (n int, err error) {
21+
fw.writeCount++
22+
if fw.failOnNthWrite > 0 && fw.writeCount == fw.failOnNthWrite {
23+
return 0, fmt.Errorf("simulated write error on write #%d", fw.writeCount)
24+
}
25+
return fw.buffer.Write(p)
26+
}
27+
28+
func TestTestServer(t *testing.T) {
29+
30+
ts := testServer()
31+
defer ts.Close()
32+
33+
t.Run("index should be not found", func(t *testing.T) {
34+
res, err := http.Get(ts.URL + "/")
35+
if err != nil {
36+
t.Fatalf("HTTP GET failed: %v", err)
37+
}
38+
defer res.Body.Close()
39+
if res.StatusCode != http.StatusNotFound {
40+
t.Errorf("expected status %d; got %d", http.StatusNotFound, res.StatusCode)
41+
}
42+
})
43+
44+
t.Run("example should return ok", func(t *testing.T) {
45+
res, err := http.Get(ts.URL + "/example")
46+
if err != nil {
47+
t.Fatalf("HTTP GET failed: %v", err)
48+
}
49+
defer res.Body.Close()
50+
body, err := io.ReadAll(res.Body)
51+
if err != nil {
52+
t.Fatalf("Failed to read response body: %v", err)
53+
}
54+
expected := "example content\n"
55+
if string(body) != expected {
56+
t.Errorf("expected body %q; got %q", expected, string(body))
57+
}
58+
})
59+
60+
t.Run("non-existent file should be not found", func(t *testing.T) {
61+
res, err := http.Get(ts.URL + "/nonexistent.txt")
62+
if err != nil {
63+
t.Fatalf("HTTP GET failed: %v", err)
64+
}
65+
defer res.Body.Close()
66+
if res.StatusCode != http.StatusNotFound {
67+
t.Errorf("expected status %d; got %d", http.StatusNotFound, res.StatusCode)
68+
}
69+
})
70+
71+
t.Run("serve plain text file", func(t *testing.T) {
72+
res, err := http.Get(ts.URL + "/test.txt")
73+
if err != nil {
74+
t.Fatalf("HTTP GET failed: %v", err)
75+
}
76+
defer res.Body.Close()
77+
body, err := io.ReadAll(res.Body)
78+
if err != nil {
79+
t.Fatalf("Failed to read response body: %v", err)
80+
}
81+
host := strings.TrimPrefix(ts.URL, "http://")
82+
expected := "Hello " + host + "\n"
83+
if string(body) != expected {
84+
t.Errorf("expected body %q; got %q", expected, string(body))
85+
}
86+
})
87+
88+
t.Run("serve gzipped file", func(t *testing.T) {
89+
res, err := http.Get(ts.URL + "/test.gz")
90+
if err != nil {
91+
t.Fatalf("HTTP GET failed: %v", err)
92+
}
93+
defer res.Body.Close()
94+
body, err := io.ReadAll(res.Body)
95+
if err != nil {
96+
t.Fatalf("Failed to read response body: %v", err)
97+
}
98+
99+
unzippedBody, err := unzip(body)
100+
if err != nil {
101+
t.Fatalf("Failed to unzip response body: %v", err)
102+
}
103+
host := strings.TrimPrefix(ts.URL, "http://")
104+
expected := "Gzipped " + host
105+
if string(unzippedBody) != expected {
106+
t.Errorf("expected body %q; got %q", expected, string(unzippedBody))
107+
}
108+
})
109+
110+
t.Run("unzip error should be handled", func(t *testing.T) {
111+
res, err := http.Get(ts.URL + "/corrupted.gz")
112+
if err != nil {
113+
t.Fatalf("HTTP GET failed: %v", err)
114+
}
115+
defer res.Body.Close()
116+
body, err := io.ReadAll(res.Body)
117+
if err != nil {
118+
t.Fatalf("Failed to read response body: %v", err)
119+
}
120+
// The handler returns the error in "error: %v\n" format
121+
expected := "error: gzip: invalid header\n"
122+
if string(body) != expected {
123+
t.Errorf("expected body %q; got %q", expected, string(body))
124+
}
125+
})
126+
127+
t.Run("handle zip error", func(t *testing.T) {
128+
// Replace the original zip function with a mock that returns an error
129+
originalZipFunc := zipFunc
130+
zipFunc = func(content []byte, w io.Writer) ([]byte, error) {
131+
return nil, fmt.Errorf("simulated zip error")
132+
}
133+
// Ensure the original function is restored after the test
134+
defer func() { zipFunc = originalZipFunc }()
135+
136+
// Request a gzipped file to trigger the code path that calls zip
137+
res, err := http.Get(ts.URL + "/test.gz")
138+
if err != nil {
139+
t.Fatalf("HTTP GET failed: %v", err)
140+
}
141+
defer res.Body.Close()
142+
143+
body, err := io.ReadAll(res.Body)
144+
if err != nil {
145+
t.Fatalf("Failed to read response body: %v", err)
146+
}
147+
148+
// Check if the handler returned the expected error message
149+
expected := "error: simulated zip error\n"
150+
if string(body) != expected {
151+
t.Errorf("expected body %q; got %q", expected, string(body))
152+
}
153+
})
154+
}
155+
156+
func TestZip(t *testing.T) {
157+
content := []byte("hello world")
158+
159+
t.Run("successful compression", func(t *testing.T) {
160+
compressed, err := zip(content, nil)
161+
if err != nil {
162+
t.Fatalf("zip failed: %v", err)
163+
}
164+
165+
r, err := gzip.NewReader(bytes.NewReader(compressed))
166+
if err != nil {
167+
t.Fatalf("failed to create gzip reader: %v", err)
168+
}
169+
defer r.Close()
170+
uncompressed, err := io.ReadAll(r)
171+
if err != nil {
172+
t.Fatalf("failed to read uncompressed data: %v", err)
173+
}
174+
if !bytes.Equal(content, uncompressed) {
175+
t.Errorf("content does not match, got: %s, want: %s", uncompressed, content)
176+
}
177+
})
178+
179+
t.Run("writer fails on write", func(t *testing.T) {
180+
writer := &failingWriter{failOnNthWrite: 1}
181+
b, err := zip(content, writer)
182+
if err == nil {
183+
t.Error("expected an error, but got nil")
184+
}
185+
if !bytes.Equal(b, content) {
186+
t.Errorf("expected original content on error, got %q, want %q", string(b), string(content))
187+
}
188+
})
189+
190+
t.Run("writer fails on close", func(t *testing.T) {
191+
// The first write in gzip.Writer.Write may succeed, but the flush during gzip.Writer.Close will fail.
192+
writer := &failingWriter{failOnNthWrite: 2}
193+
b, err := zip(content, writer)
194+
if err == nil {
195+
t.Error("expected an error, but got nil")
196+
}
197+
if !bytes.Equal(b, content) {
198+
t.Errorf("expected original content on error, got %q, want %q", string(b), string(content))
199+
}
200+
})
201+
202+
t.Run("unsupported writer type", func(t *testing.T) {
203+
writer := &failingWriter{} // This is not a *bytes.Buffer
204+
_, err := zip(content, writer)
205+
if err == nil {
206+
t.Fatal("expected an error, but got nil")
207+
}
208+
expectedErr := "cannot retrieve compressed bytes from provided writer type"
209+
if err.Error() != expectedErr {
210+
t.Errorf("expected error %q, got %q", expectedErr, err.Error())
211+
}
212+
})
213+
}

0 commit comments

Comments
 (0)