<commit_before>package main

import (
	"context"
	"flag"
	"fmt"
	"net/url"
	"os"
	"path"
	"path/filepath"
	"strings"

	"github.com/vmware/govmomi"
	"github.com/vmware/govmomi/find"
	"github.com/vmware/govmomi/object"
	"github.com/vmware/govmomi/vim25/soap"
	"github.com/vmware/govmomi/vim25/types"

	log "github.com/Sirupsen/logrus"
)

type vmConfig struct {
	vCenterURL  *string
	dsName      *string
	networkName *string
	vSphereHost *string

	vmFolder     *string
	path         *string
	persistent   *string
	persistentSz int
	vCpus        *int
	mem          *int64
	poweron      *bool
}

func runVcenter(args []string) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	var newVM vmConfig

	flags := flag.NewFlagSet("vCenter", flag.ExitOnError)
	invoked := filepath.Base(os.Args[0])

	newVM.vCenterURL = flags.String("url", os.Getenv("VCURL"), "URL of VMware vCenter in the format of https://username:password@VCaddress/sdk")
	newVM.dsName = flags.String("datastore", os.Getenv("VCDATASTORE"), "The name of the DataStore to host the VM")
	newVM.networkName = flags.String("network", os.Getenv("VCNETWORK"), "The network label the VM will use")
	newVM.vSphereHost = flags.String("hostname", os.Getenv("VCHOST"), "The server that will run the VM")

	newVM.vmFolder = flags.String("vmfolder", "", "Specify a name/folder for the virtual machine to reside in")
	newVM.path = flags.String("path", "", "Path to a specific image")
	newVM.persistent = flags.String("persistentSize", "", "Size in MB of persistent storage to allocate to the VM")
	newVM.mem = flags.Int64("mem", 1024, "Size in MB of memory to allocate to the VM")
	newVM.vCpus = flags.Int("cpus", 1, "Amount of vCPUs to allocate to the VM")
	newVM.poweron = flags.Bool("powerOn", false, "Power On the new VM once it has been created")

	flags.Usage = func() {
		fmt.Printf("USAGE: %s run vcenter [options] path\n\n", invoked)
		fmt.Printf("'path' specifies the full path of an image to run\n")
		fmt.Printf("Options:\n\n")
		flags.PrintDefaults()
	}

	if err := flags.Parse(args); err != nil {
		log.Fatalln("Unable to parse args")
	}

	remArgs := flags.Args()
	if len(remArgs) == 0 {
		fmt.Printf("Please specify the path to the image to run\n")
		flags.Usage()
		os.Exit(1)
	}
	*newVM.path = remArgs[0]

	// Ensure an iso has been passed to the vCenter run Command
	if strings.HasSuffix(*newVM.path, ".iso") {
		// Allow alternative names for new virtual machines being created in vCenter
		if *newVM.vmFolder == "" {
			*newVM.vmFolder = strings.TrimSuffix(path.Base(*newVM.path), ".iso")
		}
	} else {
		log.Fatalln("Please pass an \".iso\" file as the path")
	}

	// Test any passed in files before creating a new VM
	checkFile(*newVM.path)

	// Connect to VMware vCenter and return the default and found values needed for a new VM
	c, dss, folders, hs, net, rp := vCenterConnect(ctx, newVM)

	log.Infof("Creating new LinuxKit Virtual Machine")
	spec := types.VirtualMachineConfigSpec{
		Name:     *newVM.vmFolder,
		GuestId:  "otherLinux64Guest",
		Files:    &types.VirtualMachineFileInfo{VmPathName: fmt.Sprintf("[%s]", dss.Name())},
		NumCPUs:  int32(*newVM.vCpus),
		MemoryMB: *newVM.mem,
	}

	scsi, err := object.SCSIControllerTypes().CreateSCSIController("pvscsi")
	if err != nil {
		log.Fatalln("Error creating pvscsi controller as part of new VM")
	}

	spec.DeviceChange = append(spec.DeviceChange, &types.VirtualDeviceConfigSpec{
		Operation: types.VirtualDeviceConfigSpecOperationAdd,
		Device:    scsi,
	})

	task, err := folders.VmFolder.CreateVM(ctx, spec, rp, hs)
	if err != nil {
		log.Fatalln("Creating new VM failed, more detail can be found in vCenter tasks")
	}

	info, err := task.WaitForResult(ctx, nil)
	if err != nil {
		log.Fatalf("Creating new VM failed\n%v", err)
	}

	// Retrieve the new VM
	vm := object.NewVirtualMachine(c.Client, info.Result.(types.ManagedObjectReference))

	uploadFile(c, newVM, dss)
	addISO(ctx, newVM, vm, dss)

	if *newVM.persistent != "" {
		newVM.persistentSz, err = getDiskSizeMB(*newVM.persistent)
		if err != nil {
			log.Fatalf("Couldn't parse disk-size %s: %v", *newVM.persistent, err)
		}
		addVMDK(ctx, vm, dss, newVM)
	}

	if *newVM.networkName != "" {
		addNIC(ctx, vm, net)
	}

	if *newVM.poweron == true {
		log.Infoln("Powering on LinuxKit VM")
		powerOnVM(ctx, vm)
	}
}

func vCenterConnect(ctx context.Context, newVM vmConfig) (*govmomi.Client, *object.Datastore, *object.DatacenterFolders, *object.HostSystem, object.NetworkReference, *object.ResourcePool) {

	// Parse URL from string
	u, err := url.Parse(*newVM.vCenterURL)
	if err != nil {
		log.Fatalf("URL can't be parsed, ensure it is https://username:password/<address>/sdk %v", err)
	}

	// Connect and log in to ESX or vCenter
	c, err := govmomi.NewClient(ctx, u, true)
	if err != nil {
		log.Fatalf("Error logging into vCenter, check address and credentials %v", err)
	}

	// Create a new finder that will discover the defaults and are looked for Networks/Datastores
	f := find.NewFinder(c.Client, true)

	// Find one and only datacenter, not sure how VMware linked mode will work
	dc, err := f.DefaultDatacenter(ctx)
	if err != nil {
		log.Fatalf("No Datacenter instance could be found inside of vCenter %v", err)
	}

	// Make future calls local to this datacenter
	f.SetDatacenter(dc)

	// Find Datastore/Network
	dss, err := f.DatastoreOrDefault(ctx, *newVM.dsName)
	if err != nil {
		log.Fatalf("Datastore [%s], could not be found", *newVM.dsName)
	}

	folders, err := dc.Folders(ctx)
	if err != nil {
		log.Fatalln("Error locating default datacenter folder")
	}

	// Check if network connectivity is requested
	var net object.NetworkReference
	if *newVM.networkName != "" {
		net, err = f.NetworkOrDefault(ctx, *newVM.networkName)
		if err != nil {
			log.Fatalf("Network [%s], could not be found", *newVM.networkName)
		}
	}

	// Set the host that the VM will be created on
	hs, err := f.HostSystemOrDefault(ctx, *newVM.vSphereHost)
	if err != nil {
		log.Fatalf("vSphere host [%s], could not be found", *newVM.vSphereHost)
	}

	var rp *object.ResourcePool
	rp, err = hs.ResourcePool(ctx)
	if err != nil {
		log.Fatalln("Error locating default resource pool")
	}
	return c, dss, folders, hs, net, rp
}

func powerOnVM(ctx context.Context, vm *object.VirtualMachine) {
	task, err := vm.PowerOn(ctx)
	if err != nil {
		log.Errorln("Power On operation has failed, more detail can be found in vCenter tasks")
	}

	_, err = task.WaitForResult(ctx, nil)
	if err != nil {
		log.Errorln("Power On Task has failed, more detail can be found in vCenter tasks")
	}
}

func uploadFile(c *govmomi.Client, newVM vmConfig, dss *object.Datastore) {
	_, fileName := path.Split(*newVM.path)
	log.Infof("Uploading LinuxKit file [%s]", *newVM.path)
	if *newVM.path == "" {
		log.Fatalf("No file specified")
	}
	dsurl := dss.NewURL(fmt.Sprintf("%s/%s", *newVM.vmFolder, fileName))

	p := soap.DefaultUpload
	if err := c.Client.UploadFile(*newVM.path, dsurl, &p); err != nil {
		log.Fatalf("Unable to upload file to vCenter Datastore\n%v", err)
	}
}

func addNIC(ctx context.Context, vm *object.VirtualMachine, net object.NetworkReference) {
	backing, err := net.EthernetCardBackingInfo(ctx)
	if err != nil {
		log.Fatalf("Unable to determine vCenter network backend\n%v", err)
	}

	netdev, err := object.EthernetCardTypes().CreateEthernetCard("vmxnet3", backing)
	if err != nil {
		log.Fatalf("Unable to create vmxnet3 network interface\n%v", err)
	}

	log.Infof("Adding VM Networking")
	var add []types.BaseVirtualDevice
	add = append(add, netdev)

	if vm.AddDevice(ctx, add...); err != nil {
		log.Fatalf("Unable to add new networking device to VM configuration\n%v", err)
	}
}

func addVMDK(ctx context.Context, vm *object.VirtualMachine, dss *object.Datastore, newVM vmConfig) {
	devices, err := vm.Device(ctx)
	if err != nil {
		log.Fatalf("Unable to read devices from VM configuration\n%v", err)
	}

	controller, err := devices.FindDiskController("scsi")
	if err != nil {
		log.Fatalf("Unable to find SCSI device from VM configuration\n%v", err)
	}
	// The default is to have all persistent disks named linuxkit.vmdk
	disk := devices.CreateDisk(controller, dss.Reference(), dss.Path(fmt.Sprintf("%s/%s", *newVM.vmFolder, "linuxkit.vmdk")))

	disk.CapacityInKB = int64(newVM.persistentSz * 1024)

	var add []types.BaseVirtualDevice
	add = append(add, disk)

	log.Infof("Adding a persistent disk to the Virtual Machine")

	if vm.AddDevice(ctx, add...); err != nil {
		log.Fatalf("Unable to add new storage device to VM configuration\n%v", err)
	}
}

func addISO(ctx context.Context, newVM vmConfig, vm *object.VirtualMachine, dss *object.Datastore) {
	devices, err := vm.Device(ctx)
	if err != nil {
		log.Fatalf("Unable to read devices from VM configuration\n%v", err)
	}

	ide, err := devices.FindIDEController("")
	if err != nil {
		log.Fatalf("Unable to find IDE device from VM configuration\n%v", err)
	}

	cdrom, err := devices.CreateCdrom(ide)
	if err != nil {
		log.Fatalf("Unable to create new CDROM device\n%v", err)
	}

	var add []types.BaseVirtualDevice
	add = append(add, devices.InsertIso(cdrom, dss.Path(fmt.Sprintf("%s/%s", *newVM.vmFolder, path.Base(*newVM.path)))))

	log.Infof("Adding ISO to the Virtual Machine")

	if vm.AddDevice(ctx, add...); err != nil {
		log.Fatalf("Unable to add new CD-ROM device to VM configuration\n%v", err)
	}
}

func checkFile(file string) {
	if _, err := os.Stat(file); err != nil {
		if os.IsPermission(err) {
			log.Fatalf("Unable to read file [%s], please check permissions", file)
		} else if os.IsNotExist(err) {
			log.Fatalf("File [%s], does not exist", file)
		} else {
			log.Fatalf("Unable to stat file [%s]: %v", file, err)
		}
	}
}
<commit_msg>Added capability to wait for the OpenVM tools to report the IP of new VM<commit_after>package main

import (
	"context"
	"flag"
	"fmt"
	"net/url"
	"os"
	"path"
	"path/filepath"
	"strings"

	"github.com/vmware/govmomi"
	"github.com/vmware/govmomi/find"
	"github.com/vmware/govmomi/object"
	"github.com/vmware/govmomi/vim25/soap"
	"github.com/vmware/govmomi/vim25/types"

	log "github.com/Sirupsen/logrus"
)

type vmConfig struct {
	vCenterURL  *string
	dsName      *string
	networkName *string
	vSphereHost *string

	vmFolder     *string
	path         *string
	persistent   *string
	persistentSz int
	vCpus        *int
	mem          *int64
	poweron      *bool
	guestIP      *bool
}

