github.com/jk-he/cni@v0.8.1/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 "context" 19 "encoding/json" 20 "errors" 21 22 "github.com/containernetworking/cni/pkg/invoke" 23 "github.com/containernetworking/cni/pkg/invoke/fakes" 24 "github.com/containernetworking/cni/pkg/types/current" 25 "github.com/containernetworking/cni/pkg/version" 26 27 . "github.com/onsi/ginkgo" 28 . "github.com/onsi/gomega" 29 ) 30 31 var _ = Describe("Executing a plugin, unit tests", func() { 32 var ( 33 pluginExec invoke.Exec 34 rawExec *fakes.RawExec 35 versionDecoder *fakes.VersionDecoder 36 37 pluginPath string 38 netconf []byte 39 cniargs *fakes.CNIArgs 40 ctx context.Context 41 ) 42 43 BeforeEach(func() { 44 rawExec = &fakes.RawExec{} 45 rawExec.ExecPluginCall.Returns.ResultBytes = []byte(`{ "ips": [ { "version": "4", "address": "1.2.3.4/24" } ] }`) 46 47 versionDecoder = &fakes.VersionDecoder{} 48 versionDecoder.DecodeCall.Returns.PluginInfo = version.PluginSupports("0.42.0") 49 50 pluginExec = &struct { 51 *fakes.RawExec 52 *fakes.VersionDecoder 53 }{ 54 RawExec: rawExec, 55 VersionDecoder: versionDecoder, 56 } 57 pluginPath = "/some/plugin/path" 58 netconf = []byte(`{ "some": "stdin", "cniVersion": "0.3.1" }`) 59 cniargs = &fakes.CNIArgs{} 60 cniargs.AsEnvCall.Returns.Env = []string{"SOME=ENV"} 61 ctx = context.TODO() 62 }) 63 64 Describe("returning a result", func() { 65 It("unmarshals the result bytes into the Result type", func() { 66 r, err := invoke.ExecPluginWithResult(ctx, pluginPath, netconf, cniargs, pluginExec) 67 Expect(err).NotTo(HaveOccurred()) 68 69 result, err := current.GetResult(r) 70 Expect(err).NotTo(HaveOccurred()) 71 Expect(len(result.IPs)).To(Equal(1)) 72 Expect(result.IPs[0].Address.IP.String()).To(Equal("1.2.3.4")) 73 }) 74 75 It("passes its arguments through to the rawExec", func() { 76 invoke.ExecPluginWithResult(ctx, pluginPath, netconf, cniargs, pluginExec) 77 Expect(rawExec.ExecPluginCall.Received.PluginPath).To(Equal(pluginPath)) 78 Expect(rawExec.ExecPluginCall.Received.StdinData).To(Equal(netconf)) 79 Expect(rawExec.ExecPluginCall.Received.Environ).To(Equal([]string{"SOME=ENV"})) 80 }) 81 82 Context("when the rawExec fails", func() { 83 BeforeEach(func() { 84 rawExec.ExecPluginCall.Returns.Error = errors.New("banana") 85 }) 86 It("returns the error", func() { 87 _, err := invoke.ExecPluginWithResult(ctx, pluginPath, netconf, cniargs, pluginExec) 88 Expect(err).To(MatchError("banana")) 89 }) 90 }) 91 92 It("returns an error using the default exec interface", func() { 93 // pluginPath should not exist on-disk so we expect an error. 94 // This test simply tests that the default exec handler 95 // is run when the exec interface is nil. 96 _, err := invoke.ExecPluginWithResult(ctx, pluginPath, netconf, cniargs, nil) 97 Expect(err).To(HaveOccurred()) 98 }) 99 }) 100 101 Describe("without returning a result", func() { 102 It("passes its arguments through to the rawExec", func() { 103 invoke.ExecPluginWithoutResult(ctx, pluginPath, netconf, cniargs, pluginExec) 104 Expect(rawExec.ExecPluginCall.Received.PluginPath).To(Equal(pluginPath)) 105 Expect(rawExec.ExecPluginCall.Received.StdinData).To(Equal(netconf)) 106 Expect(rawExec.ExecPluginCall.Received.Environ).To(Equal([]string{"SOME=ENV"})) 107 }) 108 109 Context("when the rawExec fails", func() { 110 BeforeEach(func() { 111 rawExec.ExecPluginCall.Returns.Error = errors.New("banana") 112 }) 113 It("returns the error", func() { 114 err := invoke.ExecPluginWithoutResult(ctx, pluginPath, netconf, cniargs, pluginExec) 115 Expect(err).To(MatchError("banana")) 116 }) 117 }) 118 119 It("returns an error using the default exec interface", func() { 120 // pluginPath should not exist on-disk so we expect an error. 121 // This test simply tests that the default exec handler 122 // is run when the exec interface is nil. 123 err := invoke.ExecPluginWithoutResult(ctx, pluginPath, netconf, cniargs, nil) 124 Expect(err).To(HaveOccurred()) 125 }) 126 }) 127 128 Describe("discovering the plugin version", func() { 129 BeforeEach(func() { 130 rawExec.ExecPluginCall.Returns.ResultBytes = []byte(`{ "some": "version-info" }`) 131 }) 132 133 It("execs the plugin with the command VERSION", func() { 134 invoke.GetVersionInfo(ctx, pluginPath, pluginExec) 135 Expect(rawExec.ExecPluginCall.Received.PluginPath).To(Equal(pluginPath)) 136 Expect(rawExec.ExecPluginCall.Received.Environ).To(ContainElement("CNI_COMMAND=VERSION")) 137 expectedStdin, _ := json.Marshal(map[string]string{"cniVersion": version.Current()}) 138 Expect(rawExec.ExecPluginCall.Received.StdinData).To(MatchJSON(expectedStdin)) 139 }) 140 141 It("decodes and returns the version info", func() { 142 versionInfo, err := invoke.GetVersionInfo(ctx, pluginPath, pluginExec) 143 Expect(err).NotTo(HaveOccurred()) 144 Expect(versionInfo.SupportedVersions()).To(Equal([]string{"0.42.0"})) 145 Expect(versionDecoder.DecodeCall.Received.JSONBytes).To(MatchJSON(`{ "some": "version-info" }`)) 146 }) 147 148 Context("when the rawExec fails", func() { 149 BeforeEach(func() { 150 rawExec.ExecPluginCall.Returns.Error = errors.New("banana") 151 }) 152 It("returns the error", func() { 153 _, err := invoke.GetVersionInfo(ctx, pluginPath, pluginExec) 154 Expect(err).To(MatchError("banana")) 155 }) 156 }) 157 158 Context("when the plugin is too old to recognize the VERSION command", func() { 159 BeforeEach(func() { 160 rawExec.ExecPluginCall.Returns.Error = errors.New("unknown CNI_COMMAND: VERSION") 161 }) 162 163 It("interprets the error as a 0.1.0 version", func() { 164 versionInfo, err := invoke.GetVersionInfo(ctx, pluginPath, pluginExec) 165 Expect(err).NotTo(HaveOccurred()) 166 Expect(versionInfo.SupportedVersions()).To(ConsistOf("0.1.0")) 167 }) 168 169 It("sets dummy values for env vars required by very old plugins", func() { 170 invoke.GetVersionInfo(ctx, pluginPath, pluginExec) 171 172 env := rawExec.ExecPluginCall.Received.Environ 173 Expect(env).To(ContainElement("CNI_NETNS=dummy")) 174 Expect(env).To(ContainElement("CNI_IFNAME=dummy")) 175 Expect(env).To(ContainElement("CNI_PATH=dummy")) 176 }) 177 }) 178 }) 179 })