diff --git a/ext/go-plugin/synced_folder.go b/ext/go-plugin/synced_folder.go index 8a22949b7..96d811fbf 100644 --- a/ext/go-plugin/synced_folder.go +++ b/ext/go-plugin/synced_folder.go @@ -26,132 +26,145 @@ func ListSyncedFolders() *C.char { //export SyncedFolderCleanup func SyncedFolderCleanup(pluginName, machine, opts *C.char) *C.char { r := &Response{} - p, err := getSyncedFolderPlugin(pluginName) + i, err := Plugins.PluginLookup(to_gs(pluginName), "synced_folder") if err != nil { r.Error = err return r.Dump() } - m, err := vagrant.LoadMachine(C.GoString(machine), nil) + p, ok := i.(plugin.SyncedFolder) + if !ok { + r.Error = errors.New("failed to load requested plugin") + return r.Dump() + } + + m, err := vagrant.LoadMachine(to_gs(machine), nil) if err != nil { r.Error = err return r.Dump() } var o vagrant.FolderOptions - r.Error = json.Unmarshal([]byte(C.GoString(opts)), &o) + r.Error = json.Unmarshal([]byte(to_gs(opts)), &o) if r.Error != nil { return r.Dump() } - r.Error = p.SyncedFolder.Cleanup(m, o) + r.Error = p.Cleanup(m, o) return r.Dump() } //export SyncedFolderDisable func SyncedFolderDisable(pluginName, machine, folders, opts *C.char) *C.char { r := &Response{} - p, err := getSyncedFolderPlugin(pluginName) + i, err := Plugins.PluginLookup(to_gs(pluginName), "synced_folder") if err != nil { r.Error = err return r.Dump() } - m, err := vagrant.LoadMachine(C.GoString(machine), nil) + p, ok := i.(plugin.SyncedFolder) + if !ok { + r.Error = errors.New("failed to load requested plugin") + return r.Dump() + } + m, err := vagrant.LoadMachine(to_gs(machine), nil) if err != nil { r.Error = err return r.Dump() } var f vagrant.FolderList - r.Error = json.Unmarshal([]byte(C.GoString(folders)), &f) + r.Error = json.Unmarshal([]byte(to_gs(folders)), &f) if r.Error != nil { return r.Dump() } var o vagrant.FolderOptions - r.Error = json.Unmarshal([]byte(C.GoString(opts)), &o) + r.Error = json.Unmarshal([]byte(to_gs(opts)), &o) if r.Error != nil { return r.Dump() } - r.Error = p.SyncedFolder.Disable(m, f, o) + r.Error = p.Disable(m, f, o) return r.Dump() } //export SyncedFolderEnable func SyncedFolderEnable(pluginName, machine, folders, opts *C.char) *C.char { r := &Response{} - p, err := getSyncedFolderPlugin(pluginName) + i, err := Plugins.PluginLookup(to_gs(pluginName), "synced_folder") if err != nil { r.Error = err return r.Dump() } - m, err := vagrant.LoadMachine(C.GoString(machine), nil) + p, ok := i.(plugin.SyncedFolder) + if !ok { + r.Error = errors.New("failed to load requested plugin") + return r.Dump() + } + m, err := vagrant.LoadMachine(to_gs(machine), nil) if err != nil { r.Error = err return r.Dump() } var f vagrant.FolderList - r.Error = json.Unmarshal([]byte(C.GoString(folders)), &f) + r.Error = json.Unmarshal([]byte(to_gs(folders)), &f) if r.Error != nil { return r.Dump() } var o vagrant.FolderOptions - r.Error = json.Unmarshal([]byte(C.GoString(opts)), &o) + r.Error = json.Unmarshal([]byte(to_gs(opts)), &o) if r.Error != nil { return r.Dump() } - r.Error = p.SyncedFolder.Enable(m, f, o) + r.Error = p.Enable(m, f, o) return r.Dump() } //export SyncedFolderIsUsable func SyncedFolderIsUsable(pluginName, machine *C.char) *C.char { r := &Response{} - p, err := getSyncedFolderPlugin(pluginName) + i, err := Plugins.PluginLookup(to_gs(pluginName), "synced_folder") if err != nil { r.Error = err return r.Dump() } - m, err := vagrant.LoadMachine(C.GoString(machine), nil) + p, ok := i.(plugin.SyncedFolder) + if !ok { + r.Error = errors.New("failed to load requested plugin") + return r.Dump() + } + m, err := vagrant.LoadMachine(to_gs(machine), nil) if err != nil { r.Error = err return r.Dump() } - r.Result, r.Error = p.SyncedFolder.IsUsable(m) + r.Result, r.Error = p.IsUsable(m) return r.Dump() } //export SyncedFolderPrepare func SyncedFolderPrepare(pluginName, machine, folders, opts *C.char) *C.char { r := &Response{} - p, err := getSyncedFolderPlugin(pluginName) + i, err := Plugins.PluginLookup(to_gs(pluginName), "synced_folder") if err != nil { r.Error = err return r.Dump() } - m, err := vagrant.LoadMachine(C.GoString(machine), nil) + p, ok := i.(plugin.SyncedFolder) + if !ok { + r.Error = errors.New("failed to load requested plugin") + return r.Dump() + } + m, err := vagrant.LoadMachine(to_gs(machine), nil) if err != nil { r.Error = err return r.Dump() } var f vagrant.FolderList - r.Error = json.Unmarshal([]byte(C.GoString(folders)), &f) + r.Error = json.Unmarshal([]byte(to_gs(folders)), &f) if r.Error != nil { return r.Dump() } var o vagrant.FolderOptions - r.Error = json.Unmarshal([]byte(C.GoString(opts)), &o) + r.Error = json.Unmarshal([]byte(to_gs(opts)), &o) if r.Error != nil { return r.Dump() } - r.Error = p.SyncedFolder.Prepare(m, f, o) + r.Error = p.Prepare(m, f, o) return r.Dump() } - -func getSyncedFolderPlugin(pluginName *C.char) (c *plugin.RemoteSyncedFolder, err error) { - pname := C.GoString(pluginName) - p, ok := Plugins.SyncedFolders[pname] - if !ok { - err = errors.New("Failed to locate requested plugin") - return - } - c = &plugin.RemoteSyncedFolder{ - Client: p.Client, - SyncedFolder: p.SyncedFolder} - return -} diff --git a/ext/go-plugin/synced_folder_test.go b/ext/go-plugin/synced_folder_test.go new file mode 100644 index 000000000..434e7687d --- /dev/null +++ b/ext/go-plugin/synced_folder_test.go @@ -0,0 +1,347 @@ +package main + +import ( + "testing" + + "github.com/hashicorp/go-plugin" + vplugin "github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin" +) + +func TestSyncedFolder_ListSyncedFolders(t *testing.T) { + client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{ + "folder": &vplugin.SyncedFolderPlugin{Impl: &vplugin.MockSyncedFolder{}}}) + defer server.Stop() + defer client.Close() + + raw, err := client.Dispense("folder") + if err != nil { + t.Fatalf("err: %s", err) + } + impl, ok := raw.(vplugin.SyncedFolder) + if !ok { + t.Fatalf("bad %#v", raw) + } + + p := &vplugin.RemoteSyncedFolder{ + SyncedFolder: impl} + Plugins = vplugin.VagrantPluginInit() + Plugins.SyncedFolders[impl.Name()] = p + + result := ListSyncedFolders() + resp, err := LoadResponse(result) + if err != nil { + t.Fatalf("err: %s", err) + } + if resp.Error != nil { + t.Fatalf("err: %s", err) + } + + r, ok := resp.Result.(map[string]interface{}) + if !ok { + t.Fatalf("bad %#v", resp.Result) + } + + if r["mock_folder"] == nil { + t.Fatalf("bad result") + } + + i, ok := r["mock_folder"].(map[string]interface{}) + if !ok { + t.Fatalf("bad %#v", r["mock_folder"]) + } + + if i["description"] != "mock_folder" { + t.Errorf("%s != mock_folder", i["description"]) + } + if i["priority"] != 100.0 { + t.Errorf("%d != 100", i["priority"]) + } +} + +func TestSyncedFolder_SyncedFolderCleanup(t *testing.T) { + client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{ + "folder": &vplugin.SyncedFolderPlugin{Impl: &vplugin.MockSyncedFolder{}}}) + defer server.Stop() + defer client.Close() + + raw, err := client.Dispense("folder") + if err != nil { + t.Fatalf("err: %s", err) + } + impl, ok := raw.(vplugin.SyncedFolder) + if !ok { + t.Fatalf("bad %#v", raw) + } + + Plugins = vplugin.VagrantPluginInit() + Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) { + r = impl + return + } + + result := SyncedFolderCleanup(nil, to_cs("{}"), to_cs("null")) + resp, err := LoadResponse(result) + if err != nil { + t.Fatalf("err: %s", err) + } + if resp.Error != nil { + t.Fatalf("err: %s", resp.Error) + } +} + +func TestSyncedFolder_SyncedFolderCleanup_error(t *testing.T) { + client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{ + "folder": &vplugin.SyncedFolderPlugin{Impl: &vplugin.MockSyncedFolder{}}}) + defer server.Stop() + defer client.Close() + + raw, err := client.Dispense("folder") + if err != nil { + t.Fatalf("err: %s", err) + } + impl, ok := raw.(vplugin.SyncedFolder) + if !ok { + t.Fatalf("bad %#v", raw) + } + + Plugins = vplugin.VagrantPluginInit() + Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) { + r = impl + return + } + + result := SyncedFolderCleanup(nil, to_cs("{}"), to_cs("{\"error\":true}")) + resp, err := LoadResponse(result) + if err != nil { + t.Fatalf("err: %s", err) + } + if resp.Error == nil { + t.Fatalf("error expected") + } +} + +func TestSyncedFolder_SyncedFolderDisable(t *testing.T) { + client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{ + "folder": &vplugin.SyncedFolderPlugin{Impl: &vplugin.MockSyncedFolder{}}}) + defer server.Stop() + defer client.Close() + + raw, err := client.Dispense("folder") + if err != nil { + t.Fatalf("err: %s", err) + } + impl, ok := raw.(vplugin.SyncedFolder) + if !ok { + t.Fatalf("bad %#v", raw) + } + + Plugins = vplugin.VagrantPluginInit() + Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) { + r = impl + return + } + + result := SyncedFolderDisable(nil, to_cs("{}"), to_cs("{}"), to_cs("null")) + resp, err := LoadResponse(result) + if err != nil { + t.Fatalf("err: %s", err) + } + if resp.Error != nil { + t.Fatalf("err: %s", resp.Error) + } +} + +func TestSyncedFolder_SyncedFolderDisable_error(t *testing.T) { + client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{ + "folder": &vplugin.SyncedFolderPlugin{Impl: &vplugin.MockSyncedFolder{}}}) + defer server.Stop() + defer client.Close() + + raw, err := client.Dispense("folder") + if err != nil { + t.Fatalf("err: %s", err) + } + impl, ok := raw.(vplugin.SyncedFolder) + if !ok { + t.Fatalf("bad %#v", raw) + } + + Plugins = vplugin.VagrantPluginInit() + Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) { + r = impl + return + } + + result := SyncedFolderDisable(nil, to_cs("{}"), to_cs("{}"), to_cs("{\"error\":true}")) + resp, err := LoadResponse(result) + if err != nil { + t.Fatalf("err: %s", err) + } + if resp.Error == nil { + t.Fatalf("rror expected") + } +} + +func TestSyncedFolder_SyncedFolderEnable(t *testing.T) { + client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{ + "folder": &vplugin.SyncedFolderPlugin{Impl: &vplugin.MockSyncedFolder{}}}) + defer server.Stop() + defer client.Close() + + raw, err := client.Dispense("folder") + if err != nil { + t.Fatalf("err: %s", err) + } + impl, ok := raw.(vplugin.SyncedFolder) + if !ok { + t.Fatalf("bad %#v", raw) + } + + Plugins = vplugin.VagrantPluginInit() + Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) { + r = impl + return + } + + result := SyncedFolderEnable(nil, to_cs("{}"), to_cs("{}"), to_cs("null")) + resp, err := LoadResponse(result) + if err != nil { + t.Fatalf("err: %s", err) + } + if resp.Error != nil { + t.Fatalf("err: %s", resp.Error) + } +} + +func TestSyncedFolder_SyncedFolderEnable_error(t *testing.T) { + client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{ + "folder": &vplugin.SyncedFolderPlugin{Impl: &vplugin.MockSyncedFolder{}}}) + defer server.Stop() + defer client.Close() + + raw, err := client.Dispense("folder") + if err != nil { + t.Fatalf("err: %s", err) + } + impl, ok := raw.(vplugin.SyncedFolder) + if !ok { + t.Fatalf("bad %#v", raw) + } + + Plugins = vplugin.VagrantPluginInit() + Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) { + r = impl + return + } + + result := SyncedFolderEnable(nil, to_cs("{}"), to_cs("{}"), to_cs("{\"error\":true}")) + resp, err := LoadResponse(result) + if err != nil { + t.Fatalf("err: %s", err) + } + if resp.Error == nil { + t.Fatalf("rror expected") + } +} + +func TestSyncedFolder_SyncedFolderIsUsable(t *testing.T) { + client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{ + "folder": &vplugin.SyncedFolderPlugin{Impl: &vplugin.MockSyncedFolder{}}}) + defer server.Stop() + defer client.Close() + + raw, err := client.Dispense("folder") + if err != nil { + t.Fatalf("err: %s", err) + } + impl, ok := raw.(vplugin.SyncedFolder) + if !ok { + t.Fatalf("bad %#v", raw) + } + + Plugins = vplugin.VagrantPluginInit() + Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) { + r = impl + return + } + + result := SyncedFolderIsUsable(nil, to_cs("{}")) + resp, err := LoadResponse(result) + if err != nil { + t.Fatalf("err: %s", err) + } + if resp.Error != nil { + t.Fatalf("err: %s", resp.Error) + } + + usable, ok := resp.Result.(bool) + if !ok { + t.Fatalf("bad %#v", resp.Result) + } + + if !usable { + t.Fatalf("bad result") + } +} + +func TestSyncedFolder_SyncedFolderPrepare(t *testing.T) { + client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{ + "folder": &vplugin.SyncedFolderPlugin{Impl: &vplugin.MockSyncedFolder{}}}) + defer server.Stop() + defer client.Close() + + raw, err := client.Dispense("folder") + if err != nil { + t.Fatalf("err: %s", err) + } + impl, ok := raw.(vplugin.SyncedFolder) + if !ok { + t.Fatalf("bad %#v", raw) + } + + Plugins = vplugin.VagrantPluginInit() + Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) { + r = impl + return + } + + result := SyncedFolderPrepare(nil, to_cs("{}"), to_cs("{}"), to_cs("null")) + resp, err := LoadResponse(result) + if err != nil { + t.Fatalf("err: %s", err) + } + if resp.Error != nil { + t.Fatalf("err: %s", resp.Error) + } +} + +func TestSyncedFolder_SyncedFolderPrepare_error(t *testing.T) { + client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{ + "folder": &vplugin.SyncedFolderPlugin{Impl: &vplugin.MockSyncedFolder{}}}) + defer server.Stop() + defer client.Close() + + raw, err := client.Dispense("folder") + if err != nil { + t.Fatalf("err: %s", err) + } + impl, ok := raw.(vplugin.SyncedFolder) + if !ok { + t.Fatalf("bad %#v", raw) + } + + Plugins = vplugin.VagrantPluginInit() + Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) { + r = impl + return + } + + result := SyncedFolderPrepare(nil, to_cs("{}"), to_cs("{}"), to_cs("{\"error\":true}")) + resp, err := LoadResponse(result) + if err != nil { + t.Fatalf("err: %s", err) + } + if resp.Error == nil { + t.Fatalf("error expected") + } +} diff --git a/ext/go-plugin/vagrant/plugin/mocks.go b/ext/go-plugin/vagrant/plugin/mocks.go index e2a0bcbfd..df7b4e5a7 100644 --- a/ext/go-plugin/vagrant/plugin/mocks.go +++ b/ext/go-plugin/vagrant/plugin/mocks.go @@ -174,3 +174,59 @@ func (c *MockProvider) Info() *vagrant.ProviderInfo { Description: "Custom", Priority: 10} } + +type MockSyncedFolder struct { + Core + vagrant.NoGuestCapabilities + vagrant.NoHostCapabilities +} + +func (s *MockSyncedFolder) Cleanup(m *vagrant.Machine, opts vagrant.FolderOptions) error { + if opts != nil { + err, _ := opts["error"].(bool) + ui, _ := opts["ui"].(bool) + if err { + return errors.New("cleanup error") + } + if ui { + m.UI.Say("test_output_sf") + return nil + } + } + return nil +} + +func (s *MockSyncedFolder) Disable(m *vagrant.Machine, f vagrant.FolderList, opts vagrant.FolderOptions) error { + if opts != nil && opts["error"].(bool) { + return errors.New("disable error") + } + return nil +} + +func (s *MockSyncedFolder) Enable(m *vagrant.Machine, f vagrant.FolderList, opts vagrant.FolderOptions) error { + if opts != nil && opts["error"].(bool) { + return errors.New("enable error") + } + return nil +} + +func (s *MockSyncedFolder) Info() *vagrant.SyncedFolderInfo { + return &vagrant.SyncedFolderInfo{ + Description: "mock_folder", + Priority: 100} +} + +func (s *MockSyncedFolder) IsUsable(m *vagrant.Machine) (bool, error) { + return true, nil +} + +func (s *MockSyncedFolder) Name() string { + return "mock_folder" +} + +func (s *MockSyncedFolder) Prepare(m *vagrant.Machine, f vagrant.FolderList, opts vagrant.FolderOptions) error { + if opts != nil && opts["error"].(bool) { + return errors.New("prepare error") + } + return nil +} diff --git a/ext/go-plugin/vagrant/plugin/synced_folder_test.go b/ext/go-plugin/vagrant/plugin/synced_folder_test.go index d0feed4c1..77e9c1483 100644 --- a/ext/go-plugin/vagrant/plugin/synced_folder_test.go +++ b/ext/go-plugin/vagrant/plugin/synced_folder_test.go @@ -1,7 +1,6 @@ package plugin import ( - "errors" "strings" "testing" @@ -9,62 +8,6 @@ import ( "github.com/hashicorp/vagrant/ext/go-plugin/vagrant" ) -type MockSyncedFolder struct { - Core - vagrant.NoGuestCapabilities - vagrant.NoHostCapabilities -} - -func (s *MockSyncedFolder) Cleanup(m *vagrant.Machine, opts vagrant.FolderOptions) error { - if opts != nil { - err, _ := opts["error"].(bool) - ui, _ := opts["ui"].(bool) - if err { - return errors.New("cleanup error") - } - if ui { - m.UI.Say("test_output_sf") - return nil - } - } - return nil -} - -func (s *MockSyncedFolder) Disable(m *vagrant.Machine, f vagrant.FolderList, opts vagrant.FolderOptions) error { - if opts != nil && opts["error"].(bool) { - return errors.New("disable error") - } - return nil -} - -func (s *MockSyncedFolder) Enable(m *vagrant.Machine, f vagrant.FolderList, opts vagrant.FolderOptions) error { - if opts != nil && opts["error"].(bool) { - return errors.New("enable error") - } - return nil -} - -func (s *MockSyncedFolder) Info() *vagrant.SyncedFolderInfo { - return &vagrant.SyncedFolderInfo{ - Description: "mock_folder", - Priority: 100} -} - -func (s *MockSyncedFolder) IsUsable(m *vagrant.Machine) (bool, error) { - return true, nil -} - -func (s *MockSyncedFolder) Name() string { - return "mock_folder" -} - -func (s *MockSyncedFolder) Prepare(m *vagrant.Machine, f vagrant.FolderList, opts vagrant.FolderOptions) error { - if opts != nil && opts["error"].(bool) { - return errors.New("prepare error") - } - return nil -} - func TestSyncedFolder_Cleanup(t *testing.T) { client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{ "folder": &SyncedFolderPlugin{Impl: &MockSyncedFolder{}}})