func runVcenter(args []string) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	var newVM vmConfig

	flags := flag.NewFlagSet("vCenter", flag.ExitOnError)
	invoked := filepath.Base(os.Args[0])

	newVM.vCenterURL = flags.String("url", os.Getenv("VCURL"), "URL of VMware vCenter in the format of https://username:password@VCaddress/sdk")
	newVM.dsName = flags.String("datastore", os.Getenv("VCDATASTORE"), "The name of the DataStore to host the VM")
	newVM.networkName = flags.String("network", os.Getenv("VCNETWORK"), "The network label the VM will use")
	newVM.vSphereHost = flags.String("hostname", os.Getenv("VCHOST"), "The server that will run the VM")

	newVM.vmFolder = flags.String("vmfolder", "", "Specify a name/folder for the virtual machine to reside in")
	newVM.path = flags.String("path", "", "Path to a specific image")
	newVM.persistent = flags.String("persistentSize", "", "Size in MB of persistent storage to allocate to the VM")
	newVM.mem = flags.Int64("mem", 1024, "Size in MB of memory to allocate to the VM")
	newVM.vCpus = flags.Int("cpus", 1, "Amount of vCPUs to allocate to the VM")
	newVM.poweron = flags.Bool("powerOn", false, "Power On the new VM once it has been created")
	newVM.guestIP = flags.Bool("waitForIP", false, "LinuxKit will wait for the VM to power on and return the guest IP, requires open-vm-tools and the -powerOn flag to be set")

	flags.Usage = func() {
		fmt.Printf("USAGE: %s run vcenter [options] path\n\n", invoked)
		fmt.Printf("'path' specifies the full path of an image to run\n")
		fmt.Printf("Options:\n\n")
		flags.PrintDefaults()
	}

	if err := flags.Parse(args); err != nil {
		log.Fatalln("Unable to parse args")
	}

	remArgs := flags.Args()
	if len(remArgs) == 0 {
		fmt.Printf("Please specify the path to the image to run\n")
		flags.Usage()
		os.Exit(1)
	}
	*newVM.path = remArgs[0]

	if (*newVM.guestIP == true) && *newVM.poweron != true {
		log.Fatalln("The waitForIP flag can not be used without the powerOn flag")
	}
	// Ensure an iso has been passed to the vCenter run Command
	if strings.HasSuffix(*newVM.path, ".iso") {
		// Allow alternative names for new virtual machines being created in vCenter
		if *newVM.vmFolder == "" {
			*newVM.vmFolder = strings.TrimSuffix(path.Base(*newVM.path), ".iso")
		}
	} else {
		log.Fatalln("Please pass an \".iso\" file as the path")
	}

	// Test any passed in files before creating a new VM
	checkFile(*newVM.path)

	// Connect to VMware vCenter and return the default and found values needed for a new VM
	c, dss, folders, hs, net, rp := vCenterConnect(ctx, newVM)

	log.Infof("Creating new LinuxKit Virtual Machine")
	spec := types.VirtualMachineConfigSpec{
		Name:     *newVM.vmFolder,
		GuestId:  "otherLinux64Guest",
		Files:    &types.VirtualMachineFileInfo{VmPathName: fmt.Sprintf("[%s]", dss.Name())},
		NumCPUs:  int32(*newVM.vCpus),
		MemoryMB: *newVM.mem,
	}

	scsi, err := object.SCSIControllerTypes().CreateSCSIController("pvscsi")
	if err != nil {
		log.Fatalln("Error creating pvscsi controller as part of new VM")
	}

	spec.DeviceChange = append(spec.DeviceChange, &types.VirtualDeviceConfigSpec{
		Operation: types.VirtualDeviceConfigSpecOperationAdd,
		Device:    scsi,
	})

	task, err := folders.VmFolder.CreateVM(ctx, spec, rp, hs)
	if err != nil {
		log.Fatalln("Creating new VM failed, more detail can be found in vCenter tasks")
	}

	info, err := task.WaitForResult(ctx, nil)
	if err != nil {
		log.Fatalf("Creating new VM failed\n%v", err)
	}

	// Retrieve the new VM
	vm := object.NewVirtualMachine(c.Client, info.Result.(types.ManagedObjectReference))

	uploadFile(c, newVM, dss)
	addISO(ctx, newVM, vm, dss)

	if *newVM.persistent != "" {
		newVM.persistentSz, err = getDiskSizeMB(*newVM.persistent)
		if err != nil {
			log.Fatalf("Couldn't parse disk-size %s: %v", *newVM.persistent, err)
		}
		addVMDK(ctx, vm, dss, newVM)
	}

	if *newVM.networkName != "" {
		addNIC(ctx, vm, net)
	}

	if *newVM.poweron == true {
		log.Infoln("Powering on LinuxKit VM")
		powerOnVM(ctx, vm)
	}

	if *newVM.guestIP {
		log.Infof("Waiting for OpenVM Tools to come online")
		guestIP, err := getVMToolsIP(ctx, vm)
		if err != nil {
			log.Errorf("%v", err)
		}
		log.Infof("Guest IP Address: %s", guestIP)
	}
}

func getVMToolsIP(ctx context.Context, vm *object.VirtualMachine) (string, error) {
	guestIP, err := vm.WaitForIP(ctx)
	if err != nil {
		return "", err
	}
	return guestIP, err
}

func vCenterConnect(ctx context.Context, newVM vmConfig) (*govmomi.Client, *object.Datastore, *object.DatacenterFolders, *object.HostSystem, object.NetworkReference, *object.ResourcePool) {

	// Parse URL from string
	u, err := url.Parse(*newVM.vCenterURL)
	if err != nil {
		log.Fatalf("URL can't be parsed, ensure it is https://username:password/<address>/sdk %v", err)
	}

	// Connect and log in to ESX or vCenter
	c, err := govmomi.NewClient(ctx, u, true)
	if err != nil {
		log.Fatalf("Error logging into vCenter, check address and credentials %v", err)
	}

	// Create a new finder that will discover the defaults and are looked for Networks/Datastores
	f := find.NewFinder(c.Client, true)

	// Find one and only datacenter, not sure how VMware linked mode will work
	dc, err := f.DefaultDatacenter(ctx)
	if err != nil {
		log.Fatalf("No Datacenter instance could be found inside of vCenter %v", err)
	}

	// Make future calls local to this datacenter
	f.SetDatacenter(dc)

	// Find Datastore/Network
	dss, err := f.DatastoreOrDefault(ctx, *newVM.dsName)
	if err != nil {
		log.Fatalf("Datastore [%s], could not be found", *newVM.dsName)
	}

	folders, err := dc.Folders(ctx)
	if err != nil {
		log.Fatalln("Error locating default datacenter folder")
	}

	// Check if network connectivity is requested
	var net object.NetworkReference
	if *newVM.networkName != "" {
		net, err = f.NetworkOrDefault(ctx, *newVM.networkName)
		if err != nil {
			log.Fatalf("Network [%s], could not be found", *newVM.networkName)
		}
	}

	// Set the host that the VM will be created on
	hs, err := f.HostSystemOrDefault(ctx, *newVM.vSphereHost)
	if err != nil {
		log.Fatalf("vSphere host [%s], could not be found", *newVM.vSphereHost)
	}

	var rp *object.ResourcePool
	rp, err = hs.ResourcePool(ctx)
	if err != nil {
		log.Fatalln("Error locating default resource pool")
	}
	return c, dss, folders, hs, net, rp
}

func powerOnVM(ctx context.Context, vm *object.VirtualMachine) {
	task, err := vm.PowerOn(ctx)
	if err != nil {
		log.Errorln("Power On operation has failed, more detail can be found in vCenter tasks")
	}

	_, err = task.WaitForResult(ctx, nil)
	if err != nil {
		log.Errorln("Power On Task has failed, more detail can be found in vCenter tasks")
	}
}

func uploadFile(c *govmomi.Client, newVM vmConfig, dss *object.Datastore) {
	_, fileName := path.Split(*newVM.path)
	log.Infof("Uploading LinuxKit file [%s]", *newVM.path)
	if *newVM.path == "" {
		log.Fatalf("No file specified")
	}
	dsurl := dss.NewURL(fmt.Sprintf("%s/%s", *newVM.vmFolder, fileName))

	p := soap.DefaultUpload
	if err := c.Client.UploadFile(*newVM.path, dsurl, &p); err != nil {
		log.Fatalf("Unable to upload file to vCenter Datastore\n%v", err)
	}
}

func addNIC(ctx context.Context, vm *object.VirtualMachine, net object.NetworkReference) {
	backing, err := net.EthernetCardBackingInfo(ctx)
	if err != nil {
		log.Fatalf("Unable to determine vCenter network backend\n%v", err)
	}

	netdev, err := object.EthernetCardTypes().CreateEthernetCard("vmxnet3", backing)
	if err != nil {
		log.Fatalf("Unable to create vmxnet3 network interface\n%v", err)
	}

	log.Infof("Adding VM Networking")
	var add []types.BaseVirtualDevice
	add = append(add, netdev)

	if vm.AddDevice(ctx, add...); err != nil {
		log.Fatalf("Unable to add new networking device to VM configuration\n%v", err)
	}
}

func addVMDK(ctx context.Context, vm *object.VirtualMachine, dss *object.Datastore, newVM vmConfig) {
	devices, err := vm.Device(ctx)
	if err != nil {
		log.Fatalf("Unable to read devices from VM configuration\n%v", err)
	}

	controller, err := devices.FindDiskController("scsi")
	if err != nil {
		log.Fatalf("Unable to find SCSI device from VM configuration\n%v", err)
	}
	// The default is to have all persistent disks named linuxkit.vmdk
	disk := devices.CreateDisk(controller, dss.Reference(), dss.Path(fmt.Sprintf("%s/%s", *newVM.vmFolder, "linuxkit.vmdk")))

	disk.CapacityInKB = int64(newVM.persistentSz * 1024)

	var add []types.BaseVirtualDevice
	add = append(add, disk)

	log.Infof("Adding a persistent disk to the Virtual Machine")

	if vm.AddDevice(ctx, add...); err != nil {
		log.Fatalf("Unable to add new storage device to VM configuration\n%v", err)
	}
}

func addISO(ctx context.Context, newVM vmConfig, vm *object.VirtualMachine, dss *object.Datastore) {
	devices, err := vm.Device(ctx)
	if err != nil {
		log.Fatalf("Unable to read devices from VM configuration\n%v", err)
	}

	ide, err := devices.FindIDEController("")
	if err != nil {
		log.Fatalf("Unable to find IDE device from VM configuration\n%v", err)
	}

	cdrom, err := devices.CreateCdrom(ide)
	if err != nil {
		log.Fatalf("Unable to create new CDROM device\n%v", err)
	}

	var add []types.BaseVirtualDevice
	add = append(add, devices.InsertIso(cdrom, dss.Path(fmt.Sprintf("%s/%s", *newVM.vmFolder, path.Base(*newVM.path)))))

	log.Infof("Adding ISO to the Virtual Machine")

	if vm.AddDevice(ctx, add...); err != nil {
		log.Fatalf("Unable to add new CD-ROM device to VM configuration\n%v", err)
	}
}

func checkFile(file string) {
	if _, err := os.Stat(file); err != nil {
		if os.IsPermission(err) {
			log.Fatalf("Unable to read file [%s], please check permissions", file)
		} else if os.IsNotExist(err) {
			log.Fatalf("File [%s], does not exist", file)
		} else {
			log.Fatalf("Unable to stat file [%s]: %v", file, err)
		}
	}
}
<|endoftext|>


<commit_before>package sweet

import (
	"fmt"
	"path"
	"reflect"
	"strings"
	"sync"
	"testing"
	"time"
)

type suiteRunner struct {
	s     *S
	suite interface{}

	suiteFailed bool

	suppressDeprecation bool
	deprecatedUsages    []string
}

func newSuiteRunner(s *S, suite interface{}) *suiteRunner {
	return &suiteRunner{
		s:                s,
		suite:            suite,
		deprecatedUsages: make([]string, 0),
	}
}

func (s *suiteRunner) addDeprecationWarning(funcName string) {
	s.deprecatedUsages = append(s.deprecatedUsages, funcName)
}

func (s *suiteRunner) runPlugins(f func(plugin Plugin)) {
	for _, plugin := range s.s.plugins {
		f(plugin)
	}
}

