<commit_before>// +build xmlroundtrip

/*
 * This file is part of the libvirt-go-xml project
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * Copyright (C) 2016 Red Hat, Inc.
 *
 */

package libvirtxml

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
	"testing"
)

var xmldirs = []string{
	"testdata/libvirt/tests/bhyveargv2xmldata",
	"testdata/libvirt/tests/bhyvexml2argvdata",
	"testdata/libvirt/tests/bhyvexml2xmloutdata",
	"testdata/libvirt/tests/capabilityschemadata",
	"testdata/libvirt/tests/cputestdata",
	"testdata/libvirt/tests/domaincapsschemadata",
	"testdata/libvirt/tests/domainconfdata",
	"testdata/libvirt/tests/domainschemadata",
	"testdata/libvirt/tests/domainsnapshotxml2xmlin",
	"testdata/libvirt/tests/domainsnapshotxml2xmlout",
	"testdata/libvirt/tests/genericxml2xmlindata",
	"testdata/libvirt/tests/genericxml2xmloutdata",
	"testdata/libvirt/tests/interfaceschemadata",
	"testdata/libvirt/tests/libxlxml2domconfigdata",
	"testdata/libvirt/tests/lxcconf2xmldata",
	"testdata/libvirt/tests/lxcxml2xmldata",
	"testdata/libvirt/tests/lxcxml2xmloutdata",
	"testdata/libvirt/tests/networkxml2confdata",
	"testdata/libvirt/tests/networkxml2firewalldata",
	"testdata/libvirt/tests/networkxml2xmlin",
	"testdata/libvirt/tests/networkxml2xmlout",
	"testdata/libvirt/tests/networkxml2xmlupdatein",
	"testdata/libvirt/tests/networkxml2xmlupdateout",
	"testdata/libvirt/tests/nodedevschemadata",
	"testdata/libvirt/tests/nwfilterxml2firewalldata",
	"testdata/libvirt/tests/nwfilterxml2xmlin",
	"testdata/libvirt/tests/nwfilterxml2xmlout",
	"testdata/libvirt/tests/qemuagentdata",
	"testdata/libvirt/tests/qemuargv2xmldata",
	"testdata/libvirt/tests/qemucapabilitiesdata",
	"testdata/libvirt/tests/qemucaps2xmldata",
	"testdata/libvirt/tests/qemuhotplugtestcpus",
	"testdata/libvirt/tests/qemuhotplugtestdevices",
	"testdata/libvirt/tests/qemuhotplugtestdomains",
	"testdata/libvirt/tests/qemumemlockdata",
	"testdata/libvirt/tests/qemuxml2argvdata",
	"testdata/libvirt/tests/qemuxml2xmloutdata",
	"testdata/libvirt/tests/secretxml2xmlin",
	"testdata/libvirt/tests/securityselinuxlabeldata",
	"testdata/libvirt/tests/sexpr2xmldata",
	"testdata/libvirt/tests/storagepoolschemadata",
	"testdata/libvirt/tests/storagepoolxml2xmlin",
	"testdata/libvirt/tests/storagepoolxml2xmlout",
	"testdata/libvirt/tests/storagevolschemadata",
	"testdata/libvirt/tests/storagevolxml2xmlin",
	"testdata/libvirt/tests/storagevolxml2xmlout",
	"testdata/libvirt/tests/vircaps2xmldata",
	"testdata/libvirt/tests/virstorageutildata",
	"testdata/libvirt/tests/vmx2xmldata",
	"testdata/libvirt/tests/xencapsdata",
	"testdata/libvirt/tests/xlconfigdata",
	"testdata/libvirt/tests/xmconfigdata",
	"testdata/libvirt/tests/xml2sexprdata",
	"testdata/libvirt/tests/xml2vmxdata",
}

var consoletype = "/domain[0]/devices[0]/console[0]/@type"

var blacklist = map[string]bool{
	// intentionally invalid xml
	"testdata/libvirt/tests/genericxml2xmlindata/generic-chardev-unix-redirdev-missing-path.xml":  true,
	"testdata/libvirt/tests/genericxml2xmlindata/generic-chardev-unix-rng-missing-path.xml":       true,
	"testdata/libvirt/tests/qemuxml2argvdata/qemuxml2argv-virtio-rng-egd-crash.xml":               true,
	"testdata/libvirt/tests/genericxml2xmlindata/generic-chardev-unix-smartcard-missing-path.xml": true,
	"testdata/libvirt/tests/genericxml2xmlindata/generic-chardev-tcp-multiple-source.xml":         true,
	// udp source in different order
	"testdata/libvirt/tests/genericxml2xmlindata/generic-chardev-udp.xml":                 true,
	"testdata/libvirt/tests/genericxml2xmlindata/generic-chardev-udp-multiple-source.xml": true,
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-fv-serial-udp.xml":                    true,
}

var extraActualNodes = map[string][]string{

	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-pv-vcpus.xml":              []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-pv.xml":                    []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-pv-bootloader.xml":         []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-pv-bootloader-cmdline.xml": []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-pci-devs.xml":              []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-net-routed.xml":            []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-net-e1000.xml":             []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-net-bridged.xml":           []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-fv-kernel.xml":             []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-escape.xml":                []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-disk-file.xml":             []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-disk-drv-loop.xml":         []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-disk-drv-blktap2.xml":      []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-disk-drv-blktap2-raw.xml":  []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-disk-drv-blktap.xml":       []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-disk-drv-blktap-raw.xml":   []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-disk-drv-blktap-qcow.xml":  []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-disk-drv-blkback.xml":      []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-disk-block.xml":            []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-disk-block-shareable.xml":  []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-bridge-ipaddr.xml":         []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-boot-grub.xml":             []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-no-source-cdrom.xml": []string{
		"/domain[0]/devices[0]/disk[1]/@type",
	},

	"testdata/libvirt/tests/qemuxml2argvdata/qemuxml2argv-fs9p-ccw.xml": []string{
		"/domain[0]/devices[0]/filesystem[1]/@type",
		"/domain[0]/devices[0]/filesystem[2]/@type",
	},
	"testdata/libvirt/tests/qemuxml2argvdata/qemuxml2argv-fs9p.xml": []string{
		"/domain[0]/devices[0]/filesystem[1]/@type",
		"/domain[0]/devices[0]/filesystem[2]/@type",
	},
	"testdata/libvirt/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-discard.xml": []string{
		"/domain[0]/devices[0]/disk[0]/@type",
	},
	"testdata/libvirt/tests/genericxml2xmlindata/generic-chardev-udp.xml": []string{
		"/domain[0]/devices[0]/channel[0]/source[0]/@mode",
	},
	"testdata/libvirt/tests/qemuxml2argvdata/qemuxml2argv-disk-mirror-old.xml": []string{
		"/domain[0]/devices[0]/disk[0]/mirror[0]/@type",
		"/domain[0]/devices[0]/disk[0]/mirror[0]/source[0]",
		"/domain[0]/devices[0]/disk[2]/mirror[0]/@type",
		"/domain[0]/devices[0]/disk[2]/mirror[0]/format[0]",
		"/domain[0]/devices[0]/disk[2]/mirror[0]/source[0]",
	},

	"testdata/libvirt/tests/networkxml2xmlin/openvswitch-net.xml": []string{
		"/network[0]/virtualport[0]/parameters[0]",
	},
	"testdata/libvirt/tests/networkxml2xmlout/openvswitch-net.xml": []string{
		"/network[0]/virtualport[0]/parameters[0]",
	},
	"testdata/libvirt/tests/networkxml2xmlupdateout/openvswitch-net-modified.xml": []string{
		"/network[0]/virtualport[0]/parameters[0]",
	},
	"testdata/libvirt/tests/networkxml2xmlupdateout/openvswitch-net-more-portgroups.xml": []string{
		"/network[0]/virtualport[0]/parameters[0]",
	},
	"testdata/libvirt/tests/networkxml2xmlupdateout/openvswitch-net-without-alice.xml": []string{
		"/network[0]/virtualport[0]/parameters[0]",
	},
}

var extraExpectNodes = map[string][]string{
	"testdata/libvirt/tests/genericxml2xmlindata/generic-chardev-unix.xml": []string{
		"/domain[0]/devices[0]/channel[1]/source[0]",
	},
	"testdata/libvirt/tests/qemuxml2argvdata/qemuxml2argv-usb-redir-filter.xml": []string{
		"/domain[0]/devices[0]/redirfilter[0]/usbdev[1]/@vendor",
		"/domain[0]/devices[0]/redirfilter[0]/usbdev[1]/@product",
		"/domain[0]/devices[0]/redirfilter[0]/usbdev[1]/@class",
		"/domain[0]/devices[0]/redirfilter[0]/usbdev[1]/@version",
	},
	"testdata/libvirt/tests/domainschemadata/domain-parallels-ct-simple.xml": []string{
		"/domain[0]/description[0]",
	},
}

func testRoundTrip(t *testing.T, xml string, filename string) {
	if strings.HasSuffix(filename, "-invalid.xml") {
		return
	}

	var doc Document
	if strings.HasPrefix(xml, "<domain ") {
		doc = &Domain{}
	} else if strings.HasPrefix(xml, "<capabilities") {
		doc = &Caps{}
	} else if strings.HasPrefix(xml, "<network") {
		doc = &Network{}
	} else if strings.HasPrefix(xml, "<secret") {
		doc = &Secret{}
	} else {
		return
	}
	err := doc.Unmarshal(xml)
	if err != nil {
		t.Fatal(fmt.Errorf("Cannot parse file %s: %s\n", filename, err))
	}

	newxml, err := doc.Marshal()
	if err != nil {
		t.Fatal(err)
	}

	extraExpectNodes, _ := extraExpectNodes[filename]
	extraActualNodes, _ := extraActualNodes[filename]
	err = testCompareXML(filename, xml, newxml, extraExpectNodes, extraActualNodes)
	if err != nil {
		t.Fatal(err)
	}
}

func syncGit(t *testing.T) {
	_, err := os.Stat("testdata/libvirt/tests")
	if err != nil {
		if os.IsNotExist(err) {
			err := exec.Command("git", "clone", "--depth", "1", "git://libvirt.org/libvirt.git", "testdata/libvirt").Run()
			if err != nil {
				t.Fatal(err)
			}
		} else {
			t.Fatal(err)
		}
	} else {
		here, err := os.Getwd()
		if err != nil {
			t.Fatal(err)
		}
		err = os.Chdir("testdata/libvirt")
		if err != nil {
			t.Fatal(err)
		}
		defer func() {
			os.Chdir(here)
		}()
		err = exec.Command("git", "pull").Run()
		if err != nil {
			t.Fatal(err)
		}
	}
}

func TestRoundTrip(t *testing.T) {
	syncGit(t)
	for _, xmldir := range xmldirs {
		xmlfiles, err := ioutil.ReadDir(xmldir)
		if err != nil {
			t.Fatal(err)
		}

		for _, xmlfile := range xmlfiles {
			if !xmlfile.IsDir() && strings.HasSuffix(xmlfile.Name(), ".xml") {
				fname := xmldir + "/" + xmlfile.Name()
				_, ok := blacklist[fname]
				if ok {
					continue
				}
				xml, err := ioutil.ReadFile(fname)
				if err != nil {
					t.Fatal(err)
				}
				testRoundTrip(t, string(xml), fname)
			}
		}
	}
}
<commit_msg>Enable testing of node device XML<commit_after>// +build xmlroundtrip

/*
 * This file is part of the libvirt-go-xml project
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * Copyright (C) 2016 Red Hat, Inc.
 *
 */

package libvirtxml

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
	"testing"
)

var xmldirs = []string{
	"testdata/libvirt/tests/bhyveargv2xmldata",
	"testdata/libvirt/tests/bhyvexml2argvdata",
	"testdata/libvirt/tests/bhyvexml2xmloutdata",
	"testdata/libvirt/tests/capabilityschemadata",
	"testdata/libvirt/tests/cputestdata",
	"testdata/libvirt/tests/domaincapsschemadata",
	"testdata/libvirt/tests/domainconfdata",
	"testdata/libvirt/tests/domainschemadata",
	"testdata/libvirt/tests/domainsnapshotxml2xmlin",
	"testdata/libvirt/tests/domainsnapshotxml2xmlout",
	"testdata/libvirt/tests/genericxml2xmlindata",
	"testdata/libvirt/tests/genericxml2xmloutdata",
	"testdata/libvirt/tests/interfaceschemadata",
	"testdata/libvirt/tests/libxlxml2domconfigdata",
	"testdata/libvirt/tests/lxcconf2xmldata",
	"testdata/libvirt/tests/lxcxml2xmldata",
	"testdata/libvirt/tests/lxcxml2xmloutdata",
	"testdata/libvirt/tests/networkxml2confdata",
	"testdata/libvirt/tests/networkxml2firewalldata",
	"testdata/libvirt/tests/networkxml2xmlin",
	"testdata/libvirt/tests/networkxml2xmlout",
	"testdata/libvirt/tests/networkxml2xmlupdatein",
	"testdata/libvirt/tests/networkxml2xmlupdateout",
	"testdata/libvirt/tests/nodedevschemadata",
	"testdata/libvirt/tests/nwfilterxml2firewalldata",
	"testdata/libvirt/tests/nwfilterxml2xmlin",
	"testdata/libvirt/tests/nwfilterxml2xmlout",
	"testdata/libvirt/tests/qemuagentdata",
	"testdata/libvirt/tests/qemuargv2xmldata",
	"testdata/libvirt/tests/qemucapabilitiesdata",
	"testdata/libvirt/tests/qemucaps2xmldata",
	"testdata/libvirt/tests/qemuhotplugtestcpus",
	"testdata/libvirt/tests/qemuhotplugtestdevices",
	"testdata/libvirt/tests/qemuhotplugtestdomains",
	"testdata/libvirt/tests/qemumemlockdata",
	"testdata/libvirt/tests/qemuxml2argvdata",
	"testdata/libvirt/tests/qemuxml2xmloutdata",
	"testdata/libvirt/tests/secretxml2xmlin",
	"testdata/libvirt/tests/securityselinuxlabeldata",
	"testdata/libvirt/tests/sexpr2xmldata",
	"testdata/libvirt/tests/storagepoolschemadata",
	"testdata/libvirt/tests/storagepoolxml2xmlin",
	"testdata/libvirt/tests/storagepoolxml2xmlout",
	"testdata/libvirt/tests/storagevolschemadata",
	"testdata/libvirt/tests/storagevolxml2xmlin",
	"testdata/libvirt/tests/storagevolxml2xmlout",
	"testdata/libvirt/tests/vircaps2xmldata",
	"testdata/libvirt/tests/virstorageutildata",
	"testdata/libvirt/tests/vmx2xmldata",
	"testdata/libvirt/tests/xencapsdata",
	"testdata/libvirt/tests/xlconfigdata",
	"testdata/libvirt/tests/xmconfigdata",
	"testdata/libvirt/tests/xml2sexprdata",
	"testdata/libvirt/tests/xml2vmxdata",
}

