diff options
Diffstat (limited to 'internal/modules/handler_test.go')
| -rw-r--r-- | internal/modules/handler_test.go | 550 |
1 files changed, 550 insertions, 0 deletions
diff --git a/internal/modules/handler_test.go b/internal/modules/handler_test.go new file mode 100644 index 0000000..b173f98 --- /dev/null +++ b/internal/modules/handler_test.go @@ -0,0 +1,550 @@ +package modules + +import ( + "net/http" + "net/http/httptest" + "strings" + "testing" + + "git.ofmax.li/go-git-server/internal/admin" +) + +func TestNewModuleHandler_WithNilConfig(t *testing.T) { + handler := NewModuleHandler("/tmp/repos", "example.com", nil) + + // Test that it returns a valid http.Handler even with nil config + if handler == nil { + t.Error("NewModuleHandler should return a non-nil handler") + } +} + +func TestNewModuleHandler_WithConfig(t *testing.T) { + config := &admin.ServerRepos{ + Repos: []*admin.GitRepo{ + { + Name: "mylib", + GoModule: true, + }, + }, + } + + handler := NewModuleHandler("/tmp/repos", "example.com", config) + + // Test that it returns a valid http.Handler + if handler == nil { + t.Error("NewModuleHandler should return a non-nil handler") + } +} + +func TestHandleGoImport_ConfiguredModule(t *testing.T) { + config := &admin.ServerRepos{ + Repos: []*admin.GitRepo{ + { + Name: "mymodule", + GoModule: true, + }, + }, + } + + handler := NewModuleHandler("/tmp/repos", "git.example.com", config) + + req := httptest.NewRequest("GET", "/mymodule?go-get=1", nil) + w := httptest.NewRecorder() + + handler.ServeHTTP(w, req) + + if w.Code != http.StatusOK { + t.Errorf("expected status 200, got %d", w.Code) + } + + body := w.Body.String() + + // Check for go-import meta tag + if !strings.Contains(body, `<meta name="go-import"`) { + t.Error("response should contain go-import meta tag") + } + + // Check for correct module path and VCS info + expectedContent := `content="mymodule git https://git.example.com/mymodule"` + if !strings.Contains(body, expectedContent) { + t.Errorf("response should contain %s", expectedContent) + } + + // Check for go-source meta tag + if !strings.Contains(body, `<meta name="go-source"`) { + t.Error("response should contain go-source meta tag") + } + + // Check content type + contentType := w.Header().Get("Content-Type") + if contentType != "text/html; charset=utf-8" { + t.Errorf("expected content type text/html; charset=utf-8, got %s", contentType) + } +} + +func TestModuleHandler_ServeHTTP_VersionList(t *testing.T) { + config := &admin.ServerRepos{ + Repos: []*admin.GitRepo{ + { + Name: "mymodule", + GoModule: true, + }, + }, + } + + handler := NewModuleHandler("/tmp/repos", "git.example.com", config) + + req := httptest.NewRequest("GET", "/mymodule/@v/list", nil) + w := httptest.NewRecorder() + + handler.ServeHTTP(w, req) + + // Since we don't have a real repo, this should return 500 (internal server error) + // But we can test that it tries to handle the request correctly + if w.Code == http.StatusOK { + contentType := w.Header().Get("Content-Type") + if contentType != "text/plain; charset=utf-8" { + t.Errorf("expected content type text/plain; charset=utf-8, got %s", contentType) + } + } +} + +func TestGoModuleConfiguration(t *testing.T) { + config := &admin.ServerRepos{ + Repos: []*admin.GitRepo{ + { + Name: "mylib", + GoModule: true, // This should have module endpoints + }, + { + Name: "website", + GoModule: false, // This should not have module endpoints + }, + }, + } + + handler := NewModuleHandler("/tmp/repos", "git.example.com", config) + + // Test Go module repo (should work) + t.Run("go_module_true", func(t *testing.T) { + req := httptest.NewRequest("GET", "/mylib?go-get=1", nil) + w := httptest.NewRecorder() + handler.ServeHTTP(w, req) + + if w.Code != http.StatusOK { + t.Errorf("expected status 200 for Go module, got %d", w.Code) + } + }) + + // Test non-Go module repo (should return 404) + t.Run("go_module_false", func(t *testing.T) { + req := httptest.NewRequest("GET", "/website?go-get=1", nil) + w := httptest.NewRecorder() + handler.ServeHTTP(w, req) + + if w.Code != http.StatusNotFound { + t.Errorf("expected status 404 for non-Go module, got %d", w.Code) + } + }) + + // Test proxy endpoints for Go module + t.Run("go_module_proxy_endpoints", func(t *testing.T) { + endpoints := []string{ + "/mylib/@v/list", + "/mylib/@latest", + } + + for _, endpoint := range endpoints { + req := httptest.NewRequest("GET", endpoint, nil) + w := httptest.NewRecorder() + handler.ServeHTTP(w, req) + + // Should get 500 (repo doesn't exist) not 404 (route doesn't exist) + if w.Code == http.StatusNotFound { + t.Errorf("endpoint %s should be routed (got 404, want 500 or 200)", endpoint) + } + } + }) + + // Test proxy endpoints for non-Go module (should all be 404) + t.Run("non_go_module_proxy_endpoints", func(t *testing.T) { + endpoints := []string{ + "/website/@v/list", + "/website/@latest", + } + + for _, endpoint := range endpoints { + req := httptest.NewRequest("GET", endpoint, nil) + w := httptest.NewRecorder() + handler.ServeHTTP(w, req) + + if w.Code != http.StatusNotFound { + t.Errorf("endpoint %s should return 404 for non-Go module, got %d", endpoint, w.Code) + } + } + }) +} + +// Test the catch-all handler (handleAllRequests) - currently 0% coverage +func TestHandleAllRequests(t *testing.T) { + handler := &ModuleHandler{ + reposDir: "/tmp/repos", + serverHost: "git.example.com", + } + + t.Run("version_list_endpoint", func(t *testing.T) { + req := httptest.NewRequest("GET", "/mymodule/@v/list", nil) + w := httptest.NewRecorder() + + handler.handleAllRequests(w, req) + + // Should get 500 (repo doesn't exist) not 404 (route doesn't exist) + if w.Code == http.StatusNotFound { + t.Error("handleAllRequests should route version list requests") + } + }) + + t.Run("latest_endpoint", func(t *testing.T) { + req := httptest.NewRequest("GET", "/mymodule/@latest", nil) + w := httptest.NewRecorder() + + handler.handleAllRequests(w, req) + + // Should get 500 (repo doesn't exist) not 404 (route doesn't exist) + if w.Code == http.StatusNotFound { + t.Error("handleAllRequests should route latest version requests") + } + }) + + t.Run("version_info_endpoint", func(t *testing.T) { + req := httptest.NewRequest("GET", "/mymodule/@v/v1.0.0.info", nil) + w := httptest.NewRecorder() + + handler.handleAllRequests(w, req) + + // Should get 500/404 (repo/version doesn't exist) not 404 (route doesn't exist) + if w.Code == http.StatusOK { + t.Error("expected error for nonexistent repository/version") + } + }) + + t.Run("mod_file_endpoint", func(t *testing.T) { + req := httptest.NewRequest("GET", "/mymodule/@v/v1.0.0.mod", nil) + w := httptest.NewRecorder() + + handler.handleAllRequests(w, req) + + // Should get 500/404 (repo/version doesn't exist) not 404 (route doesn't exist) + if w.Code == http.StatusOK { + t.Error("expected error for nonexistent repository/version") + } + }) + + t.Run("zip_file_endpoint", func(t *testing.T) { + req := httptest.NewRequest("GET", "/mymodule/@v/v1.0.0.zip", nil) + w := httptest.NewRecorder() + + handler.handleAllRequests(w, req) + + // Should get 500/404 (repo/version doesn't exist) not 404 (route doesn't exist) + if w.Code == http.StatusOK { + t.Error("expected error for nonexistent repository/version") + } + }) + + t.Run("go_import_request", func(t *testing.T) { + req := httptest.NewRequest("GET", "/mymodule?go-get=1", nil) + w := httptest.NewRecorder() + + handler.handleAllRequests(w, req) + + if w.Code != http.StatusOK { + t.Errorf("expected 200 for go-import request, got %d", w.Code) + } + + body := w.Body.String() + if !strings.Contains(body, "go-import") { + t.Error("response should contain go-import meta tag") + } + }) + + t.Run("regular_request", func(t *testing.T) { + req := httptest.NewRequest("GET", "/mymodule", nil) + w := httptest.NewRecorder() + + handler.handleAllRequests(w, req) + + // Should get 404 because go-get=1 is required for go-import + if w.Code != http.StatusNotFound { + t.Errorf("expected 404 for regular request without go-get, got %d", w.Code) + } + }) +} + +// Test non-"ForModule" handler functions - currently 0% coverage +func TestNonForModuleHandlers(t *testing.T) { + handler := &ModuleHandler{ + reposDir: "/tmp/repos", + serverHost: "git.example.com", + } + + t.Run("handleGoImport", func(t *testing.T) { + // Test without go-get parameter + req := httptest.NewRequest("GET", "/mymodule", nil) + w := httptest.NewRecorder() + + handler.handleGoImport(w, req) + + if w.Code != http.StatusNotFound { + t.Error("expected 404 when go-get parameter is missing") + } + + // Test with go-get=1 + req = httptest.NewRequest("GET", "/mymodule?go-get=1", nil) + w = httptest.NewRecorder() + + handler.handleGoImport(w, req) + + if w.Code != http.StatusOK { + t.Errorf("expected 200 with go-get=1, got %d", w.Code) + } + + body := w.Body.String() + if !strings.Contains(body, "go-import") { + t.Error("response should contain go-import meta tag") + } + }) + + t.Run("handleVersionList", func(t *testing.T) { + req := httptest.NewRequest("GET", "/mymodule/@v/list", nil) + w := httptest.NewRecorder() + + handler.handleVersionList(w, req) + + // Should get 500 (repo doesn't exist) + if w.Code != http.StatusInternalServerError { + t.Errorf("expected 500 for nonexistent repo, got %d", w.Code) + } + }) + + t.Run("handleLatestVersion", func(t *testing.T) { + req := httptest.NewRequest("GET", "/mymodule/@latest", nil) + w := httptest.NewRecorder() + + handler.handleLatestVersion(w, req) + + // Should get 500 (repo doesn't exist) + if w.Code != http.StatusInternalServerError { + t.Errorf("expected 500 for nonexistent repo, got %d", w.Code) + } + }) + + t.Run("handleVersionInfo", func(t *testing.T) { + req := httptest.NewRequest("GET", "/mymodule/@v/v1.0.0.info", nil) + w := httptest.NewRecorder() + + handler.handleVersionInfo(w, req) + + // Should get 500 (repo doesn't exist) + if w.Code != http.StatusInternalServerError { + t.Errorf("expected 500 for nonexistent repo, got %d", w.Code) + } + }) + + t.Run("handleModFile", func(t *testing.T) { + req := httptest.NewRequest("GET", "/mymodule/@v/v1.0.0.mod", nil) + w := httptest.NewRecorder() + + handler.handleModFile(w, req) + + // Should get 500 (repo doesn't exist) + if w.Code != http.StatusInternalServerError { + t.Errorf("expected 500 for nonexistent repo, got %d", w.Code) + } + }) + + t.Run("handleModuleZip", func(t *testing.T) { + req := httptest.NewRequest("GET", "/mymodule/@v/v1.0.0.zip", nil) + w := httptest.NewRecorder() + + handler.handleModuleZip(w, req) + + // Should get 500 (repo doesn't exist) + if w.Code != http.StatusInternalServerError { + t.Errorf("expected 500 for nonexistent repo, got %d", w.Code) + } + }) +} + +// Test ForModule handlers that have 0% coverage +func TestForModuleHandlersZeroCoverage(t *testing.T) { + handler := &ModuleHandler{ + reposDir: "/tmp/repos", + serverHost: "git.example.com", + } + + t.Run("handleVersionInfoForModule", func(t *testing.T) { + req := httptest.NewRequest("GET", "/mymodule/@v/v1.0.0.info", nil) + w := httptest.NewRecorder() + + handler.handleVersionInfoForModule(w, req, "mymodule", "v1.0.0") + + // Should get 500 (repo doesn't exist) + if w.Code != http.StatusInternalServerError { + t.Errorf("expected 500 for nonexistent repo, got %d", w.Code) + } + }) + + t.Run("handleModFileForModule", func(t *testing.T) { + req := httptest.NewRequest("GET", "/mymodule/@v/v1.0.0.mod", nil) + w := httptest.NewRecorder() + + handler.handleModFileForModule(w, req, "mymodule", "v1.0.0") + + // Should get 500 (repo doesn't exist) + if w.Code != http.StatusInternalServerError { + t.Errorf("expected 500 for nonexistent repo, got %d", w.Code) + } + }) + + t.Run("handleModuleZipForModule", func(t *testing.T) { + req := httptest.NewRequest("GET", "/mymodule/@v/v1.0.0.zip", nil) + w := httptest.NewRecorder() + + handler.handleModuleZipForModule(w, req, "mymodule", "v1.0.0") + + // Should get 500 (repo doesn't exist) + if w.Code != http.StatusInternalServerError { + t.Errorf("expected 500 for nonexistent repo, got %d", w.Code) + } + }) + + t.Run("handleGoImportForModule_without_go_get", func(t *testing.T) { + req := httptest.NewRequest("GET", "/mymodule", nil) + w := httptest.NewRecorder() + + handler.handleGoImportForModule(w, req, "mymodule") + + if w.Code != http.StatusNotFound { + t.Error("expected 404 when go-get parameter is missing") + } + }) + + t.Run("handleGoImportForModule_with_go_get", func(t *testing.T) { + req := httptest.NewRequest("GET", "/mymodule?go-get=1", nil) + w := httptest.NewRecorder() + + handler.handleGoImportForModule(w, req, "mymodule") + + if w.Code != http.StatusOK { + t.Errorf("expected 200 with go-get=1, got %d", w.Code) + } + + body := w.Body.String() + if !strings.Contains(body, "go-import") { + t.Error("response should contain go-import meta tag") + } + }) +} + +// Test createGenericVersionHandler which has low coverage (8.3%) +func TestCreateGenericVersionHandler(t *testing.T) { + handler := &ModuleHandler{ + reposDir: "/tmp/repos", + serverHost: "git.example.com", + } + + genericHandler := handler.createGenericVersionHandler("mymodule") + + t.Run("info_file", func(t *testing.T) { + req := httptest.NewRequest("GET", "/mymodule/@v/v1.0.0.info", nil) + w := httptest.NewRecorder() + + genericHandler(w, req) + + if w.Code != http.StatusInternalServerError { + t.Errorf("expected 500 for nonexistent repo, got %d", w.Code) + } + }) + + t.Run("mod_file", func(t *testing.T) { + req := httptest.NewRequest("GET", "/mymodule/@v/v1.0.0.mod", nil) + w := httptest.NewRecorder() + + genericHandler(w, req) + + if w.Code != http.StatusInternalServerError { + t.Errorf("expected 500 for nonexistent repo, got %d", w.Code) + } + }) + + t.Run("zip_file", func(t *testing.T) { + req := httptest.NewRequest("GET", "/mymodule/@v/v1.0.0.zip", nil) + w := httptest.NewRecorder() + + genericHandler(w, req) + + if w.Code != http.StatusInternalServerError { + t.Errorf("expected 500 for nonexistent repo, got %d", w.Code) + } + }) + + t.Run("unknown_endpoint", func(t *testing.T) { + req := httptest.NewRequest("GET", "/mymodule/@v/unknown", nil) + w := httptest.NewRecorder() + + genericHandler(w, req) + + if w.Code != http.StatusNotFound { + t.Errorf("expected 404 for unknown endpoint, got %d", w.Code) + } + }) +} + +// Test middleware coverage +func TestModuleMiddleware(t *testing.T) { + moduleHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte("module-response")) + }) + + nextHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte("next-response")) + }) + + middleware := ModuleMiddleware(moduleHandler, nextHandler) + + t.Run("module_request_go_get", func(t *testing.T) { + req := httptest.NewRequest("GET", "/mymodule?go-get=1", nil) + w := httptest.NewRecorder() + + middleware.ServeHTTP(w, req) + + if w.Body.String() != "module-response" { + t.Error("should route to module handler for go-get requests") + } + }) + + t.Run("module_request_version_list", func(t *testing.T) { + req := httptest.NewRequest("GET", "/mymodule/@v/list", nil) + w := httptest.NewRecorder() + + middleware.ServeHTTP(w, req) + + if w.Body.String() != "module-response" { + t.Error("should route to module handler for version list requests") + } + }) + + t.Run("non_module_request", func(t *testing.T) { + req := httptest.NewRequest("GET", "/mymodule.git/info/refs", nil) + w := httptest.NewRecorder() + + middleware.ServeHTTP(w, req) + + if w.Body.String() != "next-response" { + t.Error("should route to next handler for git requests") + } + }) +} |