internal/source: enable testing without HTTP requests

Add NewClientForTesting, which returns a Client that does not
make any HTTP requests.

The practical effect is to eliminate a lot of errors from test
logs in the internal/fetch package.

Change-Id: Ie47ceb1a8984d4408ea361baefa1610aeed1b02a
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/279793
Trust: Jonathan Amsterdam <jba@google.com>
Run-TryBot: Jonathan Amsterdam <jba@google.com>
TryBot-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Julie Qiu <julie@golang.org>
diff --git a/internal/fetch/fetch_test.go b/internal/fetch/fetch_test.go
index f359f8b..b7fd746 100644
--- a/internal/fetch/fetch_test.go
+++ b/internal/fetch/fetch_test.go
@@ -28,10 +28,7 @@
 	"golang.org/x/pkgsite/internal/testing/sample"
 )
 
-var (
-	testTimeout   = 30 * time.Second
-	sourceTimeout = 1 * time.Second
-)
+var testTimeout = 30 * time.Second
 
 var templateSource = template.TrustedSourceFromConstant("../../content/static/html/doc")
 
diff --git a/internal/fetch/helper_test.go b/internal/fetch/helper_test.go
index a44e5af..f4f208c 100644
--- a/internal/fetch/helper_test.go
+++ b/internal/fetch/helper_test.go
@@ -130,14 +130,13 @@
 		fetchVersion = version
 	}
 
-	sourceClient := source.NewClient(sourceTimeout)
 	proxyClient, teardownProxy := proxy.SetupTestClient(t, []*proxy.Module{{
 		ModulePath: modulePath,
 		Version:    version,
 		Files:      mod.mod.Files,
 	}})
 	defer teardownProxy()
-	got := FetchModule(ctx, modulePath, fetchVersion, proxyClient, sourceClient, false)
+	got := FetchModule(ctx, modulePath, fetchVersion, proxyClient, source.NewClientForTesting(), false)
 	if !withLicenseDetector {
 		return got, nil
 	}
@@ -159,8 +158,7 @@
 	defer os.RemoveAll(directory)
 
 	modulePath := mod.mod.ModulePath
-	sourceClient := source.NewClient(sourceTimeout)
-	got := FetchLocalModule(ctx, modulePath, directory, sourceClient)
+	got := FetchLocalModule(ctx, modulePath, directory, source.NewClientForTesting())
 	if !withLicenseDetector {
 		return got, nil
 	}
diff --git a/internal/source/source.go b/internal/source/source.go
index d4b8af1..2610408 100644
--- a/internal/source/source.go
+++ b/internal/source/source.go
@@ -205,6 +205,7 @@
 
 type Client struct {
 	// client used for HTTP requests. It is mutable for testing purposes.
+	// If nil, then moduleInfoDynamic will return nil, nil; also for testing.
 	httpClient *http.Client
 }
 
@@ -218,6 +219,13 @@
 	}
 }
 
+// NewClientForTesting returns a Client suitable for testing. It returns the
+// same results as an ordinary client for statically recognizable paths, but
+// always returns a nil *Info for dynamic paths (those requiring HTTP requests).
+func NewClientForTesting() *Client {
+	return &Client{}
+}
+
 // doURL makes an HTTP request using the given url and method. It returns an
 // error if the request returns an error. If only200 is true, it also returns an
 // error if any status code other than 200 is returned.
@@ -273,7 +281,9 @@
 			templates: templates,
 		}
 	}
-	adjustVersionedModuleDirectory(ctx, client, info)
+	if info != nil {
+		adjustVersionedModuleDirectory(ctx, client, info)
+	}
 	return info, nil
 	// TODO(golang/go#39627): support launchpad.net, including the special case
 	// in cmd/go/internal/get/vcs.go.
@@ -350,6 +360,10 @@
 func moduleInfoDynamic(ctx context.Context, client *Client, modulePath, version string) (_ *Info, err error) {
 	defer derrors.Wrap(&err, "source.moduleInfoDynamic(ctx, client, %q, %q)", modulePath, version)
 
+	if client.httpClient == nil {
+		return nil, nil // for testing
+	}
+
 	sourceMeta, err := fetchMeta(ctx, client, modulePath)
 	if err != nil {
 		return nil, err