var consoletype = "/domain[0]/devices[0]/console[0]/@type"

var blacklist = map[string]bool{
	// intentionally invalid xml
	"testdata/libvirt/tests/genericxml2xmlindata/generic-chardev-unix-redirdev-missing-path.xml":  true,
	"testdata/libvirt/tests/genericxml2xmlindata/generic-chardev-unix-rng-missing-path.xml":       true,
	"testdata/libvirt/tests/qemuxml2argvdata/qemuxml2argv-virtio-rng-egd-crash.xml":               true,
	"testdata/libvirt/tests/genericxml2xmlindata/generic-chardev-unix-smartcard-missing-path.xml": true,
	"testdata/libvirt/tests/genericxml2xmlindata/generic-chardev-tcp-multiple-source.xml":         true,
	// udp source in different order
	"testdata/libvirt/tests/genericxml2xmlindata/generic-chardev-udp.xml":                 true,
	"testdata/libvirt/tests/genericxml2xmlindata/generic-chardev-udp-multiple-source.xml": true,
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-fv-serial-udp.xml":                    true,
}

var extraActualNodes = map[string][]string{

	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-pv-vcpus.xml":              []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-pv.xml":                    []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-pv-bootloader.xml":         []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-pv-bootloader-cmdline.xml": []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-pci-devs.xml":              []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-net-routed.xml":            []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-net-e1000.xml":             []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-net-bridged.xml":           []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-fv-kernel.xml":             []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-escape.xml":                []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-disk-file.xml":             []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-disk-drv-loop.xml":         []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-disk-drv-blktap2.xml":      []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-disk-drv-blktap2-raw.xml":  []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-disk-drv-blktap.xml":       []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-disk-drv-blktap-raw.xml":   []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-disk-drv-blktap-qcow.xml":  []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-disk-drv-blkback.xml":      []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-disk-block.xml":            []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-disk-block-shareable.xml":  []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-bridge-ipaddr.xml":         []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-boot-grub.xml":             []string{consoletype},
	"testdata/libvirt/tests/xml2sexprdata/xml2sexpr-no-source-cdrom.xml": []string{
		"/domain[0]/devices[0]/disk[1]/@type",
	},

	"testdata/libvirt/tests/qemuxml2argvdata/qemuxml2argv-fs9p-ccw.xml": []string{
		"/domain[0]/devices[0]/filesystem[1]/@type",
		"/domain[0]/devices[0]/filesystem[2]/@type",
	},
	"testdata/libvirt/tests/qemuxml2argvdata/qemuxml2argv-fs9p.xml": []string{
		"/domain[0]/devices[0]/filesystem[1]/@type",
		"/domain[0]/devices[0]/filesystem[2]/@type",
	},
	"testdata/libvirt/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-discard.xml": []string{
		"/domain[0]/devices[0]/disk[0]/@type",
	},
	"testdata/libvirt/tests/genericxml2xmlindata/generic-chardev-udp.xml": []string{
		"/domain[0]/devices[0]/channel[0]/source[0]/@mode",
	},
	"testdata/libvirt/tests/qemuxml2argvdata/qemuxml2argv-disk-mirror-old.xml": []string{
		"/domain[0]/devices[0]/disk[0]/mirror[0]/@type",
		"/domain[0]/devices[0]/disk[0]/mirror[0]/source[0]",
		"/domain[0]/devices[0]/disk[2]/mirror[0]/@type",
		"/domain[0]/devices[0]/disk[2]/mirror[0]/format[0]",
		"/domain[0]/devices[0]/disk[2]/mirror[0]/source[0]",
	},

	"testdata/libvirt/tests/networkxml2xmlin/openvswitch-net.xml": []string{
		"/network[0]/virtualport[0]/parameters[0]",
	},
	"testdata/libvirt/tests/networkxml2xmlout/openvswitch-net.xml": []string{
		"/network[0]/virtualport[0]/parameters[0]",
	},
	"testdata/libvirt/tests/networkxml2xmlupdateout/openvswitch-net-modified.xml": []string{
		"/network[0]/virtualport[0]/parameters[0]",
	},
	"testdata/libvirt/tests/networkxml2xmlupdateout/openvswitch-net-more-portgroups.xml": []string{
		"/network[0]/virtualport[0]/parameters[0]",
	},
	"testdata/libvirt/tests/networkxml2xmlupdateout/openvswitch-net-without-alice.xml": []string{
		"/network[0]/virtualport[0]/parameters[0]",
	},
}

var extraExpectNodes = map[string][]string{
	"testdata/libvirt/tests/genericxml2xmlindata/generic-chardev-unix.xml": []string{
		"/domain[0]/devices[0]/channel[1]/source[0]",
	},
	"testdata/libvirt/tests/qemuxml2argvdata/qemuxml2argv-usb-redir-filter.xml": []string{
		"/domain[0]/devices[0]/redirfilter[0]/usbdev[1]/@vendor",
		"/domain[0]/devices[0]/redirfilter[0]/usbdev[1]/@product",
		"/domain[0]/devices[0]/redirfilter[0]/usbdev[1]/@class",
		"/domain[0]/devices[0]/redirfilter[0]/usbdev[1]/@version",
	},
	"testdata/libvirt/tests/domainschemadata/domain-parallels-ct-simple.xml": []string{
		"/domain[0]/description[0]",
	},
}

func testRoundTrip(t *testing.T, xml string, filename string) {
	if strings.HasSuffix(filename, "-invalid.xml") {
		return
	}

	var doc Document
	if strings.HasPrefix(xml, "<domain ") {
		doc = &Domain{}
	} else if strings.HasPrefix(xml, "<capabilities") {
		doc = &Caps{}
	} else if strings.HasPrefix(xml, "<network") {
		doc = &Network{}
	} else if strings.HasPrefix(xml, "<secret") {
		doc = &Secret{}
	} else if strings.HasPrefix(xml, "<device") {
		doc = &NodeDevice{}
	} else {
		return
	}
	err := doc.Unmarshal(xml)
	if err != nil {
		t.Fatal(fmt.Errorf("Cannot parse file %s: %s\n", filename, err))
	}

	newxml, err := doc.Marshal()
	if err != nil {
		t.Fatal(err)
	}

	extraExpectNodes, _ := extraExpectNodes[filename]
	extraActualNodes, _ := extraActualNodes[filename]
	err = testCompareXML(filename, xml, newxml, extraExpectNodes, extraActualNodes)
	if err != nil {
		t.Fatal(err)
	}
}

func syncGit(t *testing.T) {
	_, err := os.Stat("testdata/libvirt/tests")
	if err != nil {
		if os.IsNotExist(err) {
			err := exec.Command("git", "clone", "--depth", "1", "git://libvirt.org/libvirt.git", "testdata/libvirt").Run()
			if err != nil {
				t.Fatal(err)
			}
		} else {
			t.Fatal(err)
		}
	} else {
		here, err := os.Getwd()
		if err != nil {
			t.Fatal(err)
		}
		err = os.Chdir("testdata/libvirt")
		if err != nil {
			t.Fatal(err)
		}
		defer func() {
			os.Chdir(here)
		}()
		err = exec.Command("git", "pull").Run()
		if err != nil {
			t.Fatal(err)
		}
	}
}

func TestRoundTrip(t *testing.T) {
	syncGit(t)
	for _, xmldir := range xmldirs {
		xmlfiles, err := ioutil.ReadDir(xmldir)
		if err != nil {
			t.Fatal(err)
		}

		for _, xmlfile := range xmlfiles {
			if !xmlfile.IsDir() && strings.HasSuffix(xmlfile.Name(), ".xml") {
				fname := xmldir + "/" + xmlfile.Name()
				_, ok := blacklist[fname]
				if ok {
					continue
				}
				xml, err := ioutil.ReadFile(fname)
				if err != nil {
					t.Fatal(err)
				}
				testRoundTrip(t, string(xml), fname)
			}
		}
	}
}
<|endoftext|>


<commit_before>package discovery

import (
	"strconv"

	"github.com/TeaMeow/KitSvc/config"
	"github.com/go-kit/kit/log"
	consulsd "github.com/go-kit/kit/sd/consul"
	consulapi "github.com/hashicorp/consul/api"
)

func Register(c *config.Context, logger log.Logger) {

	info := consulapi.AgentServiceRegistration{
		Name: c.Service.Name,
		Port: c.Service.Port,
		Tags: c.Consul.Tags,
		Check: &consulapi.AgentServiceCheck{
			HTTP:     "http://localhost:" + strconv.Itoa(c.Service.Port) + "/health",
			Interval: c.Consul.CheckInterval,
			Timeout:  c.Consul.CheckTimeout,
		},
	}
	// DEREGISTRE
	// DDDDDD
	// DDD
	apiConfig := consulapi.DefaultConfig()
	apiClient, _ := consulapi.NewClient(apiConfig)
	client := consulsd.NewClient(apiClient)
	reg := consulsd.NewRegistrar(client, &info, logger)
	reg.Register()
}
<commit_msg>The service will now deregister from consul<commit_after>package discovery

import (
	"os"
	"os/signal"

	"github.com/TeaMeow/KitSvc/config"
	"github.com/go-kit/kit/log"
	consulsd "github.com/go-kit/kit/sd/consul"
	consulapi "github.com/hashicorp/consul/api"
)

func Register(c *config.Context, logger log.Logger) {

	info := consulapi.AgentServiceRegistration{
		Name: c.Service.Name,
		Port: c.Service.Port,
		Tags: c.Consul.Tags,
		Check: &consulapi.AgentServiceCheck{
			HTTP:     c.Service.URL + "/health",
			Interval: c.Consul.CheckInterval,
			Timeout:  c.Consul.CheckTimeout,
		},
	}

	apiConfig := consulapi.DefaultConfig()
	apiClient, _ := consulapi.NewClient(apiConfig)
	client := consulsd.NewClient(apiClient)
	reg := consulsd.NewRegistrar(client, &info, logger)

	// Deregister the service when ctrl+c
	ch := make(chan os.Signal, 1)
	signal.Notify(ch, os.Interrupt)
	go func() {
		for range ch {
			reg.Deregister()
			os.Exit(1)
		}
	}()

	// Register the service
	reg.Register()
}
<|endoftext|>


<commit_before>// Copyright ©2013 The bíogo.bam Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package bam

import (
	"bytes"
	"flag"
	"fmt"
	"io"
	check "launchpad.net/gocheck"
	"os"
	"reflect"
	"testing"
)

var (
	bam    = flag.String("bam", "", "output first failing bam data to this file for inspection")
	allbam = flag.String("allbam", "", "output all bam data to this file base for inspection")
)

func Test(t *testing.T) { check.TestingT(t) }

type S struct{}

var _ = check.Suite(&S{})

func (s *S) TestRead(c *check.C) {
	for i, t := range []struct {
		in     []byte
		header *Header
		lines  int
	}{
		{
			in:     bamHG00096_1000,
			header: headerHG00096_1000,
			lines:  1000,
		},
	} {
		br, err := NewReader(bytes.NewBuffer(t.in), false)
		c.Assert(err, check.Equals, nil)
		c.Check(br.Header(), check.DeepEquals, t.header)
		if !reflect.DeepEqual(br.Header(), t.header) {
			c.Check(br.Header().Refs(), check.DeepEquals, t.header.Refs())
			c.Check(br.Header().RGs(), check.DeepEquals, t.header.RGs())
			c.Check(br.Header().Progs(), check.DeepEquals, t.header.Progs())
		}
		var lines int
		for {
			_, err := br.Read()
			if err != nil {
				c.Assert(err, check.Equals, io.EOF)
				break
			}
			lines++
		}
		c.Check(lines, check.Equals, t.lines)
		if *allbam != "" {
			bf, err := os.Create(fmt.Sprintf("%s-%d.bam", *allbam, i))
			c.Assert(err, check.Equals, nil)
			bf.Write(t.in)
			bf.Close()
		}
		if c.Failed() && *bam != "" {
			bf, err := os.Create(*bam)
			c.Assert(err, check.Equals, nil)
			bf.Write(t.in)
			bf.Close()
			c.FailNow()
		}
	}
}

