github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/swarmkit/agent/storage_test.go (about) 1 package agent 2 3 import ( 4 "io/ioutil" 5 "math/rand" 6 "os" 7 "path/filepath" 8 "sort" 9 "testing" 10 11 "github.com/docker/swarmkit/api" 12 "github.com/docker/swarmkit/identity" 13 "github.com/stretchr/testify/assert" 14 bolt "go.etcd.io/bbolt" 15 ) 16 17 func TestStorageInit(t *testing.T) { 18 db, cleanup := storageTestEnv(t) 19 defer cleanup() 20 21 assert.NoError(t, InitDB(db)) // ensure idempotence. 22 assert.NoError(t, db.View(func(tx *bolt.Tx) error { 23 bkt := tx.Bucket(bucketKeyStorageVersion) 24 assert.NotNil(t, bkt) 25 26 tbkt := bkt.Bucket([]byte("tasks")) 27 assert.NotNil(t, tbkt) 28 29 return nil 30 })) 31 } 32 33 func TestStoragePutGet(t *testing.T) { 34 db, cleanup := storageTestEnv(t) 35 defer cleanup() 36 37 tasks := genTasks(20) 38 39 assert.NoError(t, db.Update(func(tx *bolt.Tx) error { 40 for i, task := range tasks { 41 assert.NoError(t, PutTask(tx, task)) 42 // remove status to make comparison work 43 tasks[i].Status = api.TaskStatus{} 44 } 45 46 return nil 47 })) 48 49 assert.NoError(t, db.View(func(tx *bolt.Tx) error { 50 for _, task := range tasks { 51 retrieved, err := GetTask(tx, task.ID) 52 assert.NoError(t, err) 53 assert.Equal(t, task, retrieved) 54 } 55 56 return nil 57 })) 58 } 59 60 func TestStoragePutGetStatusAssigned(t *testing.T) { 61 db, cleanup := storageTestEnv(t) 62 defer cleanup() 63 64 tasks := genTasks(20) 65 66 // set task, status and assignment for all tasks. 67 assert.NoError(t, db.Update(func(tx *bolt.Tx) error { 68 for _, task := range tasks { 69 assert.NoError(t, PutTask(tx, task)) 70 assert.NoError(t, PutTaskStatus(tx, task.ID, &task.Status)) 71 assert.NoError(t, SetTaskAssignment(tx, task.ID, true)) 72 } 73 74 return nil 75 })) 76 77 assert.NoError(t, db.View(func(tx *bolt.Tx) error { 78 for _, task := range tasks { 79 status, err := GetTaskStatus(tx, task.ID) 80 assert.NoError(t, err) 81 assert.Equal(t, &task.Status, status) 82 83 retrieved, err := GetTask(tx, task.ID) 84 assert.NoError(t, err) 85 86 task.Status = api.TaskStatus{} 87 assert.Equal(t, task, retrieved) 88 89 assert.True(t, TaskAssigned(tx, task.ID)) 90 } 91 92 return nil 93 })) 94 95 // set evens to unassigned and updates all states plus one 96 assert.NoError(t, db.Update(func(tx *bolt.Tx) error { 97 for i, task := range tasks { 98 task.Status.State++ 99 assert.NoError(t, PutTaskStatus(tx, task.ID, &task.Status)) 100 101 if i%2 == 0 { 102 assert.NoError(t, SetTaskAssignment(tx, task.ID, false)) 103 } 104 } 105 106 return nil 107 })) 108 109 assert.NoError(t, db.View(func(tx *bolt.Tx) error { 110 for i, task := range tasks { 111 status, err := GetTaskStatus(tx, task.ID) 112 assert.NoError(t, err) 113 assert.Equal(t, &task.Status, status) 114 115 retrieved, err := GetTask(tx, task.ID) 116 assert.NoError(t, err) 117 118 task.Status = api.TaskStatus{} 119 assert.Equal(t, task, retrieved) 120 121 if i%2 == 0 { 122 assert.False(t, TaskAssigned(tx, task.ID)) 123 } else { 124 assert.True(t, TaskAssigned(tx, task.ID)) 125 } 126 127 } 128 129 return nil 130 })) 131 } 132 133 func genTasks(n int) []*api.Task { 134 var tasks []*api.Task 135 for i := 0; i < n; i++ { 136 tasks = append(tasks, genTask()) 137 } 138 139 sort.Stable(tasksByID(tasks)) 140 141 return tasks 142 } 143 144 func genTask() *api.Task { 145 return &api.Task{ 146 ID: identity.NewID(), 147 ServiceID: identity.NewID(), 148 Status: *genTaskStatus(), 149 Spec: api.TaskSpec{ 150 Runtime: &api.TaskSpec_Container{ 151 Container: &api.ContainerSpec{ 152 Image: "foo", 153 Command: []string{"this", "-w", "works"}, 154 }, 155 }, 156 }, 157 } 158 } 159 160 var taskStates = []api.TaskState{ 161 api.TaskStateAssigned, api.TaskStateAccepted, 162 api.TaskStatePreparing, api.TaskStateReady, 163 api.TaskStateStarting, api.TaskStateRunning, 164 api.TaskStateCompleted, api.TaskStateFailed, 165 api.TaskStateRejected, api.TaskStateShutdown, 166 } 167 168 func genTaskStatus() *api.TaskStatus { 169 return &api.TaskStatus{ 170 State: taskStates[rand.Intn(len(taskStates))], 171 Message: identity.NewID(), // just put some garbage here. 172 } 173 } 174 175 // storageTestEnv returns an initialized db and cleanup function for use in 176 // tests. 177 func storageTestEnv(t *testing.T) (*bolt.DB, func()) { 178 var cleanup []func() 179 dir, err := ioutil.TempDir("", "agent-TestStorage-") 180 assert.NoError(t, err) 181 182 dbpath := filepath.Join(dir, "tasks.db") 183 assert.NoError(t, os.MkdirAll(dir, 0777)) 184 cleanup = append(cleanup, func() { os.RemoveAll(dir) }) 185 186 db, err := bolt.Open(dbpath, 0666, nil) 187 assert.NoError(t, err) 188 cleanup = append(cleanup, func() { db.Close() }) 189 190 assert.NoError(t, InitDB(db)) 191 return db, func() { 192 // iterate in reverse so it works like defer 193 for i := len(cleanup) - 1; i >= 0; i-- { 194 cleanup[i]() 195 } 196 } 197 } 198 199 type tasksByID []*api.Task 200 201 func (ts tasksByID) Len() int { return len(ts) } 202 func (ts tasksByID) Less(i, j int) bool { return ts[i].ID < ts[j].ID } 203 func (ts tasksByID) Swap(i, j int) { ts[i], ts[j] = ts[j], ts[i] }