21700: Install Bundler system-wide in Rails postinst
[arvados.git] / lib / controller / dblock / dblock_test.go
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 package dblock
6
7 import (
8         "bytes"
9         "context"
10         "sync"
11         "testing"
12         "time"
13
14         "git.arvados.org/arvados.git/lib/config"
15         "git.arvados.org/arvados.git/sdk/go/arvados"
16         "git.arvados.org/arvados.git/sdk/go/arvadostest"
17         "git.arvados.org/arvados.git/sdk/go/ctxlog"
18         "github.com/jmoiron/sqlx"
19         "github.com/sirupsen/logrus"
20         check "gopkg.in/check.v1"
21 )
22
23 func Test(t *testing.T) {
24         check.TestingT(t)
25 }
26
27 var _ = check.Suite(&suite{})
28
29 type suite struct {
30         cluster *arvados.Cluster
31         db      *sqlx.DB
32         getdb   func(context.Context) (*sqlx.DB, error)
33 }
34
35 var testLocker = &DBLocker{key: 999}
36
37 func (s *suite) SetUpSuite(c *check.C) {
38         cfg, err := config.NewLoader(nil, ctxlog.TestLogger(c)).Load()
39         c.Assert(err, check.IsNil)
40         s.cluster, err = cfg.GetCluster("")
41         c.Assert(err, check.IsNil)
42         s.db = arvadostest.DB(c, s.cluster)
43         s.getdb = func(context.Context) (*sqlx.DB, error) { return s.db, nil }
44 }
45
46 func (s *suite) TestLock(c *check.C) {
47         retryDelay = 10 * time.Millisecond
48
49         var logbuf bytes.Buffer
50         logger := ctxlog.New(&logbuf, "text", "debug")
51         logger.Level = logrus.DebugLevel
52         ctx := ctxlog.Context(context.Background(), logger)
53         ctx, cancel := context.WithCancel(ctx)
54         defer cancel()
55         testLocker.Lock(ctx, s.getdb)
56         testLocker.Check()
57
58         lock2 := make(chan bool)
59         var wg sync.WaitGroup
60         defer wg.Wait()
61         wg.Add(1)
62         go func() {
63                 defer wg.Done()
64                 testLocker2 := &DBLocker{key: 999}
65                 testLocker2.Lock(ctx, s.getdb)
66                 close(lock2)
67                 testLocker2.Check()
68                 testLocker2.Unlock()
69         }()
70
71         // Second lock should wait for first to Unlock
72         select {
73         case <-time.After(time.Second / 10):
74                 c.Check(logbuf.String(), check.Matches, `(?ms).*level=info.*DBClient="[^"]+:\d+".*ID=999.*`)
75         case <-lock2:
76                 c.Log("double-lock")
77                 c.Fail()
78         }
79
80         testLocker.Check()
81         testLocker.Unlock()
82
83         // Now the second lock should succeed within retryDelay
84         select {
85         case <-time.After(retryDelay * 2):
86                 c.Log("timed out")
87                 c.Fail()
88         case <-lock2:
89         }
90         c.Logf("%s", logbuf.String())
91 }