func (s *S) TestRoundTrip(c *check.C) {
	for _, t := range []struct {
		in     []byte
		header *Header
		lines  int
	}{
		{
			in:     bamHG00096_1000,
			header: headerHG00096_1000,
			lines:  1000,
		},
	} {
		br, err := NewReader(bytes.NewBuffer(t.in), false)
		c.Assert(err, check.Equals, nil)

		var buf bytes.Buffer
		bw, err := NewWriter(&buf, br.Header().Clone())
		for {
			r, err := br.Read()
			if err != nil {
				c.Assert(err, check.Equals, io.EOF)
				break
			}
			bw.Write(r)
		}
		c.Assert(bw.Close(), check.Equals, nil)

		br, err = NewReader(bytes.NewBuffer(t.in), false)
		c.Assert(err, check.Equals, nil)
		brr, err := NewReader(&buf, false)
		c.Assert(err, check.Equals, nil)
		c.Check(brr.Header().String(), check.Equals, br.Header().String())
		c.Check(brr.Header(), check.DeepEquals, br.Header())
		if !reflect.DeepEqual(brr.Header(), br.Header()) {
			c.Check(brr.Header().Refs(), check.DeepEquals, br.Header().Refs())
			c.Check(brr.Header().RGs(), check.DeepEquals, br.Header().RGs())
			c.Check(brr.Header().Progs(), check.DeepEquals, br.Header().Progs())
		}
		for {
			r, err := br.Read()
			if err != nil {
				c.Assert(err, check.Equals, io.EOF)
			}
			rr, err := brr.Read()
			if err != nil {
				c.Assert(err, check.Equals, io.EOF)
				break
			}
			c.Check(rr, check.DeepEquals, r)
		}
	}
}
<commit_msg>Add Comments check to breakdown<commit_after>// Copyright ©2013 The bíogo.bam Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package bam

import (
	"bytes"
	"flag"
	"fmt"
	"io"
	check "launchpad.net/gocheck"
	"os"
	"reflect"
	"testing"
)

var (
	bam    = flag.String("bam", "", "output first failing bam data to this file for inspection")
	allbam = flag.String("allbam", "", "output all bam data to this file base for inspection")
)

func Test(t *testing.T) { check.TestingT(t) }

type S struct{}

var _ = check.Suite(&S{})

func (s *S) TestRead(c *check.C) {
	for i, t := range []struct {
		in     []byte
		header *Header
		lines  int
	}{
		{
			in:     bamHG00096_1000,
			header: headerHG00096_1000,
			lines:  1000,
		},
	} {
		br, err := NewReader(bytes.NewBuffer(t.in), false)
		c.Assert(err, check.Equals, nil)
		c.Check(br.Header(), check.DeepEquals, t.header)
		if !reflect.DeepEqual(br.Header(), t.header) {
			c.Check(br.Header().Refs(), check.DeepEquals, t.header.Refs())
			c.Check(br.Header().RGs(), check.DeepEquals, t.header.RGs())
			c.Check(br.Header().Progs(), check.DeepEquals, t.header.Progs())
			c.Check(br.Header().Comments, check.DeepEquals, t.header.Comments)
		}
		var lines int
		for {
			_, err := br.Read()
			if err != nil {
				c.Assert(err, check.Equals, io.EOF)
				break
			}
			lines++
		}
		c.Check(lines, check.Equals, t.lines)
		if *allbam != "" {
			bf, err := os.Create(fmt.Sprintf("%s-%d.bam", *allbam, i))
			c.Assert(err, check.Equals, nil)
			bf.Write(t.in)
			bf.Close()
		}
		if c.Failed() && *bam != "" {
			bf, err := os.Create(*bam)
			c.Assert(err, check.Equals, nil)
			bf.Write(t.in)
			bf.Close()
			c.FailNow()
		}
	}
}

