flannel: add unit tests for config loading

backfill unit tests to add coverage for loadFlannelNetConf and
loadFlannelSubnetEnv
This commit is contained in:
Mark St.Godard 2016-11-05 23:27:14 -05:00
parent fa264e6e36
commit f0daefa63d
2 changed files with 109 additions and 54 deletions

View File

@ -11,7 +11,7 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
package main_test package main
import ( import (
"encoding/json" "encoding/json"

View File

@ -11,7 +11,7 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
package main_test package main
import ( import (
"fmt" "fmt"
@ -35,6 +35,8 @@ var _ = Describe("Flannel", func() {
input string input string
debug *noop_debug.Debug debug *noop_debug.Debug
expectedCmdArgs skel.CmdArgs expectedCmdArgs skel.CmdArgs
subnetFile string
stateDir string
) )
const delegateInput = ` const delegateInput = `
@ -61,6 +63,14 @@ FLANNEL_MTU=1472
FLANNEL_IPMASQ=true FLANNEL_IPMASQ=true
` `
var writeSubnetEnv = func(contents string) string {
file, err := ioutil.TempFile("", "subnet.env")
Expect(err).NotTo(HaveOccurred())
_, err = file.WriteString(contents)
Expect(err).NotTo(HaveOccurred())
return file.Name()
}
var cniCommand = func(command, input string) *exec.Cmd { var cniCommand = func(command, input string) *exec.Cmd {
toReturn := exec.Command(paths.PathToPlugin) toReturn := exec.Command(paths.PathToPlugin)
toReturn.Env = []string{ toReturn.Env = []string{
@ -86,61 +96,50 @@ FLANNEL_IPMASQ=true
ReportVersionSupport: []string{"0.1.0", "0.2.0", "0.3.0"}, ReportVersionSupport: []string{"0.1.0", "0.2.0", "0.3.0"},
} }
Expect(debug.WriteDebug(debugFileName)).To(Succeed()) Expect(debug.WriteDebug(debugFileName)).To(Succeed())
// flannel subnet.env
subnetFile = writeSubnetEnv(flannelSubnetEnv)
// flannel state dir
stateDir, err = ioutil.TempDir("", "stateDir")
Expect(err).NotTo(HaveOccurred())
input = fmt.Sprintf(inputTemplate, subnetFile, stateDir)
}) })
AfterEach(func() { AfterEach(func() {
os.Remove(debugFileName) os.Remove(debugFileName)
os.Remove(subnetFile)
os.Remove(stateDir)
}) })
Describe("CNI lifecycle", func() { Describe("CNI lifecycle", func() {
Context("when subnetFile and stateDir are specified", func() {
var (
subnetFile string
stateDir string
)
BeforeEach(func() { BeforeEach(func() {
var err error expectedCmdArgs = skel.CmdArgs{
file, err := ioutil.TempFile("", "subnet.env") ContainerID: "some-container-id",
Expect(err).NotTo(HaveOccurred()) Netns: "/some/netns/path",
_, err = file.WriteString(flannelSubnetEnv) IfName: "some-eth0",
Expect(err).NotTo(HaveOccurred()) Args: "DEBUG=" + debugFileName,
subnetFile = file.Name() Path: "/some/bin/path",
StdinData: []byte(input),
}
cmd = cniCommand("ADD", input)
})
stateDir, err = ioutil.TempDir("", "stateDir") It("uses stateDir for storing network configuration", func() {
Expect(err).NotTo(HaveOccurred()) By("calling ADD")
input = fmt.Sprintf(inputTemplate, subnetFile, stateDir) session, err := gexec.Start(cmd, GinkgoWriter, GinkgoWriter)
Expect(err).NotTo(HaveOccurred())
Eventually(session).Should(gexec.Exit(0))
Expect(session.Out.Contents()).To(MatchJSON(`{ "ip4": { "ip": "1.2.3.4/32" }, "dns":{} }`))
expectedCmdArgs = skel.CmdArgs{ By("check that plugin writes to net config to stateDir")
ContainerID: "some-container-id", path := fmt.Sprintf("%s/%s", stateDir, "some-container-id")
Netns: "/some/netns/path", Expect(path).Should(BeAnExistingFile())
IfName: "some-eth0",
Args: "DEBUG=" + debugFileName,
Path: "/some/bin/path",
StdinData: []byte(input),
}
cmd = cniCommand("ADD", input)
})
AfterEach(func() { netConfBytes, err := ioutil.ReadFile(path)
os.Remove(subnetFile) Expect(err).NotTo(HaveOccurred())
os.Remove(stateDir) expected := `{
})
It("uses stateDir for storing network configuration", func() {
By("calling ADD")
session, err := gexec.Start(cmd, GinkgoWriter, GinkgoWriter)
Expect(err).NotTo(HaveOccurred())
Eventually(session).Should(gexec.Exit(0))
Expect(session.Out.Contents()).To(MatchJSON(`{ "ip4": { "ip": "1.2.3.4/32" }, "dns":{} }`))
By("check that plugin writes to net config to stateDir")
path := fmt.Sprintf("%s/%s", stateDir, "some-container-id")
Expect(path).Should(BeAnExistingFile())
netConfBytes, err := ioutil.ReadFile(path)
Expect(err).NotTo(HaveOccurred())
expected := `{
"name" : "cni-flannel", "name" : "cni-flannel",
"type" : "noop", "type" : "noop",
"ipam" : { "ipam" : {
@ -157,16 +156,72 @@ FLANNEL_IPMASQ=true
"some" : "other data" "some" : "other data"
} }
` `
Expect(netConfBytes).Should(MatchJSON(expected)) Expect(netConfBytes).Should(MatchJSON(expected))
By("calling DEL") By("calling DEL")
cmd = cniCommand("DEL", input) cmd = cniCommand("DEL", input)
session, err = gexec.Start(cmd, GinkgoWriter, GinkgoWriter) session, err = gexec.Start(cmd, GinkgoWriter, GinkgoWriter)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Eventually(session).Should(gexec.Exit(0)) Eventually(session).Should(gexec.Exit(0))
By("check that plugin removes net config from state dir") By("check that plugin removes net config from state dir")
Expect(path).ShouldNot(BeAnExistingFile()) Expect(path).ShouldNot(BeAnExistingFile())
})
})
Describe("loadFlannelNetConf", func() {
Context("when subnetFile and stateDir are specified", func() {
It("loads flannel network config", func() {
conf, err := loadFlannelNetConf([]byte(input))
Expect(err).ShouldNot(HaveOccurred())
Expect(conf.Name).To(Equal("cni-flannel"))
Expect(conf.Type).To(Equal("flannel"))
Expect(conf.SubnetFile).To(Equal(subnetFile))
Expect(conf.StateDir).To(Equal(stateDir))
})
})
Context("when defaulting subnetFile and stateDir", func() {
BeforeEach(func() {
input = `{
"name": "cni-flannel",
"type": "flannel",
"delegate": ` +
delegateInput +
`}`
})
It("loads flannel network config with defaults", func() {
conf, err := loadFlannelNetConf([]byte(input))
Expect(err).ShouldNot(HaveOccurred())
Expect(conf.Name).To(Equal("cni-flannel"))
Expect(conf.Type).To(Equal("flannel"))
Expect(conf.SubnetFile).To(Equal(defaultSubnetFile))
Expect(conf.StateDir).To(Equal(defaultStateDir))
})
})
Describe("loadFlannelSubnetEnv", func() {
Context("when flannel subnet env is valid", func() {
It("loads flannel subnet config", func() {
conf, err := loadFlannelSubnetEnv(subnetFile)
Expect(err).ShouldNot(HaveOccurred())
Expect(conf.nw.String()).To(Equal("10.1.0.0/16"))
Expect(conf.sn.String()).To(Equal("10.1.17.0/24"))
var mtu uint = 1472
Expect(*conf.mtu).To(Equal(mtu))
Expect(*conf.ipmasq).To(BeTrue())
})
})
Context("when flannel subnet env is invalid", func() {
BeforeEach(func() {
subnetFile = writeSubnetEnv("foo=bar")
})
It("returns an error", func() {
_, err := loadFlannelSubnetEnv(subnetFile)
Expect(err).To(MatchError(ContainSubstring("missing FLANNEL_NETWORK, FLANNEL_SUBNET, FLANNEL_MTU, FLANNEL_IPMASQ")))
})
}) })
}) })
}) })