github.com/mirantis/virtlet@v1.5.2-0.20191204181327-1659b8a48e9b/pkg/flexvolume/flexvolume_test.go (about) 1 /* 2 Copyright 2017 Mirantis 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package flexvolume 18 19 import ( 20 "encoding/json" 21 "io/ioutil" 22 "os" 23 "path" 24 "reflect" 25 "strings" 26 "testing" 27 28 fakefs "github.com/Mirantis/virtlet/pkg/fs/fake" 29 "github.com/Mirantis/virtlet/pkg/utils" 30 testutils "github.com/Mirantis/virtlet/pkg/utils/testing" 31 ) 32 33 const ( 34 fakeUUID = "abb67e3c-71b3-4ddd-5505-8c4215d5c4eb" 35 ) 36 37 func TestFlexVolume(t *testing.T) { 38 tmpDir, err := ioutil.TempDir("", "flexvolume-test") 39 if err != nil { 40 t.Fatalf("ioutil.TempDir(): %v", err) 41 } 42 defer os.RemoveAll(tmpDir) 43 44 cephJSONOpts := map[string]interface{}{ 45 "type": "ceph", 46 "monitor": "127.0.0.1:6789", 47 "pool": "libvirt-pool", 48 "volume": "rbd-test-image", 49 "secret": "foobar", 50 "user": "libvirt", 51 } 52 cephJSONVolumeInfo := map[string]interface{}{ 53 "uuid": fakeUUID, 54 } 55 for k, v := range cephJSONOpts { 56 cephJSONVolumeInfo[k] = v 57 } 58 cephDir := path.Join(tmpDir, "ceph") 59 for _, step := range []struct { 60 name string 61 args []string 62 subdir string 63 status string 64 message string 65 fields map[string]interface{} 66 files map[string]interface{} 67 mountJournal []*testutils.Record 68 }{ 69 { 70 name: "init", 71 args: []string{"init"}, 72 status: "Success", 73 }, 74 { 75 name: "attach", 76 args: []string{ 77 "attach", 78 "{}", // not actually used by our impl 79 "node1", 80 }, 81 status: "Success", 82 }, 83 { 84 name: "isattached", 85 args: []string{ 86 "isattached", 87 "{}", // not actually used by our impl 88 "node1", 89 }, 90 status: "Success", 91 fields: map[string]interface{}{ 92 "attached": true, 93 }, 94 }, 95 { 96 name: "waitforattach", 97 args: []string{ 98 "waitforattach", 99 "/dev/dummydev", 100 "{}", // not actually used by our impl 101 }, 102 status: "Success", 103 fields: map[string]interface{}{ 104 "device": "/dev/dummydev", 105 }, 106 }, 107 { 108 name: "mount-ceph", 109 args: []string{"mount", cephDir, utils.ToJSON(cephJSONOpts)}, 110 status: "Success", 111 subdir: "ceph", 112 files: map[string]interface{}{ 113 "virtlet-flexvolume.json": utils.ToJSONUnindented(cephJSONVolumeInfo), 114 ".shadowed": map[string]interface{}{ 115 "virtlet-flexvolume.json": utils.ToJSONUnindented(cephJSONVolumeInfo), 116 }, 117 }, 118 mountJournal: []*testutils.Record{ 119 { 120 Name: "Mount", 121 Value: []interface{}{"tmpfs", cephDir, "tmpfs", false}, 122 }, 123 }, 124 }, 125 { 126 name: "unmount-ceph", 127 args: []string{"unmount", cephDir}, 128 status: "Success", 129 subdir: "ceph", 130 mountJournal: []*testutils.Record{ 131 { 132 Name: "Unmount", 133 Value: []interface{}{cephDir, true}, 134 }, 135 }, 136 }, 137 { 138 name: "mount-ceph-1", 139 args: []string{"mount", cephDir, utils.ToJSON(cephJSONOpts)}, 140 status: "Success", 141 subdir: "ceph", 142 files: map[string]interface{}{ 143 "virtlet-flexvolume.json": utils.ToJSONUnindented(cephJSONVolumeInfo), 144 ".shadowed": map[string]interface{}{ 145 "virtlet-flexvolume.json": utils.ToJSONUnindented(cephJSONVolumeInfo), 146 }, 147 }, 148 mountJournal: []*testutils.Record{ 149 { 150 Name: "Mount", 151 Value: []interface{}{"tmpfs", cephDir, "tmpfs", false}, 152 }, 153 }, 154 }, 155 { 156 name: "unmount-ceph-1", 157 args: []string{"unmount", cephDir}, 158 status: "Success", 159 subdir: "ceph", 160 mountJournal: []*testutils.Record{ 161 { 162 Name: "Unmount", 163 Value: []interface{}{cephDir, true}, 164 }, 165 }, 166 }, 167 { 168 name: "detach", 169 args: []string{ 170 "detach", 171 "somedev", 172 "node1", 173 }, 174 status: "Success", 175 }, 176 { 177 name: "badop", 178 args: []string{ 179 "badop", 180 }, 181 status: "Not supported", 182 }, 183 { 184 name: "badmount", 185 args: []string{ 186 "mount", 187 }, 188 status: "Failure", 189 message: "unexpected number of args", 190 }, 191 { 192 name: "noargs", 193 args: []string{}, 194 status: "Failure", 195 message: "no arguments passed", 196 }, 197 } { 198 t.Run(step.name, func(t *testing.T) { 199 var subdir string 200 args := step.args 201 rec := testutils.NewToplevelRecorder() 202 fs := fakefs.NewFakeFileSystem(t, rec, tmpDir, nil) 203 d := NewDriver(func() string { 204 return fakeUUID 205 }, fs) 206 result := d.Run(args) 207 var m map[string]interface{} 208 if err := json.Unmarshal([]byte(result), &m); err != nil { 209 t.Fatalf("failed to unmarshal test result: %v", err) 210 } 211 212 msg := "" 213 if msgValue, ok := m["message"]; ok { 214 msg = msgValue.(string) 215 } 216 status := m["status"].(string) 217 if status != step.status { 218 t.Errorf("bad status %q instead of %q", status, step.status) 219 if status == "Failure" { 220 t.Errorf("failure reported: %q", msg) 221 } 222 } 223 224 if step.message != "" { 225 if !strings.Contains(msg, step.message) { 226 t.Errorf("bad message %q (doesn't contain %q)", msg, step.message) 227 } 228 } 229 if step.fields != nil { 230 for k, v := range step.fields { 231 if !reflect.DeepEqual(m[k], v) { 232 t.Errorf("unexpected field value: %q must be '%v' but is '%v'", k, v, m[k]) 233 } 234 } 235 } 236 if step.subdir != "" { 237 files, err := testutils.DirToMap(path.Join(tmpDir, step.subdir)) 238 if err != nil { 239 t.Fatalf("dirToMap() on %q: %v", subdir, err) 240 } 241 if !reflect.DeepEqual(files, step.files) { 242 t.Errorf("bad file content.\n%s\n-- instead of --\n%s", utils.ToJSON(files), utils.ToJSON(step.files)) 243 } 244 } 245 if !reflect.DeepEqual(rec.Content(), step.mountJournal) { 246 t.Errorf("unexpected mount journal: %#v instead of %#v", rec.Content(), step.mountJournal) 247 } 248 }) 249 } 250 } 251 252 // TODO: escape xml in iso path