From 51b51a0182c0af3c53a7a38cc59dedeea20f7637 Mon Sep 17 00:00:00 2001 From: Gabe Rosenhouse Date: Sun, 2 Oct 2016 21:43:51 -0700 Subject: [PATCH] testing: adds basic test of backwards compatibility --- libcni/backwards_compatibility_test.go | 53 +++++++ pkg/version/legacy_examples/examples.go | 138 ++++++++++++++++++ .../legacy_examples_suite_test.go | 27 ++++ .../legacy_examples/legacy_examples_test.go | 36 +++++ 4 files changed, 254 insertions(+) create mode 100644 libcni/backwards_compatibility_test.go create mode 100644 pkg/version/legacy_examples/examples.go create mode 100644 pkg/version/legacy_examples/legacy_examples_suite_test.go create mode 100644 pkg/version/legacy_examples/legacy_examples_test.go diff --git a/libcni/backwards_compatibility_test.go b/libcni/backwards_compatibility_test.go new file mode 100644 index 00000000..c13b23a1 --- /dev/null +++ b/libcni/backwards_compatibility_test.go @@ -0,0 +1,53 @@ +// Copyright 2016 CNI authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package libcni_test + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/containernetworking/cni/libcni" + "github.com/containernetworking/cni/pkg/version/legacy_examples" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Backwards compatibility", func() { + It("correctly handles the response from a legacy plugin", func() { + example := legacy_examples.V010 + pluginPath, err := example.Build() + Expect(err).NotTo(HaveOccurred()) + + netConf, err := libcni.ConfFromBytes([]byte(fmt.Sprintf( + `{ "name": "old-thing", "type": "%s" }`, example.Name))) + Expect(err).NotTo(HaveOccurred()) + + runtimeConf := &libcni.RuntimeConf{ + ContainerID: "some-container-id", + NetNS: "/some/netns/path", + IfName: "eth0", + } + + cniConfig := &libcni.CNIConfig{Path: []string{filepath.Dir(pluginPath)}} + + result, err := cniConfig.AddNetwork(netConf, runtimeConf) + Expect(err).NotTo(HaveOccurred()) + + Expect(result).To(Equal(legacy_examples.ExpectedResult)) + + Expect(os.RemoveAll(pluginPath)).To(Succeed()) + }) +}) diff --git a/pkg/version/legacy_examples/examples.go b/pkg/version/legacy_examples/examples.go new file mode 100644 index 00000000..57162312 --- /dev/null +++ b/pkg/version/legacy_examples/examples.go @@ -0,0 +1,138 @@ +// Copyright 2016 CNI authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package legacy_examples contains sample code from prior versions of +// the CNI library, for use in verifying backwards compatibility. +package legacy_examples + +import ( + "io/ioutil" + "net" + "path/filepath" + "sync" + + "github.com/containernetworking/cni/pkg/types" + "github.com/containernetworking/cni/pkg/version/testhelpers" +) + +// An Example is a Git reference to the CNI repo and a Golang CNI plugin that +// builds against that version of the repo. +// +// By convention, every Example plugin returns an ADD result that is +// semantically equivalent to the ExpectedResult. +type Example struct { + Name string + CNIRepoGitRef string + PluginSource string +} + +var buildDir = "" +var buildDirLock sync.Mutex + +func ensureBuildDirExists() error { + buildDirLock.Lock() + defer buildDirLock.Unlock() + + if buildDir != "" { + return nil + } + + var err error + buildDir, err = ioutil.TempDir("", "cni-example-plugins") + return err +} + +// Build builds the example, returning the path to the binary +func (e Example) Build() (string, error) { + if err := ensureBuildDirExists(); err != nil { + return "", err + } + + outBinPath := filepath.Join(buildDir, e.Name) + + if err := testhelpers.BuildAt([]byte(e.PluginSource), e.CNIRepoGitRef, outBinPath); err != nil { + return "", err + } + return outBinPath, nil +} + +// V010 acts like a CNI plugin from the v0.1.0 era +var V010 = Example{ + Name: "example_v010", + CNIRepoGitRef: "2c482f4", + PluginSource: `package main + +import ( + "net" + + "github.com/containernetworking/cni/pkg/skel" + "github.com/containernetworking/cni/pkg/types" +) + +var result = types.Result{ + IP4: &types.IPConfig{ + IP: net.IPNet{ + IP: net.ParseIP("10.1.2.3"), + Mask: net.CIDRMask(24, 32), + }, + Gateway: net.ParseIP("10.1.2.1"), + Routes: []types.Route{ + types.Route{ + Dst: net.IPNet{ + IP: net.ParseIP("0.0.0.0"), + Mask: net.CIDRMask(0, 32), + }, + GW: net.ParseIP("10.1.0.1"), + }, + }, + }, + DNS: types.DNS{ + Nameservers: []string{"8.8.8.8"}, + Domain: "example.com", + }, +} + +func c(_ *skel.CmdArgs) error { result.Print(); return nil } + +func main() { skel.PluginMain(c, c) } +`, +} + +// ExpectedResult is the current representation of the plugin result +// that is expected from each of the examples. +// +// As we change the CNI spec, the Result type and this value may change. +// The text of the example plugins should not. +var ExpectedResult = &types.Result{ + IP4: &types.IPConfig{ + IP: net.IPNet{ + IP: net.ParseIP("10.1.2.3"), + Mask: net.CIDRMask(24, 32), + }, + Gateway: net.ParseIP("10.1.2.1"), + Routes: []types.Route{ + types.Route{ + Dst: net.IPNet{ + IP: net.ParseIP("0.0.0.0"), + Mask: net.CIDRMask(0, 32), + }, + GW: net.ParseIP("10.1.0.1"), + }, + }, + }, + DNS: types.DNS{ + Nameservers: []string{"8.8.8.8"}, + Domain: "example.com", + }, +} diff --git a/pkg/version/legacy_examples/legacy_examples_suite_test.go b/pkg/version/legacy_examples/legacy_examples_suite_test.go new file mode 100644 index 00000000..a126531d --- /dev/null +++ b/pkg/version/legacy_examples/legacy_examples_suite_test.go @@ -0,0 +1,27 @@ +// Copyright 2016 CNI authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package legacy_examples_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestLegacyExamples(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "LegacyExamples Suite") +} diff --git a/pkg/version/legacy_examples/legacy_examples_test.go b/pkg/version/legacy_examples/legacy_examples_test.go new file mode 100644 index 00000000..41151056 --- /dev/null +++ b/pkg/version/legacy_examples/legacy_examples_test.go @@ -0,0 +1,36 @@ +// Copyright 2016 CNI authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package legacy_examples_test + +import ( + "os" + "path/filepath" + + "github.com/containernetworking/cni/pkg/version/legacy_examples" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("The v0.1.0 Example", func() { + It("builds ok", func() { + example := legacy_examples.V010 + pluginPath, err := example.Build() + Expect(err).NotTo(HaveOccurred()) + + Expect(filepath.Base(pluginPath)).To(Equal(example.Name)) + + Expect(os.RemoveAll(pluginPath)).To(Succeed()) + }) +})