Browse Source

Lower go test time

Erik Dubbelboer 7 months ago
parent
commit
9f2c63676d

+ 0 - 4
allocation_test.go

@@ -9,8 +9,6 @@ import (
 )
 
 func TestAllocationServeConn(t *testing.T) {
-	t.Parallel()
-
 	s := &Server{
 		Handler: func(ctx *RequestCtx) {
 		},
@@ -72,8 +70,6 @@ func TestAllocationClient(t *testing.T) {
 }
 
 func TestAllocationURI(t *testing.T) {
-	t.Parallel()
-
 	uri := []byte("http://username:[email protected]/some/path?foo=bar#test")
 
 	n := testing.AllocsPerRun(100, func() {

+ 18 - 19
client_test.go

@@ -21,6 +21,8 @@ import (
 )
 
 func TestCloseIdleConnections(t *testing.T) {
+	t.Parallel()
+
 	ln := fasthttputil.NewInmemoryListener()
 
 	s := &Server{
@@ -278,10 +280,7 @@ func TestClientURLAuth(t *testing.T) {
 }
 
 func TestClientNilResp(t *testing.T) {
-	// For some reason running this test in parallel sometimes
-	// triggers the race checker. I have not been able to find an
-	// actual race condition so I think it's something else going wrong.
-	// For now just don't run this test in parallel.
+	t.Parallel()
 
 	ln := fasthttputil.NewInmemoryListener()
 	s := &Server{
@@ -303,6 +302,7 @@ func TestClientNilResp(t *testing.T) {
 	if err := c.DoTimeout(req, nil, time.Second); err != nil {
 		t.Fatal(err)
 	}
+	ln.Close()
 }
 
 func TestPipelineClientNilResp(t *testing.T) {
@@ -627,19 +627,13 @@ func TestClientHeaderCase(t *testing.T) {
 func TestClientReadTimeout(t *testing.T) {
 	t.Parallel()
 
-	// This test is rather slow and increase the total test time
-	// from 2.5 seconds to 6.5 seconds.
-	if testing.Short() {
-		t.Skip("skipping test in short mode")
-	}
-
 	ln := fasthttputil.NewInmemoryListener()
 
 	timeout := false
 	s := &Server{
 		Handler: func(ctx *RequestCtx) {
 			if timeout {
-				time.Sleep(time.Minute)
+				time.Sleep(time.Second)
 			} else {
 				timeout = true
 			}
@@ -649,7 +643,7 @@ func TestClientReadTimeout(t *testing.T) {
 	go s.Serve(ln) //nolint:errcheck
 
 	c := &HostClient{
-		ReadTimeout:               time.Second * 4,
+		ReadTimeout:               time.Millisecond * 400,
 		MaxIdemponentCallAttempts: 1,
 		Dial: func(addr string) (net.Conn, error) {
 			return ln.Dial()
@@ -692,8 +686,8 @@ func TestClientReadTimeout(t *testing.T) {
 	select {
 	case <-done:
 		// This shouldn't take longer than the timeout times the number of requests it is going to try to do.
-		// Give it 2 seconds extra seconds just to be sure.
-	case <-time.After(c.ReadTimeout*time.Duration(c.MaxIdemponentCallAttempts) + time.Second*2):
+		// Give it an extra second just to be sure.
+	case <-time.After(c.ReadTimeout*time.Duration(c.MaxIdemponentCallAttempts) + time.Second):
 		t.Fatal("Client.ReadTimeout didn't work")
 	}
 }
@@ -1282,6 +1276,8 @@ func TestHostClientPendingRequests(t *testing.T) {
 }
 
 func TestHostClientMaxConnsWithDeadline(t *testing.T) {
+	t.Parallel()
+
 	var (
 		emptyBodyCount uint8
 		ln             = fasthttputil.NewInmemoryListener()
@@ -2515,9 +2511,6 @@ func startEchoServerExt(t *testing.T, network, addr string, isTLS bool) *testEch
 func TestClientTLSHandshakeTimeout(t *testing.T) {
 	t.Parallel()
 
-	if testing.Short() {
-		t.Skip("skipping test in short mode")
-	}
 	listener, err := net.Listen("tcp", "127.0.0.1:0")
 	if err != nil {
 		t.Fatal(err)
@@ -2540,8 +2533,8 @@ func TestClientTLSHandshakeTimeout(t *testing.T) {
 	}()
 
 	client := Client{
-		WriteTimeout: 1 * time.Second,
-		ReadTimeout:  1 * time.Second,
+		WriteTimeout: 100 * time.Millisecond,
+		ReadTimeout:  100 * time.Millisecond,
 	}
 
 	_, _, err = client.Get(nil, "https://"+addr)
@@ -2555,6 +2548,8 @@ func TestClientTLSHandshakeTimeout(t *testing.T) {
 }
 
 func TestHostClientMaxConnWaitTimeoutSuccess(t *testing.T) {
+	t.Parallel()
+
 	var (
 		emptyBodyCount uint8
 		ln             = fasthttputil.NewInmemoryListener()
@@ -2632,6 +2627,8 @@ func TestHostClientMaxConnWaitTimeoutSuccess(t *testing.T) {
 }
 
 func TestHostClientMaxConnWaitTimeoutError(t *testing.T) {
+	t.Parallel()
+
 	var (
 		emptyBodyCount uint8
 		ln             = fasthttputil.NewInmemoryListener()
@@ -2720,6 +2717,8 @@ func TestHostClientMaxConnWaitTimeoutError(t *testing.T) {
 }
 
 func TestHostClientMaxConnWaitTimeoutWithEarlierDeadline(t *testing.T) {
+	t.Parallel()
+
 	var (
 		emptyBodyCount uint8
 		ln             = fasthttputil.NewInmemoryListener()

+ 2 - 0
cookie_test.go

@@ -7,6 +7,8 @@ import (
 )
 
 func TestCookiePanic(t *testing.T) {
+	t.Parallel()
+
 	var c Cookie
 	if err := c.Parse(";SAMeSITe="); err != nil {
 		t.Error(err)

+ 2 - 0
expvarhandler/expvar_test.go

@@ -10,6 +10,8 @@ import (
 )
 
 func TestExpvarHandlerBasic(t *testing.T) {
+	t.Parallel()
+
 	expvar.Publish("customVar", expvar.Func(func() interface{} {
 		return "foobar"
 	}))

+ 4 - 0
fasthttpadaptor/adaptor_test.go

@@ -13,6 +13,8 @@ import (
 )
 
 func TestNewFastHTTPHandler(t *testing.T) {
+	t.Parallel()
+
 	expectedMethod := fasthttp.MethodPost
 	expectedProto := "HTTP/1.1"
 	expectedProtoMajor := 1
@@ -141,6 +143,8 @@ func setContextValueMiddleware(next fasthttp.RequestHandler, key string, value i
 }
 
 func TestContentType(t *testing.T) {
+	t.Parallel()
+
 	nethttpH := func(w http.ResponseWriter, r *http.Request) {
 		w.Write([]byte("<!doctype html><html>")) //nolint:errcheck
 	}

+ 8 - 0
fasthttputil/inmemory_listener_test.go

@@ -14,6 +14,8 @@ import (
 )
 
 func TestInmemoryListener(t *testing.T) {
+	t.Parallel()
+
 	ln := NewInmemoryListener()
 
 	ch := make(chan struct{})
@@ -156,12 +158,16 @@ func testInmemoryListenerHTTPSingle(t *testing.T, client *http.Client, content s
 }
 
 func TestInmemoryListenerHTTPSingle(t *testing.T) {
+	t.Parallel()
+
 	testInmemoryListenerHTTP(t, func(t *testing.T, client *http.Client) {
 		testInmemoryListenerHTTPSingle(t, client, "request")
 	})
 }
 
 func TestInmemoryListenerHTTPSerial(t *testing.T) {
+	t.Parallel()
+
 	testInmemoryListenerHTTP(t, func(t *testing.T, client *http.Client) {
 		for i := 0; i < 10; i++ {
 			testInmemoryListenerHTTPSingle(t, client, fmt.Sprintf("request_%d", i))
@@ -170,6 +176,8 @@ func TestInmemoryListenerHTTPSerial(t *testing.T) {
 }
 
 func TestInmemoryListenerHTTPConcurrent(t *testing.T) {
+	t.Parallel()
+
 	testInmemoryListenerHTTP(t, func(t *testing.T, client *http.Client) {
 		var wg sync.WaitGroup
 		for i := 0; i < 10; i++ {

+ 18 - 0
fasthttputil/pipeconns_test.go

@@ -11,6 +11,8 @@ import (
 )
 
 func TestPipeConnsWriteTimeout(t *testing.T) {
+	t.Parallel()
+
 	pc := NewPipeConns()
 	c1 := pc.Conn1()
 
@@ -67,10 +69,14 @@ func TestPipeConnsWriteTimeout(t *testing.T) {
 }
 
 func TestPipeConnsPositiveReadTimeout(t *testing.T) {
+	t.Parallel()
+
 	testPipeConnsReadTimeout(t, time.Millisecond)
 }
 
 func TestPipeConnsNegativeReadTimeout(t *testing.T) {
+	t.Parallel()
+
 	testPipeConnsReadTimeout(t, -time.Second)
 }
 
@@ -116,6 +122,8 @@ func testPipeConnsReadTimeout(t *testing.T, timeout time.Duration) {
 }
 
 func TestPipeConnsCloseWhileReadWriteConcurrent(t *testing.T) {
+	t.Parallel()
+
 	concurrency := 4
 	ch := make(chan struct{}, concurrency)
 	for i := 0; i < concurrency; i++ {
@@ -135,6 +143,8 @@ func TestPipeConnsCloseWhileReadWriteConcurrent(t *testing.T) {
 }
 
 func TestPipeConnsCloseWhileReadWriteSerial(t *testing.T) {
+	t.Parallel()
+
 	testPipeConnsCloseWhileReadWriteSerial(t)
 }
 
@@ -205,10 +215,14 @@ func testPipeConnsCloseWhileReadWrite(t *testing.T) {
 }
 
 func TestPipeConnsReadWriteSerial(t *testing.T) {
+	t.Parallel()
+
 	testPipeConnsReadWriteSerial(t)
 }
 
 func TestPipeConnsReadWriteConcurrent(t *testing.T) {
+	t.Parallel()
+
 	testConcurrency(t, 10, testPipeConnsReadWriteSerial)
 }
 
@@ -262,10 +276,14 @@ func testPipeConnsReadWrite(t *testing.T, c1, c2 net.Conn) {
 }
 
 func TestPipeConnsCloseSerial(t *testing.T) {
+	t.Parallel()
+
 	testPipeConnsCloseSerial(t)
 }
 
 func TestPipeConnsCloseConcurrent(t *testing.T) {
+	t.Parallel()
+
 	testConcurrency(t, 10, testPipeConnsCloseSerial)
 }
 

+ 6 - 4
fs_test.go

@@ -50,6 +50,8 @@ func TestNewVHostPathRewriter(t *testing.T) {
 }
 
 func TestNewVHostPathRewriterMaliciousHost(t *testing.T) {
+	t.Parallel()
+
 	var ctx RequestCtx
 	var req Request
 	req.Header.SetHost("/../../../etc/passwd")
@@ -301,7 +303,7 @@ func TestServeFileUncompressed(t *testing.T) {
 }
 
 func TestFSByteRangeConcurrent(t *testing.T) {
-	t.Parallel()
+	// This test can't run parallel as files in / might by changed by other tests.
 
 	stop := make(chan struct{})
 	defer close(stop)
@@ -335,7 +337,7 @@ func TestFSByteRangeConcurrent(t *testing.T) {
 }
 
 func TestFSByteRangeSingleThread(t *testing.T) {
-	t.Parallel()
+	// This test can't run parallel as files in / might by changed by other tests.
 
 	stop := make(chan struct{})
 	defer close(stop)
@@ -818,12 +820,12 @@ func TestServeFileContentType(t *testing.T) {
 }
 
 func TestServeFileDirectoryRedirect(t *testing.T) {
+	t.Parallel()
+
 	if runtime.GOOS == "windows" {
 		t.SkipNow()
 	}
 
-	t.Parallel()
-
 	var ctx RequestCtx
 	var req Request
 	req.SetRequestURI("http://foobar.com")

+ 16 - 0
header_test.go

@@ -34,6 +34,8 @@ func TestResponseHeaderAddContentType(t *testing.T) {
 }
 
 func TestResponseHeaderMultiLineValue(t *testing.T) {
+	t.Parallel()
+
 	s := "HTTP/1.1 200 OK\r\n" +
 		"EmptyValue1:\r\n" +
 		"Content-Type: foo/bar;\r\n\tnewline;\r\n another/newline\r\n" +
@@ -61,6 +63,8 @@ func TestResponseHeaderMultiLineValue(t *testing.T) {
 }
 
 func TestResponseHeaderMultiLineName(t *testing.T) {
+	t.Parallel()
+
 	s := "HTTP/1.1 200 OK\r\n" +
 		"Host: golang.org\r\n" +
 		"Gopher-New-\r\n" +
@@ -77,6 +81,8 @@ func TestResponseHeaderMultiLineName(t *testing.T) {
 }
 
 func TestResponseHeaderMultiLinePaniced(t *testing.T) {
+	t.Parallel()
+
 	// Input generated by fuzz testing that caused the parser to panic.
 	s, _ := base64.StdEncoding.DecodeString("aAEAIDoKKDoKICA6CgkKCiA6CiA6CgkpCiA6CiA6CiA6Cig6CiAgOgoJCgogOgogOgoJKQogOgogOgogOgogOgogOgoJOg86CiA6CiA6Cig6CiAyCg==")
 	header := new(RequestHeader)
@@ -399,6 +405,8 @@ func TestResponseHeaderAdd(t *testing.T) {
 }
 
 func TestRequestHeaderAdd(t *testing.T) {
+	t.Parallel()
+
 	m := make(map[string]struct{})
 	var h RequestHeader
 	h.Add("aaa", "bbb")
@@ -838,6 +846,8 @@ func TestResponseHeaderOldVersion(t *testing.T) {
 }
 
 func TestRequestHeaderSetByteRange(t *testing.T) {
+	t.Parallel()
+
 	testRequestHeaderSetByteRange(t, 0, 10, "bytes=0-10")
 	testRequestHeaderSetByteRange(t, 123, -1, "bytes=123-")
 	testRequestHeaderSetByteRange(t, -234, 58349, "bytes=-234")
@@ -1897,6 +1907,8 @@ func TestRequestHeaderSetGet(t *testing.T) {
 }
 
 func TestResponseHeaderSetGet(t *testing.T) {
+	t.Parallel()
+
 	h := &ResponseHeader{}
 	h.Set("foo", "bar")
 	h.Set("content-type", "aaa/bbb")
@@ -2396,6 +2408,8 @@ func TestRequestHeaderReadSuccess(t *testing.T) {
 }
 
 func TestResponseHeaderReadError(t *testing.T) {
+	t.Parallel()
+
 	h := &ResponseHeader{}
 
 	// incorrect first line
@@ -2419,6 +2433,8 @@ func TestResponseHeaderReadError(t *testing.T) {
 }
 
 func TestResponseHeaderReadErrorSecureLog(t *testing.T) {
+	t.Parallel()
+
 	h := &ResponseHeader{
 		secureErrorLogMessage: true,
 	}

+ 4 - 0
http_test.go

@@ -34,6 +34,8 @@ func TestResponseEmptyTransferEncoding(t *testing.T) {
 
 // Don't send the fragment/hash/# part of a URL to the server.
 func TestFragmentInURIRequest(t *testing.T) {
+	t.Parallel()
+
 	var req Request
 	req.SetRequestURI("https://docs.gitlab.com/ee/user/project/integrations/webhooks.html#events")
 
@@ -48,6 +50,8 @@ func TestFragmentInURIRequest(t *testing.T) {
 }
 
 func TestIssue875(t *testing.T) {
+	t.Parallel()
+
 	type testcase struct {
 		uri              string
 		expectedRedirect string

+ 18 - 8
prefork/prefork_test.go

@@ -25,22 +25,25 @@ func getAddr() string {
 }
 
 func Test_IsChild(t *testing.T) {
+	// This test can't run parallel as it modifies os.Args.
+
 	v := IsChild()
 	if v {
 		t.Errorf("IsChild() == %v, want %v", v, false)
 	}
 
 	setUp()
+	defer tearDown()
 
 	v = IsChild()
 	if !v {
 		t.Errorf("IsChild() == %v, want %v", v, true)
 	}
-
-	tearDown()
 }
 
 func Test_New(t *testing.T) {
+	t.Parallel()
+
 	s := &fasthttp.Server{}
 	p := New(s)
 
@@ -62,6 +65,8 @@ func Test_New(t *testing.T) {
 }
 
 func Test_listen(t *testing.T) {
+	t.Parallel()
+
 	p := &Prefork{
 		Reuseport: true,
 	}
@@ -91,6 +96,8 @@ func Test_listen(t *testing.T) {
 }
 
 func Test_setTCPListenerFiles(t *testing.T) {
+	t.Parallel()
+
 	if runtime.GOOS == "windows" {
 		t.SkipNow()
 	}
@@ -125,7 +132,10 @@ func Test_setTCPListenerFiles(t *testing.T) {
 }
 
 func Test_ListenAndServe(t *testing.T) {
+	// This test can't run parallel as it modifies os.Args.
+
 	setUp()
+	defer tearDown()
 
 	s := &fasthttp.Server{}
 	p := New(s)
@@ -151,12 +161,13 @@ func Test_ListenAndServe(t *testing.T) {
 	if p.ln == nil {
 		t.Error("Prefork.ln is nil")
 	}
-
-	tearDown()
 }
 
 func Test_ListenAndServeTLS(t *testing.T) {
+	// This test can't run parallel as it modifies os.Args.
+
 	setUp()
+	defer tearDown()
 
 	s := &fasthttp.Server{}
 	p := New(s)
@@ -182,12 +193,13 @@ func Test_ListenAndServeTLS(t *testing.T) {
 	if p.ln == nil {
 		t.Error("Prefork.ln is nil")
 	}
-
-	tearDown()
 }
 
 func Test_ListenAndServeTLSEmbed(t *testing.T) {
+	// This test can't run parallel as it modifies os.Args.
+
 	setUp()
+	defer tearDown()
 
 	s := &fasthttp.Server{}
 	p := New(s)
@@ -213,6 +225,4 @@ func Test_ListenAndServeTLSEmbed(t *testing.T) {
 	if p.ln == nil {
 		t.Error("Prefork.ln is nil")
 	}
-
-	tearDown()
 }

+ 4 - 1
reuseport/reuseport_test.go

@@ -9,10 +9,14 @@ import (
 )
 
 func TestTCP4(t *testing.T) {
+	t.Parallel()
+
 	testNewListener(t, "tcp4", "localhost:10081", 20, 1000)
 }
 
 func TestTCP6(t *testing.T) {
+	t.Parallel()
+
 	// Run this test only if tcp6 interface exists.
 	if hasLocalIPv6(t) {
 		testNewListener(t, "tcp6", "[::1]:10082", 20, 1000)
@@ -33,7 +37,6 @@ func hasLocalIPv6(t *testing.T) bool {
 }
 
 func testNewListener(t *testing.T, network, addr string, serversCount, requestsCount int) {
-
 	var lns []net.Listener
 	doneCh := make(chan struct{}, serversCount)
 

+ 13 - 1
server_test.go

@@ -1551,6 +1551,8 @@ func TestServerHTTP10ConnectionClose(t *testing.T) {
 }
 
 func TestRequestCtxFormValue(t *testing.T) {
+	t.Parallel()
+
 	var ctx RequestCtx
 	var req Request
 	req.SetRequestURI("/foo/bar?baz=123&aaa=bbb")
@@ -1609,6 +1611,8 @@ func TestRequestCtxUserValue(t *testing.T) {
 }
 
 func TestServerHeadRequest(t *testing.T) {
+	t.Parallel()
+
 	s := &Server{
 		Handler: func(ctx *RequestCtx) {
 			fmt.Fprintf(ctx, "Request method is %q", ctx.Method())
@@ -2334,6 +2338,8 @@ func TestRequestCtxNoHijackNoResponse(t *testing.T) {
 }
 
 func TestRequestCtxInit(t *testing.T) {
+	// This test can't run parallel as it modifies globalConnID.
+
 	var ctx RequestCtx
 	var logger testLogger
 	globalConnID = 0x123456
@@ -2871,6 +2877,8 @@ func TestServerEmptyResponse(t *testing.T) {
 }
 
 func TestServerLogger(t *testing.T) {
+	// This test can't run parallel as it modifies globalConnID.
+
 	cl := &testLogger{}
 	s := &Server{
 		Handler: func(ctx *RequestCtx) {
@@ -3118,6 +3126,8 @@ func TestServeConnSingleRequest(t *testing.T) {
 }
 
 func TestServeConnMultiRequests(t *testing.T) {
+	t.Parallel()
+
 	s := &Server{
 		Handler: func(ctx *RequestCtx) {
 			h := &ctx.Request.Header
@@ -3278,7 +3288,7 @@ func TestShutdownReuse(t *testing.T) {
 		Handler: func(ctx *RequestCtx) {
 			ctx.Success("aaa/bbb", []byte("real response"))
 		},
-		ReadTimeout: time.Second,
+		ReadTimeout: time.Millisecond * 100,
 		Logger:      &testLogger{}, // Ignore log output.
 	}
 	go func() {
@@ -3736,6 +3746,8 @@ func TestMaxWriteTimeoutPerRequest(t *testing.T) {
 }
 
 func TestIncompleteBodyReturnsUnexpectedEOF(t *testing.T) {
+	t.Parallel()
+
 	rw := &readWriter{}
 	rw.r.WriteString("POST /foo HTTP/1.1\r\nHost: google.com\r\nContent-Length: 5\r\n\r\n123")
 	s := &Server{

+ 4 - 0
stackless/func_test.go

@@ -8,6 +8,8 @@ import (
 )
 
 func TestNewFuncSimple(t *testing.T) {
+	t.Parallel()
+
 	var n uint64
 	f := NewFunc(func(ctx interface{}) {
 		atomic.AddUint64(&n, uint64(ctx.(int)))
@@ -25,6 +27,8 @@ func TestNewFuncSimple(t *testing.T) {
 }
 
 func TestNewFuncMulti(t *testing.T) {
+	t.Parallel()
+
 	var n1, n2 uint64
 	f1 := NewFunc(func(ctx interface{}) {
 		atomic.AddUint64(&n1, uint64(ctx.(int)))

+ 8 - 0
stackless/writer_test.go

@@ -12,12 +12,16 @@ import (
 )
 
 func TestCompressFlateSerial(t *testing.T) {
+	t.Parallel()
+
 	if err := testCompressFlate(); err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
 }
 
 func TestCompressFlateConcurrent(t *testing.T) {
+	t.Parallel()
+
 	if err := testConcurrent(testCompressFlate, 10); err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
@@ -36,12 +40,16 @@ func testCompressFlate() error {
 }
 
 func TestCompressGzipSerial(t *testing.T) {
+	t.Parallel()
+
 	if err := testCompressGzip(); err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
 }
 
 func TestCompressGzipConcurrent(t *testing.T) {
+	t.Parallel()
+
 	if err := testConcurrent(testCompressGzip, 10); err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}

+ 2 - 0
streaming_test.go

@@ -143,6 +143,8 @@ func getChunkedTestEnv(t testing.TB) (*fasthttputil.InmemoryListener, []byte) {
 }
 
 func TestRequestStream(t *testing.T) {
+	t.Parallel()
+
 	ln, formattedRequest := getChunkedTestEnv(t)
 
 	c, err := ln.Dial()

+ 6 - 0
uri_test.go

@@ -142,6 +142,8 @@ func testURIUpdate(t *testing.T, base, update, result string) {
 }
 
 func TestURIPathNormalize(t *testing.T) {
+	t.Parallel()
+
 	var u URI
 
 	// double slash
@@ -274,6 +276,8 @@ func testURIFullURI(t *testing.T, scheme, host, path, hash string, args *Args, e
 }
 
 func TestURIParseNilHost(t *testing.T) {
+	t.Parallel()
+
 	testURIParseScheme(t, "http://google.com/foo?bar#baz", "http", "google.com", "/foo?bar", "baz")
 	testURIParseScheme(t, "HTtP://google.com/", "http", "google.com", "/", "")
 	testURIParseScheme(t, "://google.com/xyz", "http", "google.com", "/xyz", "")
@@ -388,6 +392,8 @@ func testURIParse(t *testing.T, u *URI, host, uri,
 }
 
 func TestURIWithQuerystringOverride(t *testing.T) {
+	t.Parallel()
+
 	var u URI
 	u.SetQueryString("q1=foo&q2=bar")
 	u.QueryArgs().Add("q3", "baz")