20559: Test concurrent writes using same token.
authorTom Clegg <tom@curii.com>
Tue, 13 Jun 2023 21:47:14 +0000 (17:47 -0400)
committerTom Clegg <tom@curii.com>
Thu, 29 Jun 2023 18:14:13 +0000 (14:14 -0400)
Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom@curii.com>

services/keep-web/handler_test.go

index c9b48f99a73c01407374c046fcde443ce11abe4b..60fe4acc46bb56dd2838503bb40aba9460ea2ca8 100644 (file)
@@ -18,6 +18,7 @@ import (
        "path/filepath"
        "regexp"
        "strings"
+       "sync"
        "time"
 
        "git.arvados.org/arvados.git/lib/config"
@@ -1624,3 +1625,59 @@ func (s *IntegrationSuite) TestUploadLoggingPermission(c *check.C) {
                }
        }
 }
+
+func (s *IntegrationSuite) TestConcurrentWrites(c *check.C) {
+       client := arvados.NewClientFromEnv()
+       client.AuthToken = arvadostest.ActiveTokenV2
+       // Start small, and increase concurrency (2^2, 4^2, 8^2, 16^2)
+       // only until hitting failure. Avoids unnecessarily long
+       // failure reports.
+       for n := 2; n < 32 && !c.Failed(); n++ {
+               var coll arvados.Collection
+               err := client.RequestAndDecode(&coll, "POST", "arvados/v1/collections", nil, nil)
+               c.Assert(err, check.IsNil)
+               defer client.RequestAndDecode(&coll, "DELETE", "arvados/v1/collections/"+coll.UUID, nil, nil)
+
+               var wg sync.WaitGroup
+               for i := 0; i < n && !c.Failed(); i++ {
+                       i := i
+                       wg.Add(1)
+                       go func() {
+                               defer wg.Done()
+                               u := mustParseURL(fmt.Sprintf("http://%s.collections.example.com/i=%d", coll.UUID, i))
+                               resp := httptest.NewRecorder()
+                               req, err := http.NewRequest("MKCOL", u.String(), nil)
+                               c.Assert(err, check.IsNil)
+                               req.Header.Set("Authorization", "Bearer "+client.AuthToken)
+                               s.handler.ServeHTTP(resp, req)
+                               c.Assert(resp.Code, check.Equals, http.StatusCreated)
+                               for j := 0; j < n && !c.Failed(); j++ {
+                                       j := j
+                                       wg.Add(1)
+                                       go func() {
+                                               defer wg.Done()
+                                               content := fmt.Sprintf("i=%d/j=%d", i, j)
+                                               u := mustParseURL("http://" + coll.UUID + ".collections.example.com/" + content)
+
+                                               resp := httptest.NewRecorder()
+                                               req, err := http.NewRequest("PUT", u.String(), strings.NewReader(content))
+                                               c.Assert(err, check.IsNil)
+                                               req.Header.Set("Authorization", "Bearer "+client.AuthToken)
+                                               s.handler.ServeHTTP(resp, req)
+                                               c.Check(resp.Code, check.Equals, http.StatusCreated)
+
+                                               time.Sleep(time.Second)
+                                               resp = httptest.NewRecorder()
+                                               req, err = http.NewRequest("GET", u.String(), nil)
+                                               c.Assert(err, check.IsNil)
+                                               req.Header.Set("Authorization", "Bearer "+client.AuthToken)
+                                               s.handler.ServeHTTP(resp, req)
+                                               c.Check(resp.Code, check.Equals, http.StatusOK)
+                                               c.Check(resp.Body.String(), check.Equals, content)
+                                       }()
+                               }
+                       }()
+               }
+               wg.Wait()
+       }
+}