github.com/mccv1r0/cni@v0.7.0-alpha1/pkg/invoke/exec_test.go (about) 1 // Copyright 2016 CNI authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package invoke_test 16 17 import ( 18 "encoding/json" 19 "errors" 20 21 "github.com/containernetworking/cni/pkg/invoke" 22 "github.com/containernetworking/cni/pkg/invoke/fakes" 23 "github.com/containernetworking/cni/pkg/types/current" 24 "github.com/containernetworking/cni/pkg/version" 25 26 . "github.com/onsi/ginkgo" 27 . "github.com/onsi/gomega" 28 ) 29 30 var _ = Describe("Executing a plugin, unit tests", func() { 31 var ( 32 pluginExec invoke.Exec 33 rawExec *fakes.RawExec 34 versionDecoder *fakes.VersionDecoder 35 36 pluginPath string 37 netconf []byte 38 cniargs *fakes.CNIArgs 39 ) 40 41 BeforeEach(func() { 42 rawExec = &fakes.RawExec{} 43 rawExec.ExecPluginCall.Returns.ResultBytes = []byte(`{ "ips": [ { "version": "4", "address": "1.2.3.4/24" } ] }`) 44 45 versionDecoder = &fakes.VersionDecoder{} 46 versionDecoder.DecodeCall.Returns.PluginInfo = version.PluginSupports("0.42.0") 47 48 pluginExec = &struct { 49 *fakes.RawExec 50 *fakes.VersionDecoder 51 }{ 52 RawExec: rawExec, 53 VersionDecoder: versionDecoder, 54 } 55 pluginPath = "/some/plugin/path" 56 netconf = []byte(`{ "some": "stdin", "cniVersion": "0.3.1" }`) 57 cniargs = &fakes.CNIArgs{} 58 cniargs.AsEnvCall.Returns.Env = []string{"SOME=ENV"} 59 }) 60 61 Describe("returning a result", func() { 62 It("unmarshals the result bytes into the Result type", func() { 63 r, err := invoke.ExecPluginWithResult(pluginPath, netconf, cniargs, pluginExec) 64 Expect(err).NotTo(HaveOccurred()) 65 66 result, err := current.GetResult(r) 67 Expect(err).NotTo(HaveOccurred()) 68 Expect(len(result.IPs)).To(Equal(1)) 69 Expect(result.IPs[0].Address.IP.String()).To(Equal("1.2.3.4")) 70 }) 71 72 It("passes its arguments through to the rawExec", func() { 73 invoke.ExecPluginWithResult(pluginPath, netconf, cniargs, pluginExec) 74 Expect(rawExec.ExecPluginCall.Received.PluginPath).To(Equal(pluginPath)) 75 Expect(rawExec.ExecPluginCall.Received.StdinData).To(Equal(netconf)) 76 Expect(rawExec.ExecPluginCall.Received.Environ).To(Equal([]string{"SOME=ENV"})) 77 }) 78 79 Context("when the rawExec fails", func() { 80 BeforeEach(func() { 81 rawExec.ExecPluginCall.Returns.Error = errors.New("banana") 82 }) 83 It("returns the error", func() { 84 _, err := invoke.ExecPluginWithResult(pluginPath, netconf, cniargs, pluginExec) 85 Expect(err).To(MatchError("banana")) 86 }) 87 }) 88 89 It("returns an error using the default exec interface", func() { 90 // pluginPath should not exist on-disk so we expect an error. 91 // This test simply tests that the default exec handler 92 // is run when the exec interface is nil. 93 _, err := invoke.ExecPluginWithResult(pluginPath, netconf, cniargs, nil) 94 Expect(err).To(HaveOccurred()) 95 }) 96 }) 97 98 Describe("without returning a result", func() { 99 It("passes its arguments through to the rawExec", func() { 100 invoke.ExecPluginWithoutResult(pluginPath, netconf, cniargs, pluginExec) 101 Expect(rawExec.ExecPluginCall.Received.PluginPath).To(Equal(pluginPath)) 102 Expect(rawExec.ExecPluginCall.Received.StdinData).To(Equal(netconf)) 103 Expect(rawExec.ExecPluginCall.Received.Environ).To(Equal([]string{"SOME=ENV"})) 104 }) 105 106 Context("when the rawExec fails", func() { 107 BeforeEach(func() { 108 rawExec.ExecPluginCall.Returns.Error = errors.New("banana") 109 }) 110 It("returns the error", func() { 111 err := invoke.ExecPluginWithoutResult(pluginPath, netconf, cniargs, pluginExec) 112 Expect(err).To(MatchError("banana")) 113 }) 114 }) 115 116 It("returns an error using the default exec interface", func() { 117 // pluginPath should not exist on-disk so we expect an error. 118 // This test simply tests that the default exec handler 119 // is run when the exec interface is nil. 120 err := invoke.ExecPluginWithoutResult(pluginPath, netconf, cniargs, nil) 121 Expect(err).To(HaveOccurred()) 122 }) 123 }) 124 125 Describe("discovering the plugin version", func() { 126 BeforeEach(func() { 127 rawExec.ExecPluginCall.Returns.ResultBytes = []byte(`{ "some": "version-info" }`) 128 }) 129 130 It("execs the plugin with the command VERSION", func() { 131 invoke.GetVersionInfo(pluginPath, pluginExec) 132 Expect(rawExec.ExecPluginCall.Received.PluginPath).To(Equal(pluginPath)) 133 Expect(rawExec.ExecPluginCall.Received.Environ).To(ContainElement("CNI_COMMAND=VERSION")) 134 expectedStdin, _ := json.Marshal(map[string]string{"cniVersion": version.Current()}) 135 Expect(rawExec.ExecPluginCall.Received.StdinData).To(MatchJSON(expectedStdin)) 136 }) 137 138 It("decodes and returns the version info", func() { 139 versionInfo, err := invoke.GetVersionInfo(pluginPath, pluginExec) 140 Expect(err).NotTo(HaveOccurred()) 141 Expect(versionInfo.SupportedVersions()).To(Equal([]string{"0.42.0"})) 142 Expect(versionDecoder.DecodeCall.Received.JSONBytes).To(MatchJSON(`{ "some": "version-info" }`)) 143 }) 144 145 Context("when the rawExec fails", func() { 146 BeforeEach(func() { 147 rawExec.ExecPluginCall.Returns.Error = errors.New("banana") 148 }) 149 It("returns the error", func() { 150 _, err := invoke.GetVersionInfo(pluginPath, pluginExec) 151 Expect(err).To(MatchError("banana")) 152 }) 153 }) 154 155 Context("when the plugin is too old to recognize the VERSION command", func() { 156 BeforeEach(func() { 157 rawExec.ExecPluginCall.Returns.Error = errors.New("unknown CNI_COMMAND: VERSION") 158 }) 159 160 It("interprets the error as a 0.1.0 version", func() { 161 versionInfo, err := invoke.GetVersionInfo(pluginPath, pluginExec) 162 Expect(err).NotTo(HaveOccurred()) 163 Expect(versionInfo.SupportedVersions()).To(ConsistOf("0.1.0")) 164 }) 165 166 It("sets dummy values for env vars required by very old plugins", func() { 167 invoke.GetVersionInfo(pluginPath, pluginExec) 168 169 env := rawExec.ExecPluginCall.Received.Environ 170 Expect(env).To(ContainElement("CNI_NETNS=dummy")) 171 Expect(env).To(ContainElement("CNI_IFNAME=dummy")) 172 Expect(env).To(ContainElement("CNI_PATH=dummy")) 173 }) 174 }) 175 }) 176 })