func (s *suiteRunner) Run(t *testing.T) {
	suiteStart := time.Now()

	var testGroup sync.WaitGroup

	suiteVal := reflect.ValueOf(s.suite)
	suiteType := suiteVal.Type()

	suiteName := suiteType.Name()
	if suiteVal.CanInterface() {
		suiteIfaceVal := reflect.Indirect(suiteVal)
		if suiteIfaceVal == reflect.Zero(suiteType) {
			suiteName = "UnknownSuite"
		} else {
			suiteName = suiteIfaceVal.Type().Name()
		}
	}

	lowerName := strings.ToLower(suiteName)
	if len(flagInclude) > 0 {
		found := false
		for _, name := range flagInclude {
			if strings.ToLower(name) == lowerName {
				found = true
				break
			}
		}
		if !found {
			return
		}
	}
	if len(flagExclude) > 0 {
		for _, name := range flagExclude {
			if strings.ToLower(name) == lowerName {
				return
			}
		}
	}

	setUpSuiteVal := suiteVal.MethodByName(defSetUpSuite.Name)
	tearDownSuiteVal := suiteVal.MethodByName(defTearDownSuite.Name)

	setUpTestVal := suiteVal.MethodByName(defSetUpTest.Name)
	tearDownTestVal := suiteVal.MethodByName(defTearDownTest.Name)

	v, err := defSetUpSuite.Validate(setUpSuiteVal)
	if err == errDeprecated {
		if !s.suppressDeprecation {
			s.addDeprecationWarning(formatName(suiteName, defSetUpSuite.Name))
		}

		// We handled the error, clear it so the set up still runs
		err = nil
	} else if err == errInvalidValue {
		// Skip running the suite set up because it doesn't exist.
	} else if err != nil {
		panic(fmt.Sprintf("%s has an unsupported method signature",
			formatName(suiteName, defSetUpSuite.Name)))
	}
	if err == nil {
		switch v {
		case 1:
			setUpSuiteVal.Call(nil)
		}
	}

	s.runPlugins(func(plugin Plugin) {
		plugin.SuiteStarting(suiteName)
	})
	for idx := 0; idx < suiteVal.NumMethod(); idx++ {
		methodType := suiteType.Method(idx)

		if methodType.Name[:4] == "Test" {
			methodVal := suiteVal.Method(idx)
			testName := methodType.Name
			testFullName := formatName(suiteName, methodType.Name)
			testStart := time.Now()
			t.Run(testFullName, func(t *testing.T) {
				wrapT := newSweetT(t)

				tVal := reflect.ValueOf(t)
				wrapTVal := reflect.ValueOf(wrapT)

				if setUpAllTests != nil {
					setUpAllTests(wrapT)
				}

				v, err := defSetUpTest.Validate(setUpTestVal)
				if err == errDeprecated {
					if !s.suppressDeprecation {
						s.addDeprecationWarning(formatName(suiteName, defSetUpTest.Name))
					}

					// Clean out the error because we've handled it
					err = nil
				} else if err == errInvalidValue {
					// Continue on because a test set up wasn't provided.
				} else if err != nil {
					panic(fmt.Sprintf("%s has an unsupported method signature",
						formatName(suiteName, defSetUpTest.Name)))
				}
				if err == nil {
					switch v {
					case 1:
						setUpTestVal.Call([]reflect.Value{tVal})
					case 2:
						setUpTestVal.Call([]reflect.Value{wrapTVal})
					}
				}

				// Call the actual test function in something that we can recover from
				failureStats := &TestFailedStats{
					Name:   testFullName,
					Frames: make([]*TestFailedFrame, 0),
				}
				func() {
					defer func() {
						if r := recover(); r != nil {
							switch result := r.(type) {
							case *testFailed:
								failureStats.Message = result.Message
								failureStats.Frames = make(
									[]*TestFailedFrame,
									len(result.Frames),
								)
								frameCount := len(result.Frames) - 1
								for idx := frameCount; idx >= 0; idx-- {
									frame := result.Frames[idx]
									failureStats.Frames[frameCount-idx] = &TestFailedFrame{
										File: frame.Filename,
										Line: frame.LineNumber,
									}
								}
							case *testSkipped:
								fmt.Printf("test skipped\n")
							default:
								panic(r)
							}

							wrapT.Fail()
						}

						testGroup.Done()
					}()

					testGroup.Add(1)
					s.runPlugins(func(plugin Plugin) {
						plugin.TestStarting(suiteName, testName)
					})

					v, err := defTest.Validate(methodVal)
					if err == errDeprecated {
						if !s.suppressDeprecation {
							s.addDeprecationWarning(formatName(suiteName, testName))
						}

						// We handled the error, clear it so the test still runs
						err = nil
					} else if err == errInvalidValue {
						panic("There's a test we can't get info for, context the Sweet dev!\n")
					} else if err != nil {
						panic(fmt.Sprintf("%s has an unsupported method signature.",
							formatName(suiteName, testName)))
					}
					if err == nil {
						switch v {
						case 1:
							methodVal.Call([]reflect.Value{tVal})
						case 2:
							methodVal.Call([]reflect.Value{wrapTVal})
						}
					}
				}()

				v, err = defTearDownTest.Validate(tearDownTestVal)
				if err == errDeprecated {
					if !s.suppressDeprecation {
						s.addDeprecationWarning(formatName(suiteName, defTearDownTest.Name))
					}

					// We handled the error, clear it so the clean up still runs
					err = nil
				} else if err == errInvalidValue {
					// Continue on because a test tear down was not provided
				} else if err != nil {
					panic(fmt.Sprintf("%s has an unsupported method signature",
						formatName(suiteName, defTearDownTest.Name)))
				}
				if err == nil {
					switch v {
					case 1:
						tearDownTestVal.Call([]reflect.Value{tVal})
					}
				}

				if tearDownAllTests != nil {
					tearDownAllTests(wrapT)
				}

				s.runPlugins(func(plugin Plugin) {
					if wrapT.Failed() {
						plugin.TestFailed(suiteName, testName, failureStats)
					} else if wrapT.Skipped() {
						plugin.TestSkipped(suiteName, testName, &TestSkippedStats{
							Time: time.Since(testStart),
						})
					} else {
						plugin.TestPassed(suiteName, testName, &TestPassedStats{
							Time: time.Since(testStart),
						})
					}
				})

				if wrapT.Failed() {
					s.suiteFailed = true

					fmt.Printf("-------------------------------------------------\n")
					fmt.Printf("FAIL: %s\n\n", failureStats.Name)

					for _, line := range wrapT.output {
						fmt.Print(line)
					}
					if len(wrapT.output) > 0 {
						fmt.Printf("\n\n")
					}

					for _, frame := range failureStats.Frames {
						fmt.Printf("%s:%d\n", path.Base(frame.File), frame.Line)
					}

					fmt.Printf("%s\n\n", failureStats.Message)
				}
			})
		}
	}

	v, err = defTearDownSuite.Validate(tearDownSuiteVal)
	if err == errDeprecated {
		if !s.suppressDeprecation {
			s.addDeprecationWarning(formatName(suiteName, defTearDownSuite.Name))
		}

		// We handled the error, clear it so the tear down is still run
		err = nil
	} else if err == errInvalidValue {
		// Continue on because a suite tear down was not provided.
	} else if err != nil {
		panic(fmt.Sprintf("%s has an unsupported method signature",
			formatName(suiteName, defTearDownSuite.Name)))
	}
	if err == nil {
		switch v {
		case 1:
			tearDownSuiteVal.Call(nil)
		}
	}

	testGroup.Wait()

	s.runPlugins(func(plugin Plugin) {
		plugin.SuiteFinished(suiteName, &SuiteFinishedStats{
			Time: time.Since(suiteStart),
		})
	})
}
<commit_msg>Fix skipped tests with the new T interface<commit_after>package sweet

import (
	"fmt"
	"path"
	"reflect"
	"strings"
	"sync"
	"testing"
	"time"
)

type suiteRunner struct {
	s     *S
	suite interface{}

	suiteFailed bool

	suppressDeprecation bool
	deprecatedUsages    []string
}

func newSuiteRunner(s *S, suite interface{}) *suiteRunner {
	return &suiteRunner{
		s:                s,
		suite:            suite,
		deprecatedUsages: make([]string, 0),
	}
}

func (s *suiteRunner) addDeprecationWarning(funcName string) {
	s.deprecatedUsages = append(s.deprecatedUsages, funcName)
}

func (s *suiteRunner) runPlugins(f func(plugin Plugin)) {
	for _, plugin := range s.s.plugins {
		f(plugin)
	}
}

func (s *suiteRunner) Run(t *testing.T) {
	suiteStart := time.Now()

	var testGroup sync.WaitGroup

	suiteVal := reflect.ValueOf(s.suite)
	suiteType := suiteVal.Type()

	suiteName := suiteType.Name()
	if suiteVal.CanInterface() {
		suiteIfaceVal := reflect.Indirect(suiteVal)
		if suiteIfaceVal == reflect.Zero(suiteType) {
			suiteName = "UnknownSuite"
		} else {
			suiteName = suiteIfaceVal.Type().Name()
		}
	}

	lowerName := strings.ToLower(suiteName)
	if len(flagInclude) > 0 {
		found := false
		for _, name := range flagInclude {
			if strings.ToLower(name) == lowerName {
				found = true
				break
			}
		}
		if !found {
			return
		}
	}
	if len(flagExclude) > 0 {
		for _, name := range flagExclude {
			if strings.ToLower(name) == lowerName {
				return
			}
		}
	}

	setUpSuiteVal := suiteVal.MethodByName(defSetUpSuite.Name)
	tearDownSuiteVal := suiteVal.MethodByName(defTearDownSuite.Name)

	setUpTestVal := suiteVal.MethodByName(defSetUpTest.Name)
	tearDownTestVal := suiteVal.MethodByName(defTearDownTest.Name)

	v, err := defSetUpSuite.Validate(setUpSuiteVal)
	if err == errDeprecated {
		if !s.suppressDeprecation {
			s.addDeprecationWarning(formatName(suiteName, defSetUpSuite.Name))
		}

		// We handled the error, clear it so the set up still runs
		err = nil
	} else if err == errInvalidValue {
		// Skip running the suite set up because it doesn't exist.
	} else if err != nil {
		panic(fmt.Sprintf("%s has an unsupported method signature",
			formatName(suiteName, defSetUpSuite.Name)))
	}
	if err == nil {
		switch v {
		case 1:
			setUpSuiteVal.Call(nil)
		}
	}

	s.runPlugins(func(plugin Plugin) {
		plugin.SuiteStarting(suiteName)
	})
	for idx := 0; idx < suiteVal.NumMethod(); idx++ {
		methodType := suiteType.Method(idx)

		if methodType.Name[:4] == "Test" {
			methodVal := suiteVal.Method(idx)
			testName := methodType.Name
			testFullName := formatName(suiteName, methodType.Name)
			testStart := time.Now()
			t.Run(testFullName, func(t *testing.T) {
				wrapT := newSweetT(t)

				tVal := reflect.ValueOf(t)
				wrapTVal := reflect.ValueOf(wrapT)

				if setUpAllTests != nil {
					setUpAllTests(wrapT)
				}

				v, err := defSetUpTest.Validate(setUpTestVal)
				if err == errDeprecated {
					if !s.suppressDeprecation {
						s.addDeprecationWarning(formatName(suiteName, defSetUpTest.Name))
					}

					// Clean out the error because we've handled it
					err = nil
				} else if err == errInvalidValue {
					// Continue on because a test set up wasn't provided.
				} else if err != nil {
					panic(fmt.Sprintf("%s has an unsupported method signature",
						formatName(suiteName, defSetUpTest.Name)))
				}
				if err == nil {
					switch v {
					case 1:
						setUpTestVal.Call([]reflect.Value{tVal})
					case 2:
						setUpTestVal.Call([]reflect.Value{wrapTVal})
					}
				}

				// Call the actual test function in something that we can recover from
				failureStats := &TestFailedStats{
					Name:   testFullName,
					Frames: make([]*TestFailedFrame, 0),
				}
				func() {
					defer func() {
						if r := recover(); r != nil {
							switch result := r.(type) {
							case *testFailed:
								failureStats.Message = result.Message
								failureStats.Frames = make(
									[]*TestFailedFrame,
									len(result.Frames),
								)
								frameCount := len(result.Frames) - 1
								for idx := frameCount; idx >= 0; idx-- {
									frame := result.Frames[idx]
									failureStats.Frames[frameCount-idx] = &TestFailedFrame{
										File: frame.Filename,
										Line: frame.LineNumber,
									}
								}
								wrapT.Fail()
							case *testSkipped:
								// Nothing to do for this because it was handled before
								// the panic
							default:
								panic(r)
							}
						}

						testGroup.Done()
					}()

					testGroup.Add(1)
					s.runPlugins(func(plugin Plugin) {
						plugin.TestStarting(suiteName, testName)
					})

					v, err := defTest.Validate(methodVal)
					if err == errDeprecated {
						if !s.suppressDeprecation {
							s.addDeprecationWarning(formatName(suiteName, testName))
						}

						// We handled the error, clear it so the test still runs
						err = nil
					} else if err == errInvalidValue {
						panic("There's a test we can't get info for, context the Sweet dev!\n")
					} else if err != nil {
						panic(fmt.Sprintf("%s has an unsupported method signature.",
							formatName(suiteName, testName)))
					}
					if err == nil {
						switch v {
						case 1:
							methodVal.Call([]reflect.Value{tVal})
						case 2:
							methodVal.Call([]reflect.Value{wrapTVal})
						}
					}
				}()

				v, err = defTearDownTest.Validate(tearDownTestVal)
				if err == errDeprecated {
					if !s.suppressDeprecation {
						s.addDeprecationWarning(formatName(suiteName, defTearDownTest.Name))
					}

					// We handled the error, clear it so the clean up still runs
					err = nil
				} else if err == errInvalidValue {
					// Continue on because a test tear down was not provided
				} else if err != nil {
					panic(fmt.Sprintf("%s has an unsupported method signature",
						formatName(suiteName, defTearDownTest.Name)))
				}
				if err == nil {
					switch v {
					case 1:
						tearDownTestVal.Call([]reflect.Value{tVal})
					}
				}

				if tearDownAllTests != nil {
					tearDownAllTests(wrapT)
				}

				s.runPlugins(func(plugin Plugin) {
					if wrapT.Failed() {
						plugin.TestFailed(suiteName, testName, failureStats)
					} else if wrapT.Skipped() {
						plugin.TestSkipped(suiteName, testName, &TestSkippedStats{
							Time: time.Since(testStart),
						})
					} else {
						plugin.TestPassed(suiteName, testName, &TestPassedStats{
							Time: time.Since(testStart),
						})
					}
				})

				if wrapT.Failed() {
					s.suiteFailed = true

					fmt.Printf("-------------------------------------------------\n")
					fmt.Printf("FAIL: %s\n\n", failureStats.Name)

					for _, line := range wrapT.output {
						fmt.Print(line)
					}
					if len(wrapT.output) > 0 {
						fmt.Printf("\n\n")
					}

					for _, frame := range failureStats.Frames {
						fmt.Printf("%s:%d\n", path.Base(frame.File), frame.Line)
					}

					fmt.Printf("%s\n\n", failureStats.Message)
				}
			})
		}
	}

	v, err = defTearDownSuite.Validate(tearDownSuiteVal)
	if err == errDeprecated {
		if !s.suppressDeprecation {
			s.addDeprecationWarning(formatName(suiteName, defTearDownSuite.Name))
		}

		// We handled the error, clear it so the tear down is still run
		err = nil
	} else if err == errInvalidValue {
		// Continue on because a suite tear down was not provided.
	} else if err != nil {
		panic(fmt.Sprintf("%s has an unsupported method signature",
			formatName(suiteName, defTearDownSuite.Name)))
	}
	if err == nil {
		switch v {
		case 1:
			tearDownSuiteVal.Call(nil)
		}
	}

	testGroup.Wait()

	s.runPlugins(func(plugin Plugin) {
		plugin.SuiteFinished(suiteName, &SuiteFinishedStats{
			Time: time.Since(suiteStart),
		})
	})
}
<|endoftext|>


