// Copyright 2019 Yunion // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package lockman import ( "context" "fmt" "sync" "testing" "time" "yunion.io/x/pkg/util/stringutils" ) type FakeObject struct { Id string playerId int playerIdCount int } func (o *FakeObject) GetId() string { return o.Id } func (o *FakeObject) Keyword() string { return "fake" } func (o *FakeObject) push(playerId int) { if o.playerId >= 0 { if o.playerId != playerId { panic(fmt.Sprintf("obj locked by %d, locked again by %d", o.playerId, playerId)) } } else { if o.playerIdCount != 0 { panic(fmt.Sprintf("obj unlocked but player id count %d", o.playerIdCount)) } o.playerId = playerId } o.playerIdCount += 1 } func (o *FakeObject) pop(playerId int) { if o.playerId != playerId { panic(fmt.Sprintf("obj previously locked by %d, now unlocked by %d", o.playerId, playerId)) } o.playerIdCount -= 1 if o.playerIdCount < 0 { panic("obj overly unlocked") } else if o.playerIdCount == 0 { o.playerId = -1 } } func newSharedObject() *FakeObject { obj := &FakeObject{ Id: stringutils.UUID4(), playerId: -1, playerIdCount: 0, } return obj } type testLockManagerConfig struct { players int cycles int shared *FakeObject lockman ILockManager } func testLockManager(t *testing.T, cfg *testLockManagerConfig) { players := cfg.players cycles := cfg.cycles shared := cfg.shared lockman := cfg.lockman bug = func(fmtStr string, fmtArgs ...interface{}) { t.Fatalf(fmtStr, fmtArgs...) } run := func(ctx context.Context, id int, cycle int, sleep time.Duration) { key := getObjectKey(shared) indents := []string{" ", " "} logpref := fmt.Sprintf("%p: %02d: %p", lockman, id, ctx) func() { fmt.Printf("%s: %s >acquire\n", logpref, indents[0]) lockman.LockKey(ctx, key) shared.push(id) fmt.Printf("%s: %s >>acquired\n", logpref, indents[1]) }() defer func() { fmt.Printf("%s: %s <