github.com/jk-he/cni@v0.8.1/pkg/invoke/raw_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  	"bytes"
    19  	"context"
    20  	"io/ioutil"
    21  	"os"
    22  
    23  	"github.com/containernetworking/cni/pkg/invoke"
    24  
    25  	noop_debug "github.com/containernetworking/cni/plugins/test/noop/debug"
    26  
    27  	. "github.com/onsi/ginkgo"
    28  	. "github.com/onsi/gomega"
    29  )
    30  
    31  var _ = Describe("RawExec", func() {
    32  	var (
    33  		debugFileName string
    34  		debug         *noop_debug.Debug
    35  		environ       []string
    36  		stdin         []byte
    37  		execer        *invoke.RawExec
    38  		ctx           context.Context
    39  	)
    40  
    41  	const reportResult = `{ "some": "result" }`
    42  
    43  	BeforeEach(func() {
    44  		debugFile, err := ioutil.TempFile("", "cni_debug")
    45  		Expect(err).NotTo(HaveOccurred())
    46  		Expect(debugFile.Close()).To(Succeed())
    47  		debugFileName = debugFile.Name()
    48  
    49  		debug = &noop_debug.Debug{
    50  			ReportResult: reportResult,
    51  			ReportStderr: "some stderr message",
    52  		}
    53  		Expect(debug.WriteDebug(debugFileName)).To(Succeed())
    54  
    55  		environ = []string{
    56  			"CNI_COMMAND=ADD",
    57  			"CNI_CONTAINERID=some-container-id",
    58  			"CNI_ARGS=DEBUG=" + debugFileName,
    59  			"CNI_NETNS=/some/netns/path",
    60  			"CNI_PATH=/some/bin/path",
    61  			"CNI_IFNAME=some-eth0",
    62  		}
    63  		stdin = []byte(`{"name": "raw-exec-test", "some":"stdin-json", "cniVersion": "0.3.1"}`)
    64  		execer = &invoke.RawExec{}
    65  		ctx = context.TODO()
    66  	})
    67  
    68  	AfterEach(func() {
    69  		Expect(os.Remove(debugFileName)).To(Succeed())
    70  	})
    71  
    72  	It("runs the plugin with the given stdin and environment", func() {
    73  		_, err := execer.ExecPlugin(ctx, pathToPlugin, stdin, environ)
    74  		Expect(err).NotTo(HaveOccurred())
    75  
    76  		debug, err := noop_debug.ReadDebug(debugFileName)
    77  		Expect(err).NotTo(HaveOccurred())
    78  		Expect(debug.Command).To(Equal("ADD"))
    79  		Expect(debug.CmdArgs.StdinData).To(Equal(stdin))
    80  		Expect(debug.CmdArgs.Netns).To(Equal("/some/netns/path"))
    81  	})
    82  
    83  	It("returns the resulting stdout as bytes", func() {
    84  		resultBytes, err := execer.ExecPlugin(ctx, pathToPlugin, stdin, environ)
    85  		Expect(err).NotTo(HaveOccurred())
    86  
    87  		Expect(resultBytes).To(BeEquivalentTo(reportResult))
    88  	})
    89  
    90  	Context("when the Stderr writer is set", func() {
    91  		var stderrBuffer *bytes.Buffer
    92  
    93  		BeforeEach(func() {
    94  			stderrBuffer = &bytes.Buffer{}
    95  			execer.Stderr = stderrBuffer
    96  		})
    97  
    98  		It("forwards any stderr bytes to the Stderr writer", func() {
    99  			_, err := execer.ExecPlugin(ctx, pathToPlugin, stdin, environ)
   100  			Expect(err).NotTo(HaveOccurred())
   101  
   102  			Expect(stderrBuffer.String()).To(Equal("some stderr message"))
   103  		})
   104  	})
   105  
   106  	Context("when the plugin errors", func() {
   107  		BeforeEach(func() {
   108  			debug.ReportResult = ""
   109  		})
   110  
   111  		Context("and writes valid error JSON to stdout", func() {
   112  			It("wraps and returns the error", func() {
   113  				debug.ReportError = "banana"
   114  				Expect(debug.WriteDebug(debugFileName)).To(Succeed())
   115  				_, err := execer.ExecPlugin(ctx, pathToPlugin, stdin, environ)
   116  				Expect(err).To(HaveOccurred())
   117  				Expect(err).To(MatchError("banana"))
   118  			})
   119  		})
   120  
   121  		Context("and writes to stderr", func() {
   122  			It("returns an error message with stderr output", func() {
   123  				debug.ExitWithCode = 1
   124  				Expect(debug.WriteDebug(debugFileName)).To(Succeed())
   125  				_, err := execer.ExecPlugin(ctx, pathToPlugin, stdin, environ)
   126  				Expect(err).To(HaveOccurred())
   127  				Expect(err).To(MatchError(`netplugin failed: "some stderr message"`))
   128  			})
   129  		})
   130  	})
   131  
   132  	Context("when the plugin errors with no output on stdout or stderr", func() {
   133  		It("returns the exec error message", func() {
   134  			debug.ExitWithCode = 1
   135  			debug.ReportResult = ""
   136  			debug.ReportStderr = ""
   137  			Expect(debug.WriteDebug(debugFileName)).To(Succeed())
   138  			_, err := execer.ExecPlugin(ctx, pathToPlugin, stdin, environ)
   139  			Expect(err).To(HaveOccurred())
   140  			Expect(err).To(MatchError("netplugin failed with no error message: exit status 1"))
   141  		})
   142  	})
   143  
   144  	Context("when the system is unable to execute the plugin", func() {
   145  		It("returns the error", func() {
   146  			_, err := execer.ExecPlugin(ctx, "/tmp/some/invalid/plugin/path", stdin, environ)
   147  			Expect(err).To(HaveOccurred())
   148  			Expect(err).To(MatchError(ContainSubstring("/tmp/some/invalid/plugin/path")))
   149  		})
   150  	})
   151  })