<commit_before>package classfile

/*
InnerClasses_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 number_of_classes;
    {   u2 inner_class_info_index;
        u2 outer_class_info_index;
        u2 inner_name_index;
        u2 inner_class_access_flags;
    } classes[number_of_classes];
}
*/
type InnerClassesAttribute struct {
	classes []*InnerClassInfo
}

func (self *InnerClassesAttribute) readInfo(reader *ClassReader) {
	numberOfClasses := reader.readUint16()
	self.classes = make([]*InnerClassInfo, numberOfClasses)
	for i := range self.classes {
		self.classes[i] = readInnerClassInfo(reader)
	}
}

type InnerClassInfo struct {
	innerClassInfoIndex   uint16
	outerClassInfoIndex   uint16
	innerNameIndex        uint16
	innerClassAccessFlags uint16
}

func readInnerClassInfo(reader *ClassReader) *InnerClassInfo {
	return &InnerClassInfo{
		innerClassInfoIndex:   reader.readUint16(),
		outerClassInfoIndex:   reader.readUint16(),
		innerNameIndex:        reader.readUint16(),
		innerClassAccessFlags: reader.readUint16(),
	}
}
<commit_msg>code refactor<commit_after>package classfile

/*
InnerClasses_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 number_of_classes;
    {   u2 inner_class_info_index;
        u2 outer_class_info_index;
        u2 inner_name_index;
        u2 inner_class_access_flags;
    } classes[number_of_classes];
}
*/
type InnerClassesAttribute struct {
	classes []*InnerClassInfo
}

type InnerClassInfo struct {
	innerClassInfoIndex   uint16
	outerClassInfoIndex   uint16
	innerNameIndex        uint16
	innerClassAccessFlags uint16
}