func (s *S) TestRoundTrip(c *check.C) {
	for _, t := range []struct {
		in     []byte
		header *Header
		lines  int
	}{
		{
			in:     bamHG00096_1000,
			header: headerHG00096_1000,
			lines:  1000,
		},
	} {
		br, err := NewReader(bytes.NewBuffer(t.in), false)
		c.Assert(err, check.Equals, nil)

		var buf bytes.Buffer
		bw, err := NewWriter(&buf, br.Header().Clone())
		for {
			r, err := br.Read()
			if err != nil {
				c.Assert(err, check.Equals, io.EOF)
				break
			}
			bw.Write(r)
		}
		c.Assert(bw.Close(), check.Equals, nil)

		br, err = NewReader(bytes.NewBuffer(t.in), false)
		c.Assert(err, check.Equals, nil)
		brr, err := NewReader(&buf, false)
		c.Assert(err, check.Equals, nil)
		c.Check(brr.Header().String(), check.Equals, br.Header().String())
		c.Check(brr.Header(), check.DeepEquals, br.Header())
		if !reflect.DeepEqual(brr.Header(), br.Header()) {
			c.Check(brr.Header().Refs(), check.DeepEquals, br.Header().Refs())
			c.Check(brr.Header().RGs(), check.DeepEquals, br.Header().RGs())
			c.Check(brr.Header().Progs(), check.DeepEquals, br.Header().Progs())
			c.Check(brr.Header().Comments, check.DeepEquals, br.Header().Comments)
		}
		for {
			r, err := br.Read()
			if err != nil {
				c.Assert(err, check.Equals, io.EOF)
			}
			rr, err := brr.Read()
			if err != nil {
				c.Assert(err, check.Equals, io.EOF)
				break
			}
			c.Check(rr, check.DeepEquals, r)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"crypto/rand"
	"encoding/json"
	"io/ioutil"
	"log"
	"os"

	"github.com/cloudfoundry/bosh-bootloader/application"
	"github.com/cloudfoundry/bosh-bootloader/aws"
	"github.com/cloudfoundry/bosh-bootloader/aws/clientmanager"
	"github.com/cloudfoundry/bosh-bootloader/aws/cloudformation"
	"github.com/cloudfoundry/bosh-bootloader/aws/cloudformation/templates"
	"github.com/cloudfoundry/bosh-bootloader/aws/ec2"
	"github.com/cloudfoundry/bosh-bootloader/aws/iam"
	"github.com/cloudfoundry/bosh-bootloader/azure"
	"github.com/cloudfoundry/bosh-bootloader/bosh"
	"github.com/cloudfoundry/bosh-bootloader/certs"
	"github.com/cloudfoundry/bosh-bootloader/cloudconfig"
	"github.com/cloudfoundry/bosh-bootloader/commands"
	"github.com/cloudfoundry/bosh-bootloader/config"
	"github.com/cloudfoundry/bosh-bootloader/gcp"
	"github.com/cloudfoundry/bosh-bootloader/helpers"
	"github.com/cloudfoundry/bosh-bootloader/proxy"
	"github.com/cloudfoundry/bosh-bootloader/stack"
	"github.com/cloudfoundry/bosh-bootloader/storage"
	"github.com/cloudfoundry/bosh-bootloader/terraform"

	awsapplication "github.com/cloudfoundry/bosh-bootloader/application/aws"
	gcpapplication "github.com/cloudfoundry/bosh-bootloader/application/gcp"
	awscloudconfig "github.com/cloudfoundry/bosh-bootloader/cloudconfig/aws"
	azurecloudconfig "github.com/cloudfoundry/bosh-bootloader/cloudconfig/azure"
	gcpcloudconfig "github.com/cloudfoundry/bosh-bootloader/cloudconfig/gcp"
	awsterraform "github.com/cloudfoundry/bosh-bootloader/terraform/aws"
	azureterraform "github.com/cloudfoundry/bosh-bootloader/terraform/azure"
	gcpterraform "github.com/cloudfoundry/bosh-bootloader/terraform/gcp"
)

var (
	Version     string
	gcpBasePath string
)

func main() {
	newConfig := config.NewConfig(storage.GetState)
	appConfig, err := newConfig.Bootstrap(os.Args)
	log.SetFlags(0)
	if err != nil {
		log.Fatalf("\n\n%s\n", err)
	}

	needsIAASConfig := config.NeedsIAASConfig(appConfig.Command) && !appConfig.ShowCommandHelp
	if needsIAASConfig {
		err = config.ValidateIAAS(appConfig.State, appConfig.Command)
		if err != nil {
			log.Fatalf("\n\n%s\n", err)
		}
	}

	// Utilities
	envIDGenerator := helpers.NewEnvIDGenerator(rand.Reader)
	logger := application.NewLogger(os.Stdout)
	stderrLogger := application.NewLogger(os.Stderr)

	// Usage Command
	usage := commands.NewUsage(logger)

	storage.GetStateLogger = stderrLogger

	stateStore := storage.NewStore(appConfig.Global.StateDir)
	stateValidator := application.NewStateValidator(appConfig.Global.StateDir)

	// Terraform
	terraformOutputBuffer := bytes.NewBuffer([]byte{})
	terraformCmd := terraform.NewCmd(os.Stderr, terraformOutputBuffer)
	terraformExecutor := terraform.NewExecutor(terraformCmd, appConfig.Global.Debug)

	var (
		stackMigrator             stack.Migrator
		availabilityZoneRetriever ec2.AvailabilityZoneRetriever
		certificateDeleter        iam.CertificateDeleter
		certificateValidator      certs.Validator
		infrastructureManager     cloudformation.InfrastructureManager
		stackManager              cloudformation.StackManager
		networkClient             helpers.NetworkClient
		networkDeletionValidator  commands.NetworkDeletionValidator

		// this should be replaced by an IAAS agnostic variable, but that needs a common interface. We don't have time right now. AWS clients should also be combined into one struct.
		gcpClient gcp.Client
	)
	if appConfig.State.IAAS == "aws" && needsIAASConfig {
		awsClientProvider := &clientmanager.ClientProvider{}
		awsConfiguration := aws.Config{
			AccessKeyID:     appConfig.State.AWS.AccessKeyID,
			SecretAccessKey: appConfig.State.AWS.SecretAccessKey,
			Region:          appConfig.State.AWS.Region,
		}
		awsClientProvider.SetConfig(awsConfiguration, logger)
		awsClient := awsClientProvider.Client()
		iamClient := awsClientProvider.GetIAMClient()
		cloudFormationClient := awsClientProvider.GetCloudFormationClient()

		templateBuilder := templates.NewTemplateBuilder(logger)
		certificateDescriber := iam.NewCertificateDescriber(iamClient)
		userPolicyDeleter := iam.NewUserPolicyDeleter(iamClient)
		awsKeyPairDeleter := awsClient

		availabilityZoneRetriever = awsClient
		certificateDeleter = iam.NewCertificateDeleter(iamClient)
		certificateValidator = certs.NewValidator()
		networkDeletionValidator = awsClient
		stackManager = cloudformation.NewStackManager(cloudFormationClient, logger)
		infrastructureManager = cloudformation.NewInfrastructureManager(templateBuilder, stackManager)

		stackMigrator = stack.NewMigrator(terraformExecutor, infrastructureManager, certificateDescriber, userPolicyDeleter, availabilityZoneRetriever, awsKeyPairDeleter)
		networkClient = awsClient
	}

	if appConfig.State.IAAS == "gcp" && needsIAASConfig {
		gcpClientProvider := gcp.NewClientProvider(gcpBasePath)
		err = gcpClientProvider.SetConfig(appConfig.State.GCP.ServiceAccountKey, appConfig.State.GCP.ProjectID, appConfig.State.GCP.Region, appConfig.State.GCP.Zone)
		if err != nil {
			log.Fatalf("\n\n%s\n", err)
		}
		gcpClient = gcpClientProvider.Client()
		networkClient = gcpClient
		networkDeletionValidator = gcpClient
	}

	var envIDManager helpers.EnvIDManager
	if appConfig.State.IAAS != "" {
		envIDManager = helpers.NewEnvIDManager(envIDGenerator, infrastructureManager, networkClient)
	}

	var (
		inputGenerator    terraform.InputGenerator
		outputGenerator   terraform.OutputGenerator
		templateGenerator terraform.TemplateGenerator
	)

	if appConfig.State.IAAS == "aws" {
		templateGenerator = awsterraform.NewTemplateGenerator()
		inputGenerator = awsterraform.NewInputGenerator(availabilityZoneRetriever)
		outputGenerator = awsterraform.NewOutputGenerator(terraformExecutor)
	} else if appConfig.State.IAAS == "azure" {
		templateGenerator = azureterraform.NewTemplateGenerator()
		inputGenerator = azureterraform.NewInputGenerator()
		outputGenerator = azureterraform.NewOutputGenerator(terraformExecutor)
	} else if appConfig.State.IAAS == "gcp" {
		outputGenerator = gcpterraform.NewOutputGenerator(terraformExecutor)
		templateGenerator = gcpterraform.NewTemplateGenerator()
		inputGenerator = gcpterraform.NewInputGenerator()
	}

	terraformManager := terraform.NewManager(terraform.NewManagerArgs{
		Executor:              terraformExecutor,
		TemplateGenerator:     templateGenerator,
		InputGenerator:        inputGenerator,
		OutputGenerator:       outputGenerator,
		TerraformOutputBuffer: terraformOutputBuffer,
		Logger:                logger,
		StackMigrator:         stackMigrator,
	})

	// BOSH
	hostKeyGetter := proxy.NewHostKeyGetter()
	socks5Proxy := proxy.NewSocks5Proxy(logger, hostKeyGetter, 0)
	boshCommand := bosh.NewCmd(os.Stderr)
	boshExecutor := bosh.NewExecutor(boshCommand, ioutil.TempDir, ioutil.ReadFile, json.Unmarshal,
		json.Marshal, ioutil.WriteFile)
	boshManager := bosh.NewManager(boshExecutor, logger, socks5Proxy)
	boshClientProvider := bosh.NewClientProvider(socks5Proxy)

	// Environment Validators
	var environmentValidator commands.EnvironmentValidator
	if appConfig.State.IAAS == "aws" {
		environmentValidator = awsapplication.NewEnvironmentValidator(infrastructureManager, boshClientProvider)
	}
	if appConfig.State.IAAS == "gcp" {
		environmentValidator = gcpapplication.NewEnvironmentValidator(boshClientProvider)
	}

	// Cloud Config
	sshKeyGetter := bosh.NewSSHKeyGetter()
	var cloudConfigOpsGenerator cloudconfig.OpsGenerator
	if appConfig.State.IAAS == "aws" {
		awsCloudFormationOpsGenerator := awscloudconfig.NewCloudFormationOpsGenerator(availabilityZoneRetriever, infrastructureManager)
		awsTerraformOpsGenerator := awscloudconfig.NewTerraformOpsGenerator(terraformManager)
		cloudConfigOpsGenerator = awscloudconfig.NewOpsGenerator(awsCloudFormationOpsGenerator, awsTerraformOpsGenerator)
	}
	if appConfig.State.IAAS == "gcp" {
		cloudConfigOpsGenerator = gcpcloudconfig.NewOpsGenerator(terraformManager)
	}
	if appConfig.State.IAAS == "azure" {
		cloudConfigOpsGenerator = azurecloudconfig.NewOpsGenerator(terraformManager)
	}
	cloudConfigManager := cloudconfig.NewManager(logger, boshCommand, cloudConfigOpsGenerator, boshClientProvider, socks5Proxy, terraformManager, sshKeyGetter)

	// Subcommands
	var (
		upCmd        commands.UpCmd
		createLBsCmd commands.CreateLBsCmd
		lbsCmd       commands.LBsCmd
		deleteLBsCmd commands.DeleteLBsCmd
	)
	if appConfig.State.IAAS == "aws" {
		upCmd = commands.NewAWSUp(boshManager, cloudConfigManager, stateStore, envIDManager, terraformManager)
		createLBsCmd = commands.NewAWSCreateLBs(cloudConfigManager, stateStore, terraformManager, environmentValidator)
		lbsCmd = commands.NewAWSLBs(terraformManager, logger)
		deleteLBsCmd = commands.NewAWSDeleteLBs(cloudConfigManager, stateStore, environmentValidator, terraformManager)
	} else if appConfig.State.IAAS == "gcp" {
		upCmd = commands.NewGCPUp(stateStore, terraformManager, boshManager, cloudConfigManager, envIDManager, gcpClient)
		createLBsCmd = commands.NewGCPCreateLBs(terraformManager, cloudConfigManager, stateStore, environmentValidator, gcpClient)
		lbsCmd = commands.NewGCPLBs(terraformManager, logger)
		deleteLBsCmd = commands.NewGCPDeleteLBs(stateStore, environmentValidator, terraformManager, cloudConfigManager)
	} else if appConfig.State.IAAS == "azure" {
		azureClient := azure.NewClient()
		upCmd = commands.NewAzureUp(azureClient, boshManager, cloudConfigManager, envIDManager, logger, stateStore, terraformManager)
		deleteLBsCmd = commands.NewAzureDeleteLBs(cloudConfigManager, stateStore, terraformManager)
	}

	up := commands.NewUp(upCmd, boshManager)

	// Commands
	commandSet := application.CommandSet{}
	commandSet["help"] = usage
	commandSet["version"] = commands.NewVersion(Version, logger)
	commandSet["up"] = up
	sshKeyDeleter := bosh.NewSSHKeyDeleter()
	commandSet["rotate"] = commands.NewRotate(stateValidator, sshKeyDeleter, up)
	commandSet["destroy"] = commands.NewDestroy(logger, os.Stdin, boshManager, stackManager, infrastructureManager, certificateDeleter, stateStore, stateValidator, terraformManager, networkDeletionValidator)
	commandSet["down"] = commandSet["destroy"]
	commandSet["create-lbs"] = commands.NewCreateLBs(createLBsCmd, logger, stateValidator, certificateValidator, boshManager)
	commandSet["update-lbs"] = commandSet["create-lbs"]
	commandSet["delete-lbs"] = commands.NewDeleteLBs(deleteLBsCmd, logger, stateValidator, boshManager)
	commandSet["lbs"] = commands.NewLBs(lbsCmd, stateValidator)
	commandSet["jumpbox-address"] = commands.NewStateQuery(logger, stateValidator, terraformManager, infrastructureManager, commands.JumpboxAddressPropertyName)
	commandSet["director-address"] = commands.NewStateQuery(logger, stateValidator, terraformManager, infrastructureManager, commands.DirectorAddressPropertyName)
	commandSet["director-username"] = commands.NewStateQuery(logger, stateValidator, terraformManager, infrastructureManager, commands.DirectorUsernamePropertyName)
	commandSet["director-password"] = commands.NewStateQuery(logger, stateValidator, terraformManager, infrastructureManager, commands.DirectorPasswordPropertyName)
	commandSet["director-ca-cert"] = commands.NewStateQuery(logger, stateValidator, terraformManager, infrastructureManager, commands.DirectorCACertPropertyName)
	commandSet["ssh-key"] = commands.NewSSHKey(logger, stateValidator, sshKeyGetter)
	commandSet["env-id"] = commands.NewStateQuery(logger, stateValidator, terraformManager, infrastructureManager, commands.EnvIDPropertyName)
	commandSet["latest-error"] = commands.NewLatestError(logger, stateValidator)
	commandSet["print-env"] = commands.NewPrintEnv(logger, stateValidator, terraformManager)
	commandSet["cloud-config"] = commands.NewCloudConfig(logger, stateValidator, cloudConfigManager)
	commandSet["bosh-deployment-vars"] = commands.NewBOSHDeploymentVars(logger, boshManager, stateValidator, terraformManager)

	app := application.New(commandSet, appConfig, usage)

	err = app.Run()
	if err != nil {
		log.Fatalf("\n\n%s\n", err)
	}
}
<commit_msg>Create environment validator only where needed.<commit_after>package main

import (
	"bytes"
	"crypto/rand"
	"encoding/json"
	"io/ioutil"
	"log"
	"os"

	"github.com/cloudfoundry/bosh-bootloader/application"
	"github.com/cloudfoundry/bosh-bootloader/aws"
	"github.com/cloudfoundry/bosh-bootloader/aws/clientmanager"
	"github.com/cloudfoundry/bosh-bootloader/aws/cloudformation"
	"github.com/cloudfoundry/bosh-bootloader/aws/cloudformation/templates"
	"github.com/cloudfoundry/bosh-bootloader/aws/ec2"
	"github.com/cloudfoundry/bosh-bootloader/aws/iam"
	"github.com/cloudfoundry/bosh-bootloader/azure"
	"github.com/cloudfoundry/bosh-bootloader/bosh"
	"github.com/cloudfoundry/bosh-bootloader/certs"
	"github.com/cloudfoundry/bosh-bootloader/cloudconfig"
	"github.com/cloudfoundry/bosh-bootloader/commands"
	"github.com/cloudfoundry/bosh-bootloader/config"
	"github.com/cloudfoundry/bosh-bootloader/gcp"
	"github.com/cloudfoundry/bosh-bootloader/helpers"
	"github.com/cloudfoundry/bosh-bootloader/proxy"
	"github.com/cloudfoundry/bosh-bootloader/stack"
	"github.com/cloudfoundry/bosh-bootloader/storage"
	"github.com/cloudfoundry/bosh-bootloader/terraform"

	awsapplication "github.com/cloudfoundry/bosh-bootloader/application/aws"
	gcpapplication "github.com/cloudfoundry/bosh-bootloader/application/gcp"
	awscloudconfig "github.com/cloudfoundry/bosh-bootloader/cloudconfig/aws"
	azurecloudconfig "github.com/cloudfoundry/bosh-bootloader/cloudconfig/azure"
	gcpcloudconfig "github.com/cloudfoundry/bosh-bootloader/cloudconfig/gcp"
	awsterraform "github.com/cloudfoundry/bosh-bootloader/terraform/aws"
	azureterraform "github.com/cloudfoundry/bosh-bootloader/terraform/azure"
	gcpterraform "github.com/cloudfoundry/bosh-bootloader/terraform/gcp"
)

var (
	Version     string
	gcpBasePath string
)

func main() {
	newConfig := config.NewConfig(storage.GetState)
	appConfig, err := newConfig.Bootstrap(os.Args)
	log.SetFlags(0)
	if err != nil {
		log.Fatalf("\n\n%s\n", err)
	}

	needsIAASConfig := config.NeedsIAASConfig(appConfig.Command) && !appConfig.ShowCommandHelp
	if needsIAASConfig {
		err = config.ValidateIAAS(appConfig.State, appConfig.Command)
		if err != nil {
			log.Fatalf("\n\n%s\n", err)
		}
	}

	// Utilities
	envIDGenerator := helpers.NewEnvIDGenerator(rand.Reader)
	logger := application.NewLogger(os.Stdout)
	stderrLogger := application.NewLogger(os.Stderr)
	storage.GetStateLogger = stderrLogger
	stateStore := storage.NewStore(appConfig.Global.StateDir)
	stateValidator := application.NewStateValidator(appConfig.Global.StateDir)

	// Terraform
	terraformOutputBuffer := bytes.NewBuffer([]byte{})
	terraformCmd := terraform.NewCmd(os.Stderr, terraformOutputBuffer)
	terraformExecutor := terraform.NewExecutor(terraformCmd, appConfig.Global.Debug)

	var (
		stackMigrator             stack.Migrator
		availabilityZoneRetriever ec2.AvailabilityZoneRetriever
		certificateDeleter        iam.CertificateDeleter
		certificateValidator      certs.Validator
		infrastructureManager     cloudformation.InfrastructureManager
		stackManager              cloudformation.StackManager
		networkClient             helpers.NetworkClient
		networkDeletionValidator  commands.NetworkDeletionValidator

		// this should be replaced by an IAAS agnostic variable, but that needs a common interface. We don't have time right now. AWS clients should also be combined into one struct.
		gcpClient gcp.Client
	)
	if appConfig.State.IAAS == "aws" && needsIAASConfig {
		awsClientProvider := &clientmanager.ClientProvider{}
		awsConfiguration := aws.Config{
			AccessKeyID:     appConfig.State.AWS.AccessKeyID,
			SecretAccessKey: appConfig.State.AWS.SecretAccessKey,
			Region:          appConfig.State.AWS.Region,
		}
		awsClientProvider.SetConfig(awsConfiguration, logger)
		awsClient := awsClientProvider.Client()
		iamClient := awsClientProvider.GetIAMClient()
		cloudFormationClient := awsClientProvider.GetCloudFormationClient()

		templateBuilder := templates.NewTemplateBuilder(logger)
		certificateDescriber := iam.NewCertificateDescriber(iamClient)
		userPolicyDeleter := iam.NewUserPolicyDeleter(iamClient)
		awsKeyPairDeleter := awsClient

		availabilityZoneRetriever = awsClient
		certificateDeleter = iam.NewCertificateDeleter(iamClient)
		certificateValidator = certs.NewValidator()
		networkDeletionValidator = awsClient
		stackManager = cloudformation.NewStackManager(cloudFormationClient, logger)
		infrastructureManager = cloudformation.NewInfrastructureManager(templateBuilder, stackManager)

		stackMigrator = stack.NewMigrator(terraformExecutor, infrastructureManager, certificateDescriber, userPolicyDeleter, availabilityZoneRetriever, awsKeyPairDeleter)
		networkClient = awsClient
	}

	if appConfig.State.IAAS == "gcp" && needsIAASConfig {
		gcpClientProvider := gcp.NewClientProvider(gcpBasePath)
		err = gcpClientProvider.SetConfig(appConfig.State.GCP.ServiceAccountKey, appConfig.State.GCP.ProjectID, appConfig.State.GCP.Region, appConfig.State.GCP.Zone)
		if err != nil {
			log.Fatalf("\n\n%s\n", err)
		}
		gcpClient = gcpClientProvider.Client()
		networkClient = gcpClient
		networkDeletionValidator = gcpClient
	}

	var envIDManager helpers.EnvIDManager
	if appConfig.State.IAAS != "" {
		envIDManager = helpers.NewEnvIDManager(envIDGenerator, infrastructureManager, networkClient)
	}

	var (
		inputGenerator    terraform.InputGenerator
		outputGenerator   terraform.OutputGenerator
		templateGenerator terraform.TemplateGenerator
	)

	if appConfig.State.IAAS == "aws" {
		templateGenerator = awsterraform.NewTemplateGenerator()
		inputGenerator = awsterraform.NewInputGenerator(availabilityZoneRetriever)
		outputGenerator = awsterraform.NewOutputGenerator(terraformExecutor)
	} else if appConfig.State.IAAS == "azure" {
		templateGenerator = azureterraform.NewTemplateGenerator()
		inputGenerator = azureterraform.NewInputGenerator()
		outputGenerator = azureterraform.NewOutputGenerator(terraformExecutor)
	} else if appConfig.State.IAAS == "gcp" {
		outputGenerator = gcpterraform.NewOutputGenerator(terraformExecutor)
		templateGenerator = gcpterraform.NewTemplateGenerator()
		inputGenerator = gcpterraform.NewInputGenerator()
	}

	terraformManager := terraform.NewManager(terraform.NewManagerArgs{
		Executor:              terraformExecutor,
		TemplateGenerator:     templateGenerator,
		InputGenerator:        inputGenerator,
		OutputGenerator:       outputGenerator,
		TerraformOutputBuffer: terraformOutputBuffer,
		Logger:                logger,
		StackMigrator:         stackMigrator,
	})

	// BOSH
	hostKeyGetter := proxy.NewHostKeyGetter()
	socks5Proxy := proxy.NewSocks5Proxy(logger, hostKeyGetter, 0)
	boshCommand := bosh.NewCmd(os.Stderr)
	boshExecutor := bosh.NewExecutor(boshCommand, ioutil.TempDir, ioutil.ReadFile, json.Unmarshal,
		json.Marshal, ioutil.WriteFile)
	boshManager := bosh.NewManager(boshExecutor, logger, socks5Proxy)
	boshClientProvider := bosh.NewClientProvider(socks5Proxy)
	sshKeyGetter := bosh.NewSSHKeyGetter()

	// Cloud Config
	var cloudConfigOpsGenerator cloudconfig.OpsGenerator
	if appConfig.State.IAAS == "aws" {
		awsCloudFormationOpsGenerator := awscloudconfig.NewCloudFormationOpsGenerator(availabilityZoneRetriever, infrastructureManager)
		awsTerraformOpsGenerator := awscloudconfig.NewTerraformOpsGenerator(terraformManager)
		cloudConfigOpsGenerator = awscloudconfig.NewOpsGenerator(awsCloudFormationOpsGenerator, awsTerraformOpsGenerator)
	}
	if appConfig.State.IAAS == "gcp" {
		cloudConfigOpsGenerator = gcpcloudconfig.NewOpsGenerator(terraformManager)
	}
	if appConfig.State.IAAS == "azure" {
		cloudConfigOpsGenerator = azurecloudconfig.NewOpsGenerator(terraformManager)
	}
	cloudConfigManager := cloudconfig.NewManager(logger, boshCommand, cloudConfigOpsGenerator, boshClientProvider, socks5Proxy, terraformManager, sshKeyGetter)

	// Subcommands
	var (
		upCmd        commands.UpCmd
		createLBsCmd commands.CreateLBsCmd
		lbsCmd       commands.LBsCmd
		deleteLBsCmd commands.DeleteLBsCmd
	)
	if appConfig.State.IAAS == "aws" {
		environmentValidator := awsapplication.NewEnvironmentValidator(infrastructureManager, boshClientProvider)

		upCmd = commands.NewAWSUp(boshManager, cloudConfigManager, stateStore, envIDManager, terraformManager)
		createLBsCmd = commands.NewAWSCreateLBs(cloudConfigManager, stateStore, terraformManager, environmentValidator)
		lbsCmd = commands.NewAWSLBs(terraformManager, logger)
		deleteLBsCmd = commands.NewAWSDeleteLBs(cloudConfigManager, stateStore, environmentValidator, terraformManager)
	} else if appConfig.State.IAAS == "gcp" {
		environmentValidator := gcpapplication.NewEnvironmentValidator(boshClientProvider)

		upCmd = commands.NewGCPUp(stateStore, terraformManager, boshManager, cloudConfigManager, envIDManager, gcpClient)
		createLBsCmd = commands.NewGCPCreateLBs(terraformManager, cloudConfigManager, stateStore, environmentValidator, gcpClient)
		lbsCmd = commands.NewGCPLBs(terraformManager, logger)
		deleteLBsCmd = commands.NewGCPDeleteLBs(stateStore, environmentValidator, terraformManager, cloudConfigManager)
	} else if appConfig.State.IAAS == "azure" {
		azureClient := azure.NewClient()
		upCmd = commands.NewAzureUp(azureClient, boshManager, cloudConfigManager, envIDManager, logger, stateStore, terraformManager)
		deleteLBsCmd = commands.NewAzureDeleteLBs(cloudConfigManager, stateStore, terraformManager)
	}

	up := commands.NewUp(upCmd, boshManager)

	// Usage Command
	usage := commands.NewUsage(logger)

	// Commands
	commandSet := application.CommandSet{}
	commandSet["help"] = usage
	commandSet["version"] = commands.NewVersion(Version, logger)
	commandSet["up"] = up
	sshKeyDeleter := bosh.NewSSHKeyDeleter()
	commandSet["rotate"] = commands.NewRotate(stateValidator, sshKeyDeleter, up)
	commandSet["destroy"] = commands.NewDestroy(logger, os.Stdin, boshManager, stackManager, infrastructureManager, certificateDeleter, stateStore, stateValidator, terraformManager, networkDeletionValidator)
	commandSet["down"] = commandSet["destroy"]
	commandSet["create-lbs"] = commands.NewCreateLBs(createLBsCmd, logger, stateValidator, certificateValidator, boshManager)
	commandSet["update-lbs"] = commandSet["create-lbs"]
	commandSet["delete-lbs"] = commands.NewDeleteLBs(deleteLBsCmd, logger, stateValidator, boshManager)
	commandSet["lbs"] = commands.NewLBs(lbsCmd, stateValidator)
	commandSet["jumpbox-address"] = commands.NewStateQuery(logger, stateValidator, terraformManager, infrastructureManager, commands.JumpboxAddressPropertyName)
	commandSet["director-address"] = commands.NewStateQuery(logger, stateValidator, terraformManager, infrastructureManager, commands.DirectorAddressPropertyName)
	commandSet["director-username"] = commands.NewStateQuery(logger, stateValidator, terraformManager, infrastructureManager, commands.DirectorUsernamePropertyName)
	commandSet["director-password"] = commands.NewStateQuery(logger, stateValidator, terraformManager, infrastructureManager, commands.DirectorPasswordPropertyName)
	commandSet["director-ca-cert"] = commands.NewStateQuery(logger, stateValidator, terraformManager, infrastructureManager, commands.DirectorCACertPropertyName)
	commandSet["ssh-key"] = commands.NewSSHKey(logger, stateValidator, sshKeyGetter)
	commandSet["env-id"] = commands.NewStateQuery(logger, stateValidator, terraformManager, infrastructureManager, commands.EnvIDPropertyName)
	commandSet["latest-error"] = commands.NewLatestError(logger, stateValidator)
	commandSet["print-env"] = commands.NewPrintEnv(logger, stateValidator, terraformManager)
	commandSet["cloud-config"] = commands.NewCloudConfig(logger, stateValidator, cloudConfigManager)
	commandSet["bosh-deployment-vars"] = commands.NewBOSHDeploymentVars(logger, boshManager, stateValidator, terraformManager)

	app := application.New(commandSet, appConfig, usage)

	err = app.Run()
	if err != nil {
		log.Fatalf("\n\n%s\n", err)
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2010, Suryandaru Triandana. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This package implements the Rabbit encryption algorithm as defined in eSTREAM portfolio.
package rabbit

// This Go implementation is derived in part from the reference
// ANSI C implementation, which carries the following notice:
//
//	File name: rabbit.c
//
//	Source file for reference C version of the Rabbit stream cipher.
//
//	For further documentation, see "Rabbit Stream Cipher, Algorithm
//	Specification" which can be found at http://www.cryptico.com/.
//
//	This source code is for little-endian processors (e.g. x86).
//
//	Copyright (C) Cryptico ApS. All rights reserved.
//
//	YOU SHOULD CAREFULLY READ THIS LEGAL NOTICE BEFORE USING THIS SOFTWARE.
//
//	This software is developed by Cryptico ApS and/or its suppliers. It is
//	free for commercial and non-commercial use.
//
//	Cryptico ApS shall not in any way be liable for any use or export/import
//	of this software. The software is provided "as is" without any express or
//	implied warranty.
//
//	Cryptico, CryptiCore, the Cryptico logo and "Re-thinking encryption" are
//	either trademarks or registered trademarks of Cryptico ApS.

import (
	"os"
	"strconv"
)

// A Cipher is an instance of Rabbit encryption using a particular key.
type Cipher struct {
	x, c, cx, cc [8]uint32
	carry, ccarry bool
}

type KeySizeError struct {
	t, sz int
}

func (k *KeySizeError) String() string {
	switch(k.t) {
	case 1:
		return "crypto/rabbit: invalid key size " + strconv.Itoa(int(k.sz))
	case 2:
		return "crypto/rabbit: invalid iv size " + strconv.Itoa(int(k.sz))
	}
	return "crypto/rabbit: unknown key error type"
}

func rotl(v, n uint32) uint32 {
	return v<<n | v>>(32-n)
}

func rabbitCalcG(x uint32) uint32 {
	var a, b uint32
	a = x&0xFFFF;
	b = x>>16;
	return ((((a*a)>>17 + a*b)>>15) + b*b)^(x*x)
}

func booltoi(b bool) uint32 {
	if b {
		return 1
	}
	return 0
}

func (c *Cipher) rabbitNext() {
	var c0, c1, c2, c3, c4, c5, c6, c7 uint32

	c0, c1, c2, c3 = c.c[0], c.c[1], c.c[2], c.c[3]
	c4, c5, c6, c7 = c.c[4], c.c[5], c.c[6], c.c[7]

	c0 = c0 + 0x4D34D34D + booltoi(c.carry)
	c1 = c1 + 0xD34D34D3 + booltoi(c0 < c.c[0])
	c2 = c2 + 0x34D34D34 + booltoi(c1 < c.c[1])
	c3 = c3 + 0x4D34D34D + booltoi(c2 < c.c[2])
	c4 = c4 + 0xD34D34D3 + booltoi(c3 < c.c[3])
	c5 = c5 + 0x34D34D34 + booltoi(c4 < c.c[4])
	c6 = c6 + 0x4D34D34D + booltoi(c5 < c.c[5])
	c7 = c7 + 0xD34D34D3 + booltoi(c6 < c.c[6])
	c.carry = (c7 < c.c[7])

	g0 := rabbitCalcG(c.x[0] + c0)
	g1 := rabbitCalcG(c.x[1] + c1)
	g2 := rabbitCalcG(c.x[2] + c2)
	g3 := rabbitCalcG(c.x[3] + c3)
	g4 := rabbitCalcG(c.x[4] + c4)
	g5 := rabbitCalcG(c.x[5] + c5)
	g6 := rabbitCalcG(c.x[6] + c6)
	g7 := rabbitCalcG(c.x[7] + c7)

	c.x[0] = g0 + rotl(g7,16) + rotl(g6, 16)
	c.x[1] = g1 + rotl(g0, 8) + g7
	c.x[2] = g2 + rotl(g1,16) + rotl(g0, 16)
	c.x[3] = g3 + rotl(g2, 8) + g1
	c.x[4] = g4 + rotl(g3,16) + rotl(g2, 16)
	c.x[5] = g5 + rotl(g4, 8) + g3
	c.x[6] = g6 + rotl(g5,16) + rotl(g4, 16)
	c.x[7] = g7 + rotl(g6, 8) + g5

	c.c[0], c.c[1], c.c[2], c.c[3] = c0, c1, c2, c3
	c.c[4], c.c[5], c.c[6], c.c[7] = c4, c5, c6, c7
}

func (c *Cipher) rabbitGen(buf *[16]byte) {
	c.rabbitNext()
	var d0, d1, d2, d3 uint32
	d0 = c.x[0] ^ (c.x[5]>>16 ^ c.x[3]<<16)
	d1 = c.x[2] ^ (c.x[7]>>16 ^ c.x[5]<<16)
	d2 = c.x[4] ^ (c.x[1]>>16 ^ c.x[7]<<16)
	d3 = c.x[6] ^ (c.x[3]>>16 ^ c.x[1]<<16)
	buf[ 0], buf[ 1], buf[ 2], buf[ 3] = byte(d0), byte(d0>>8), byte(d0>>16), byte(d0>>24)
	buf[ 4], buf[ 5], buf[ 6], buf[ 7] = byte(d1), byte(d1>>8), byte(d1>>16), byte(d1>>24)
	buf[ 8], buf[ 9], buf[10], buf[11] = byte(d2), byte(d2>>8), byte(d2>>16), byte(d2>>24)
	buf[12], buf[13], buf[14], buf[15] = byte(d3), byte(d3>>8), byte(d3>>16), byte(d3>>24)
}

// NewCipher creates and returns a Cipher.
// Rabbit key, must be 16 bytes.
func NewCipher(key []byte) (*Cipher, os.Error) {
	k := len(key)
	if k != 16 {
		return nil, &KeySizeError{1, k}
	}
	var c Cipher

	var k0, k1, k2, k3 uint32
	k0 = uint32(key[ 0]) | uint32(key[ 1])<<8 | uint32(key[ 2])<<16 | uint32(key[ 3])<<24
	k1 = uint32(key[ 4]) | uint32(key[ 5])<<8 | uint32(key[ 6])<<16 | uint32(key[ 7])<<24
	k2 = uint32(key[ 8]) | uint32(key[ 9])<<8 | uint32(key[10])<<16 | uint32(key[11])<<24
	k3 = uint32(key[12]) | uint32(key[13])<<8 | uint32(key[14])<<16 | uint32(key[15])<<24

	c.x[0] = k0
	c.x[2] = k1
	c.x[4] = k2
	c.x[6] = k3
	c.x[1] = k3<<16 | k2>>16
	c.x[3] = k0<<16 | k3>>16
	c.x[5] = k1<<16 | k0>>16
	c.x[7] = k2<<16 | k1>>16

	c.c[0] = rotl(k2, 16)
	c.c[2] = rotl(k3, 16)
	c.c[4] = rotl(k0, 16)
	c.c[6] = rotl(k1, 16)
	c.c[1] = (k0&0xFFFF0000) | (k1&0xFFFF)
	c.c[3] = (k1&0xFFFF0000) | (k2&0xFFFF)
	c.c[5] = (k2&0xFFFF0000) | (k3&0xFFFF)
	c.c[7] = (k3&0xFFFF0000) | (k0&0xFFFF)

	c.carry = false

	for i := 0; i < 4; i++ {
		c.rabbitNext()
	}

	for i := range c.c {
		c.c[i] ^= c.x[(i+4)&0x7]
	}

	for i := range c.c {
		c.cx[i] = c.x[i]
		c.cc[i] = c.c[i]
	}
	c.ccarry = c.carry

	return &c, nil
}

// SetupIV will setup Initialization vector.
// Rabbit iv, must be 8 bytes.
func (c *Cipher) SetupIV(iv []byte) os.Error {
	k := len(iv)
	if k != 8 {
		return &KeySizeError{2, k}
	}

	var d0, d1, d2, d3 uint32
	d0 = uint32(iv[0]) | uint32(iv[1])<<8 | uint32(iv[2])<<16 | uint32(iv[3])<<24
	d2 = uint32(iv[4]) | uint32(iv[5])<<8 | uint32(iv[6])<<16 | uint32(iv[7])<<24
	d1 = d0>>16 | (d2&0xFFFF0000)
	d3 = d2<<16 | (d0&0x0000FFFF)

	c.c[0] = c.cc[0] ^ d0
	c.c[1] = c.cc[1] ^ d1
	c.c[2] = c.cc[2] ^ d2
	c.c[3] = c.cc[3] ^ d3
	c.c[4] = c.cc[4] ^ d0
	c.c[5] = c.cc[5] ^ d1
	c.c[6] = c.cc[6] ^ d2
	c.c[7] = c.cc[7] ^ d3

	for i := range c.x {
		c.x[i] = c.cx[i]
	}
	c.carry = c.ccarry

	for i := 0; i < 4; i++ {
		c.rabbitNext()
	}

	return nil
}

// ProcessStream will encrypt or decrypt given buffer.
func (c *Cipher) ProcessStream(buf []byte) {
	var b [16]byte
	l := len(buf)
	for i := 0; ; {
		c.rabbitGen(&b)
		for j := 0; j < 16; j++ {
			buf[i] ^= b[j]
			i += 1
			if i >= l {
				return
			}
		}
	}
}

// Reset zeros the key data so that it will no longer appear in the
// process's memory.
func (c *Cipher) Reset() {
	for i := range c.x {
		c.x[i], c.c[i], c.cx[i], c.cc[i] = 0, 0, 0, 0
	}
	c.carry, c.carry = false, false
}

<commit_msg>crpto/rabbit: add ResetCipher method<commit_after>// Copyright (c) 2010, Suryandaru Triandana. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This package implements the Rabbit encryption algorithm as defined in eSTREAM portfolio.
package rabbit

// This Go implementation is derived in part from the reference
// ANSI C implementation, which carries the following notice:
//
//	File name: rabbit.c
//
//	Source file for reference C version of the Rabbit stream cipher.
//
//	For further documentation, see "Rabbit Stream Cipher, Algorithm
//	Specification" which can be found at http://www.cryptico.com/.
//
//	This source code is for little-endian processors (e.g. x86).
//
//	Copyright (C) Cryptico ApS. All rights reserved.
//
//	YOU SHOULD CAREFULLY READ THIS LEGAL NOTICE BEFORE USING THIS SOFTWARE.
//
//	This software is developed by Cryptico ApS and/or its suppliers. It is
//	free for commercial and non-commercial use.
//
//	Cryptico ApS shall not in any way be liable for any use or export/import
//	of this software. The software is provided "as is" without any express or
//	implied warranty.
//
//	Cryptico, CryptiCore, the Cryptico logo and "Re-thinking encryption" are
//	either trademarks or registered trademarks of Cryptico ApS.

import (
	"os"
	"strconv"
)

// A Cipher is an instance of Rabbit encryption using a particular key.
type Cipher struct {
	x, c, cx, cc [8]uint32
	carry, ccarry bool
}

type KeySizeError struct {
	t, sz int
}

func (k *KeySizeError) String() string {
	switch(k.t) {
	case 1:
		return "crypto/rabbit: invalid key size " + strconv.Itoa(int(k.sz))
	case 2:
		return "crypto/rabbit: invalid iv size " + strconv.Itoa(int(k.sz))
	}
	return "crypto/rabbit: unknown key error type"
}

func rotl(v, n uint32) uint32 {
	return v<<n | v>>(32-n)
}

func rabbitCalcG(x uint32) uint32 {
	var a, b uint32
	a = x&0xFFFF;
	b = x>>16;
	return ((((a*a)>>17 + a*b)>>15) + b*b)^(x*x)
}

func booltoi(b bool) uint32 {
	if b {
		return 1
	}
	return 0
}

func (c *Cipher) rabbitNext() {
	var c0, c1, c2, c3, c4, c5, c6, c7 uint32

	c0, c1, c2, c3 = c.c[0], c.c[1], c.c[2], c.c[3]
	c4, c5, c6, c7 = c.c[4], c.c[5], c.c[6], c.c[7]

	c0 = c0 + 0x4D34D34D + booltoi(c.carry)
	c1 = c1 + 0xD34D34D3 + booltoi(c0 < c.c[0])
	c2 = c2 + 0x34D34D34 + booltoi(c1 < c.c[1])
	c3 = c3 + 0x4D34D34D + booltoi(c2 < c.c[2])
	c4 = c4 + 0xD34D34D3 + booltoi(c3 < c.c[3])
	c5 = c5 + 0x34D34D34 + booltoi(c4 < c.c[4])
	c6 = c6 + 0x4D34D34D + booltoi(c5 < c.c[5])
	c7 = c7 + 0xD34D34D3 + booltoi(c6 < c.c[6])
	c.carry = (c7 < c.c[7])

	g0 := rabbitCalcG(c.x[0] + c0)
	g1 := rabbitCalcG(c.x[1] + c1)
	g2 := rabbitCalcG(c.x[2] + c2)
	g3 := rabbitCalcG(c.x[3] + c3)
	g4 := rabbitCalcG(c.x[4] + c4)
	g5 := rabbitCalcG(c.x[5] + c5)
	g6 := rabbitCalcG(c.x[6] + c6)
	g7 := rabbitCalcG(c.x[7] + c7)

	c.x[0] = g0 + rotl(g7,16) + rotl(g6, 16)
	c.x[1] = g1 + rotl(g0, 8) + g7
	c.x[2] = g2 + rotl(g1,16) + rotl(g0, 16)
	c.x[3] = g3 + rotl(g2, 8) + g1
	c.x[4] = g4 + rotl(g3,16) + rotl(g2, 16)
	c.x[5] = g5 + rotl(g4, 8) + g3
	c.x[6] = g6 + rotl(g5,16) + rotl(g4, 16)
	c.x[7] = g7 + rotl(g6, 8) + g5

	c.c[0], c.c[1], c.c[2], c.c[3] = c0, c1, c2, c3
	c.c[4], c.c[5], c.c[6], c.c[7] = c4, c5, c6, c7
}

func (c *Cipher) rabbitGen(buf *[16]byte) {
	c.rabbitNext()
	var d0, d1, d2, d3 uint32
	d0 = c.x[0] ^ (c.x[5]>>16 ^ c.x[3]<<16)
	d1 = c.x[2] ^ (c.x[7]>>16 ^ c.x[5]<<16)
	d2 = c.x[4] ^ (c.x[1]>>16 ^ c.x[7]<<16)
	d3 = c.x[6] ^ (c.x[3]>>16 ^ c.x[1]<<16)
	buf[ 0], buf[ 1], buf[ 2], buf[ 3] = byte(d0), byte(d0>>8), byte(d0>>16), byte(d0>>24)
	buf[ 4], buf[ 5], buf[ 6], buf[ 7] = byte(d1), byte(d1>>8), byte(d1>>16), byte(d1>>24)
	buf[ 8], buf[ 9], buf[10], buf[11] = byte(d2), byte(d2>>8), byte(d2>>16), byte(d2>>24)
	buf[12], buf[13], buf[14], buf[15] = byte(d3), byte(d3>>8), byte(d3>>16), byte(d3>>24)
}

// NewCipher creates and returns a Cipher.
// Rabbit key, must be 16 bytes.
func NewCipher(key []byte) (*Cipher, os.Error) {
	k := len(key)
	if k != 16 {
		return nil, &KeySizeError{1, k}
	}
	var c Cipher

	var k0, k1, k2, k3 uint32
	k0 = uint32(key[ 0]) | uint32(key[ 1])<<8 | uint32(key[ 2])<<16 | uint32(key[ 3])<<24
	k1 = uint32(key[ 4]) | uint32(key[ 5])<<8 | uint32(key[ 6])<<16 | uint32(key[ 7])<<24
	k2 = uint32(key[ 8]) | uint32(key[ 9])<<8 | uint32(key[10])<<16 | uint32(key[11])<<24
	k3 = uint32(key[12]) | uint32(key[13])<<8 | uint32(key[14])<<16 | uint32(key[15])<<24

	c.x[0] = k0
	c.x[2] = k1
	c.x[4] = k2
	c.x[6] = k3
	c.x[1] = k3<<16 | k2>>16
	c.x[3] = k0<<16 | k3>>16
	c.x[5] = k1<<16 | k0>>16
	c.x[7] = k2<<16 | k1>>16

	c.c[0] = rotl(k2, 16)
	c.c[2] = rotl(k3, 16)
	c.c[4] = rotl(k0, 16)
	c.c[6] = rotl(k1, 16)
	c.c[1] = (k0&0xFFFF0000) | (k1&0xFFFF)
	c.c[3] = (k1&0xFFFF0000) | (k2&0xFFFF)
	c.c[5] = (k2&0xFFFF0000) | (k3&0xFFFF)
	c.c[7] = (k3&0xFFFF0000) | (k0&0xFFFF)

	c.carry = false

	for i := 0; i < 4; i++ {
		c.rabbitNext()
	}

	for i := range c.c {
		c.c[i] ^= c.x[(i+4)&0x7]
	}

	for i := range c.c {
		c.cx[i] = c.x[i]
		c.cc[i] = c.c[i]
	}
	c.ccarry = c.carry

	return &c, nil
}

// SetupIV will setup Initialization vector.
// Rabbit iv, must be 8 bytes.
func (c *Cipher) SetupIV(iv []byte) os.Error {
	k := len(iv)
	if k != 8 {
		return &KeySizeError{2, k}
	}

	var d0, d1, d2, d3 uint32
	d0 = uint32(iv[0]) | uint32(iv[1])<<8 | uint32(iv[2])<<16 | uint32(iv[3])<<24
	d2 = uint32(iv[4]) | uint32(iv[5])<<8 | uint32(iv[6])<<16 | uint32(iv[7])<<24
	d1 = d0>>16 | (d2&0xFFFF0000)
	d3 = d2<<16 | (d0&0x0000FFFF)

	c.c[0] = c.cc[0] ^ d0
	c.c[1] = c.cc[1] ^ d1
	c.c[2] = c.cc[2] ^ d2
	c.c[3] = c.cc[3] ^ d3
	c.c[4] = c.cc[4] ^ d0
	c.c[5] = c.cc[5] ^ d1
	c.c[6] = c.cc[6] ^ d2
	c.c[7] = c.cc[7] ^ d3

	for i := range c.x {
		c.x[i] = c.cx[i]
	}
	c.carry = c.ccarry

	for i := 0; i < 4; i++ {
		c.rabbitNext()
	}

	return nil
}

// ProcessStream will encrypt or decrypt given buffer.
func (c *Cipher) ProcessStream(buf []byte) {
	var b [16]byte
	l := len(buf)
	for i := 0; ; {
		c.rabbitGen(&b)
		for j := 0; j < 16; j++ {
			buf[i] ^= b[j]
			i += 1
			if i >= l {
				return
			}
		}
	}
}

// ResetCipher reset cipher round to original state. Initialization vector will be erased.
func (c *Cipher) ResetCipher() {
	for i := range c.c {
		c.c[i] = c.cc[i]
	}
	for i := range c.x {
		c.x[i] = c.cx[i]
	}
	c.carry = c.ccarry
}

// Reset zeros the key data so that it will no longer appear in the
// process's memory.
func (c *Cipher) Reset() {
	for i := range c.x {
		c.x[i], c.c[i], c.cx[i], c.cc[i] = 0, 0, 0, 0
	}
	c.carry, c.carry = false, false
}

<|endoftext|>


<commit_before>package adminsock

import (
	"fmt"
	"math/rand"
	"net"
	"testing"
	"time"
)

// functions echo() and readConn() are defined in test 02.

func TestMultiServer(t *testing.T) {
	// implement an echo server
	d := make(Dispatch) // create Dispatch
	d["echo"] = echo    // and put a function in it
	// instantiate an adminsocket
	as, err := New(d, 0)
	if err != nil {
		t.Errorf("Couldn't create socket: %v", err)
	}
	// launch clients
	rand.Seed(time.Now().Unix())
	x := 5
	for i := 0; i < x; i++ {
		go multiclient(buildSockName(), t)
	}
	for i := 0; i < x; i++ {
		msg := <-as.Msgr
		if msg.Err != nil {
			t.Errorf("connection creation returned error: %v", msg.Err)
		}
	}
	// wait for disconnect Msg
	for i := 0; i < x; i++ {
		msg := <-as.Msgr
		if msg.Err == nil {
			t.Errorf("connection drop should be an err, but got nil")
		}
	}
	// shut down adminsocket
	as.Quit()
}

// connect and send 50 messages, separated by small random sleeps
func multiclient(sn string, t *testing.T) {
	conn, err := net.Dial("unix", sn)
	defer conn.Close()
	if err != nil {
		t.Errorf("Couldn't connect to %v: %v", sn, err)
	}
	for i := 0; i < 50; i++ {
		msg  := fmt.Sprintf("echo message %d", i)
		rmsg := fmt.Sprintf("message %d", i)
		conn.Write([]byte(msg))
		res, err := readConn(conn)
		if err != nil {
			t.Errorf("Error on read: %v", err)
		}
		if string(res) != rmsg {
			t.Errorf("Expected '%v' but got '%v'", rmsg, string(res))
		}
		time.Sleep(time.Duration(rand.Intn(50)) * time.Millisecond)
	}
}
<commit_msg>test improvements<commit_after>package adminsock

import (
	"fmt"
	"math/rand"
	"net"
	"testing"
	"time"
)

// functions echo() and readConn() are defined in test 02.

func TestMultiServer(t *testing.T) {
	// implement an echo server
	d := make(Dispatch) // create Dispatch
	d["echo"] = echo    // and put a function in it
	// instantiate an adminsocket
	as, err := New(d, 0)
	if err != nil {
		t.Errorf("Couldn't create socket: %v", err)
	}
	// launch clients
	rand.Seed(time.Now().Unix())
	x := 5
	for i := 0; i < x; i++ {
		go multiclient(buildSockName(), t)
	}
	for i := 0; i < x; i++ {
		msg := <-as.Msgr
		if msg.Err != nil {
			t.Errorf("connection creation returned error: %v", msg.Err)
		}
	}
	// wait for disconnect Msg
	for i := 0; i < x; i++ {
		msg := <-as.Msgr
		if msg.Err == nil {
			t.Errorf("connection drop should be an err, but got nil")
		}
	}
	// shut down adminsocket
	as.Quit()
}

// connect and send 50 messages, separated by small random sleeps
func multiclient(sn string, t *testing.T) {
	conn, err := net.Dial("unix", sn)
	defer conn.Close()
	if err != nil {
		t.Errorf("Couldn't connect to %v: %v", sn, err)
	}
	for i := 0; i < 50; i++ {
		msg  := fmt.Sprintf("echo message %d (which should be longer than 64 bytes to exercise a path)", i)
		rmsg := fmt.Sprintf("message %d (which should be longer than 64 bytes to exercise a path)", i)
		conn.Write([]byte(msg))
		res, err := readConn(conn)
		if err != nil {
			t.Errorf("Error on read: %v", err)
		}
		if string(res) != rmsg {
			t.Errorf("Expected '%v' but got '%v'", rmsg, string(res))
		}
		time.Sleep(time.Duration(rand.Intn(50)) * time.Millisecond)
	}
}
<|endoftext|>


<commit_before>package zfs_test

import (
	"fmt"
	"io/ioutil"
	"math"
	"os"
	"path/filepath"
	"reflect"
	"runtime"
	"testing"
	"time"

	zfs "github.com/mistifyio/go-zfs"
)

func sleep(delay int) {
	time.Sleep(time.Duration(delay) * time.Second)
}

func pow2(x int) int64 {
	return int64(math.Pow(2, float64(x)))
}

//https://github.com/benbjohnson/testing
// assert fails the test if the condition is false.
func assert(tb testing.TB, condition bool, msg string, v ...interface{}) {
	if !condition {
		_, file, line, _ := runtime.Caller(1)
		fmt.Printf("\033[31m%s:%d: "+msg+"\033[39m\n\n", append([]interface{}{filepath.Base(file), line}, v...)...)
		tb.FailNow()
	}
}

// ok fails the test if an err is not nil.
func ok(tb testing.TB, err error) {
	if err != nil {
		_, file, line, _ := runtime.Caller(1)
		fmt.Printf("\033[31m%s:%d: unexpected error: %s\033[39m\n\n", filepath.Base(file), line, err.Error())
		tb.FailNow()
	}
}

// nok fails the test if an err is nil.
func nok(tb testing.TB, err error) {
	if err == nil {
		_, file, line, _ := runtime.Caller(1)
		fmt.Printf("\033[31m%s:%d: expected error: %s\033[39m\n\n", filepath.Base(file), line)
		tb.FailNow()
	}
}

// equals fails the test if exp is not equal to act.
func equals(tb testing.TB, exp, act interface{}) {
	if !reflect.DeepEqual(exp, act) {
		_, file, line, _ := runtime.Caller(1)
		fmt.Printf("\033[31m%s:%d:\n\n\texp: %#v\n\n\tgot: %#v\033[39m\n\n", filepath.Base(file), line, exp, act)
		tb.FailNow()
	}
}

func zpoolTest(t *testing.T, fn func()) {
	tempfiles := make([]string, 3)
	for i := range tempfiles {
		f, _ := ioutil.TempFile("/tmp/", "zfs-")
		defer f.Close()
		err := f.Truncate(pow2(30))
		ok(t, err)
		tempfiles[i] = f.Name()
		defer os.Remove(f.Name())
	}

	pool, err := zfs.CreateZpool("test", nil, tempfiles...)
	ok(t, err)
	defer pool.Destroy()
	ok(t, err)
	fn()

}

func TestDatasets(t *testing.T) {
	zpoolTest(t, func() {
		_, err := zfs.Datasets("")
		ok(t, err)

		ds, err := zfs.GetDataset("test")
		ok(t, err)
		equals(t, zfs.DatasetFilesystem, ds.Type)
		equals(t, "", ds.Origin)
		if runtime.GOOS != "solaris" {
			assert(t, ds.Logicalused != 0, "Logicalused is not greater than 0")
		}
	})
}

func TestDatasetGetProperty(t *testing.T) {
	zpoolTest(t, func() {
		ds, err := zfs.GetDataset("test")
		ok(t, err)

		prop, err := ds.GetProperty("foobarbaz")
		nok(t, err)
		equals(t, "", prop)

		prop, err = ds.GetProperty("compression")
		ok(t, err)
		equals(t, "off", prop)
	})
}

func TestSnapshots(t *testing.T) {

	zpoolTest(t, func() {
		snapshots, err := zfs.Snapshots("")
		ok(t, err)

		for _, snapshot := range snapshots {
			equals(t, zfs.DatasetSnapshot, snapshot.Type)
		}
	})
}

func TestFilesystems(t *testing.T) {
	zpoolTest(t, func() {
		f, err := zfs.CreateFilesystem("test/filesystem-test", nil)
		ok(t, err)

		filesystems, err := zfs.Filesystems("")
		ok(t, err)

		for _, filesystem := range filesystems {
			equals(t, zfs.DatasetFilesystem, filesystem.Type)
		}

		ok(t, f.Destroy(zfs.DestroyDefault))
	})
}

func TestCreateFilesystemWithProperties(t *testing.T) {
	zpoolTest(t, func() {
		props := map[string]string{
			"compression": "lz4",
		}

		f, err := zfs.CreateFilesystem("test/filesystem-test", props)
		ok(t, err)

		equals(t, "lz4", f.Compression)

		filesystems, err := zfs.Filesystems("")
		ok(t, err)

		for _, filesystem := range filesystems {
			equals(t, zfs.DatasetFilesystem, filesystem.Type)
		}

		ok(t, f.Destroy(zfs.DestroyDefault))
	})
}

func TestVolumes(t *testing.T) {
	zpoolTest(t, func() {
		v, err := zfs.CreateVolume("test/volume-test", uint64(pow2(23)), nil)
		ok(t, err)

		// volumes are sometimes "busy" if you try to manipulate them right away
		sleep(1)

		equals(t, zfs.DatasetVolume, v.Type)
		volumes, err := zfs.Volumes("")
		ok(t, err)

		for _, volume := range volumes {
			equals(t, zfs.DatasetVolume, volume.Type)
		}

		ok(t, v.Destroy(zfs.DestroyDefault))
	})
}

func TestSnapshot(t *testing.T) {
	zpoolTest(t, func() {
		f, err := zfs.CreateFilesystem("test/snapshot-test", nil)
		ok(t, err)

		filesystems, err := zfs.Filesystems("")
		ok(t, err)

		for _, filesystem := range filesystems {
			equals(t, zfs.DatasetFilesystem, filesystem.Type)
		}

		s, err := f.Snapshot("test", false)
		ok(t, err)

		equals(t, zfs.DatasetSnapshot, s.Type)

		equals(t, "test/snapshot-test@test", s.Name)

		ok(t, s.Destroy(zfs.DestroyDefault))

		ok(t, f.Destroy(zfs.DestroyDefault))
	})
}

func TestClone(t *testing.T) {
	zpoolTest(t, func() {
		f, err := zfs.CreateFilesystem("test/snapshot-test", nil)
		ok(t, err)

		filesystems, err := zfs.Filesystems("")
		ok(t, err)

		for _, filesystem := range filesystems {
			equals(t, zfs.DatasetFilesystem, filesystem.Type)
		}

		s, err := f.Snapshot("test", false)
		ok(t, err)

		equals(t, zfs.DatasetSnapshot, s.Type)
		equals(t, "test/snapshot-test@test", s.Name)

		c, err := s.Clone("test/clone-test", nil)
		ok(t, err)

		equals(t, zfs.DatasetFilesystem, c.Type)

		ok(t, c.Destroy(zfs.DestroyDefault))

		ok(t, s.Destroy(zfs.DestroyDefault))

		ok(t, f.Destroy(zfs.DestroyDefault))
	})
}

func TestSendSnapshot(t *testing.T) {
	zpoolTest(t, func() {
		f, err := zfs.CreateFilesystem("test/snapshot-test", nil)
		ok(t, err)

		filesystems, err := zfs.Filesystems("")
		ok(t, err)

		for _, filesystem := range filesystems {
			equals(t, zfs.DatasetFilesystem, filesystem.Type)
		}

		s, err := f.Snapshot("test", false)
		ok(t, err)

		file, _ := ioutil.TempFile("/tmp/", "zfs-")
		defer file.Close()
		err = file.Truncate(pow2(30))
		ok(t, err)
		defer os.Remove(file.Name())

		err = s.SendSnapshot(file)
		ok(t, err)

		ok(t, s.Destroy(zfs.DestroyDefault))

		ok(t, f.Destroy(zfs.DestroyDefault))
	})
}

func TestChildren(t *testing.T) {
	zpoolTest(t, func() {
		f, err := zfs.CreateFilesystem("test/snapshot-test", nil)
		ok(t, err)

		s, err := f.Snapshot("test", false)
		ok(t, err)

		equals(t, zfs.DatasetSnapshot, s.Type)
		equals(t, "test/snapshot-test@test", s.Name)

		children, err := f.Children(0)
		ok(t, err)

		equals(t, 1, len(children))
		equals(t, "test/snapshot-test@test", children[0].Name)

		ok(t, s.Destroy(zfs.DestroyDefault))
		ok(t, f.Destroy(zfs.DestroyDefault))
	})
}

func TestListZpool(t *testing.T) {
	zpoolTest(t, func() {
		pools, err := zfs.ListZpools()
		ok(t, err)
		for _, pool := range pools {
			if pool.Name == "test" {
				equals(t, "test", pool.Name)
				return
			}
		}
		t.Fatal("Failed to find test pool")
	})
}

func TestRollback(t *testing.T) {
	zpoolTest(t, func() {
		f, err := zfs.CreateFilesystem("test/snapshot-test", nil)
		ok(t, err)

		filesystems, err := zfs.Filesystems("")
		ok(t, err)

		for _, filesystem := range filesystems {
			equals(t, zfs.DatasetFilesystem, filesystem.Type)
		}

		s1, err := f.Snapshot("test", false)
		ok(t, err)

		_, err = f.Snapshot("test2", false)
		ok(t, err)

		s3, err := f.Snapshot("test3", false)
		ok(t, err)

		err = s3.Rollback(false)
		ok(t, err)

		err = s1.Rollback(false)
		assert(t, err != nil, "should error when rolling back beyond most recent without destroyMoreRecent = true")

		err = s1.Rollback(true)
		ok(t, err)

		ok(t, s1.Destroy(zfs.DestroyDefault))

		ok(t, f.Destroy(zfs.DestroyDefault))
	})
}

func TestDiff(t *testing.T) {
	zpoolTest(t, func() {
		fs, err := zfs.CreateFilesystem("test/origin", nil)
		ok(t, err)

		linkedFile, err := os.Create(filepath.Join(fs.Mountpoint, "linked"))
		ok(t, err)

		movedFile, err := os.Create(filepath.Join(fs.Mountpoint, "file"))
		ok(t, err)

		snapshot, err := fs.Snapshot("snapshot", false)
		ok(t, err)

		unicodeFile, err := os.Create(filepath.Join(fs.Mountpoint, "i ❤ unicode"))
		ok(t, err)

		err = os.Rename(movedFile.Name(), movedFile.Name()+"-new")
		ok(t, err)

		err = os.Link(linkedFile.Name(), linkedFile.Name()+"_hard")
		ok(t, err)

		inodeChanges, err := fs.Diff(snapshot.Name)
		ok(t, err)
		equals(t, 4, len(inodeChanges))

		equals(t, "/test/origin/", inodeChanges[0].Path)
		equals(t, zfs.Directory, inodeChanges[0].Type)
		equals(t, zfs.Modified, inodeChanges[0].Change)

		equals(t, "/test/origin/linked", inodeChanges[1].Path)
		equals(t, zfs.File, inodeChanges[1].Type)
		equals(t, zfs.Modified, inodeChanges[1].Change)
		equals(t, 1, inodeChanges[1].ReferenceCountChange)

		equals(t, "/test/origin/file", inodeChanges[2].Path)
		equals(t, "/test/origin/file-new", inodeChanges[2].NewPath)
		equals(t, zfs.File, inodeChanges[2].Type)
		equals(t, zfs.Renamed, inodeChanges[2].Change)

		equals(t, "/test/origin/i ❤ unicode", inodeChanges[3].Path)
		equals(t, zfs.File, inodeChanges[3].Type)
		equals(t, zfs.Created, inodeChanges[3].Change)

		ok(t, movedFile.Close())
		ok(t, unicodeFile.Close())
		ok(t, linkedFile.Close())
		ok(t, snapshot.Destroy(zfs.DestroyForceUmount))
		ok(t, fs.Destroy(zfs.DestroyForceUmount))
	})
}
<commit_msg>fix test nok error printing<commit_after>package zfs_test

import (
	"fmt"
	"io/ioutil"
	"math"
	"os"
	"path/filepath"
	"reflect"
	"runtime"
	"testing"
	"time"

	zfs "github.com/mistifyio/go-zfs"
)

func sleep(delay int) {
	time.Sleep(time.Duration(delay) * time.Second)
}

func pow2(x int) int64 {
	return int64(math.Pow(2, float64(x)))
}

//https://github.com/benbjohnson/testing
// assert fails the test if the condition is false.
func assert(tb testing.TB, condition bool, msg string, v ...interface{}) {
	if !condition {
		_, file, line, _ := runtime.Caller(1)
		fmt.Printf("\033[31m%s:%d: "+msg+"\033[39m\n\n", append([]interface{}{filepath.Base(file), line}, v...)...)
		tb.FailNow()
	}
}

// ok fails the test if an err is not nil.
func ok(tb testing.TB, err error) {
	if err != nil {
		_, file, line, _ := runtime.Caller(1)
		fmt.Printf("\033[31m%s:%d: unexpected error: %s\033[39m\n\n", filepath.Base(file), line, err.Error())
		tb.FailNow()
	}
}

// nok fails the test if an err is nil.
func nok(tb testing.TB, err error) {
	if err == nil {
		_, file, line, _ := runtime.Caller(1)
		fmt.Printf("\033[31m%s:%d: expected error: %s\033[39m\n\n", filepath.Base(file), line, err.Error())
		tb.FailNow()
	}
}

// equals fails the test if exp is not equal to act.
func equals(tb testing.TB, exp, act interface{}) {
	if !reflect.DeepEqual(exp, act) {
		_, file, line, _ := runtime.Caller(1)
		fmt.Printf("\033[31m%s:%d:\n\n\texp: %#v\n\n\tgot: %#v\033[39m\n\n", filepath.Base(file), line, exp, act)
		tb.FailNow()
	}
}

func zpoolTest(t *testing.T, fn func()) {
	tempfiles := make([]string, 3)
	for i := range tempfiles {
		f, _ := ioutil.TempFile("/tmp/", "zfs-")
		defer f.Close()
		err := f.Truncate(pow2(30))
		ok(t, err)
		tempfiles[i] = f.Name()
		defer os.Remove(f.Name())
	}

	pool, err := zfs.CreateZpool("test", nil, tempfiles...)
	ok(t, err)
	defer pool.Destroy()
	ok(t, err)
	fn()

}

func TestDatasets(t *testing.T) {
	zpoolTest(t, func() {
		_, err := zfs.Datasets("")
		ok(t, err)

		ds, err := zfs.GetDataset("test")
		ok(t, err)
		equals(t, zfs.DatasetFilesystem, ds.Type)
		equals(t, "", ds.Origin)
		if runtime.GOOS != "solaris" {
			assert(t, ds.Logicalused != 0, "Logicalused is not greater than 0")
		}
	})
}

func TestDatasetGetProperty(t *testing.T) {
	zpoolTest(t, func() {
		ds, err := zfs.GetDataset("test")
		ok(t, err)

		prop, err := ds.GetProperty("foobarbaz")
		nok(t, err)
		equals(t, "", prop)

		prop, err = ds.GetProperty("compression")
		ok(t, err)
		equals(t, "off", prop)
	})
}

func TestSnapshots(t *testing.T) {

	zpoolTest(t, func() {
		snapshots, err := zfs.Snapshots("")
		ok(t, err)

		for _, snapshot := range snapshots {
			equals(t, zfs.DatasetSnapshot, snapshot.Type)
		}
	})
}

func TestFilesystems(t *testing.T) {
	zpoolTest(t, func() {
		f, err := zfs.CreateFilesystem("test/filesystem-test", nil)
		ok(t, err)

		filesystems, err := zfs.Filesystems("")
		ok(t, err)

		for _, filesystem := range filesystems {
			equals(t, zfs.DatasetFilesystem, filesystem.Type)
		}

		ok(t, f.Destroy(zfs.DestroyDefault))
	})
}

func TestCreateFilesystemWithProperties(t *testing.T) {
	zpoolTest(t, func() {
		props := map[string]string{
			"compression": "lz4",
		}

		f, err := zfs.CreateFilesystem("test/filesystem-test", props)
		ok(t, err)

		equals(t, "lz4", f.Compression)

		filesystems, err := zfs.Filesystems("")
		ok(t, err)

		for _, filesystem := range filesystems {
			equals(t, zfs.DatasetFilesystem, filesystem.Type)
		}

		ok(t, f.Destroy(zfs.DestroyDefault))
	})
}

func TestVolumes(t *testing.T) {
	zpoolTest(t, func() {
		v, err := zfs.CreateVolume("test/volume-test", uint64(pow2(23)), nil)
		ok(t, err)

		// volumes are sometimes "busy" if you try to manipulate them right away
		sleep(1)

		equals(t, zfs.DatasetVolume, v.Type)
		volumes, err := zfs.Volumes("")
		ok(t, err)

		for _, volume := range volumes {
			equals(t, zfs.DatasetVolume, volume.Type)
		}

		ok(t, v.Destroy(zfs.DestroyDefault))
	})
}

func TestSnapshot(t *testing.T) {
	zpoolTest(t, func() {
		f, err := zfs.CreateFilesystem("test/snapshot-test", nil)
		ok(t, err)

		filesystems, err := zfs.Filesystems("")
		ok(t, err)

		for _, filesystem := range filesystems {
			equals(t, zfs.DatasetFilesystem, filesystem.Type)
		}

		s, err := f.Snapshot("test", false)
		ok(t, err)

		equals(t, zfs.DatasetSnapshot, s.Type)

		equals(t, "test/snapshot-test@test", s.Name)

		ok(t, s.Destroy(zfs.DestroyDefault))

		ok(t, f.Destroy(zfs.DestroyDefault))
	})
}

func TestClone(t *testing.T) {
	zpoolTest(t, func() {
		f, err := zfs.CreateFilesystem("test/snapshot-test", nil)
		ok(t, err)

		filesystems, err := zfs.Filesystems("")
		ok(t, err)

		for _, filesystem := range filesystems {
			equals(t, zfs.DatasetFilesystem, filesystem.Type)
		}

		s, err := f.Snapshot("test", false)
		ok(t, err)

		equals(t, zfs.DatasetSnapshot, s.Type)
		equals(t, "test/snapshot-test@test", s.Name)

		c, err := s.Clone("test/clone-test", nil)
		ok(t, err)

		equals(t, zfs.DatasetFilesystem, c.Type)

		ok(t, c.Destroy(zfs.DestroyDefault))

		ok(t, s.Destroy(zfs.DestroyDefault))

		ok(t, f.Destroy(zfs.DestroyDefault))
	})
}

func TestSendSnapshot(t *testing.T) {
	zpoolTest(t, func() {
		f, err := zfs.CreateFilesystem("test/snapshot-test", nil)
		ok(t, err)

		filesystems, err := zfs.Filesystems("")
		ok(t, err)

		for _, filesystem := range filesystems {
			equals(t, zfs.DatasetFilesystem, filesystem.Type)
		}

		s, err := f.Snapshot("test", false)
		ok(t, err)

		file, _ := ioutil.TempFile("/tmp/", "zfs-")
		defer file.Close()
		err = file.Truncate(pow2(30))
		ok(t, err)
		defer os.Remove(file.Name())

		err = s.SendSnapshot(file)
		ok(t, err)

		ok(t, s.Destroy(zfs.DestroyDefault))

		ok(t, f.Destroy(zfs.DestroyDefault))
	})
}

func TestChildren(t *testing.T) {
	zpoolTest(t, func() {
		f, err := zfs.CreateFilesystem("test/snapshot-test", nil)
		ok(t, err)

		s, err := f.Snapshot("test", false)
		ok(t, err)

		equals(t, zfs.DatasetSnapshot, s.Type)
		equals(t, "test/snapshot-test@test", s.Name)

		children, err := f.Children(0)
		ok(t, err)

		equals(t, 1, len(children))
		equals(t, "test/snapshot-test@test", children[0].Name)

		ok(t, s.Destroy(zfs.DestroyDefault))
		ok(t, f.Destroy(zfs.DestroyDefault))
	})
}

func TestListZpool(t *testing.T) {
	zpoolTest(t, func() {
		pools, err := zfs.ListZpools()
		ok(t, err)
		for _, pool := range pools {
			if pool.Name == "test" {
				equals(t, "test", pool.Name)
				return
			}
		}
		t.Fatal("Failed to find test pool")
	})
}

func TestRollback(t *testing.T) {
	zpoolTest(t, func() {
		f, err := zfs.CreateFilesystem("test/snapshot-test", nil)
		ok(t, err)

		filesystems, err := zfs.Filesystems("")
		ok(t, err)

		for _, filesystem := range filesystems {
			equals(t, zfs.DatasetFilesystem, filesystem.Type)
		}

		s1, err := f.Snapshot("test", false)
		ok(t, err)

		_, err = f.Snapshot("test2", false)
		ok(t, err)

		s3, err := f.Snapshot("test3", false)
		ok(t, err)

		err = s3.Rollback(false)
		ok(t, err)

		err = s1.Rollback(false)
		assert(t, err != nil, "should error when rolling back beyond most recent without destroyMoreRecent = true")

		err = s1.Rollback(true)
		ok(t, err)

		ok(t, s1.Destroy(zfs.DestroyDefault))

		ok(t, f.Destroy(zfs.DestroyDefault))
	})
}

func TestDiff(t *testing.T) {
	zpoolTest(t, func() {
		fs, err := zfs.CreateFilesystem("test/origin", nil)
		ok(t, err)

		linkedFile, err := os.Create(filepath.Join(fs.Mountpoint, "linked"))
		ok(t, err)

		movedFile, err := os.Create(filepath.Join(fs.Mountpoint, "file"))
		ok(t, err)

		snapshot, err := fs.Snapshot("snapshot", false)
		ok(t, err)

		unicodeFile, err := os.Create(filepath.Join(fs.Mountpoint, "i ❤ unicode"))
		ok(t, err)

		err = os.Rename(movedFile.Name(), movedFile.Name()+"-new")
		ok(t, err)

		err = os.Link(linkedFile.Name(), linkedFile.Name()+"_hard")
		ok(t, err)

		inodeChanges, err := fs.Diff(snapshot.Name)
		ok(t, err)
		equals(t, 4, len(inodeChanges))

		equals(t, "/test/origin/", inodeChanges[0].Path)
		equals(t, zfs.Directory, inodeChanges[0].Type)
		equals(t, zfs.Modified, inodeChanges[0].Change)

		equals(t, "/test/origin/linked", inodeChanges[1].Path)
		equals(t, zfs.File, inodeChanges[1].Type)
		equals(t, zfs.Modified, inodeChanges[1].Change)
		equals(t, 1, inodeChanges[1].ReferenceCountChange)

		equals(t, "/test/origin/file", inodeChanges[2].Path)
		equals(t, "/test/origin/file-new", inodeChanges[2].NewPath)
		equals(t, zfs.File, inodeChanges[2].Type)
		equals(t, zfs.Renamed, inodeChanges[2].Change)

		equals(t, "/test/origin/i ❤ unicode", inodeChanges[3].Path)
		equals(t, zfs.File, inodeChanges[3].Type)
		equals(t, zfs.Created, inodeChanges[3].Change)

		ok(t, movedFile.Close())
		ok(t, unicodeFile.Close())
		ok(t, linkedFile.Close())
		ok(t, snapshot.Destroy(zfs.DestroyForceUmount))
		ok(t, fs.Destroy(zfs.DestroyForceUmount))
	})
}
<|endoftext|>


<commit_before>package adaptlog
<commit_msg>added versioning<commit_after>package adaptlog

// VERSION provides the current version of adaptlog.
const VERSION = "0.1.0"<|endoftext|>