Merge branch 'main' into 18842-arv-mount-disk-config
[arvados.git] / lib / controller / dblock / dblock_test.go
diff --git a/lib/controller/dblock/dblock_test.go b/lib/controller/dblock/dblock_test.go
new file mode 100644 (file)
index 0000000..b10b2a3
--- /dev/null
@@ -0,0 +1,91 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+package dblock
+
+import (
+       "bytes"
+       "context"
+       "sync"
+       "testing"
+       "time"
+
+       "git.arvados.org/arvados.git/lib/config"
+       "git.arvados.org/arvados.git/sdk/go/arvados"
+       "git.arvados.org/arvados.git/sdk/go/arvadostest"
+       "git.arvados.org/arvados.git/sdk/go/ctxlog"
+       "github.com/jmoiron/sqlx"
+       "github.com/sirupsen/logrus"
+       check "gopkg.in/check.v1"
+)
+
+func Test(t *testing.T) {
+       check.TestingT(t)
+}
+
+var _ = check.Suite(&suite{})
+
+type suite struct {
+       cluster *arvados.Cluster
+       db      *sqlx.DB
+       getdb   func(context.Context) (*sqlx.DB, error)
+}
+
+var testLocker = &DBLocker{key: 999}
+
+func (s *suite) SetUpSuite(c *check.C) {
+       cfg, err := config.NewLoader(nil, ctxlog.TestLogger(c)).Load()
+       c.Assert(err, check.IsNil)
+       s.cluster, err = cfg.GetCluster("")
+       c.Assert(err, check.IsNil)
+       s.db = arvadostest.DB(c, s.cluster)
+       s.getdb = func(context.Context) (*sqlx.DB, error) { return s.db, nil }
+}
+
+func (s *suite) TestLock(c *check.C) {
+       retryDelay = 10 * time.Millisecond
+
+       var logbuf bytes.Buffer
+       logger := ctxlog.New(&logbuf, "text", "debug")
+       logger.Level = logrus.DebugLevel
+       ctx := ctxlog.Context(context.Background(), logger)
+       ctx, cancel := context.WithCancel(ctx)
+       defer cancel()
+       testLocker.Lock(ctx, s.getdb)
+       testLocker.Check()
+
+       lock2 := make(chan bool)
+       var wg sync.WaitGroup
+       defer wg.Wait()
+       wg.Add(1)
+       go func() {
+               defer wg.Done()
+               testLocker2 := &DBLocker{key: 999}
+               testLocker2.Lock(ctx, s.getdb)
+               close(lock2)
+               testLocker2.Check()
+               testLocker2.Unlock()
+       }()
+
+       // Second lock should wait for first to Unlock
+       select {
+       case <-time.After(time.Second / 10):
+               c.Check(logbuf.String(), check.Matches, `(?ms).*level=info.*DBClient="[^"]+:\d+".*ID=999.*`)
+       case <-lock2:
+               c.Log("double-lock")
+               c.Fail()
+       }
+
+       testLocker.Check()
+       testLocker.Unlock()
+
+       // Now the second lock should succeed within retryDelay
+       select {
+       case <-time.After(retryDelay * 2):
+               c.Log("timed out")
+               c.Fail()
+       case <-lock2:
+       }
+       c.Logf("%s", logbuf.String())
+}