func (self *InnerClassesAttribute) readInfo(reader *ClassReader) {
	numberOfClasses := reader.readUint16()
	self.classes = make([]*InnerClassInfo, numberOfClasses)
	for i := range self.classes {
		self.classes[i] = &InnerClassInfo{
			innerClassInfoIndex:   reader.readUint16(),
			outerClassInfoIndex:   reader.readUint16(),
			innerNameIndex:        reader.readUint16(),
			innerClassAccessFlags: reader.readUint16(),
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"flag"
	"fmt"
	"io"
	"strings"
	"sync"
	"time"

	"github.com/PuerkitoBio/goquery"
	"github.com/catatsuy/private-isu/benchmarker/score"
	"github.com/catatsuy/private-isu/benchmarker/util"
	"github.com/catatsuy/private-isu/benchmarker/worker"
)

// Exit codes are int values that represent an exit code for a particular error.
const (
	ExitCodeOK    int = 0
	ExitCodeError int = 1 + iota
)

// CLI is the command line object
type CLI struct {
	// outStream and errStream are the stdout and stderr
	// to write message from the CLI.
	outStream, errStream io.Writer
}

// Run invokes the CLI with the given arguments.
func (cli *CLI) Run(args []string) int {
	var (
		target string

		version bool
	)

	// Define option flag parse
	flags := flag.NewFlagSet(Name, flag.ContinueOnError)
	flags.SetOutput(cli.errStream)

	flags.StringVar(&target, "target", "", "")
	flags.StringVar(&target, "t", "", "(Short)")

	flags.BoolVar(&version, "version", false, "Print version information and quit.")

	// Parse commandline flag
	if err := flags.Parse(args[1:]); err != nil {
		return ExitCodeError
	}

	// Show version
	if version {
		fmt.Fprintf(cli.errStream, "%s version %s\n", Name, Version)
		return ExitCodeOK
	}

	worker.SetTargetHost(target)

	type user struct {
		AccountName string
		Password    string
	}
	users := []*user{
		&user{
			AccountName: "user1",
			Password:    "user1user1",
		},
		&user{
			AccountName: "user2",
			Password:    "user2user2",
		},
		&user{
			AccountName: "user3",
			Password:    "user3user3",
		},
		&user{
			AccountName: "user4",
			Password:    "user4user4",
		},
		&user{
			AccountName: "user5",
			Password:    "user5user5",
		},
	}
	adminUsers := []*user{
		&user{
			AccountName: "adminuser1",
			Password:    "adminuser1",
		},
		&user{
			AccountName: "adminuser2",
			Password:    "adminuser2",
		},
		&user{
			AccountName: "adminuser3",
			Password:    "adminuser3",
		},
		&user{
			AccountName: "adminuser4",
			Password:    "adminuser4",
		},
	}

	images := []*worker.Asset{
		&worker.Asset{
			MD5:  "8c4d0286cc2c92b418cb6b20fa2055d4",
			Path: "./userdata/img/Cb0e066UYAAwxtT.jpg",
		},
		&worker.Asset{
			MD5:  "e43267883243c297d8f6f66582fc098b",
			Path: "./userdata/img/Cb0rChYUUAAERl8.jpg",
		},
		&worker.Asset{
			MD5:  "623176077a8da7cc7602c132cb91deeb",
			Path: "./userdata/img/Cb5XdejUcAA78Nz.jpg",
		},
		&worker.Asset{
			MD5:  "45d7ba976202a85a90e17282d7f7a781",
			Path: "./userdata/img/CbJLMlcUcAER_Sg.jpg",
		},
		&worker.Asset{
			MD5:  "de906699516c228eee7f025d3e88057b",
			Path: "./userdata/img/CbOuZvjUEAA5r0K.jpg",
		},
		&worker.Asset{
			MD5:  "b50e41b163b501f1aa3cada9a21696c4",
			Path: "./userdata/img/CbT1pABVAAA1OMG.jpg",
		},
		&worker.Asset{
			MD5:  "aa7929fb4ec357063e12701226d0fa3d",
			Path: "./userdata/img/Cba_gezUMAApMPw.jpg",
		},
		&worker.Asset{
			MD5:  "a36c35c8db3e32bde24f9e77d811fecb",
			Path: "./userdata/img/CbyvdPtUcAMiasE.jpg",
		},
		&worker.Asset{
			MD5:  "5985d209ba9d3fe9c0ded4fdbf4cdeb5",
			Path: "./userdata/img/CcCJ26eVAAAf9sh.jpg",
		},
		&worker.Asset{
			MD5:  "c5e0fb9d1132ed936813c07c480730b9",
			Path: "./userdata/img/CcJYpMDUUAA2xXc.jpg",
		},
	}

	timeUp := time.After(30 * time.Second)
	done := make(chan bool)
	quit := false
	var mu sync.RWMutex

	workersC := make(chan *worker.Worker, 20)

	// workersCにworkerを用意しておく
	// キューとして使って並列度が高くなりすぎないようにするのと、
	// 時間が来たらcloseする
	go func() {
		for {
			workersC <- worker.NewWorker()
			mu.RLock()
			if quit {
				done <- true
				break
			}
			mu.RUnlock()
		}
	}()

	toppageNotLogin := worker.NewScenario("GET", "/mypage")
	toppageNotLogin.ExpectedStatusCode = 200
	toppageNotLogin.ExpectedLocation = "/"
	toppageNotLogin.Description = "/mypageは非ログイン時に/にリダイレクトがかかる"
	toppageNotLogin.Checked = true
	toppageNotLogin.CheckFunc = func(w *worker.Worker, body io.Reader) error {
		doc, _ := goquery.NewDocumentFromReader(body)

		exit := 0
		doc.Find("img").EachWithBreak(func(_ int, s *goquery.Selection) bool {
			url, _ := s.Attr("src")
			imgReq := worker.NewScenario("GET", url)
			imgReq.ExpectedStatusCode = 200
			imgReq.Asset = &worker.Asset{}
			imgReq.PlayWithImage(w)
			if exit > 15 {
				return false
			} else {
				exit += 1
				return true
			}
		})

		return nil
	}

	// TOPページに非ログイン状態でひたすらアクセス
	// 画像にもリクエストを送っている
	go func() {
		for {
			toppageNotLogin.Play(<-workersC)
		}
	}()

	login := worker.NewScenario("POST", "/login")
	login.ExpectedStatusCode = 200
	login.ExpectedLocation = "/"
	login.Description = "ログイン"

	mypage := worker.NewScenario("GET", "/mypage")
	mypage.ExpectedStatusCode = 200
	mypage.ExpectedLocation = "/mypage"
	mypage.Description = "ログインして、/mypageに"

	// ログインしてmypageをちゃんと見れるか確認
	go func() {
		for {
			u := users[util.RandomNumber(len(users))]
			login.PostData = map[string]string{
				"account_name": u.AccountName,
				"password":     u.Password,
			}
			w := <-workersC
			login.Play(w)
			mypage.Play(w)
		}
	}()

	postTopImg := worker.NewScenario("POST", "/")
	postTopImg.ExpectedStatusCode = 200
	postTopImg.ExpectedLocation = "/"
	postTopImg.Description = "画像を投稿"

	mypageCheck := worker.NewScenario("GET", "/mypage")
	mypageCheck.ExpectedStatusCode = 200
	mypageCheck.Checked = true

	mypageCheck.CheckFunc = func(w *worker.Worker, body io.Reader) error {
		doc, _ := goquery.NewDocumentFromReader(body)

		url, _ := doc.Find(`img`).First().Attr("src")
		imgReq := worker.NewScenario("GET", url)
		imgReq.ExpectedStatusCode = 200
		imgReq.Checked = true
		imgReq.CheckFunc = func(w *worker.Worker, body io.Reader) error {
			if util.GetMD5ByIO(body) == postTopImg.Asset.MD5 {
				return nil
			} else {
				return fmt.Errorf("Error")
			}
		}
		imgReq.Play(w)

		return nil
	}

	getIndexAfterPostImg := worker.NewScenario("GET", "/")
	getIndexAfterPostImg.ExpectedStatusCode = 200
	getIndexAfterPostImg.Checked = true

	getIndexAfterPostImg.CheckFunc = func(w *worker.Worker, body io.Reader) error {
		doc, _ := goquery.NewDocumentFromReader(body)

		token, _ := doc.Find(`input[name="csrf_token"]`).First().Attr("value")
		postTopImg.PostData = map[string]string{
			"body":       util.RandomLUNStr(util.RandomNumber(20) + 10),
			"csrf_token": token,
			"type":       "image/jpeg",
		}
		postTopImg.PlayWithPostFile(w, "file")
		mypageCheck.Play(w)

		return nil
	}

	postComment := worker.NewScenario("POST", "/comment")
	postComment.ExpectedStatusCode = 200
	postComment.ExpectedLocation = "/"

	getIndexAfterPostComment := worker.NewScenario("GET", "/")
	getIndexAfterPostComment.ExpectedStatusCode = 200
	getIndexAfterPostComment.Checked = true

	getIndexAfterPostComment.CheckFunc = func(w *worker.Worker, body io.Reader) error {
		doc, _ := goquery.NewDocumentFromReader(body)

		token, _ := doc.Find(`input[name="csrf_token"]`).First().Attr("value")
		postID, _ := doc.Find(`input[name="post_id"]`).First().Attr("value")
		postComment.PostData = map[string]string{
			"post_id":    postID,
			"comment":    "comment",
			"csrf_token": token,
		}
		postComment.Play(w)

		return nil
	}

	// ログインして、画像を投稿して、mypageをcheckして、コメントを投稿
	go func() {
		for {
			u := users[util.RandomNumber(len(users))]
			login.PostData = map[string]string{
				"account_name": u.AccountName,
				"password":     u.Password,
			}
			postTopImg.Asset = images[util.RandomNumber(len(images))]
			w := <-workersC
			login.Play(w)
			getIndexAfterPostImg.Play(w)
			getIndexAfterPostComment.Play(w)
		}
	}()

	postRegister := worker.NewScenario("POST", "/register")
	postRegister.ExpectedStatusCode = 200
	postRegister.ExpectedLocation = "/"

	interval := time.Tick(10 * time.Second)

	// ユーザーを作って、ログインして画像を投稿する
	// そのユーザーはBAN機能を使って消される
	go func() {
		for {
			w1 := <-workersC

			deletedStr := util.RandomLUNStr(25)
			deletedUser := map[string]string{
				"account_name": deletedStr,
				"password":     deletedStr,
			}

			postRegister.PostData = deletedUser
			postRegister.Play(w1)
			login.PostData = deletedUser
			login.Play(w1)
			postTopImg.Asset = images[util.RandomNumber(len(images))]
			getIndexAfterPostImg.Play(w1)
			postTopImg.PlayWithPostFile(w1, "file")

			u := adminUsers[util.RandomNumber(len(adminUsers))]
			login.PostData = map[string]string{
				"account_name": u.AccountName,
				"password":     u.Password,
			}
			w2 := <-workersC
			login.Play(w2)

			getAdminBanned := worker.NewScenario("GET", "/admin/banned")
			getAdminBanned.ExpectedStatusCode = 200
			getAdminBanned.ExpectedLocation = "/admin/banned"
			getAdminBanned.Checked = true
			getAdminBanned.CheckFunc = func(w *worker.Worker, body io.Reader) error {
				doc, _ := goquery.NewDocumentFromReader(body)
				token, _ := doc.Find(`input[name="csrf_token"]`).First().Attr("value")
				uid, _ := doc.Find(`input[data-account-name="` + deletedStr + `"]`).First().Attr("value")

				postAdminBanned := worker.NewScenario("POST", "/admin/banned")
				postAdminBanned.ExpectedStatusCode = 200
				postAdminBanned.ExpectedLocation = "/admin/banned"
				postAdminBanned.PostData = map[string]string{
					"uid[]":      uid,
					"csrf_token": token,
				}
				postAdminBanned.Play(w)

				return nil
			}
			getAdminBanned.Play(w2)

			checkBanned := worker.NewScenario("GET", "/")
			checkBanned.ExpectedStatusCode = 200
			checkBanned.Checked = true

			checkBanned.CheckFunc = func(w *worker.Worker, body io.Reader) error {
				doc, _ := goquery.NewDocumentFromReader(body)

				exit := 0
				existErr := false

				doc.Find(`.isu-post-account-name`).EachWithBreak(func(_ int, s *goquery.Selection) bool {
					account_name := strings.TrimSpace(s.Text())
					if account_name == deletedStr {
						existErr = true
						return false
					}
					if exit > 20 {
						return false
					} else {
						exit += 1
						return true
					}
					return true
				})

				if existErr {
					return errors.New("BANされたユーザーの投稿が表示されています")
				}

				return nil
			}
			checkBanned.Play(w2)
			<-interval
		}
	}()

	<-timeUp

	mu.Lock()
	quit = true
	mu.Unlock()

	<-done
	close(workersC)

	fmt.Printf("score: %d, suceess: %d, fail: %d\n",
		score.GetInstance().GetScore(),
		score.GetInstance().GetSucesses(),
		score.GetInstance().GetFails(),
	)

	for _, err := range worker.GetFails() {
		fmt.Println(err)
	}

	return ExitCodeOK
}
<commit_msg>細かい調整<commit_after>package main

import (
	"flag"
	"fmt"
	"io"
	"strings"
	"sync"
	"time"

	"github.com/PuerkitoBio/goquery"
	"github.com/catatsuy/private-isu/benchmarker/score"
	"github.com/catatsuy/private-isu/benchmarker/util"
	"github.com/catatsuy/private-isu/benchmarker/worker"
)

// Exit codes are int values that represent an exit code for a particular error.
const (
	ExitCodeOK    int = 0
	ExitCodeError int = 1 + iota
)

// CLI is the command line object
type CLI struct {
	// outStream and errStream are the stdout and stderr
	// to write message from the CLI.
	outStream, errStream io.Writer
}

// Run invokes the CLI with the given arguments.
func (cli *CLI) Run(args []string) int {
	var (
		target string

		version bool
	)

	// Define option flag parse
	flags := flag.NewFlagSet(Name, flag.ContinueOnError)
	flags.SetOutput(cli.errStream)

	flags.StringVar(&target, "target", "", "")
	flags.StringVar(&target, "t", "", "(Short)")

	flags.BoolVar(&version, "version", false, "Print version information and quit.")

	// Parse commandline flag
	if err := flags.Parse(args[1:]); err != nil {
		return ExitCodeError
	}

	// Show version
	if version {
		fmt.Fprintf(cli.errStream, "%s version %s\n", Name, Version)
		return ExitCodeOK
	}

	worker.SetTargetHost(target)

	type user struct {
		AccountName string
		Password    string
	}
	users := []*user{
		&user{
			AccountName: "user1",
			Password:    "user1user1",
		},
		&user{
			AccountName: "user2",
			Password:    "user2user2",
		},
		&user{
			AccountName: "user3",
			Password:    "user3user3",
		},
		&user{
			AccountName: "user4",
			Password:    "user4user4",
		},
		&user{
			AccountName: "user5",
			Password:    "user5user5",
		},
	}
	adminUsers := []*user{
		&user{
			AccountName: "adminuser1",
			Password:    "adminuser1",
		},
		&user{
			AccountName: "adminuser2",
			Password:    "adminuser2",
		},
		&user{
			AccountName: "adminuser3",
			Password:    "adminuser3",
		},
		&user{
			AccountName: "adminuser4",
			Password:    "adminuser4",
		},
	}

	images := []*worker.Asset{
		&worker.Asset{
			MD5:  "8c4d0286cc2c92b418cb6b20fa2055d4",
			Path: "./userdata/img/Cb0e066UYAAwxtT.jpg",
		},
		&worker.Asset{
			MD5:  "e43267883243c297d8f6f66582fc098b",
			Path: "./userdata/img/Cb0rChYUUAAERl8.jpg",
		},
		&worker.Asset{
			MD5:  "623176077a8da7cc7602c132cb91deeb",
			Path: "./userdata/img/Cb5XdejUcAA78Nz.jpg",
		},
		&worker.Asset{
			MD5:  "45d7ba976202a85a90e17282d7f7a781",
			Path: "./userdata/img/CbJLMlcUcAER_Sg.jpg",
		},
		&worker.Asset{
			MD5:  "de906699516c228eee7f025d3e88057b",
			Path: "./userdata/img/CbOuZvjUEAA5r0K.jpg",
		},
		&worker.Asset{
			MD5:  "b50e41b163b501f1aa3cada9a21696c4",
			Path: "./userdata/img/CbT1pABVAAA1OMG.jpg",
		},
		&worker.Asset{
			MD5:  "aa7929fb4ec357063e12701226d0fa3d",
			Path: "./userdata/img/Cba_gezUMAApMPw.jpg",
		},
		&worker.Asset{
			MD5:  "a36c35c8db3e32bde24f9e77d811fecb",
			Path: "./userdata/img/CbyvdPtUcAMiasE.jpg",
		},
		&worker.Asset{
			MD5:  "5985d209ba9d3fe9c0ded4fdbf4cdeb5",
			Path: "./userdata/img/CcCJ26eVAAAf9sh.jpg",
		},
		&worker.Asset{
			MD5:  "c5e0fb9d1132ed936813c07c480730b9",
			Path: "./userdata/img/CcJYpMDUUAA2xXc.jpg",
		},
	}

	timeUp := time.After(30 * time.Second)
	done := make(chan bool)
	quit := false
	var mu sync.RWMutex

	workersC := make(chan *worker.Worker, 20)

	// workersCにworkerを用意しておく
	// キューとして使って並列度が高くなりすぎないようにするのと、
	// 時間が来たらcloseする
	go func() {
		for {
			workersC <- worker.NewWorker()
			mu.RLock()
			if quit {
				done <- true
				break
			}
			mu.RUnlock()
		}
	}()

	toppageNotLogin := worker.NewScenario("GET", "/mypage")
	toppageNotLogin.ExpectedStatusCode = 200
	toppageNotLogin.ExpectedLocation = "/"
	toppageNotLogin.Description = "/mypageは非ログイン時に/にリダイレクトがかかる"
	toppageNotLogin.Checked = true
	toppageNotLogin.CheckFunc = func(w *worker.Worker, body io.Reader) error {
		doc, _ := goquery.NewDocumentFromReader(body)

		exit := 0
		doc.Find("img").EachWithBreak(func(_ int, s *goquery.Selection) bool {
			url, _ := s.Attr("src")
			imgReq := worker.NewScenario("GET", url)
			imgReq.ExpectedStatusCode = 200
			imgReq.Asset = &worker.Asset{}
			imgReq.PlayWithImage(w)
			if exit > 15 {
				return false
			} else {
				exit += 1
				return true
			}
		})

		return nil
	}

	// TOPページに非ログイン状態でひたすらアクセス
	// 画像にもリクエストを送っている
	go func() {
		for {
			toppageNotLogin.Play(<-workersC)
		}
	}()

	login := worker.NewScenario("POST", "/login")
	login.ExpectedStatusCode = 200
	login.ExpectedLocation = "/"
	login.Description = "ログイン"

	mypage := worker.NewScenario("GET", "/mypage")
	mypage.ExpectedStatusCode = 200
	mypage.ExpectedLocation = "/mypage"
	mypage.Description = "ログインして、/mypageに"

	// ログインしてmypageをちゃんと見れるか確認
	go func() {
		for {
			u := users[util.RandomNumber(len(users))]
			login.PostData = map[string]string{
				"account_name": u.AccountName,
				"password":     u.Password,
			}
			w := <-workersC
			login.Play(w)
			mypage.Play(w)
		}
	}()

	postTopImg := worker.NewScenario("POST", "/")
	postTopImg.ExpectedStatusCode = 200
	postTopImg.ExpectedLocation = "/"
	postTopImg.Description = "画像を投稿"

	mypageCheck := worker.NewScenario("GET", "/mypage")
	mypageCheck.ExpectedStatusCode = 200
	mypageCheck.Checked = true

	mypageCheck.CheckFunc = func(w *worker.Worker, body io.Reader) error {
		doc, _ := goquery.NewDocumentFromReader(body)

		url, _ := doc.Find(`img`).First().Attr("src")
		imgReq := worker.NewScenario("GET", url)
		imgReq.ExpectedStatusCode = 200
		imgReq.Asset = &worker.Asset{}
		imgReq.PlayWithImage(w)

		return nil
	}

	getIndexAfterPostImg := worker.NewScenario("GET", "/")
	getIndexAfterPostImg.ExpectedStatusCode = 200
	getIndexAfterPostImg.Checked = true

	getIndexAfterPostImg.CheckFunc = func(w *worker.Worker, body io.Reader) error {
		doc, _ := goquery.NewDocumentFromReader(body)

		token, _ := doc.Find(`input[name="csrf_token"]`).First().Attr("value")
		postTopImg.PostData = map[string]string{
			"body":       util.RandomLUNStr(util.RandomNumber(20) + 10),
			"csrf_token": token,
			"type":       "image/jpeg",
		}
		postTopImg.PlayWithPostFile(w, "file")
		mypageCheck.Play(w)

		return nil
	}

	postComment := worker.NewScenario("POST", "/comment")
	postComment.ExpectedStatusCode = 200
	postComment.ExpectedLocation = "/"

	getIndexAfterPostComment := worker.NewScenario("GET", "/")
	getIndexAfterPostComment.ExpectedStatusCode = 200
	getIndexAfterPostComment.Checked = true

	getIndexAfterPostComment.CheckFunc = func(w *worker.Worker, body io.Reader) error {
		doc, _ := goquery.NewDocumentFromReader(body)

		token, _ := doc.Find(`input[name="csrf_token"]`).First().Attr("value")
		postID, _ := doc.Find(`input[name="post_id"]`).First().Attr("value")
		postComment.PostData = map[string]string{
			"post_id":    postID,
			"comment":    "comment",
			"csrf_token": token,
		}
		postComment.Play(w)

		return nil
	}

	// ログインして、画像を投稿して、mypageをcheckして、コメントを投稿
	go func() {
		for {
			u := users[util.RandomNumber(len(users))]
			login.PostData = map[string]string{
				"account_name": u.AccountName,
				"password":     u.Password,
			}
			postTopImg.Asset = images[util.RandomNumber(len(images))]
			w := <-workersC
			login.Play(w)
			getIndexAfterPostImg.Play(w)
			getIndexAfterPostComment.Play(w)
		}
	}()

	postRegister := worker.NewScenario("POST", "/register")
	postRegister.ExpectedStatusCode = 200
	postRegister.ExpectedLocation = "/"

	interval := time.Tick(10 * time.Second)

	// ユーザーを作って、ログインして画像を投稿する
	// そのユーザーはBAN機能を使って消される
	go func() {
		for {
			w1 := <-workersC

			deletedStr := util.RandomLUNStr(25)
			deletedUser := map[string]string{
				"account_name": deletedStr,
				"password":     deletedStr,
			}

			postRegister.PostData = deletedUser
			postRegister.Play(w1)
			login.PostData = deletedUser
			login.Play(w1)
			postTopImg.Asset = images[util.RandomNumber(len(images))]
			getIndexAfterPostImg.Play(w1)
			postTopImg.PlayWithPostFile(w1, "file")

			u := adminUsers[util.RandomNumber(len(adminUsers))]
			login.PostData = map[string]string{
				"account_name": u.AccountName,
				"password":     u.Password,
			}
			w2 := <-workersC
			login.Play(w2)

			getAdminBanned := worker.NewScenario("GET", "/admin/banned")
			getAdminBanned.ExpectedStatusCode = 200
			getAdminBanned.ExpectedLocation = "/admin/banned"
			getAdminBanned.Checked = true
			getAdminBanned.CheckFunc = func(w *worker.Worker, body io.Reader) error {
				doc, _ := goquery.NewDocumentFromReader(body)
				token, _ := doc.Find(`input[name="csrf_token"]`).First().Attr("value")
				uid, _ := doc.Find(`input[data-account-name="` + deletedStr + `"]`).First().Attr("value")

				postAdminBanned := worker.NewScenario("POST", "/admin/banned")
				postAdminBanned.ExpectedStatusCode = 200
				postAdminBanned.ExpectedLocation = "/admin/banned"
				postAdminBanned.PostData = map[string]string{
					"uid[]":      uid,
					"csrf_token": token,
				}
				postAdminBanned.Play(w)

				return nil
			}
			getAdminBanned.Play(w2)

			checkBanned := worker.NewScenario("GET", "/")
			checkBanned.ExpectedStatusCode = 200
			checkBanned.Checked = true

			checkBanned.CheckFunc = func(w *worker.Worker, body io.Reader) error {
				doc, _ := goquery.NewDocumentFromReader(body)

				exit := 0
				existErr := false

				doc.Find(`.isu-post-account-name`).EachWithBreak(func(_ int, s *goquery.Selection) bool {
					account_name := strings.TrimSpace(s.Text())
					if account_name == deletedStr {
						existErr = true
						return false
					}
					if exit > 20 {
						return false
					} else {
						exit += 1
						return true
					}
					return true
				})

				if existErr {
					return fmt.Errorf("BANされたユーザーの投稿が表示されています")
				}

				return nil
			}
			checkBanned.Play(w2)
			<-interval
		}
	}()

	<-timeUp

	mu.Lock()
	quit = true
	mu.Unlock()

	<-done
	close(workersC)

	fmt.Printf("score: %d, suceess: %d, fail: %d\n",
		score.GetInstance().GetScore(),
		score.GetInstance().GetSucesses(),
		score.GetInstance().GetFails(),
	)

	for _, err := range worker.GetFails() {
		fmt.Println(err)
	}

	return ExitCodeOK
}
<|endoftext|>


<commit_before>// Package ninow implements a magical sql database ORM.
package ninow

import (
	"database/sql"
	"reflect"
	"strings"
)

type Table struct {
	db    *sql.DB
	rtype reflect.Type

	name    string
	columns []string
	fields  []string
}

func TableFor(row interface{}, db *sql.DB) *Table {
	rtype := reflect.TypeOf(row)
	name := strings.ToLower(rtype.Name()) + "s"

	columns := []string{}
	fields := []string{}
	for i := 0; i < rtype.NumField(); i++ {
		fieldValue := rtype.Field(i)
		//TODO fix this piece
		columns = append(columns, fieldNameToColumnName(fieldValue.Name))
		fields = append(fields, fieldValue.Name)
	}

	return &Table{db, rtype, name, columns, fields}
}

func (t *Table) Select(id int) (interface{}, error) {
	row := t.db.QueryRow("SELECT "+csv(t.columns)+" FROM "+t.name+" WHERE id=?", id)
	value := reflect.New(t.rtype)
	err := row.Scan(fieldPointers(t.fields, value)...)

	return value.Interface(), err
}

func (t *Table) SelectAllBy(column, value string) (interface{}, error) {
	query := "SELECT " + csv(t.columns) + " FROM " + t.name

	if column != "" && value != "" {
		// TODO Make sure this line is safe
		query += " WHERE " + column + "=" + value
	}

	rows, err := t.db.Query(query)
	if err != nil {
		return nil, err
	}

	sliceOfValue := reflect.MakeSlice(reflect.SliceOf(reflect.PtrTo(t.rtype)), 0, 10)

	for rows.Next() {
		value := reflect.New(t.rtype)
		err := rows.Scan(fieldPointers(t.fields, value)...)
		if err != nil {
			return nil, err
		}

		sliceOfValue = reflect.Append(sliceOfValue, value)
	}

	return sliceOfValue.Interface(), nil
}

func (t *Table) Delete(id int) error {
	query := "DELETE FROM " + t.name + " WHERE id =? "

	_, err := t.db.Exec(query, id)
	return err
}
<commit_msg>Add Table.Insert(row interface{}) (int, error)<commit_after>// Package ninow implements a magical sql database ORM.
package ninow

import (
	"database/sql"
	"reflect"
	"strings"
)

type Table struct {
	db    *sql.DB
	rtype reflect.Type

	name    string
	columns []string
	fields  []string
}

func TableFor(row interface{}, db *sql.DB) *Table {
	rtype := reflect.TypeOf(row)
	name := strings.ToLower(rtype.Name()) + "s"

	columns := []string{}
	fields := []string{}
	for i := 0; i < rtype.NumField(); i++ {
		fieldValue := rtype.Field(i)
		//TODO fix this piece
		columns = append(columns, fieldNameToColumnName(fieldValue.Name))
		fields = append(fields, fieldValue.Name)
	}

	return &Table{db, rtype, name, columns, fields}
}

func (t *Table) Select(id int) (interface{}, error) {
	row := t.db.QueryRow("SELECT "+csv(t.columns)+" FROM "+t.name+" WHERE id=?", id)
	value := reflect.New(t.rtype)
	err := row.Scan(fieldPointers(t.fields, value)...)

	return value.Interface(), err
}

func (t *Table) SelectAllBy(column, value string) (interface{}, error) {
	query := "SELECT " + csv(t.columns) + " FROM " + t.name

	if column != "" && value != "" {
		// TODO Make sure this line is safe
		query += " WHERE " + column + "=" + value
	}

	rows, err := t.db.Query(query)
	if err != nil {
		return nil, err
	}

	sliceOfValue := reflect.MakeSlice(reflect.SliceOf(reflect.PtrTo(t.rtype)), 0, 10)

	for rows.Next() {
		value := reflect.New(t.rtype)
		err := rows.Scan(fieldPointers(t.fields, value)...)
		if err != nil {
			return nil, err
		}

		sliceOfValue = reflect.Append(sliceOfValue, value)
	}

	return sliceOfValue.Interface(), nil
}

func (t *Table) Insert(row interface{}) (int, error) {
	query := "INSERT INTO " + t.name
	query += " (" + csv(t.columns[1:]) + ") "
	query += " values (" + csQ(len(t.columns)-1) + ")"

	res, err := t.db.Exec(query, fieldValues(t.fields[1:], reflect.ValueOf(row))...)
	if err != nil {
		return 0, err
	}

	id, err := res.LastInsertId()
	if err != nil {
		return 0, err
	}

	return int(id), nil
}

func (t *Table) Delete(id int) error {
	query := "DELETE FROM " + t.name + " WHERE id =? "

	_, err := t.db.Exec(query, id)
	return err
}
<|endoftext|>


<commit_before>package xorm

import (
	"reflect"
	"sort"
	"strings"
	"time"
)

// xorm SQL types
type SQLType struct {
	Name           string
	DefaultLength  int
	DefaultLength2 int
}

func (s *SQLType) IsText() bool {
	return s.Name == Char || s.Name == Varchar || s.Name == TinyText ||
		s.Name == Text || s.Name == MediumText || s.Name == LongText
}

func (s *SQLType) IsBlob() bool {
	return (s.Name == TinyBlob) || (s.Name == Blob) ||
		s.Name == MediumBlob || s.Name == LongBlob ||
		s.Name == Binary || s.Name == VarBinary || s.Name == Bytea
}

const ()

var (
	Bit       = "BIT"
	TinyInt   = "TINYINT"
	SmallInt  = "SMALLINT"
	MediumInt = "MEDIUMINT"
	Int       = "INT"
	Integer   = "INTEGER"
	BigInt    = "BIGINT"

	Char       = "CHAR"
	Varchar    = "VARCHAR"
	TinyText   = "TINYTEXT"
	Text       = "TEXT"
	MediumText = "MEDIUMTEXT"
	LongText   = "LONGTEXT"

	Date       = "DATE"
	DateTime   = "DATETIME"
	Time       = "TIME"
	TimeStamp  = "TIMESTAMP"
	TimeStampz = "TIMESTAMPZ"

	Decimal = "DECIMAL"
	Numeric = "NUMERIC"

	Real   = "REAL"
	Float  = "FLOAT"
	Double = "DOUBLE"

	Binary     = "BINARY"
	VarBinary  = "VARBINARY"
	TinyBlob   = "TINYBLOB"
	Blob       = "BLOB"
	MediumBlob = "MEDIUMBLOB"
	LongBlob   = "LONGBLOB"
	Bytea      = "BYTEA"

	Bool = "BOOL"

	Serial    = "SERIAL"
	BigSerial = "BIGSERIAL"

	sqlTypes = map[string]bool{
		Bit:       true,
		TinyInt:   true,
		SmallInt:  true,
		MediumInt: true,
		Int:       true,
		Integer:   true,
		BigInt:    true,

		Char:       true,
		Varchar:    true,
		TinyText:   true,
		Text:       true,
		MediumText: true,
		LongText:   true,

		Date:       true,
		DateTime:   true,
		Time:       true,
		TimeStamp:  true,
		TimeStampz: true,

		Decimal: true,
		Numeric: true,

		Binary:     true,
		VarBinary:  true,
		Real:       true,
		Float:      true,
		Double:     true,
		TinyBlob:   true,
		Blob:       true,
		MediumBlob: true,
		LongBlob:   true,
		Bytea:      true,

		Bool: true,

		Serial:    true,
		BigSerial: true,
	}

	intTypes  = sort.StringSlice{"*int", "*int16", "*int32", "*int8"}
	uintTypes = sort.StringSlice{"*uint", "*uint16", "*uint32", "*uint8"}
)

// !nashtsai! treat following var as interal const values, these are used for reflect.TypeOf comparision
var (
	c_EMPTY_STRING       string
	c_BOOL_DEFAULT       bool
	c_BYTE_DEFAULT       byte
	c_COMPLEX64_DEFAULT  complex64
	c_COMPLEX128_DEFAULT complex128
	c_FLOAT32_DEFAULT    float32
	c_FLOAT64_DEFAULT    float64
	c_INT64_DEFAULT      int64
	c_UINT64_DEFAULT     uint64
	c_INT32_DEFAULT      int32
	c_UINT32_DEFAULT     uint32
	c_INT16_DEFAULT      int16
	c_UINT16_DEFAULT     uint16
	c_INT8_DEFAULT       int8
	c_UINT8_DEFAULT      uint8
	c_INT_DEFAULT        int
	c_UINT_DEFAULT       uint
	c_TIME_DEFAULT       time.Time
)

func Type2SQLType(t reflect.Type) (st SQLType) {
	switch k := t.Kind(); k {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
		st = SQLType{Int, 0, 0}
	case reflect.Int64, reflect.Uint64:
		st = SQLType{BigInt, 0, 0}
	case reflect.Float32:
		st = SQLType{Float, 0, 0}
	case reflect.Float64:
		st = SQLType{Double, 0, 0}
	case reflect.Complex64, reflect.Complex128:
		st = SQLType{Varchar, 64, 0}
	case reflect.Array, reflect.Slice, reflect.Map:
		if t.Elem() == reflect.TypeOf(c_BYTE_DEFAULT) {
			st = SQLType{Blob, 0, 0}
		} else {
			st = SQLType{Text, 0, 0}
		}
	case reflect.Bool:
		st = SQLType{Bool, 0, 0}
	case reflect.String:
		st = SQLType{Varchar, 255, 0}
	case reflect.Struct:
		if t == reflect.TypeOf(c_TIME_DEFAULT) {
			st = SQLType{DateTime, 0, 0}
		} else {
			// TODO need to handle association struct
			st = SQLType{Text, 0, 0}
		}
	case reflect.Ptr:
		st, _ = ptrType2SQLType(t)
	default:
		st = SQLType{Text, 0, 0}
	}
	return
}

func ptrType2SQLType(t reflect.Type) (st SQLType, has bool) {
	has = true

	switch t {
	case reflect.TypeOf(&c_EMPTY_STRING):
		st = SQLType{Varchar, 255, 0}
		return
	case reflect.TypeOf(&c_BOOL_DEFAULT):
		st = SQLType{Bool, 0, 0}
	case reflect.TypeOf(&c_COMPLEX64_DEFAULT), reflect.TypeOf(&c_COMPLEX128_DEFAULT):
		st = SQLType{Varchar, 64, 0}
	case reflect.TypeOf(&c_FLOAT32_DEFAULT):
		st = SQLType{Float, 0, 0}
	case reflect.TypeOf(&c_FLOAT64_DEFAULT):
		st = SQLType{Double, 0, 0}
	case reflect.TypeOf(&c_INT64_DEFAULT), reflect.TypeOf(&c_UINT64_DEFAULT):
		st = SQLType{BigInt, 0, 0}
	case reflect.TypeOf(&c_TIME_DEFAULT):
		st = SQLType{DateTime, 0, 0}
	case reflect.TypeOf(&c_INT_DEFAULT), reflect.TypeOf(&c_INT32_DEFAULT), reflect.TypeOf(&c_INT8_DEFAULT), reflect.TypeOf(&c_INT16_DEFAULT), reflect.TypeOf(&c_UINT_DEFAULT), reflect.TypeOf(&c_UINT32_DEFAULT), reflect.TypeOf(&c_UINT8_DEFAULT), reflect.TypeOf(&c_UINT16_DEFAULT):
		st = SQLType{Int, 0, 0}
	default:
		has = false
	}
	return
}

// default sql type change to go types
func SQLType2Type(st SQLType) reflect.Type {
	name := strings.ToUpper(st.Name)
	switch name {
	case Bit, TinyInt, SmallInt, MediumInt, Int, Integer, Serial:
		return reflect.TypeOf(1)
	case BigInt, BigSerial:
		return reflect.TypeOf(int64(1))
	case Float, Real:
		return reflect.TypeOf(float32(1))
	case Double:
		return reflect.TypeOf(float64(1))
	case Char, Varchar, TinyText, Text, MediumText, LongText:
		return reflect.TypeOf("")
	case TinyBlob, Blob, LongBlob, Bytea, Binary, MediumBlob, VarBinary:
		return reflect.TypeOf([]byte{})
	case Bool:
		return reflect.TypeOf(true)
	case DateTime, Date, Time, TimeStamp, TimeStampz:
		return reflect.TypeOf(c_TIME_DEFAULT)
	case Decimal, Numeric:
		return reflect.TypeOf("")
	default:
		return reflect.TypeOf("")
	}
}

const (
	IndexType = iota + 1
	UniqueType
)

// database index
type Index struct {
	Name string
	Type int
	Cols []string
}

// add columns which will be composite index
func (index *Index) AddColumn(cols ...string) {
	for _, col := range cols {
		index.Cols = append(index.Cols, col)
	}
}

// new an index
func NewIndex(name string, indexType int) *Index {
	return &Index{name, indexType, make([]string, 0)}
}

const (
	TWOSIDES = iota + 1
	ONLYTODB
	ONLYFROMDB
)

// database column
type Column struct {
	Name            string
	FieldName       string
	SQLType         SQLType
	Length          int
	Length2         int
	Nullable        bool
	Default         string
	Indexes         map[string]bool
	IsPrimaryKey    bool
	IsAutoIncrement bool
	MapType         int
	IsCreated       bool
	IsUpdated       bool
	IsCascade       bool
	IsVersion       bool
}

// generate column description string according dialect
func (col *Column) String(d dialect) string {
	sql := d.QuoteStr() + col.Name + d.QuoteStr() + " "

	sql += d.SqlType(col) + " "

	if col.IsPrimaryKey {
		sql += "PRIMARY KEY "
		if col.IsAutoIncrement {
			sql += d.AutoIncrStr() + " "
		}
	}

	if col.Nullable {
		sql += "NULL "
	} else {
		sql += "NOT NULL "
	}

	if col.Default != "" {
		sql += "DEFAULT " + col.Default + " "
	}

	return sql
}

func (col *Column) stringNoPk(d dialect) string {
	sql := d.QuoteStr() + col.Name + d.QuoteStr() + " "

	sql += d.SqlType(col) + " "

	if col.Nullable {
		sql += "NULL "
	} else {
		sql += "NOT NULL "
	}

	if col.Default != "" {
		sql += "DEFAULT " + col.Default + " "
	}

	return sql
}

// return col's filed of struct's value
func (col *Column) ValueOf(bean interface{}) reflect.Value {
	var fieldValue reflect.Value
	if strings.Contains(col.FieldName, ".") {
		fields := strings.Split(col.FieldName, ".")
		if len(fields) > 2 {
			return reflect.ValueOf(nil)
		}

		fieldValue = reflect.Indirect(reflect.ValueOf(bean)).FieldByName(fields[0])
		fieldValue = fieldValue.FieldByName(fields[1])
	} else {
		fieldValue = reflect.Indirect(reflect.ValueOf(bean)).FieldByName(col.FieldName)
	}
	return fieldValue
}

// database table
type Table struct {
	Name          string
	Type          reflect.Type
	ColumnsSeq    []string
	Columns       map[string]*Column
	Indexes       map[string]*Index
	PrimaryKeys   []string
	AutoIncrement string
	Created       map[string]bool
	Updated       string
	Version       string
	Cacher        Cacher
}

/*
func NewTable(name string, t reflect.Type) *Table {
    return &Table{Name: name, Type: t,
        ColumnsSeq: make([]string, 0),
        Columns:    make(map[string]*Column),
        Indexes:    make(map[string]*Index),
        Created:    make(map[string]bool),
    }
}*/

// if has primary key, return column
func (table *Table) PKColumns() []*Column {
	columns := make([]*Column, 0)
	for _, name := range table.PrimaryKeys {
		columns = append(columns, table.Columns[strings.ToLower(name)])
	}
	return columns
}

func (table *Table) AutoIncrColumn() *Column {
	return table.Columns[strings.ToLower(table.AutoIncrement)]
}

func (table *Table) VersionColumn() *Column {
	return table.Columns[strings.ToLower(table.Version)]
}

// add a column to table
func (table *Table) AddColumn(col *Column) {
	table.ColumnsSeq = append(table.ColumnsSeq, col.Name)
	table.Columns[strings.ToLower(col.Name)] = col
	if col.IsPrimaryKey {
		table.PrimaryKeys = append(table.PrimaryKeys, col.Name)
	}
	if col.IsAutoIncrement {
		table.AutoIncrement = col.Name
	}
	if col.IsCreated {
		table.Created[col.Name] = true
	}
	if col.IsUpdated {
		table.Updated = col.Name
	}
	if col.IsVersion {
		table.Version = col.Name
	}
}

// add an index or an unique to table
func (table *Table) AddIndex(index *Index) {
	table.Indexes[index.Name] = index
}

func (table *Table) genCols(session *Session, bean interface{}, useCol bool, includeQuote bool) ([]string, []interface{}, error) {
	colNames := make([]string, 0)
	args := make([]interface{}, 0)

	for _, col := range table.Columns {
		lColName := strings.ToLower(col.Name)
		if useCol && !col.IsVersion && !col.IsCreated && !col.IsUpdated {
			if _, ok := session.Statement.columnMap[lColName]; !ok {
				continue
			}
		}
		if col.MapType == ONLYFROMDB {
			continue
		}

		fieldValue := col.ValueOf(bean)
		if col.IsAutoIncrement {
			switch fieldValue.Type().Kind() {
			case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int, reflect.Int64:
				if fieldValue.Int() == 0 {
					continue
				}
			case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint, reflect.Uint64:
				if fieldValue.Uint() == 0 {
					continue
				}
			case reflect.String:
				if len(fieldValue.String()) == 0 {
					continue
				}
			}
		}

		if session.Statement.ColumnStr != "" {
			if _, ok := session.Statement.columnMap[lColName]; !ok {
				continue
			}
		}
		if session.Statement.OmitStr != "" {
			if _, ok := session.Statement.columnMap[lColName]; ok {
				continue
			}
		}

		if (col.IsCreated || col.IsUpdated) && session.Statement.UseAutoTime {
			args = append(args, time.Now())
		} else if col.IsVersion && session.Statement.checkVersion {
			args = append(args, 1)
		} else {
			arg, err := session.value2Interface(col, fieldValue)
			if err != nil {
				return colNames, args, err
			}
			args = append(args, arg)
		}

		if includeQuote {
			colNames = append(colNames, session.Engine.Quote(col.Name)+" = ?")
		} else {
			colNames = append(colNames, col.Name)
		}
	}
	return colNames, args, nil
}

// Conversion is an interface. A type implements Conversion will according
// the custom method to fill into database and retrieve from database.
type Conversion interface {
	FromDB([]byte) error
	ToDB() ([]byte, error)
}
<commit_msg>bug fixed<commit_after>package xorm

import (
	"reflect"
	"sort"
	"strings"
	"time"
)

// xorm SQL types
type SQLType struct {
	Name           string
	DefaultLength  int
	DefaultLength2 int
}

func (s *SQLType) IsText() bool {
	return s.Name == Char || s.Name == Varchar || s.Name == TinyText ||
		s.Name == Text || s.Name == MediumText || s.Name == LongText
}

func (s *SQLType) IsBlob() bool {
	return (s.Name == TinyBlob) || (s.Name == Blob) ||
		s.Name == MediumBlob || s.Name == LongBlob ||
		s.Name == Binary || s.Name == VarBinary || s.Name == Bytea
}

const ()

var (
	Bit       = "BIT"
	TinyInt   = "TINYINT"
	SmallInt  = "SMALLINT"
	MediumInt = "MEDIUMINT"
	Int       = "INT"
	Integer   = "INTEGER"
	BigInt    = "BIGINT"

	Char       = "CHAR"
	Varchar    = "VARCHAR"
	TinyText   = "TINYTEXT"
	Text       = "TEXT"
	MediumText = "MEDIUMTEXT"
	LongText   = "LONGTEXT"

	Date       = "DATE"
	DateTime   = "DATETIME"
	Time       = "TIME"
	TimeStamp  = "TIMESTAMP"
	TimeStampz = "TIMESTAMPZ"

	Decimal = "DECIMAL"
	Numeric = "NUMERIC"

	Real   = "REAL"
	Float  = "FLOAT"
	Double = "DOUBLE"

	Binary     = "BINARY"
	VarBinary  = "VARBINARY"
	TinyBlob   = "TINYBLOB"
	Blob       = "BLOB"
	MediumBlob = "MEDIUMBLOB"
	LongBlob   = "LONGBLOB"
	Bytea      = "BYTEA"

	Bool = "BOOL"

	Serial    = "SERIAL"
	BigSerial = "BIGSERIAL"

	sqlTypes = map[string]bool{
		Bit:       true,
		TinyInt:   true,
		SmallInt:  true,
		MediumInt: true,
		Int:       true,
		Integer:   true,
		BigInt:    true,

		Char:       true,
		Varchar:    true,
		TinyText:   true,
		Text:       true,
		MediumText: true,
		LongText:   true,

		Date:       true,
		DateTime:   true,
		Time:       true,
		TimeStamp:  true,
		TimeStampz: true,

		Decimal: true,
		Numeric: true,

		Binary:     true,
		VarBinary:  true,
		Real:       true,
		Float:      true,
		Double:     true,
		TinyBlob:   true,
		Blob:       true,
		MediumBlob: true,
		LongBlob:   true,
		Bytea:      true,

		Bool: true,

		Serial:    true,
		BigSerial: true,
	}

	intTypes  = sort.StringSlice{"*int", "*int16", "*int32", "*int8"}
	uintTypes = sort.StringSlice{"*uint", "*uint16", "*uint32", "*uint8"}
)

// !nashtsai! treat following var as interal const values, these are used for reflect.TypeOf comparision
var (
	c_EMPTY_STRING       string
	c_BOOL_DEFAULT       bool
	c_BYTE_DEFAULT       byte
	c_COMPLEX64_DEFAULT  complex64
	c_COMPLEX128_DEFAULT complex128
	c_FLOAT32_DEFAULT    float32
	c_FLOAT64_DEFAULT    float64
	c_INT64_DEFAULT      int64
	c_UINT64_DEFAULT     uint64
	c_INT32_DEFAULT      int32
	c_UINT32_DEFAULT     uint32
	c_INT16_DEFAULT      int16
	c_UINT16_DEFAULT     uint16
	c_INT8_DEFAULT       int8
	c_UINT8_DEFAULT      uint8
	c_INT_DEFAULT        int
	c_UINT_DEFAULT       uint
	c_TIME_DEFAULT       time.Time
)

func Type2SQLType(t reflect.Type) (st SQLType) {
	switch k := t.Kind(); k {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
		st = SQLType{Int, 0, 0}
	case reflect.Int64, reflect.Uint64:
		st = SQLType{BigInt, 0, 0}
	case reflect.Float32:
		st = SQLType{Float, 0, 0}
	case reflect.Float64:
		st = SQLType{Double, 0, 0}
	case reflect.Complex64, reflect.Complex128:
		st = SQLType{Varchar, 64, 0}
	case reflect.Array, reflect.Slice, reflect.Map:
		if t.Elem() == reflect.TypeOf(c_BYTE_DEFAULT) {
			st = SQLType{Blob, 0, 0}
		} else {
			st = SQLType{Text, 0, 0}
		}
	case reflect.Bool:
		st = SQLType{Bool, 0, 0}
	case reflect.String:
		st = SQLType{Varchar, 255, 0}
	case reflect.Struct:
		if t == reflect.TypeOf(c_TIME_DEFAULT) {
			st = SQLType{DateTime, 0, 0}
		} else {
			// TODO need to handle association struct
			st = SQLType{Text, 0, 0}
		}
	case reflect.Ptr:
		st, _ = ptrType2SQLType(t)
	default:
		st = SQLType{Text, 0, 0}
	}
	return
}

func ptrType2SQLType(t reflect.Type) (st SQLType, has bool) {
	has = true

	switch t {
	case reflect.TypeOf(&c_EMPTY_STRING):
		st = SQLType{Varchar, 255, 0}
		return
	case reflect.TypeOf(&c_BOOL_DEFAULT):
		st = SQLType{Bool, 0, 0}
	case reflect.TypeOf(&c_COMPLEX64_DEFAULT), reflect.TypeOf(&c_COMPLEX128_DEFAULT):
		st = SQLType{Varchar, 64, 0}
	case reflect.TypeOf(&c_FLOAT32_DEFAULT):
		st = SQLType{Float, 0, 0}
	case reflect.TypeOf(&c_FLOAT64_DEFAULT):
		st = SQLType{Double, 0, 0}
	case reflect.TypeOf(&c_INT64_DEFAULT), reflect.TypeOf(&c_UINT64_DEFAULT):
		st = SQLType{BigInt, 0, 0}
	case reflect.TypeOf(&c_TIME_DEFAULT):
		st = SQLType{DateTime, 0, 0}
	case reflect.TypeOf(&c_INT_DEFAULT), reflect.TypeOf(&c_INT32_DEFAULT), reflect.TypeOf(&c_INT8_DEFAULT), reflect.TypeOf(&c_INT16_DEFAULT), reflect.TypeOf(&c_UINT_DEFAULT), reflect.TypeOf(&c_UINT32_DEFAULT), reflect.TypeOf(&c_UINT8_DEFAULT), reflect.TypeOf(&c_UINT16_DEFAULT):
		st = SQLType{Int, 0, 0}
	default:
		has = false
	}
	return
}

// default sql type change to go types
func SQLType2Type(st SQLType) reflect.Type {
	name := strings.ToUpper(st.Name)
	switch name {
	case Bit, TinyInt, SmallInt, MediumInt, Int, Integer, Serial:
		return reflect.TypeOf(1)
	case BigInt, BigSerial:
		return reflect.TypeOf(int64(1))
	case Float, Real:
		return reflect.TypeOf(float32(1))
	case Double:
		return reflect.TypeOf(float64(1))
	case Char, Varchar, TinyText, Text, MediumText, LongText:
		return reflect.TypeOf("")
	case TinyBlob, Blob, LongBlob, Bytea, Binary, MediumBlob, VarBinary:
		return reflect.TypeOf([]byte{})
	case Bool:
		return reflect.TypeOf(true)
	case DateTime, Date, Time, TimeStamp, TimeStampz:
		return reflect.TypeOf(c_TIME_DEFAULT)
	case Decimal, Numeric:
		return reflect.TypeOf("")
	default:
		return reflect.TypeOf("")
	}
}

const (
	IndexType = iota + 1
	UniqueType
)

// database index
type Index struct {
	Name string
	Type int
	Cols []string
}

// add columns which will be composite index
func (index *Index) AddColumn(cols ...string) {
	for _, col := range cols {
		index.Cols = append(index.Cols, col)
	}
}

// new an index
func NewIndex(name string, indexType int) *Index {
	return &Index{name, indexType, make([]string, 0)}
}

const (
	TWOSIDES = iota + 1
	ONLYTODB
	ONLYFROMDB
)

// database column
type Column struct {
	Name            string
	FieldName       string
	SQLType         SQLType
	Length          int
	Length2         int
	Nullable        bool
	Default         string
	Indexes         map[string]bool
	IsPrimaryKey    bool
	IsAutoIncrement bool
	MapType         int
	IsCreated       bool
	IsUpdated       bool
	IsCascade       bool
	IsVersion       bool
}

// generate column description string according dialect
func (col *Column) String(d dialect) string {
	sql := d.QuoteStr() + col.Name + d.QuoteStr() + " "

	sql += d.SqlType(col) + " "

	if col.IsPrimaryKey {
		sql += "PRIMARY KEY "
		if col.IsAutoIncrement {
			sql += d.AutoIncrStr() + " "
		}
	}

	if col.Nullable {
		sql += "NULL "
	} else {
		sql += "NOT NULL "
	}

	if col.Default != "" {
		sql += "DEFAULT " + col.Default + " "
	} else if col.IsVersion {
		sql += "DEFAULT 1 "
	}

	return sql
}

func (col *Column) stringNoPk(d dialect) string {
	sql := d.QuoteStr() + col.Name + d.QuoteStr() + " "

	sql += d.SqlType(col) + " "

	if col.Nullable {
		sql += "NULL "
	} else {
		sql += "NOT NULL "
	}

	if col.Default != "" {
		sql += "DEFAULT " + col.Default + " "
	} else if col.IsVersion {
		sql += "DEFAULT 1 "
	}

	return sql
}

// return col's filed of struct's value
func (col *Column) ValueOf(bean interface{}) reflect.Value {
	var fieldValue reflect.Value
	if strings.Contains(col.FieldName, ".") {
		fields := strings.Split(col.FieldName, ".")
		if len(fields) > 2 {
			return reflect.ValueOf(nil)
		}

		fieldValue = reflect.Indirect(reflect.ValueOf(bean)).FieldByName(fields[0])
		fieldValue = fieldValue.FieldByName(fields[1])
	} else {
		fieldValue = reflect.Indirect(reflect.ValueOf(bean)).FieldByName(col.FieldName)
	}
	return fieldValue
}

// database table
type Table struct {
	Name          string
	Type          reflect.Type
	ColumnsSeq    []string
	Columns       map[string]*Column
	Indexes       map[string]*Index
	PrimaryKeys   []string
	AutoIncrement string
	Created       map[string]bool
	Updated       string
	Version       string
	Cacher        Cacher
}

/*
func NewTable(name string, t reflect.Type) *Table {
    return &Table{Name: name, Type: t,
        ColumnsSeq: make([]string, 0),
        Columns:    make(map[string]*Column),
        Indexes:    make(map[string]*Index),
        Created:    make(map[string]bool),
    }
}*/

// if has primary key, return column
func (table *Table) PKColumns() []*Column {
	columns := make([]*Column, 0)
	for _, name := range table.PrimaryKeys {
		columns = append(columns, table.Columns[strings.ToLower(name)])
	}
	return columns
}

func (table *Table) AutoIncrColumn() *Column {
	return table.Columns[strings.ToLower(table.AutoIncrement)]
}

func (table *Table) VersionColumn() *Column {
	return table.Columns[strings.ToLower(table.Version)]
}

// add a column to table
func (table *Table) AddColumn(col *Column) {
	table.ColumnsSeq = append(table.ColumnsSeq, col.Name)
	table.Columns[strings.ToLower(col.Name)] = col
	if col.IsPrimaryKey {
		table.PrimaryKeys = append(table.PrimaryKeys, col.Name)
	}
	if col.IsAutoIncrement {
		table.AutoIncrement = col.Name
	}
	if col.IsCreated {
		table.Created[col.Name] = true
	}
	if col.IsUpdated {
		table.Updated = col.Name
	}
	if col.IsVersion {
		table.Version = col.Name
	}
}

// add an index or an unique to table
func (table *Table) AddIndex(index *Index) {
	table.Indexes[index.Name] = index
}

func (table *Table) genCols(session *Session, bean interface{}, useCol bool, includeQuote bool) ([]string, []interface{}, error) {
	colNames := make([]string, 0)
	args := make([]interface{}, 0)

	for _, col := range table.Columns {
		lColName := strings.ToLower(col.Name)
		if useCol && !col.IsVersion && !col.IsCreated && !col.IsUpdated {
			if _, ok := session.Statement.columnMap[lColName]; !ok {
				continue
			}
		}
		if col.MapType == ONLYFROMDB {
			continue
		}

		fieldValue := col.ValueOf(bean)
		if col.IsAutoIncrement {
			switch fieldValue.Type().Kind() {
			case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int, reflect.Int64:
				if fieldValue.Int() == 0 {
					continue
				}
			case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint, reflect.Uint64:
				if fieldValue.Uint() == 0 {
					continue
				}
			case reflect.String:
				if len(fieldValue.String()) == 0 {
					continue
				}
			}
		}

		if session.Statement.ColumnStr != "" {
			if _, ok := session.Statement.columnMap[lColName]; !ok {
				continue
			}
		}
		if session.Statement.OmitStr != "" {
			if _, ok := session.Statement.columnMap[lColName]; ok {
				continue
			}
		}

		if (col.IsCreated || col.IsUpdated) && session.Statement.UseAutoTime {
			args = append(args, time.Now())
		} else if col.IsVersion && session.Statement.checkVersion {
			args = append(args, 1)
		} else {
			arg, err := session.value2Interface(col, fieldValue)
			if err != nil {
				return colNames, args, err
			}
			args = append(args, arg)
		}

		if includeQuote {
			colNames = append(colNames, session.Engine.Quote(col.Name)+" = ?")
		} else {
			colNames = append(colNames, col.Name)
		}
	}
	return colNames, args, nil
}

// Conversion is an interface. A type implements Conversion will according
// the custom method to fill into database and retrieve from database.
type Conversion interface {
	FromDB([]byte) error
	ToDB() ([]byte, error)
}
<|endoftext|>