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