Skip to content

Commit ac199b5

Browse files
committed
test: complete app/main coverage and verify 100%
1 parent e1dbf9c commit ac199b5

File tree

5 files changed

+642
-10
lines changed

5 files changed

+642
-10
lines changed

src/app/app.go

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,17 @@ func (app *App) CompressFiles() {
136136
}
137137

138138
func (app *App) GetOrCreateResponseItem(requestedPath string, compression Compression, actualContentType *string) (*ResponseItem, int) {
139+
return app.getOrCreateResponseItemWithOpener(requestedPath, compression, actualContentType, nil)
140+
}
141+
142+
func (app *App) getOrCreateResponseItemWithOpener(requestedPath string, compression Compression, actualContentType *string, opener func(string, string) (http.File, error)) (*ResponseItem, int) {
143+
if opener == nil {
144+
opener = func(dirPath, fileName string) (http.File, error) {
145+
dir := http.Dir(dirPath)
146+
return dir.Open(fileName)
147+
}
148+
}
149+
139150
rootIndexPath := path.Join(app.params.Directory, "index.html")
140151

141152
switch compression {
@@ -153,22 +164,20 @@ func (app *App) GetOrCreateResponseItem(requestedPath string, compression Compre
153164
return &responseItem, 0
154165
} else {
155166
localRedirectItem := cacheValue.(string)
156-
return app.GetOrCreateResponseItem(localRedirectItem, compression, actualContentType)
167+
return app.getOrCreateResponseItemWithOpener(localRedirectItem, compression, actualContentType, opener)
157168
}
158169
}
159170
}
160171

161172
dirPath, fileName := filepath.Split(requestedPath)
162-
dir := http.Dir(dirPath)
163-
164-
file, err := dir.Open(fileName)
173+
file, err := opener(dirPath, fileName)
165174
if err != nil {
166175
if app.params.SpaMode && compression == None && requestedPath != rootIndexPath {
167176
newPath := path.Join(app.params.Directory, "index.html")
168177
if app.cache != nil {
169178
app.cache.Add(requestedPath, newPath)
170179
}
171-
return app.GetOrCreateResponseItem(newPath, compression, actualContentType)
180+
return app.getOrCreateResponseItemWithOpener(newPath, compression, actualContentType, opener)
172181
}
173182
return nil, http.StatusNotFound
174183
}
@@ -181,7 +190,7 @@ func (app *App) GetOrCreateResponseItem(requestedPath string, compression Compre
181190
if app.cache != nil {
182191
app.cache.Add(requestedPath, newPath)
183192
}
184-
return app.GetOrCreateResponseItem(newPath, compression, actualContentType)
193+
return app.getOrCreateResponseItemWithOpener(newPath, compression, actualContentType, opener)
185194
}
186195
return nil, http.StatusNotFound
187196
}
@@ -192,13 +201,13 @@ func (app *App) GetOrCreateResponseItem(requestedPath string, compression Compre
192201
if app.cache != nil {
193202
app.cache.Add(requestedPath, newPath)
194203
}
195-
return app.GetOrCreateResponseItem(newPath, compression, actualContentType)
204+
return app.getOrCreateResponseItemWithOpener(newPath, compression, actualContentType, opener)
196205
} else if !app.params.SpaMode && compression == None {
197206
newPath := path.Join(requestedPath, "index.html")
198207
if app.cache != nil {
199208
app.cache.Add(requestedPath, newPath)
200209
}
201-
return app.GetOrCreateResponseItem(newPath, compression, actualContentType)
210+
return app.getOrCreateResponseItemWithOpener(newPath, compression, actualContentType, opener)
202211
}
203212

204213
return nil, http.StatusNotFound

src/app/app_internal_test.go

Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
package app
2+
3+
import (
4+
"go-http-server/param"
5+
"io"
6+
"io/fs"
7+
"net/http"
8+
"os"
9+
"path/filepath"
10+
"testing"
11+
"time"
12+
)
13+
14+
func TestNewAppWithListenAndServeDefault(t *testing.T) {
15+
params := param.Params{
16+
Directory: ".",
17+
}
18+
app := NewAppWithListenAndServe(&params, nil)
19+
if app.listenAndServe == nil {
20+
t.Fatal("expected listenAndServe to be set")
21+
}
22+
}
23+
24+
func TestGetOrCreateResponseItemCacheHit(t *testing.T) {
25+
params := param.Params{
26+
Directory: ".",
27+
CacheEnabled: true,
28+
CacheBuffer: 10,
29+
}
30+
app := NewApp(&params)
31+
32+
cached := ResponseItem{
33+
Name: "cached.txt",
34+
Path: "/cached.txt",
35+
ModTime: time.Now(),
36+
Content: []byte("cached"),
37+
ContentType: "text/plain",
38+
}
39+
40+
app.cache.Add("/cached.txt", cached)
41+
42+
got, code := app.GetOrCreateResponseItem("/cached.txt", None, nil)
43+
if code != 0 {
44+
t.Fatalf("expected code 0, got %d", code)
45+
}
46+
if got == nil || got.Name != "cached.txt" {
47+
t.Fatalf("expected cached response item, got %#v", got)
48+
}
49+
}
50+
51+
func TestGetOrCreateResponseItemCacheRedirect(t *testing.T) {
52+
dir := t.TempDir()
53+
indexPath := filepath.Join(dir, "index.html")
54+
if err := os.WriteFile(indexPath, []byte("index"), 0600); err != nil {
55+
t.Fatalf("failed to write file: %v", err)
56+
}
57+
58+
params := param.Params{
59+
Directory: dir,
60+
CacheEnabled: true,
61+
CacheBuffer: 10,
62+
SpaMode: true,
63+
}
64+
app := NewApp(&params)
65+
66+
app.cache.Add("/alias", indexPath)
67+
68+
got, code := app.GetOrCreateResponseItem("/alias", None, nil)
69+
if code != 0 {
70+
t.Fatalf("expected code 0, got %d", code)
71+
}
72+
if got == nil || got.Name != "index.html" {
73+
t.Fatalf("expected index.html, got %#v", got)
74+
}
75+
}
76+
77+
type errStatFile struct{}
78+
79+
func (f *errStatFile) Close() error { return nil }
80+
func (f *errStatFile) Read(_ []byte) (int, error) { return 0, io.EOF }
81+
func (f *errStatFile) Seek(_ int64, _ int) (int64, error) { return 0, nil }
82+
func (f *errStatFile) Readdir(_ int) ([]fs.FileInfo, error) {
83+
return nil, nil
84+
}
85+
func (f *errStatFile) Stat() (fs.FileInfo, error) {
86+
return nil, fs.ErrInvalid
87+
}
88+
89+
type fixedFileInfo struct {
90+
name string
91+
size int64
92+
mode fs.FileMode
93+
modTime time.Time
94+
isDir bool
95+
}
96+
97+
func (fi fixedFileInfo) Name() string { return fi.name }
98+
func (fi fixedFileInfo) Size() int64 { return fi.size }
99+
func (fi fixedFileInfo) Mode() fs.FileMode { return fi.mode }
100+
func (fi fixedFileInfo) ModTime() time.Time { return fi.modTime }
101+
func (fi fixedFileInfo) IsDir() bool { return fi.isDir }
102+
func (fi fixedFileInfo) Sys() interface{} { return nil }
103+
104+
type shortReadFile struct {
105+
info fs.FileInfo
106+
}
107+
108+
func (f *shortReadFile) Close() error { return nil }
109+
func (f *shortReadFile) Read(_ []byte) (int, error) { return 0, io.EOF }
110+
func (f *shortReadFile) Seek(_ int64, _ int) (int64, error) { return 0, nil }
111+
func (f *shortReadFile) Readdir(_ int) ([]fs.FileInfo, error) {
112+
return nil, nil
113+
}
114+
func (f *shortReadFile) Stat() (fs.FileInfo, error) { return f.info, nil }
115+
116+
func TestGetOrCreateResponseItemOpenErrorSpaRedirect(t *testing.T) {
117+
dir := t.TempDir()
118+
indexPath := filepath.Join(dir, "index.html")
119+
if err := os.WriteFile(indexPath, []byte("index"), 0600); err != nil {
120+
t.Fatalf("failed to write file: %v", err)
121+
}
122+
123+
params := param.Params{
124+
Directory: dir,
125+
SpaMode: true,
126+
CacheEnabled: true,
127+
CacheBuffer: 10,
128+
}
129+
app := NewApp(&params)
130+
131+
opener := func(dirPath, fileName string) (http.File, error) {
132+
if fileName == "index.html" {
133+
return os.Open(filepath.Join(dirPath, fileName))
134+
}
135+
return nil, fs.ErrNotExist
136+
}
137+
138+
got, code := app.getOrCreateResponseItemWithOpener(filepath.Join(dir, "missing.txt"), None, nil, opener)
139+
if code != 0 {
140+
t.Fatalf("expected code 0, got %d", code)
141+
}
142+
if got == nil || got.Name != "index.html" {
143+
t.Fatalf("expected index.html, got %#v", got)
144+
}
145+
}
146+
147+
func TestGetOrCreateResponseItemStatError(t *testing.T) {
148+
params := param.Params{
149+
Directory: ".",
150+
SpaMode: false,
151+
}
152+
app := NewApp(&params)
153+
154+
opener := func(_, _ string) (http.File, error) {
155+
return &errStatFile{}, nil
156+
}
157+
158+
got, code := app.getOrCreateResponseItemWithOpener("file.txt", None, nil, opener)
159+
if got != nil {
160+
t.Fatalf("expected nil response, got %#v", got)
161+
}
162+
if code != http.StatusNotFound {
163+
t.Fatalf("expected status %d, got %d", http.StatusNotFound, code)
164+
}
165+
}
166+
167+
func TestGetOrCreateResponseItemStatErrorSpaRedirect(t *testing.T) {
168+
dir := t.TempDir()
169+
indexPath := filepath.Join(dir, "index.html")
170+
if err := os.WriteFile(indexPath, []byte("index"), 0600); err != nil {
171+
t.Fatalf("failed to write file: %v", err)
172+
}
173+
174+
params := param.Params{
175+
Directory: dir,
176+
SpaMode: true,
177+
CacheEnabled: true,
178+
CacheBuffer: 10,
179+
}
180+
app := NewApp(&params)
181+
182+
opener := func(dirPath, fileName string) (http.File, error) {
183+
if fileName == "index.html" {
184+
return os.Open(filepath.Join(dirPath, fileName))
185+
}
186+
return &errStatFile{}, nil
187+
}
188+
189+
got, code := app.getOrCreateResponseItemWithOpener(filepath.Join(dir, "missing.txt"), None, nil, opener)
190+
if code != 0 {
191+
t.Fatalf("expected code 0, got %d", code)
192+
}
193+
if got == nil || got.Name != "index.html" {
194+
t.Fatalf("expected index.html, got %#v", got)
195+
}
196+
}
197+
198+
func TestGetOrCreateResponseItemReadError(t *testing.T) {
199+
params := param.Params{
200+
Directory: ".",
201+
SpaMode: false,
202+
}
203+
app := NewApp(&params)
204+
205+
info := fixedFileInfo{
206+
name: "file.txt",
207+
size: 10,
208+
mode: 0600,
209+
modTime: time.Now(),
210+
isDir: false,
211+
}
212+
opener := func(_, _ string) (http.File, error) {
213+
return &shortReadFile{info: info}, nil
214+
}
215+
216+
got, code := app.getOrCreateResponseItemWithOpener("file.txt", None, nil, opener)
217+
if got != nil {
218+
t.Fatalf("expected nil response, got %#v", got)
219+
}
220+
if code != http.StatusInternalServerError {
221+
t.Fatalf("expected status %d, got %d", http.StatusInternalServerError, code)
222+
}
223+
}
224+
225+
func TestGetOrCreateResponseItemDirWithCompressionNotFound(t *testing.T) {
226+
dir := t.TempDir()
227+
if err := os.Mkdir(filepath.Join(dir, "dir.gz"), 0700); err != nil {
228+
t.Fatalf("failed to create directory: %v", err)
229+
}
230+
231+
params := param.Params{
232+
Directory: dir,
233+
SpaMode: true,
234+
}
235+
app := NewApp(&params)
236+
237+
got, code := app.getOrCreateResponseItemWithOpener(filepath.Join(dir, "dir"), Gzip, nil, nil)
238+
if got != nil {
239+
t.Fatalf("expected nil response, got %#v", got)
240+
}
241+
if code != http.StatusNotFound {
242+
t.Fatalf("expected status %d, got %d", http.StatusNotFound, code)
243+
}
244+
}

0 commit comments

Comments
 (0)