<commit_before>package volman_test

import (
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"time"

	"github.com/nu7hatch/gouuid"

	"code.cloudfoundry.org/bbs/models"
	"code.cloudfoundry.org/clock"
	"code.cloudfoundry.org/executor"
	executorinit "code.cloudfoundry.org/executor/initializer"
	"code.cloudfoundry.org/lager"
	"code.cloudfoundry.org/lager/lagertest"
	"github.com/cloudfoundry-incubator/cf-test-helpers/generator"
	. "github.com/onsi/ginkgo"
	ginkgoconfig "github.com/onsi/ginkgo/config"
	. "github.com/onsi/gomega"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/ginkgomon"
	"github.com/tedsuo/ifrit/grouper"
	"code.cloudfoundry.org/voldriver"
)

// these tests could eventually be folded into ../executor/executor_garden_test.go
var _ = Describe("Executor/Garden/Volman", func() {
	var (
		executorClient executor.Client
		process        ifrit.Process
		runner         ifrit.Runner
		cachePath      string
		config         executorinit.Configuration
		logger         lager.Logger
		err            error
	)

	getContainer := func(guid string) executor.Container {
		container, err := executorClient.GetContainer(logger, guid)
		Expect(err).NotTo(HaveOccurred())

		return container
	}

	containerStatePoller := func(guid string) func() executor.State {
		return func() executor.State {
			return getContainer(guid).State
		}
	}
	BeforeEach(func() {
		logger = lagertest.NewTestLogger("volman-executor-tests")

		cachePath, err = ioutil.TempDir("", "executor-tmp")
		Expect(err).NotTo(HaveOccurred())

		config = executorinit.DefaultConfiguration
		config.VolmanDriverPaths = []string{path.Join(componentMaker.VolmanDriverConfigDir, fmt.Sprintf("node-%d", ginkgoconfig.GinkgoConfig.ParallelNode))}
		config.GardenNetwork = "tcp"
		config.GardenAddr = componentMaker.Addresses.GardenLinux
		config.HealthyMonitoringInterval = time.Second
		config.UnhealthyMonitoringInterval = 100 * time.Millisecond
		config.ContainerOwnerName = "executor" + generator.RandomName()
		config.GardenHealthcheckProcessPath = "/bin/sh"
		config.GardenHealthcheckProcessArgs = []string{"-c", "echo", "checking health"}
		config.GardenHealthcheckProcessUser = "vcap"

	})

	Describe("Starting up", func() {
		var (
			//ownerName string
		)

		BeforeEach(func() {
			//ownerName = "executor"

			os.RemoveAll(cachePath)

			executorClient, runner = initializeExecutor(logger, config)

			_, err = gardenClient.Capacity()
			Expect(err).NotTo(HaveOccurred())
		})

		JustBeforeEach(func() {
			process = ginkgomon.Invoke(runner)
		})

		Context("when there are volumes", func() {

			BeforeEach(func() {
				errorResponse := driverClient.Create(logger, voldriver.CreateRequest{
					Name: "a-volume",
					Opts: map[string]interface{}{
						"volume_id": "a-volume",
					},
				})
				Expect(errorResponse.Err).To(BeEmpty())

				mountResponse := driverClient.Mount(logger, voldriver.MountRequest{
					Name: "a-volume",
				})
				Expect(mountResponse.Err).To(BeEmpty())
			})

			It("deletes the volumes", func() {
				listResponse := driverClient.List(logger)
				Expect(listResponse.Err).To(BeEmpty())
				Expect(len(listResponse.Volumes)).To(Equal(1))
				Expect(listResponse.Volumes[0].Mountpoint).To(BeEmpty())
			})
		})
	})

	Context("when volman is not correctly configured", func() {
		BeforeEach(func() {
			var invalidDriverPath = []string{""}
			config.VolmanDriverPaths = invalidDriverPath

			executorClient, runner = initializeExecutor(logger, config)

			_, err = gardenClient.Capacity()
			Expect(err).NotTo(HaveOccurred())
		})

		AfterEach(func() {
			if executorClient != nil {
				executorClient.Cleanup(logger)
			}

			if process != nil {
				ginkgomon.Interrupt(process)
			}

			os.RemoveAll(cachePath)
		})

		Context("when allocating a container without any volman mounts", func() {
			var (
				guid               string
				allocationRequest  executor.AllocationRequest
				allocationFailures []executor.AllocationFailure
			)

			JustBeforeEach(func() {
				process = ginkgomon.Invoke(runner)
			})

			BeforeEach(func() {
				id, err := uuid.NewV4()
				Expect(err).NotTo(HaveOccurred())
				guid = id.String()

				tags := executor.Tags{"some-tag": "some-value"}

				allocationRequest = executor.NewAllocationRequest(guid, &executor.Resource{}, tags)

				allocationFailures, err = executorClient.AllocateContainers(logger, []executor.AllocationRequest{allocationRequest})

				Expect(err).NotTo(HaveOccurred())
				Expect(allocationFailures).To(BeEmpty())
			})

			Context("when running the container", func() {
				var (
					runReq executor.RunRequest
				)

				BeforeEach(func() {
					runInfo := executor.RunInfo{
						Action: models.WrapAction(&models.RunAction{
							Path: "/bin/touch",
							User: "root",
							Args: []string{"/tmp"},
						}),
					}
					runReq = executor.NewRunRequest(guid, &runInfo, executor.Tags{})
				})

				It("container start should succeed", func() {
					err := executorClient.RunContainer(logger, &runReq)
					Expect(err).NotTo(HaveOccurred())
					Eventually(containerStatePoller(guid)).Should(Equal(executor.StateCompleted))
					Expect(getContainer(guid).RunResult.Failed).Should(BeFalse())
				})
			})
		})
	})

	Context("when volman is correctly configured", func() {
		BeforeEach(func() {
			executorClient, runner = initializeExecutor(logger, config)

			_, err = gardenClient.Capacity()
			Expect(err).NotTo(HaveOccurred())
		})

		AfterEach(func() {
			if executorClient != nil {
				executorClient.Cleanup(logger)
			}

			if process != nil {
				ginkgomon.Interrupt(process)
			}

			os.RemoveAll(cachePath)
		})

		Context("when running an executor in front of garden and volman", func() {
			BeforeEach(func() {
				process = ginkgomon.Invoke(runner)
			})

			Context("when allocating a container", func() {
				var (
					guid               string
					allocationRequest  executor.AllocationRequest
					allocationFailures []executor.AllocationFailure
				)

				BeforeEach(func() {
					id, err := uuid.NewV4()
					Expect(err).NotTo(HaveOccurred())
					guid = id.String()

					tags := executor.Tags{"some-tag": "some-value"}

					allocationRequest = executor.NewAllocationRequest(guid, &executor.Resource{}, tags)

					allocationFailures, err = executorClient.AllocateContainers(logger, []executor.AllocationRequest{allocationRequest})

					Expect(err).NotTo(HaveOccurred())
					Expect(allocationFailures).To(BeEmpty())
				})

				Context("when running the container", func() {
					var (
						runReq       executor.RunRequest
						volumeId     string
						fileName     string
						volumeMounts []executor.VolumeMount
					)

					BeforeEach(func() {
						fileName = fmt.Sprintf("testfile-%d.txt", time.Now().UnixNano())
						volumeId = fmt.Sprintf("some-volumeID-%d", time.Now().UnixNano())
						someConfig := map[string]interface{}{"volume_id": volumeId}
						volumeMounts = []executor.VolumeMount{executor.VolumeMount{ContainerPath: "/testmount", Driver: "localdriver", VolumeId: volumeId, Config: someConfig, Mode: executor.BindMountModeRW}}
						runInfo := executor.RunInfo{
							VolumeMounts: volumeMounts,
							Privileged:   true,
							Action: models.WrapAction(&models.RunAction{
								Path: "/bin/touch",
								User: "root",
								Args: []string{"/testmount/" + fileName},
							}),
						}
						runReq = executor.NewRunRequest(guid, &runInfo, executor.Tags{})
					})

					Context("when successfully mounting a RW Mode volume", func() {
						BeforeEach(func() {
							err := executorClient.RunContainer(logger, &runReq)
							Expect(err).NotTo(HaveOccurred())
							Eventually(containerStatePoller(guid)).Should(Equal(executor.StateCompleted))
							Expect(getContainer(guid).RunResult.Failed).Should(BeFalse())
						})

						AfterEach(func() {
							err := executorClient.DeleteContainer(logger, guid)
							Expect(err).NotTo(HaveOccurred())

							err = os.RemoveAll(path.Join(componentMaker.VolmanDriverConfigDir, "_volumes", volumeId))
							Expect(err).ToNot(HaveOccurred())

							files, err := filepath.Glob(path.Join(componentMaker.VolmanDriverConfigDir, "_volumes", volumeId, fileName))
							Expect(err).ToNot(HaveOccurred())
							Expect(len(files)).To(Equal(0))
						})

						It("can write files to the mounted volume", func() {
							By("we expect the file it wrote to be available outside of the container")
							volmanPath := path.Join(componentMaker.VolmanDriverConfigDir, "_volumes", volumeId, fileName)
							files, err := filepath.Glob(volmanPath)
							Expect(err).ToNot(HaveOccurred())
							Expect(len(files)).To(Equal(1))
						})

						Context("when a second container using the same volume loads and then unloads", func() {
							var (
								runReq2   executor.RunRequest
								fileName2 string
								guid2     string
							)
							BeforeEach(func() {
								id, err := uuid.NewV4()
								Expect(err).NotTo(HaveOccurred())
								guid2 = id.String()

								tags := executor.Tags{"some-tag": "some-value"}
								allocationRequest2 := executor.NewAllocationRequest(guid2, &executor.Resource{}, tags)
								allocationFailures, err := executorClient.AllocateContainers(logger, []executor.AllocationRequest{allocationRequest2})
								Expect(err).NotTo(HaveOccurred())
								Expect(allocationFailures).To(BeEmpty())

								fileName2 = fmt.Sprintf("testfile2-%d.txt", time.Now().UnixNano())
								runInfo := executor.RunInfo{
									VolumeMounts: volumeMounts,
									Privileged:   true,
									Action: models.WrapAction(&models.RunAction{
										Path: "/bin/touch",
										User: "root",
										Args: []string{"/testmount/" + fileName2},
									}),
								}
								runReq2 = executor.NewRunRequest(guid2, &runInfo, executor.Tags{})
								err = executorClient.RunContainer(logger, &runReq2)
								Expect(err).NotTo(HaveOccurred())
								Eventually(containerStatePoller(guid2)).Should(Equal(executor.StateCompleted))
								Expect(getContainer(guid2).RunResult.Failed).Should(BeFalse())
								err = executorClient.DeleteContainer(logger, guid2)
								Expect(err).NotTo(HaveOccurred())
							})
							It("can still read files on the mounted volume for the first container", func() {
								volmanPath := path.Join(componentMaker.VolmanDriverConfigDir, "_volumes", volumeId, fileName)
								files, err := filepath.Glob(volmanPath)
								Expect(err).ToNot(HaveOccurred())
								Expect(len(files)).To(Equal(1))
							})
						})

					})
				})
			})
		})
	})
})

func initializeExecutor(logger lager.Logger, config executorinit.Configuration) (executor.Client, ifrit.Runner) {
	var executorMembers grouper.Members
	var err error
	var executorClient executor.Client
	executorClient, executorMembers, err = executorinit.Initialize(logger, config, clock.NewClock())
	Expect(err).NotTo(HaveOccurred())

	return executorClient, grouper.NewParallel(os.Kill, executorMembers)
}
<commit_msg>Add missing inigo tests for voldriver logic that removes mounts at startup [#130659367](https://www.pivotaltracker.com/story/show/130659367)<commit_after>package volman_test

import (
	"context"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"time"

	"github.com/nu7hatch/gouuid"

	"code.cloudfoundry.org/bbs/models"
	"code.cloudfoundry.org/clock"
	"code.cloudfoundry.org/executor"
	executorinit "code.cloudfoundry.org/executor/initializer"
	"code.cloudfoundry.org/lager"
	"code.cloudfoundry.org/lager/lagertest"
	"code.cloudfoundry.org/voldriver"
	"code.cloudfoundry.org/voldriver/driverhttp"
	"github.com/cloudfoundry-incubator/cf-test-helpers/generator"
	. "github.com/onsi/ginkgo"
	ginkgoconfig "github.com/onsi/ginkgo/config"
	. "github.com/onsi/gomega"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/ginkgomon"
	"github.com/tedsuo/ifrit/grouper"
)

// these tests could eventually be folded into ../executor/executor_garden_test.go
var _ = Describe("Executor/Garden/Volman", func() {
	var (
		executorClient executor.Client
		process        ifrit.Process
		runner         ifrit.Runner
		cachePath      string
		config         executorinit.Configuration
		logger         lager.Logger
		env            voldriver.Env
		err            error
	)

	getContainer := func(guid string) executor.Container {
		container, err := executorClient.GetContainer(logger, guid)
		Expect(err).NotTo(HaveOccurred())

		return container
	}

	containerStatePoller := func(guid string) func() executor.State {
		return func() executor.State {
			return getContainer(guid).State
		}
	}
	BeforeEach(func() {
		logger = lagertest.NewTestLogger("volman-executor-tests")
		ctx := context.TODO()
		env = driverhttp.NewHttpDriverEnv(logger, ctx)

		cachePath, err = ioutil.TempDir("", "executor-tmp")
		Expect(err).NotTo(HaveOccurred())

		config = executorinit.DefaultConfiguration
		config.VolmanDriverPaths = []string{path.Join(componentMaker.VolmanDriverConfigDir, fmt.Sprintf("node-%d", ginkgoconfig.GinkgoConfig.ParallelNode))}
		config.GardenNetwork = "tcp"
		config.GardenAddr = componentMaker.Addresses.GardenLinux
		config.HealthyMonitoringInterval = time.Second
		config.UnhealthyMonitoringInterval = 100 * time.Millisecond
		config.ContainerOwnerName = "executor" + generator.RandomName()
		config.GardenHealthcheckProcessPath = "/bin/sh"
		config.GardenHealthcheckProcessArgs = []string{"-c", "echo", "checking health"}
		config.GardenHealthcheckProcessUser = "vcap"

	})

	Describe("Starting up", func() {
		var (
		//ownerName string
		)

		BeforeEach(func() {
			//ownerName = "executor"

			os.RemoveAll(cachePath)

			executorClient, runner = initializeExecutor(logger, config)

			_, err = gardenClient.Capacity()
			Expect(err).NotTo(HaveOccurred())
		})

		JustBeforeEach(func() {
			process = ginkgomon.Invoke(runner)
		})

		Context("when there are volumes", func() {

			BeforeEach(func() {
				errorResponse := driverClient.Create(env, voldriver.CreateRequest{
					Name: "a-volume",
					Opts: map[string]interface{}{
						"volume_id": "a-volume",
					},
				})
				Expect(errorResponse.Err).To(BeEmpty())

				mountResponse := driverClient.Mount(env, voldriver.MountRequest{
					Name: "a-volume",
				})
				Expect(mountResponse.Err).To(BeEmpty())
			})

			It("deletes the volumes", func() {
				listResponse := driverClient.List(env)
				Expect(listResponse.Err).To(BeEmpty())
				Expect(len(listResponse.Volumes)).To(Equal(1))
				Expect(listResponse.Volumes[0].Mountpoint).To(BeEmpty())
			})
		})
	})

	Context("when volman is not correctly configured", func() {
		BeforeEach(func() {
			var invalidDriverPath = []string{""}
			config.VolmanDriverPaths = invalidDriverPath

			executorClient, runner = initializeExecutor(logger, config)

			_, err = gardenClient.Capacity()
			Expect(err).NotTo(HaveOccurred())
		})

		AfterEach(func() {
			if executorClient != nil {
				executorClient.Cleanup(logger)
			}

			if process != nil {
				ginkgomon.Interrupt(process)
			}

			os.RemoveAll(cachePath)
		})

		Context("when allocating a container without any volman mounts", func() {
			var (
				guid               string
				allocationRequest  executor.AllocationRequest
				allocationFailures []executor.AllocationFailure
			)

			JustBeforeEach(func() {
				process = ginkgomon.Invoke(runner)
			})

			BeforeEach(func() {
				id, err := uuid.NewV4()
				Expect(err).NotTo(HaveOccurred())
				guid = id.String()

				tags := executor.Tags{"some-tag": "some-value"}

				allocationRequest = executor.NewAllocationRequest(guid, &executor.Resource{}, tags)

				allocationFailures, err = executorClient.AllocateContainers(logger, []executor.AllocationRequest{allocationRequest})

				Expect(err).NotTo(HaveOccurred())
				Expect(allocationFailures).To(BeEmpty())
			})

			Context("when running the container", func() {
				var (
					runReq executor.RunRequest
				)

				BeforeEach(func() {
					runInfo := executor.RunInfo{
						Action: models.WrapAction(&models.RunAction{
							Path: "/bin/touch",
							User: "root",
							Args: []string{"/tmp"},
						}),
					}
					runReq = executor.NewRunRequest(guid, &runInfo, executor.Tags{})
				})

				It("container start should succeed", func() {
					err := executorClient.RunContainer(logger, &runReq)
					Expect(err).NotTo(HaveOccurred())
					Eventually(containerStatePoller(guid)).Should(Equal(executor.StateCompleted))
					Expect(getContainer(guid).RunResult.Failed).Should(BeFalse())
				})
			})
		})
	})

	Context("when volman is correctly configured", func() {
		BeforeEach(func() {
			executorClient, runner = initializeExecutor(logger, config)

			_, err = gardenClient.Capacity()
			Expect(err).NotTo(HaveOccurred())
		})

		AfterEach(func() {
			if executorClient != nil {
				executorClient.Cleanup(logger)
			}

			if process != nil {
				ginkgomon.Interrupt(process)
			}

			os.RemoveAll(cachePath)
		})

		Context("when running an executor in front of garden and volman", func() {
			BeforeEach(func() {
				process = ginkgomon.Invoke(runner)
			})

			Context("when allocating a container", func() {
				var (
					guid               string
					allocationRequest  executor.AllocationRequest
					allocationFailures []executor.AllocationFailure
				)

				BeforeEach(func() {
					id, err := uuid.NewV4()
					Expect(err).NotTo(HaveOccurred())
					guid = id.String()

					tags := executor.Tags{"some-tag": "some-value"}

					allocationRequest = executor.NewAllocationRequest(guid, &executor.Resource{}, tags)

					allocationFailures, err = executorClient.AllocateContainers(logger, []executor.AllocationRequest{allocationRequest})

					Expect(err).NotTo(HaveOccurred())
					Expect(allocationFailures).To(BeEmpty())
				})

				Context("when running the container", func() {
					var (
						runReq       executor.RunRequest
						volumeId     string
						fileName     string
						volumeMounts []executor.VolumeMount
					)

					BeforeEach(func() {
						fileName = fmt.Sprintf("testfile-%d.txt", time.Now().UnixNano())
						volumeId = fmt.Sprintf("some-volumeID-%d", time.Now().UnixNano())
						someConfig := map[string]interface{}{"volume_id": volumeId}
						volumeMounts = []executor.VolumeMount{executor.VolumeMount{ContainerPath: "/testmount", Driver: "localdriver", VolumeId: volumeId, Config: someConfig, Mode: executor.BindMountModeRW}}
						runInfo := executor.RunInfo{
							VolumeMounts: volumeMounts,
							Privileged:   true,
							Action: models.WrapAction(&models.RunAction{
								Path: "/bin/touch",
								User: "root",
								Args: []string{"/testmount/" + fileName},
							}),
						}
						runReq = executor.NewRunRequest(guid, &runInfo, executor.Tags{})
					})

					Context("when successfully mounting a RW Mode volume", func() {
						BeforeEach(func() {
							err := executorClient.RunContainer(logger, &runReq)
							Expect(err).NotTo(HaveOccurred())
							Eventually(containerStatePoller(guid)).Should(Equal(executor.StateCompleted))
							Expect(getContainer(guid).RunResult.Failed).Should(BeFalse())
						})

						AfterEach(func() {
							err := executorClient.DeleteContainer(logger, guid)
							Expect(err).NotTo(HaveOccurred())

							err = os.RemoveAll(path.Join(componentMaker.VolmanDriverConfigDir, "_volumes", volumeId))
							Expect(err).ToNot(HaveOccurred())

							files, err := filepath.Glob(path.Join(componentMaker.VolmanDriverConfigDir, "_volumes", volumeId, fileName))
							Expect(err).ToNot(HaveOccurred())
							Expect(len(files)).To(Equal(0))
						})

						It("can write files to the mounted volume", func() {
							By("we expect the file it wrote to be available outside of the container")
							volmanPath := path.Join(componentMaker.VolmanDriverConfigDir, "_volumes", volumeId, fileName)
							files, err := filepath.Glob(volmanPath)
							Expect(err).ToNot(HaveOccurred())
							Expect(len(files)).To(Equal(1))
						})

						Context("when a second container using the same volume loads and then unloads", func() {
							var (
								runReq2   executor.RunRequest
								fileName2 string
								guid2     string
							)
							BeforeEach(func() {
								id, err := uuid.NewV4()
								Expect(err).NotTo(HaveOccurred())
								guid2 = id.String()

								tags := executor.Tags{"some-tag": "some-value"}
								allocationRequest2 := executor.NewAllocationRequest(guid2, &executor.Resource{}, tags)
								allocationFailures, err := executorClient.AllocateContainers(logger, []executor.AllocationRequest{allocationRequest2})
								Expect(err).NotTo(HaveOccurred())
								Expect(allocationFailures).To(BeEmpty())

								fileName2 = fmt.Sprintf("testfile2-%d.txt", time.Now().UnixNano())
								runInfo := executor.RunInfo{
									VolumeMounts: volumeMounts,
									Privileged:   true,
									Action: models.WrapAction(&models.RunAction{
										Path: "/bin/touch",
										User: "root",
										Args: []string{"/testmount/" + fileName2},
									}),
								}
								runReq2 = executor.NewRunRequest(guid2, &runInfo, executor.Tags{})
								err = executorClient.RunContainer(logger, &runReq2)
								Expect(err).NotTo(HaveOccurred())
								Eventually(containerStatePoller(guid2)).Should(Equal(executor.StateCompleted))
								Expect(getContainer(guid2).RunResult.Failed).Should(BeFalse())
								err = executorClient.DeleteContainer(logger, guid2)
								Expect(err).NotTo(HaveOccurred())
							})
							It("can still read files on the mounted volume for the first container", func() {
								volmanPath := path.Join(componentMaker.VolmanDriverConfigDir, "_volumes", volumeId, fileName)
								files, err := filepath.Glob(volmanPath)
								Expect(err).ToNot(HaveOccurred())
								Expect(len(files)).To(Equal(1))
							})
						})

					})
				})
			})
		})
	})
})

func initializeExecutor(logger lager.Logger, config executorinit.Configuration) (executor.Client, ifrit.Runner) {
	var executorMembers grouper.Members
	var err error
	var executorClient executor.Client
	executorClient, executorMembers, err = executorinit.Initialize(logger, config, clock.NewClock())
	Expect(err).NotTo(HaveOccurred())

	return executorClient, grouper.NewParallel(os.Kill, executorMembers)
}
<|endoftext|>


<commit_before>package eventsocket

type ClientMessage struct {
	ClientId string
	Message  Message
}

type Message struct {
	MessageType MessageType            `json:MessageType`
	Event       string                 `json:Event,omitempty`
	Payload     map[string]interface{} `json:Payload`
}

type MessageType int

const MESSAGE_TYPE_BROADCAST = 0
const MESSAGE_TYPE_STANDARD = 1
const MESSAGE_TYPE_REQUEST = 2
const MESSAGE_TYPE_REPLY = 3
const MESSAGE_TYPE_SUSCRIBE = 4
const MESSAGE_TYPE_UNSUSCRIBE = 5
<commit_msg>message: increment types<commit_after>package eventsocket

type ClientMessage struct {
	ClientId string
	Message  Message
}

type Message struct {
	MessageType MessageType            `json:MessageType`
	Event       string                 `json:Event,omitempty`
	Payload     map[string]interface{} `json:Payload`
}

type MessageType int

const MESSAGE_TYPE_BROADCAST = 1
const MESSAGE_TYPE_STANDARD = 2
const MESSAGE_TYPE_REQUEST = 3
const MESSAGE_TYPE_REPLY = 4
const MESSAGE_TYPE_SUSCRIBE = 5
const MESSAGE_TYPE_UNSUSCRIBE = 6
<|endoftext|>


<commit_before>package contentsignaturepki // import "go.mozilla.org/autograph/signer/contentsignaturepki"

import (
	"crypto"
	"crypto/ecdsa"
	"crypto/rand"
	"crypto/sha256"
	"crypto/sha512"
	"encoding/asn1"
	"fmt"
	"hash"
	"io"
	"time"

	"go.mozilla.org/autograph/database"
	"go.mozilla.org/autograph/signer"

	"github.com/pkg/errors"
	log "github.com/sirupsen/logrus"
	"go.mozilla.org/mozlogrus"
)

func init() {
	// initialize the logger
	mozlogrus.Enable("autograph")
}

const (
	// Type of this signer is 'contentsignaturepki'
	Type = "contentsignaturepki"

	// P256ECDSA defines an ecdsa content signature on the P-256 curve
	P256ECDSA = "p256ecdsa"

	// P256ECDSABYTESIZE defines the bytes length of a P256ECDSA signature
	P256ECDSABYTESIZE = 64

	// P384ECDSA defines an ecdsa content signature on the P-384 curve
	P384ECDSA = "p384ecdsa"

	// P384ECDSABYTESIZE defines the bytes length of a P384ECDSA signature
	P384ECDSABYTESIZE = 96

	// SignaturePrefix is a string preprended to data prior to signing
	SignaturePrefix = "Content-Signature:\x00"

	// CSNameSpace is a string that contains the namespace on which
	// content signature certificates are issued
	CSNameSpace = ".content-signature.mozilla.org"
)

// ContentSigner implements an issuer of content signatures
type ContentSigner struct {
	signer.Configuration
	issuerPriv, eePriv  crypto.PrivateKey
	issuerPub, eePub    crypto.PublicKey
	eeLabel             string
	rand                io.Reader
	validity            time.Duration
	clockSkewTolerance  time.Duration
	chainUploadLocation string
	chain               string
	caCert              string
	db                  *database.Handler
}

// New initializes a ContentSigner using a signer configuration
func New(conf signer.Configuration) (s *ContentSigner, err error) {
	s = new(ContentSigner)
	s.ID = conf.ID
	s.Type = conf.Type
	s.PrivateKey = conf.PrivateKey
	s.PublicKey = conf.PublicKey
	s.X5U = conf.X5U
	s.validity = conf.Validity
	s.clockSkewTolerance = conf.ClockSkewTolerance
	s.chainUploadLocation = conf.ChainUploadLocation
	s.caCert = conf.CaCert
	s.db = conf.DB

	if conf.Type != Type {
		return nil, fmt.Errorf("contentsignaturepki %q: invalid type %q, must be %q", s.ID, conf.Type, Type)
	}
	if conf.ID == "" {
		return nil, fmt.Errorf("contentsignaturepki %q: missing signer ID in signer configuration", s.ID)
	}
	if conf.PrivateKey == "" {
		return nil, fmt.Errorf("contentsignaturepki %q: missing private key in signer configuration", s.ID)
	}
	s.issuerPriv, s.issuerPub, s.rand, _, err = conf.GetKeysAndRand()
	if err != nil {
		return nil, errors.Wrapf(err, "contentsignaturepki %q: failed to get keys and rand", s.ID)
	}
	// if validity is undef, default to 30 days
	if s.validity == 0 {
		log.Printf("contentsignaturepki %q: no validity configured, defaulting to 30 days", s.ID)
		s.validity = 720 * time.Hour
	}

	switch s.issuerPub.(type) {
	case *ecdsa.PublicKey:
	default:
		return nil, fmt.Errorf("contentsignaturepki %q: invalid public key type for issuer, must be ecdsa", s.ID)
	}
	s.Mode = s.getModeFromCurve()

	// the end-entity key is not stored in configuration but may already
	// exist in an hsm, if present. Try to retrieve it, or make a new one.
	var tx *database.Transaction
	if s.db != nil {
		tx, err = s.db.BeginEndEntityOperations()
		if err != nil {
			return nil, errors.Wrapf(err, "contentsignaturepki %q: failed to begin db operations", s.ID)
		}
	}
	err = s.findAndSetEE(conf, tx)
	if err == nil {
		log.Printf("contentsignaturepki %q: reusing existing EE %q", s.ID, s.eeLabel)
	} else {
		// No suitable end-entity found, making a new chain
		if err == database.ErrNoSuitableEEFound {
			log.Printf("contentsignaturepki %q: making new end-entity", s.ID)
			// create a label and generate the key
			s.eeLabel = fmt.Sprintf("%s-%s", s.ID, time.Now().UTC().Format("20060102150405"))
			s.eePriv, s.eePub, err = conf.MakeKey(s.issuerPub, s.eeLabel)
			if err != nil {
				err = errors.Wrapf(err, "contentsignaturepki %q: failed to generate end entity", s.ID)
				return
			}
			// make the certificate and upload the chain
			err = s.makeAndUploadChain()
			if err != nil {
				return nil, errors.Wrapf(err, "contentsignaturepki %q: failed to make chain and x5u", s.ID)
			}
			if tx != nil {
				// insert it in database
				hsmHandle := signer.GetPrivKeyHandle(s.eePriv)
				err = tx.InsertEE(s.X5U, s.eeLabel, s.ID, hsmHandle)
				if err != nil {
					return nil, errors.Wrapf(err, "contentsignaturepki %q: failed to insert EE into database", s.ID)
				}
			}
		} else {
			return nil, errors.Wrapf(err, "contentsignaturepki %q: failed to find suitable end-entity", s.ID)
		}
	}
	_, err = GetX5U(s.X5U)
	if err != nil {
		return nil, errors.Wrapf(err, "contentsignaturepki %q: failed to verify x5u", s.ID)
	}
	if tx != nil {
		err = tx.End()
		if err != nil {
			return nil, errors.Wrapf(err, "contentsignaturepki %q: failed to commit end-entity operations in database", s.ID)
		}
	}
	return
}

// Config returns the configuration of the current signer
func (s *ContentSigner) Config() signer.Configuration {
	return signer.Configuration{
		ID:                  s.ID,
		Type:                s.Type,
		Mode:                s.Mode,
		PrivateKey:          s.PrivateKey,
		PublicKey:           s.PublicKey,
		X5U:                 s.X5U,
		Validity:            s.validity,
		ClockSkewTolerance:  s.clockSkewTolerance,
		ChainUploadLocation: s.chainUploadLocation,
		CaCert:              s.caCert,
	}
}

// SignData takes input data, templates it, hashes it and signs it.
// The returned signature is of type ContentSignature and ready to be Marshalled.
func (s *ContentSigner) SignData(input []byte, options interface{}) (signer.Signature, error) {
	if len(input) < 10 {
		return nil, fmt.Errorf("contentsignaturepki %q: refusing to sign input data shorter than 10 bytes", s.ID)
	}
	alg, hash := MakeTemplatedHash(input, s.Mode)
	sig, err := s.SignHash(hash, options)
	sig.(*ContentSignature).storeHashName(alg)
	return sig, err
}

// MakeTemplatedHash returns the templated sha384 of the input data. The template adds
// the string "Content-Signature:\x00" before the input data prior to
// calculating the sha384.
//
// The name of the hash function is returned, followed by the hash bytes
func MakeTemplatedHash(data []byte, curvename string) (alg string, out []byte) {
	templated := make([]byte, len(SignaturePrefix)+len(data))
	copy(templated[:len(SignaturePrefix)], []byte(SignaturePrefix))
	copy(templated[len(SignaturePrefix):], data)
	var md hash.Hash
	switch curvename {
	case P384ECDSA:
		md = sha512.New384()
		alg = "sha384"
	default:
		md = sha256.New()
		alg = "sha256"
	}
	md.Write(templated)
	return alg, md.Sum(nil)
}

// SignHash takes an input hash and returns a signature. It assumes the input data
// has already been hashed with something like sha384
func (s *ContentSigner) SignHash(input []byte, options interface{}) (signer.Signature, error) {
	if len(input) != 32 && len(input) != 48 && len(input) != 64 {
		return nil, fmt.Errorf("contentsignaturepki %q: refusing to sign input hash. length %d, expected 32, 48 or 64", s.ID, len(input))
	}
	var err error
	csig := new(ContentSignature)
	csig = &ContentSignature{
		Len:  getSignatureLen(s.Mode),
		Mode: s.Mode,
		X5U:  s.X5U,
		ID:   s.ID,
	}

	asn1Sig, err := s.eePriv.(crypto.Signer).Sign(rand.Reader, input, nil)
	if err != nil {
		return nil, errors.Wrapf(err, "contentsignaturepki %q: failed to sign hash", s.ID)
	}
	var ecdsaSig ecdsaAsn1Signature
	_, err = asn1.Unmarshal(asn1Sig, &ecdsaSig)
	if err != nil {
		return nil, errors.Wrapf(err, "contentsignaturepki %q: failed to parse signature", s.ID)
	}
	csig.R = ecdsaSig.R
	csig.S = ecdsaSig.S
	csig.Finished = true
	return csig, nil
}

// getSignatureLen returns the size of an ECDSA signature issued by the signer,
// or -1 if the mode is unknown
//
// The signature length is double the size size of the curve field, in bytes
// (each R and S value is equal to the size of the curve field).
// If the curve field it not a multiple of 8, round to the upper multiple of 8.
func getSignatureLen(mode string) int {
	switch mode {
	case P256ECDSA:
		return P256ECDSABYTESIZE
	case P384ECDSA:
		return P384ECDSABYTESIZE
	}
	return -1
}

// getSignatureHash returns the name of the hash function used by a given mode,
// or an empty string if the mode is unknown
func getSignatureHash(mode string) string {
	switch mode {
	case P256ECDSA:
		return "sha256"
	case P384ECDSA:
		return "sha384"
	}
	return ""
}

// getModeFromCurve returns a content signature algorithm name, or an empty string if the mode is unknown
func (s *ContentSigner) getModeFromCurve() string {
	switch s.issuerPub.(*ecdsa.PublicKey).Params().Name {
	case "P-256":
		return P256ECDSA
	case "P-384":
		return P384ECDSA
	default:
		return ""
	}
}

// GetDefaultOptions returns nil because this signer has no option
func (s *ContentSigner) GetDefaultOptions() interface{} {
	return nil
}

// Verify takes the location of a cert chain (x5u), a signature in its
// raw base64_url format and input data. It then performs a verification
// of the signature on the input data using the end-entity certificate
// of the chain, and returns an error if it fails, or nil on success.
func Verify(x5u, signature string, input []byte) error {
	certs, err := GetX5U(x5u)
	if err != nil {
		return err
	}
	// Get the public key from the end-entity
	if len(certs) < 1 {
		return fmt.Errorf("no certificate found in x5u")
	}
	key := certs[0].PublicKey.(*ecdsa.PublicKey)
	// parse the json signature
	sig, err := Unmarshal(signature)
	if err != nil {
		return err
	}
	// make a templated hash
	if !sig.VerifyData(input, key) {
		return fmt.Errorf("ecdsa signature verification failed")
	}
	return nil
}
<commit_msg>cspki: use switch statement to handle errors<commit_after>package contentsignaturepki // import "go.mozilla.org/autograph/signer/contentsignaturepki"

import (
	"crypto"
	"crypto/ecdsa"
	"crypto/rand"
	"crypto/sha256"
	"crypto/sha512"
	"encoding/asn1"
	"fmt"
	"hash"
	"io"
	"time"

	"go.mozilla.org/autograph/database"
	"go.mozilla.org/autograph/signer"

	"github.com/pkg/errors"
	log "github.com/sirupsen/logrus"
	"go.mozilla.org/mozlogrus"
)

func init() {
	// initialize the logger
	mozlogrus.Enable("autograph")
}

const (
	// Type of this signer is 'contentsignaturepki'
	Type = "contentsignaturepki"

	// P256ECDSA defines an ecdsa content signature on the P-256 curve
	P256ECDSA = "p256ecdsa"

	// P256ECDSABYTESIZE defines the bytes length of a P256ECDSA signature
	P256ECDSABYTESIZE = 64

	// P384ECDSA defines an ecdsa content signature on the P-384 curve
	P384ECDSA = "p384ecdsa"

	// P384ECDSABYTESIZE defines the bytes length of a P384ECDSA signature
	P384ECDSABYTESIZE = 96

	// SignaturePrefix is a string preprended to data prior to signing
	SignaturePrefix = "Content-Signature:\x00"

	// CSNameSpace is a string that contains the namespace on which
	// content signature certificates are issued
	CSNameSpace = ".content-signature.mozilla.org"
)

// ContentSigner implements an issuer of content signatures
type ContentSigner struct {
	signer.Configuration
	issuerPriv, eePriv  crypto.PrivateKey
	issuerPub, eePub    crypto.PublicKey
	eeLabel             string
	rand                io.Reader
	validity            time.Duration
	clockSkewTolerance  time.Duration
	chainUploadLocation string
	chain               string
	caCert              string
	db                  *database.Handler
}

// New initializes a ContentSigner using a signer configuration
func New(conf signer.Configuration) (s *ContentSigner, err error) {
	s = new(ContentSigner)
	s.ID = conf.ID
	s.Type = conf.Type
	s.PrivateKey = conf.PrivateKey
	s.PublicKey = conf.PublicKey
	s.X5U = conf.X5U
	s.validity = conf.Validity
	s.clockSkewTolerance = conf.ClockSkewTolerance
	s.chainUploadLocation = conf.ChainUploadLocation
	s.caCert = conf.CaCert
	s.db = conf.DB

	if conf.Type != Type {
		return nil, fmt.Errorf("contentsignaturepki %q: invalid type %q, must be %q", s.ID, conf.Type, Type)
	}
	if conf.ID == "" {
		return nil, fmt.Errorf("contentsignaturepki %q: missing signer ID in signer configuration", s.ID)
	}
	if conf.PrivateKey == "" {
		return nil, fmt.Errorf("contentsignaturepki %q: missing private key in signer configuration", s.ID)
	}
	s.issuerPriv, s.issuerPub, s.rand, _, err = conf.GetKeysAndRand()
	if err != nil {
		return nil, errors.Wrapf(err, "contentsignaturepki %q: failed to get keys and rand", s.ID)
	}
	// if validity is undef, default to 30 days
	if s.validity == 0 {
		log.Printf("contentsignaturepki %q: no validity configured, defaulting to 30 days", s.ID)
		s.validity = 720 * time.Hour
	}

	switch s.issuerPub.(type) {
	case *ecdsa.PublicKey:
	default:
		return nil, fmt.Errorf("contentsignaturepki %q: invalid public key type for issuer, must be ecdsa", s.ID)
	}
	s.Mode = s.getModeFromCurve()

	// the end-entity key is not stored in configuration but may already
	// exist in an hsm, if present. Try to retrieve it, or make a new one.
	var tx *database.Transaction
	if s.db != nil {
		tx, err = s.db.BeginEndEntityOperations()
		if err != nil {
			return nil, errors.Wrapf(err, "contentsignaturepki %q: failed to begin db operations", s.ID)
		}
	}
	err = s.findAndSetEE(conf, tx)
	switch err {
	case nil:
		log.Printf("contentsignaturepki %q: reusing existing EE %q", s.ID, s.eeLabel)
	case database.ErrNoSuitableEEFound:
		// No suitable end-entity found, making a new chain
		log.Printf("contentsignaturepki %q: making new end-entity", s.ID)
		// create a label and generate the key
		s.eeLabel = fmt.Sprintf("%s-%s", s.ID, time.Now().UTC().Format("20060102150405"))
		s.eePriv, s.eePub, err = conf.MakeKey(s.issuerPub, s.eeLabel)
		if err != nil {
			err = errors.Wrapf(err, "contentsignaturepki %q: failed to generate end entity", s.ID)
			return
		}
		// make the certificate and upload the chain
		err = s.makeAndUploadChain()
		if err != nil {
			return nil, errors.Wrapf(err, "contentsignaturepki %q: failed to make chain and x5u", s.ID)
		}
		if tx != nil {
			// insert it in database
			hsmHandle := signer.GetPrivKeyHandle(s.eePriv)
			err = tx.InsertEE(s.X5U, s.eeLabel, s.ID, hsmHandle)
			if err != nil {
				return nil, errors.Wrapf(err, "contentsignaturepki %q: failed to insert EE into database", s.ID)
			}
		}
	default:
		return nil, errors.Wrapf(err, "contentsignaturepki %q: failed to find suitable end-entity", s.ID)

	}
	_, err = GetX5U(s.X5U)
	if err != nil {
		return nil, errors.Wrapf(err, "contentsignaturepki %q: failed to verify x5u", s.ID)
	}
	if tx != nil {
		err = tx.End()
		if err != nil {
			return nil, errors.Wrapf(err, "contentsignaturepki %q: failed to commit end-entity operations in database", s.ID)
		}
	}
	return
}

// Config returns the configuration of the current signer
func (s *ContentSigner) Config() signer.Configuration {
	return signer.Configuration{
		ID:                  s.ID,
		Type:                s.Type,
		Mode:                s.Mode,
		PrivateKey:          s.PrivateKey,
		PublicKey:           s.PublicKey,
		X5U:                 s.X5U,
		Validity:            s.validity,
		ClockSkewTolerance:  s.clockSkewTolerance,
		ChainUploadLocation: s.chainUploadLocation,
		CaCert:              s.caCert,
	}
}

// SignData takes input data, templates it, hashes it and signs it.
// The returned signature is of type ContentSignature and ready to be Marshalled.
func (s *ContentSigner) SignData(input []byte, options interface{}) (signer.Signature, error) {
	if len(input) < 10 {
		return nil, fmt.Errorf("contentsignaturepki %q: refusing to sign input data shorter than 10 bytes", s.ID)
	}
	alg, hash := MakeTemplatedHash(input, s.Mode)
	sig, err := s.SignHash(hash, options)
	sig.(*ContentSignature).storeHashName(alg)
	return sig, err
}

// MakeTemplatedHash returns the templated sha384 of the input data. The template adds
// the string "Content-Signature:\x00" before the input data prior to
// calculating the sha384.
//
// The name of the hash function is returned, followed by the hash bytes
func MakeTemplatedHash(data []byte, curvename string) (alg string, out []byte) {
	templated := make([]byte, len(SignaturePrefix)+len(data))
	copy(templated[:len(SignaturePrefix)], []byte(SignaturePrefix))
	copy(templated[len(SignaturePrefix):], data)
	var md hash.Hash
	switch curvename {
	case P384ECDSA:
		md = sha512.New384()
		alg = "sha384"
	default:
		md = sha256.New()
		alg = "sha256"
	}
	md.Write(templated)
	return alg, md.Sum(nil)
}

// SignHash takes an input hash and returns a signature. It assumes the input data
// has already been hashed with something like sha384
func (s *ContentSigner) SignHash(input []byte, options interface{}) (signer.Signature, error) {
	if len(input) != 32 && len(input) != 48 && len(input) != 64 {
		return nil, fmt.Errorf("contentsignaturepki %q: refusing to sign input hash. length %d, expected 32, 48 or 64", s.ID, len(input))
	}
	var err error
	csig := new(ContentSignature)
	csig = &ContentSignature{
		Len:  getSignatureLen(s.Mode),
		Mode: s.Mode,
		X5U:  s.X5U,
		ID:   s.ID,
	}

	asn1Sig, err := s.eePriv.(crypto.Signer).Sign(rand.Reader, input, nil)
	if err != nil {
		return nil, errors.Wrapf(err, "contentsignaturepki %q: failed to sign hash", s.ID)
	}
	var ecdsaSig ecdsaAsn1Signature
	_, err = asn1.Unmarshal(asn1Sig, &ecdsaSig)
	if err != nil {
		return nil, errors.Wrapf(err, "contentsignaturepki %q: failed to parse signature", s.ID)
	}
	csig.R = ecdsaSig.R
	csig.S = ecdsaSig.S
	csig.Finished = true
	return csig, nil
}

// getSignatureLen returns the size of an ECDSA signature issued by the signer,
// or -1 if the mode is unknown
//
// The signature length is double the size size of the curve field, in bytes
// (each R and S value is equal to the size of the curve field).
// If the curve field it not a multiple of 8, round to the upper multiple of 8.
func getSignatureLen(mode string) int {
	switch mode {
	case P256ECDSA:
		return P256ECDSABYTESIZE
	case P384ECDSA:
		return P384ECDSABYTESIZE
	}
	return -1
}

// getSignatureHash returns the name of the hash function used by a given mode,
// or an empty string if the mode is unknown
func getSignatureHash(mode string) string {
	switch mode {
	case P256ECDSA:
		return "sha256"
	case P384ECDSA:
		return "sha384"
	}
	return ""
}

// getModeFromCurve returns a content signature algorithm name, or an empty string if the mode is unknown
func (s *ContentSigner) getModeFromCurve() string {
	switch s.issuerPub.(*ecdsa.PublicKey).Params().Name {
	case "P-256":
		return P256ECDSA
	case "P-384":
		return P384ECDSA
	default:
		return ""
	}
}

// GetDefaultOptions returns nil because this signer has no option
func (s *ContentSigner) GetDefaultOptions() interface{} {
	return nil
}

// Verify takes the location of a cert chain (x5u), a signature in its
// raw base64_url format and input data. It then performs a verification
// of the signature on the input data using the end-entity certificate
// of the chain, and returns an error if it fails, or nil on success.
func Verify(x5u, signature string, input []byte) error {
	certs, err := GetX5U(x5u)
	if err != nil {
		return err
	}
	// Get the public key from the end-entity
	if len(certs) < 1 {
		return fmt.Errorf("no certificate found in x5u")
	}
	key := certs[0].PublicKey.(*ecdsa.PublicKey)
	// parse the json signature
	sig, err := Unmarshal(signature)
	if err != nil {
		return err
	}
	// make a templated hash
	if !sig.VerifyData(input, key) {
		return fmt.Errorf("ecdsa signature verification failed")
	}
	return nil
}
<|endoftext|>


<commit_before>package core

import (
	"sync"
	"sync/atomic"

	"github.com/tisp-lang/tisp/src/lib/debug"
)

type thunkState int32

const (
	normal thunkState = iota
	app
)

// Thunk you all!
type Thunk struct {
	result    Value
	function  *Thunk
	args      Arguments
	state     thunkState
	blackHole sync.WaitGroup
	info      debug.Info
}

// Normal creates a thunk of a WHNF value as its result.
func Normal(v Value) *Thunk {
	assertValueIsWHNF("Normal's argument", v)
	return &Thunk{result: v, state: normal}
}

// App creates a thunk applying a function to arguments.
func App(f *Thunk, args Arguments) *Thunk {
	return AppWithInfo(f, args, debug.NewGoInfo(1))
}

// AppWithInfo is the same as App except that it stores debug information
// in the thunk.
func AppWithInfo(f *Thunk, args Arguments, i debug.Info) *Thunk {
	t := &Thunk{
		function: f,
		args:     args,
		state:    app,
		info:     i,
	}
	t.blackHole.Add(1)
	return t
}

// PApp is not PPap.
func PApp(f *Thunk, ps ...*Thunk) *Thunk {
	return AppWithInfo(f, NewPositionalArguments(ps...), debug.NewGoInfo(1))
}

// EvalAny evaluates a thunk and returns a pure or output value.
func (t *Thunk) EvalAny(isPure bool) Value {
	if t.lock() {
		children := make([]*Thunk, 0)

		for {
			v := t.moveFunction().Eval()

			if t.chainError(v) {
				break
			}

			f, ok := v.(callable)

			if !ok {
				t.result = NotCallableError(v).Eval()
				break
			}

			t.result = f.call(t.moveArguments())

			if t.chainError(t.result) {
				break
			}

			child, ok := t.result.(*Thunk)

			if !ok {
				break
			}

			t.function, t.args, ok = child.delegateEval()

			if !ok {
				t.result = child.EvalAny(isPure)
				t.chainError(t.result)
				break
			}

			children = append(children, child)
		}

		assertValueIsWHNF("Thunk.result", t.result)

		if _, ok := t.result.(OutputType); isPure && ok {
			t.result = ImpureFunctionError(t.result).Eval()
		} else if !isPure && !ok {
			t.result = NotOutputError(t.result).Eval()
		}

		for _, child := range children {
			// TODO: Use children's debug informations, child.info?
			child.result = t.result
			child.finalize()
		}

		t.finalize()
	} else {
		t.blackHole.Wait()
	}

	assertValueIsWHNF("Thunk.result", t.result)

	return t.result
}

func (t *Thunk) lock() bool {
	return t.compareAndSwapState(app, normal)
}

func (t *Thunk) delegateEval() (*Thunk, Arguments, bool) {
	if t.lock() {
		return t.moveFunction(), t.moveArguments(), true
	}

	return nil, Arguments{}, false
}

func (t *Thunk) moveFunction() *Thunk {
	f := t.function
	t.function = nil
	return f
}

func (t *Thunk) moveArguments() Arguments {
	args := t.args
	t.args = Arguments{}
	return args
}

func (t *Thunk) finalize() {
	t.function = nil
	t.args = Arguments{}
	t.storeState(normal)
	t.blackHole.Done()
}

func (t *Thunk) compareAndSwapState(old, new thunkState) bool {
	return atomic.CompareAndSwapInt32((*int32)(&t.state), int32(old), int32(new))
}

func (t *Thunk) storeState(new thunkState) {
	atomic.StoreInt32((*int32)(&t.state), int32(new))
}

func (t *Thunk) chainError(v Value) bool {
	if e, ok := v.(ErrorType); ok {
		e.callTrace = append(e.callTrace, t.info)
		t.result = e
		return true
	}

	return false
}

func assertValueIsWHNF(s string, v Value) {
	if _, ok := v.(*Thunk); ok {
		panic(s + " is *Thunk")
	}
}

// Eval evaluates a pure value.
func (t *Thunk) Eval() Value {
	return t.EvalAny(true)
}

// EvalOutput evaluates an output expression.
func (t *Thunk) EvalOutput() Value {
	v := t.EvalAny(false)

	if err, ok := v.(ErrorType); ok {
		return err
	}

	return v.(OutputType).value.Eval()
}
<commit_msg>Improve comment on Thunk.EvalAny()<commit_after>package core

import (
	"sync"
	"sync/atomic"

	"github.com/tisp-lang/tisp/src/lib/debug"
)

type thunkState int32

const (
	normal thunkState = iota
	app
)

// Thunk you all!
type Thunk struct {
	result    Value
	function  *Thunk
	args      Arguments
	state     thunkState
	blackHole sync.WaitGroup
	info      debug.Info
}

// Normal creates a thunk of a WHNF value as its result.
func Normal(v Value) *Thunk {
	assertValueIsWHNF("Normal's argument", v)
	return &Thunk{result: v, state: normal}
}

// App creates a thunk applying a function to arguments.
func App(f *Thunk, args Arguments) *Thunk {
	return AppWithInfo(f, args, debug.NewGoInfo(1))
}

// AppWithInfo is the same as App except that it stores debug information
// in the thunk.
func AppWithInfo(f *Thunk, args Arguments, i debug.Info) *Thunk {
	t := &Thunk{
		function: f,
		args:     args,
		state:    app,
		info:     i,
	}
	t.blackHole.Add(1)
	return t
}

// PApp is not PPap.
func PApp(f *Thunk, ps ...*Thunk) *Thunk {
	return AppWithInfo(f, NewPositionalArguments(ps...), debug.NewGoInfo(1))
}

// EvalAny evaluates a thunk and returns a pure or impure (output) value.
func (t *Thunk) EvalAny(isPure bool) Value {
	if t.lock() {
		children := make([]*Thunk, 0)

		for {
			v := t.moveFunction().Eval()

			if t.chainError(v) {
				break
			}

			f, ok := v.(callable)

			if !ok {
				t.result = NotCallableError(v).Eval()
				break
			}

			t.result = f.call(t.moveArguments())

			if t.chainError(t.result) {
				break
			}

			child, ok := t.result.(*Thunk)

			if !ok {
				break
			}

			t.function, t.args, ok = child.delegateEval()

			if !ok {
				t.result = child.EvalAny(isPure)
				t.chainError(t.result)
				break
			}

			children = append(children, child)
		}

		assertValueIsWHNF("Thunk.result", t.result)

		if _, ok := t.result.(OutputType); isPure && ok {
			t.result = ImpureFunctionError(t.result).Eval()
		} else if !isPure && !ok {
			t.result = NotOutputError(t.result).Eval()
		}

		for _, child := range children {
			// TODO: Use children's debug informations, child.info?
			child.result = t.result
			child.finalize()
		}

		t.finalize()
	} else {
		t.blackHole.Wait()
	}

	assertValueIsWHNF("Thunk.result", t.result)

	return t.result
}

func (t *Thunk) lock() bool {
	return t.compareAndSwapState(app, normal)
}

func (t *Thunk) delegateEval() (*Thunk, Arguments, bool) {
	if t.lock() {
		return t.moveFunction(), t.moveArguments(), true
	}

	return nil, Arguments{}, false
}

func (t *Thunk) moveFunction() *Thunk {
	f := t.function
	t.function = nil
	return f
}

func (t *Thunk) moveArguments() Arguments {
	args := t.args
	t.args = Arguments{}
	return args
}

func (t *Thunk) finalize() {
	t.function = nil
	t.args = Arguments{}
	t.storeState(normal)
	t.blackHole.Done()
}

func (t *Thunk) compareAndSwapState(old, new thunkState) bool {
	return atomic.CompareAndSwapInt32((*int32)(&t.state), int32(old), int32(new))
}

func (t *Thunk) storeState(new thunkState) {
	atomic.StoreInt32((*int32)(&t.state), int32(new))
}

func (t *Thunk) chainError(v Value) bool {
	if e, ok := v.(ErrorType); ok {
		e.callTrace = append(e.callTrace, t.info)
		t.result = e
		return true
	}

	return false
}

func assertValueIsWHNF(s string, v Value) {
	if _, ok := v.(*Thunk); ok {
		panic(s + " is *Thunk")
	}
}

// Eval evaluates a pure value.
func (t *Thunk) Eval() Value {
	return t.EvalAny(true)
}

// EvalOutput evaluates an output expression.
func (t *Thunk) EvalOutput() Value {
	v := t.EvalAny(false)

	if err, ok := v.(ErrorType); ok {
		return err
	}

	return v.(OutputType).value.Eval()
}
<|endoftext|>


<commit_before>package webp

import (
	"os"
	"path/filepath"
	"reflect"
	"testing"
)

func TestWebp_Decode(t *testing.T) {
	testPath := filepath.Join("../test-fixtures", "lena.jpg")

	f, err := os.Open(testPath)
	defer f.Close()

	_, err = Decode(f)

	if !reflect.DeepEqual(err, nil) {
		t.Errorf("TestWebp_Decode returned %+v, want %+v", err, nil)
	}
}

func TestWebp_Encode(t *testing.T) {
	testPath := filepath.Join("../test-fixtures", "lena.jpg")
	defer func() {
		_ = os.Remove("new.webp")
	}()

	f, err := os.Open(testPath)
	defer f.Close()

	m, err := Decode(f)

	if !reflect.DeepEqual(err, nil) {
		t.Errorf("TestWebp_Encode Decode() returned %+v", err)
	}

	toimg, _ := os.Create("new.webp")
	defer toimg.Close()

	err = Encode(toimg, m, &Options{false, 50})

	if !reflect.DeepEqual(err, nil) {
		t.Errorf("TestWebp_Encode Encode() returned %+v", err)
	}
}
<commit_msg>fix test<commit_after>package webp

import (
	"os"
	"path/filepath"
	"reflect"
	"testing"
)

func TestWebp_Decode(t *testing.T) {
	testPath := filepath.Join("../test-fixtures", "lena.jpg")

	f, err := os.Open(testPath)
	defer f.Close()

	_, err = Decode(f)

	if !reflect.DeepEqual(err, nil) {
		t.Errorf("TestWebp_Decode returned %+v", err)
	}
}

func TestWebp_Encode(t *testing.T) {
	testPath := filepath.Join("../test-fixtures", "lena.jpg")
	defer func() {
		_ = os.Remove("new.webp")
	}()

	f, err := os.Open(testPath)
	defer f.Close()

	m, err := Decode(f)

	if !reflect.DeepEqual(err, nil) {
		t.Errorf("TestWebp_Encode Decode() returned %+v", err)
	}

	toimg, _ := os.Create("new.webp")
	defer toimg.Close()

	err = Encode(toimg, m, &Options{false, 50})

	if !reflect.DeepEqual(err, nil) {
		t.Errorf("TestWebp_Encode Encode() returned %+v", err)
	}
}
<|endoftext|>


<commit_before>package util

import "testing"

func TestRemoveDiacritics(t *testing.T) {
	r := RemoveDiacritics("maçã")
	if r != "maca" {
		t.Fail()
	}
}
<commit_msg>:white_check_mark: Aumenta o coverage do util.string<commit_after>package util

import (
	"testing"

	. "github.com/smartystreets/goconvey/convey"
)

func TestRemoveDiacritics(t *testing.T) {
	Convey("Deve receber um texto com acentos e retornar o texto sem acentos", t, func() {
		r := RemoveDiacritics("maçã")
		So(r, ShouldEqual, "maca")
		r = RemoveDiacritics("áÉçãẽś")
		So(r, ShouldEqual, "aEcaes")
		r = RemoveDiacritics("Týr")
		So(r, ShouldEqual, "Tyr")
		r = RemoveDiacritics("párãlèlëpípêdö")
		So(r, ShouldEqual, "paralelepipedo")
	})
}

func TestPadLeft(t *testing.T) {
	Convey("Deve completar o tamanho de um texto com zeros a esquerda", t, func() {
		s := PadLeft("123", "0", 10)
		So(len(s), ShouldEqual, 10)

		Convey("Se o texto for do mesmo tamanho da quantidade de caracteres não deve haver zero a esquerda", func() {
			s := PadLeft("333", "0", 3)
			So(len(s), ShouldEqual, 3)
		})

	})
}
<|endoftext|>


<commit_before>package net

// Basic imports
import (
	"context"
	"errors"
	"testing"

	mock "github.com/stretchr/testify/mock"
	suite "github.com/stretchr/testify/suite"
)

// NetDialerTestSuite -
type NetDialerTestSuite struct {
	suite.Suite
	fnet *nnet
	ctx  context.Context
}

func (suite *NetDialerTestSuite) SetupTest() {
	suite.ctx = context.Background()
	suite.fnet = New(suite.ctx).(*nnet)
}

func (suite *NetDialerTestSuite) TestDialContextSuccess() {
	ctx := context.Background()

	prot := &MockProtocol{}
	prot.On("Name").Return("test")
	var handler HandlerFunc = func(ctx context.Context, c Conn) error {
		return nil
	}
	var negotiator NegotiatorFunc = func(ctx context.Context, c Conn) error {
		return nil
	}
	prot.On("Handle", mock.Anything).Return(handler)
	prot.On("Negotiate", mock.Anything).Return(negotiator)
	protErr := suite.fnet.AddProtocols(prot)
	suite.Assert().Nil(protErr)
	suite.Assert().Len(suite.fnet.protocols, 1)

	addrString := "test"
	addr := NewAddress(addrString)
	mockConn := &MockConn{}
	mockConn.On("GetAddress").Return(addr)

	tran := &MockTransport{}
	tran.On("Listen", mock.Anything, mock.Anything).Return(nil)
	tran.On("CanDial", addr).Return(true, nil)
	tran.On("DialContext", mock.Anything, mock.Anything).Return(ctx, mockConn, nil)
	err := suite.fnet.AddTransport(tran, prot)
	suite.Assert().Nil(err)
	suite.Assert().Len(suite.fnet.transports, 1)

	_, _, retErr := suite.fnet.DialContext(ctx, addrString)
	suite.Assert().Nil(retErr)
	tran.AssertCalled(suite.T(), "CanDial", addr)
	tran.AssertCalled(suite.T(), "DialContext", mock.Anything, mock.Anything)
}

func (suite *NetDialerTestSuite) TestDialTransportCannotDial() {
	ctx := context.Background()

	addrString := "test"
	addr := NewAddress(addrString)
	mockConn := &MockConn{}
	mockConn.On("GetAddress").Return(addr)

	tran := &MockTransport{}
	tran.On("Listen", mock.Anything, mock.Anything).Return(nil)
	tran.On("CanDial", addr).Return(false, nil)
	err := suite.fnet.AddTransport(tran)
	suite.Assert().Nil(err)
	suite.Assert().Len(suite.fnet.transports, 1)

	_, _, retErr := suite.fnet.DialContext(ctx, addrString)
	suite.Assert().Equal(ErrNoSuchTransport, retErr)
	tran.AssertCalled(suite.T(), "CanDial", addr)
}

func (suite *NetDialerTestSuite) TestDialTransportError() {
	ctx := context.Background()

	addrString := "test"
	addr := NewAddress(addrString)
	mockConn := &MockConn{}
	mockConn.On("GetAddress").Return(addr)

	tran := &MockTransport{}
	tran.On("Listen", mock.Anything, mock.Anything).Return(nil)
	tran.On("CanDial", addr).Return(false, errors.New("error"))
	err := suite.fnet.AddTransport(tran)
	suite.Assert().Nil(err)
	suite.Assert().Len(suite.fnet.transports, 1)

	_, _, retErr := suite.fnet.DialContext(ctx, addrString)
	suite.Assert().Equal(ErrNoSuchTransport, retErr)
	tran.AssertCalled(suite.T(), "CanDial", addr)
}

func (suite *NetDialerTestSuite) TestDialContextFails() {
	ctx := context.Background()

	prot := &MockProtocol{}
	prot.On("Name").Return("test")
	var handler HandlerFunc = func(ctx context.Context, c Conn) error {
		return nil
	}
	var negotiator NegotiatorFunc = func(ctx context.Context, c Conn) error {
		return nil
	}
	prot.On("Handle", mock.Anything).Return(handler)
	prot.On("Negotiate", mock.Anything).Return(negotiator)
	protErr := suite.fnet.AddProtocols(prot)
	suite.Assert().Nil(protErr)
	suite.Assert().Len(suite.fnet.protocols, 1)

	addrString := "test"
	addr := NewAddress(addrString)
	mockConn := &MockConn{}
	mockConn.On("GetAddress").Return(addr)

	tran := &MockTransport{}
	tran.On("Listen", mock.Anything, mock.Anything).Return(nil)
	tran.On("CanDial", addr).Return(true, nil)
	tran.On("DialContext", mock.Anything, mock.Anything).Return(nil, nil, errors.New("error"))
	err := suite.fnet.AddTransport(tran, prot)
	suite.Assert().Nil(err)
	suite.Assert().Len(suite.fnet.transports, 1)

	_, _, retErr := suite.fnet.DialContext(ctx, addrString)
	suite.Assert().Equal(ErrNoSuchTransport, retErr)
	tran.AssertCalled(suite.T(), "CanDial", addr)
	tran.AssertCalled(suite.T(), "DialContext", mock.Anything, mock.Anything)
}

func (suite *NetDialerTestSuite) TestNegotiatorFails() {
	ctx := context.Background()

	prot := &MockProtocol{}
	prot.On("Name").Return("test")
	var handler HandlerFunc = func(ctx context.Context, c Conn) error {
		return nil
	}
	var negotiator NegotiatorFunc = func(ctx context.Context, c Conn) error {
		return errors.New("error")
	}
	prot.On("Handle", mock.Anything).Return(handler)
	prot.On("Negotiate", mock.Anything).Return(negotiator)
	protErr := suite.fnet.AddProtocols(prot)
	suite.Assert().Nil(protErr)
	suite.Assert().Len(suite.fnet.protocols, 1)

	addrString := "test"
	addr := NewAddress(addrString)
	mockConn := &MockConn{}
	mockConn.On("GetAddress").Return(addr)

	tran := &MockTransport{}
	tran.On("Listen", mock.Anything, mock.Anything).Return(nil)
	tran.On("CanDial", addr).Return(true, nil)
	tran.On("DialContext", mock.Anything, mock.Anything).Return(ctx, mockConn, nil)
	err := suite.fnet.AddTransport(tran, prot)
	suite.Assert().Nil(err)
	suite.Assert().Len(suite.fnet.transports, 1)

	_, _, retErr := suite.fnet.DialContext(ctx, addrString)
	suite.Assert().Equal(ErrCouldNotDial, retErr)
	tran.AssertCalled(suite.T(), "CanDial", addr)
	tran.AssertCalled(suite.T(), "DialContext", mock.Anything, mock.Anything)
}

func (suite *NetDialerTestSuite) TestInvalidProtocolFails() {
	ctx := context.Background()

	prot := &MockProtocol{}
	prot.On("Name").Return("nope")
	var handler HandlerFunc = func(ctx context.Context, c Conn) error {
		return nil
	}
	var negotiator NegotiatorFunc = func(ctx context.Context, c Conn) error {
		return nil
	}
	prot.On("Handle", mock.Anything).Return(handler)
	prot.On("Negotiate", mock.Anything).Return(negotiator)
	protErr := suite.fnet.AddProtocols(prot)
	suite.Assert().Nil(protErr)
	suite.Assert().Len(suite.fnet.protocols, 1)

	addrString := "test"
	addr := NewAddress(addrString)
	mockConn := &MockConn{}
	mockConn.On("GetAddress").Return(addr)

	tran := &MockTransport{}
	tran.On("Listen", mock.Anything, mock.Anything).Return(nil)
	tran.On("CanDial", addr).Return(true, nil)
	tran.On("DialContext", mock.Anything, mock.Anything).Return(ctx, mockConn, nil)
	err := suite.fnet.AddTransport(tran, prot)
	suite.Assert().Nil(err)
	suite.Assert().Len(suite.fnet.transports, 1)

	_, _, retErr := suite.fnet.DialContext(ctx, addrString)
	suite.Assert().Equal(ErrInvalidProtocol, retErr)
	tran.AssertCalled(suite.T(), "CanDial", addr)
	tran.AssertCalled(suite.T(), "DialContext", mock.Anything, mock.Anything)
}

func TestNetDialerTestSuite(t *testing.T) {
	suite.Run(t, new(NetDialerTestSuite))
}
<commit_msg>"Fix" net tests<commit_after>package net

// Basic imports
import (
	"context"
	"errors"
	"testing"

	mock "github.com/stretchr/testify/mock"
	suite "github.com/stretchr/testify/suite"
)

// NetDialerTestSuite -
type NetDialerTestSuite struct {
	suite.Suite
	fnet *nnet
	ctx  context.Context
}

func (suite *NetDialerTestSuite) SetupTest() {
	suite.ctx = context.Background()
	suite.fnet = New(suite.ctx).(*nnet)
}

func (suite *NetDialerTestSuite) TestDialContextSuccess() {
	ctx := context.Background()

	prot := &MockProtocol{}
	prot.On("Name").Return("test")
	var handler HandlerFunc = func(ctx context.Context, c Conn) error {
		return nil
	}
	var negotiator NegotiatorFunc = func(ctx context.Context, c Conn) error {
		return nil
	}
	prot.On("Handle", mock.Anything).Return(handler)
	prot.On("Negotiate", mock.Anything).Return(negotiator)
	protErr := suite.fnet.AddProtocols(prot)
	suite.Assert().Nil(protErr)
	suite.Assert().Len(suite.fnet.protocols, 1)

	addrString := "test"
	addr := NewAddress(addrString)
	mockConn := &MockConn{}
	mockConn.On("GetAddress").Return(addr)

	tran := &MockTransport{}
	tran.On("Listen", mock.Anything, mock.Anything).Return(nil)
	tran.On("CanDial", addr).Return(true, nil)
	tran.On("DialContext", mock.Anything, mock.Anything).Return(ctx, mockConn, nil)
	err := suite.fnet.AddTransport(tran, prot)
	suite.Assert().Nil(err)
	suite.Assert().Len(suite.fnet.transports, 1)

	_, _, retErr := suite.fnet.DialContext(ctx, addrString)
	suite.Assert().Nil(retErr)
	tran.AssertCalled(suite.T(), "CanDial", addr)
	tran.AssertCalled(suite.T(), "DialContext", mock.Anything, mock.Anything)
}

func (suite *NetDialerTestSuite) TestDialTransportCannotDial() {
	ctx := context.Background()

	addrString := "test"
	addr := NewAddress(addrString)
	mockConn := &MockConn{}
	mockConn.On("GetAddress").Return(addr)

	tran := &MockTransport{}
	tran.On("Listen", mock.Anything, mock.Anything).Return(nil)
	tran.On("CanDial", addr).Return(false, nil)
	err := suite.fnet.AddTransport(tran)
	suite.Assert().Nil(err)
	suite.Assert().Len(suite.fnet.transports, 1)

	_, _, retErr := suite.fnet.DialContext(ctx, addrString)
	suite.Assert().Equal(ErrNoSuchTransport, retErr)
	tran.AssertCalled(suite.T(), "CanDial", addr)
}

func (suite *NetDialerTestSuite) TestDialTransportError() {
	ctx := context.Background()

	addrString := "test"
	addr := NewAddress(addrString)
	mockConn := &MockConn{}
	mockConn.On("GetAddress").Return(addr)

	tran := &MockTransport{}
	tran.On("Listen", mock.Anything, mock.Anything).Return(nil)
	tran.On("CanDial", addr).Return(false, errors.New("error"))
	err := suite.fnet.AddTransport(tran)
	suite.Assert().Nil(err)
	suite.Assert().Len(suite.fnet.transports, 1)

	_, _, retErr := suite.fnet.DialContext(ctx, addrString)
	suite.Assert().Equal(ErrNoSuchTransport, retErr)
	tran.AssertCalled(suite.T(), "CanDial", addr)
}

func (suite *NetDialerTestSuite) TestDialContextFails() {
	ctx := context.Background()

	prot := &MockProtocol{}
	prot.On("Name").Return("test")
	var handler HandlerFunc = func(ctx context.Context, c Conn) error {
		return nil
	}
	var negotiator NegotiatorFunc = func(ctx context.Context, c Conn) error {
		return nil
	}
	prot.On("Handle", mock.Anything).Return(handler)
	prot.On("Negotiate", mock.Anything).Return(negotiator)
	protErr := suite.fnet.AddProtocols(prot)
	suite.Assert().Nil(protErr)
	suite.Assert().Len(suite.fnet.protocols, 1)

	addrString := "test"
	addr := NewAddress(addrString)
	mockConn := &MockConn{}
	mockConn.On("GetAddress").Return(addr)

	tran := &MockTransport{}
	tran.On("Listen", mock.Anything, mock.Anything).Return(nil)
	tran.On("CanDial", addr).Return(true, nil)
	tran.On("DialContext", mock.Anything, mock.Anything).Return(nil, nil, errors.New("error"))
	err := suite.fnet.AddTransport(tran, prot)
	suite.Assert().Nil(err)
	suite.Assert().Len(suite.fnet.transports, 1)

	_, _, retErr := suite.fnet.DialContext(ctx, addrString)
	suite.Assert().Equal(ErrNoSuchTransport, retErr)
	tran.AssertCalled(suite.T(), "CanDial", addr)
	tran.AssertCalled(suite.T(), "DialContext", mock.Anything, mock.Anything)
}

func (suite *NetDialerTestSuite) TestNegotiatorFails() {
	ctx := context.Background()

	prot := &MockProtocol{}
	prot.On("Name").Return("test")
	var handler HandlerFunc = func(ctx context.Context, c Conn) error {
		return nil
	}
	var negotiator NegotiatorFunc = func(ctx context.Context, c Conn) error {
		return errors.New("error")
	}
	prot.On("Handle", mock.Anything).Return(handler)
	prot.On("Negotiate", mock.Anything).Return(negotiator)
	protErr := suite.fnet.AddProtocols(prot)
	suite.Assert().Nil(protErr)
	suite.Assert().Len(suite.fnet.protocols, 1)

	addrString := "test"
	addr := NewAddress(addrString)
	mockConn := &MockConn{}
	mockConn.On("GetAddress").Return(addr)

	tran := &MockTransport{}
	tran.On("Listen", mock.Anything, mock.Anything).Return(nil)
	tran.On("CanDial", addr).Return(true, nil)
	tran.On("DialContext", mock.Anything, mock.Anything).Return(ctx, mockConn, nil)
	err := suite.fnet.AddTransport(tran, prot)
	suite.Assert().Nil(err)
	suite.Assert().Len(suite.fnet.transports, 1)

	_, _, retErr := suite.fnet.DialContext(ctx, addrString)
	suite.Assert().Equal(ErrNoSuchTransport, retErr)
	tran.AssertCalled(suite.T(), "CanDial", addr)
	tran.AssertCalled(suite.T(), "DialContext", mock.Anything, mock.Anything)
}

func (suite *NetDialerTestSuite) TestInvalidProtocolFails() {
	ctx := context.Background()

	prot := &MockProtocol{}
	prot.On("Name").Return("nope")
	var handler HandlerFunc = func(ctx context.Context, c Conn) error {
		return nil
	}
	var negotiator NegotiatorFunc = func(ctx context.Context, c Conn) error {
		return nil
	}
	prot.On("Handle", mock.Anything).Return(handler)
	prot.On("Negotiate", mock.Anything).Return(negotiator)
	protErr := suite.fnet.AddProtocols(prot)
	suite.Assert().Nil(protErr)
	suite.Assert().Len(suite.fnet.protocols, 1)

	addrString := "test"
	addr := NewAddress(addrString)
	mockConn := &MockConn{}
	mockConn.On("GetAddress").Return(addr)

	tran := &MockTransport{}
	tran.On("Listen", mock.Anything, mock.Anything).Return(nil)
	tran.On("CanDial", addr).Return(true, nil)
	tran.On("DialContext", mock.Anything, mock.Anything).Return(ctx, mockConn, nil)
	err := suite.fnet.AddTransport(tran, prot)
	suite.Assert().Nil(err)
	suite.Assert().Len(suite.fnet.transports, 1)

	_, _, retErr := suite.fnet.DialContext(ctx, addrString)
	suite.Assert().Equal(nil, retErr)
	tran.AssertCalled(suite.T(), "CanDial", addr)
	tran.AssertCalled(suite.T(), "DialContext", mock.Anything, mock.Anything)
}

func TestNetDialerTestSuite(t *testing.T) {
	suite.Run(t, new(NetDialerTestSuite))
}
<|endoftext|>


<commit_before>// a2filter.go - A2 bloom filter
//
// To the extent possible under law, the Yawning Angel waived all copyright
// and related or neighboring rights to a2filter, using the creative
// commons "cc0" public domain dedication. See LICENSE or
// <http://creativecommons.org/publicdomain/zero/1.0/> for full details.

// Package a2filter implements a SipHash-2-4 based Active-Active Bloom Filter.
// It is designed to be stable over time even when filled to max capacity by
// implementing the active-active buffering (A2 buffering) scheme presented in
// "Aging Bloom Filter with Two Active Buffers for Dynamic Sets" (MyungKeun
// Yoon).
//
// Note that none of the operations on the filter are constant time, and the
// the max backing Bloom Filter size is limited to 2^31 bytes.  This package is
// threadsafe.
package a2filter

import (
	"crypto/rand"
	"encoding/binary"
	"fmt"
	"math"
	"sync"

	"github.com/dchest/siphash"
)

const (
	ln2         = 0.69314718055994529
	ln2Sq       = 0.48045301391820139
	maxMln2     = 31
	maxNrHashes = 32
)

// A2Filter is an Active-Active Bloom Filter.
type A2Filter struct {
	sync.Mutex
	k1, k2 uint64

	nrEntries    int
	nrEntriesMax int

	nrHashes int
	hashMask uint32
	active1  []byte
	active2  []byte
}

// New constructs a new A2Filter with a filter set size 2^mLn2, and false
// postive rate p.  The actual in memory footprint of the datastructure will be
// approximately 2^(mLn2+1) bits due to the double buffered nature of the
// filter.
func New(mLn2 int, p float64) (*A2Filter, error) {
	var key [16]byte
	_, err := rand.Read(key[:])
	if err != nil {
		return nil, err
	}

	if mLn2 > maxMln2 {
		return nil, fmt.Errorf("requested filter too large: %d", mLn2)
	}

	m := 1 << uint32(mLn2)
	n := -1.0 * float64(m) * ln2Sq / math.Log(p)
	k := int((float64(m) * ln2 / n) + 0.5)

	f := new(A2Filter)
	f.k1 = binary.BigEndian.Uint64(key[0:8])
	f.k2 = binary.BigEndian.Uint64(key[8:16])
	f.nrEntriesMax = int(n)
	f.nrHashes = k
	f.hashMask = uint32(m - 1)
	if f.nrHashes < 2 {
		f.nrHashes = 2
	}
	if f.nrHashes > maxNrHashes {
		return nil, fmt.Errorf("requested parameters need too many hashes")
	}
	f.active1 = make([]byte, m/8)
	f.active2 = make([]byte, m/8)
	return f, nil
}

// TestAndSet tests the A2Filter for a given value's membership, adds the
// value to the filter and returns if it was present at the time of the call.
func (f *A2Filter) TestAndSet(b []byte) bool {
	hashes := f.getHashes(b)

	f.Lock()
	defer f.Unlock()

	// If the member is present in Active1, just return.
	if f.testCache(f.active1, hashes) {
		return true
	}

	// Test Active2 for membership, and add the value to Active1.
	ret := f.testCache(f.active2, hashes)
	if f.nrEntries++; f.nrEntries > f.nrEntriesMax {
		// Active1 is full, clear Active2 and swap the buffers, this leaves
		// Active1 empty, and Active2 populated to saturation, immediately
		// after the tested entry will be added to Active1.
		f.active2 = make([]byte, len(f.active2))
		f.active1, f.active2 = f.active2, f.active1
		f.nrEntries = 1
	}
	f.addActive1(hashes)
	return ret
}

// MaxEntries returns the maximum capacity of the A2Filter.  This value is
// usually an underestimate as the filter is double buffered, however entry
// count accounting is only done for Active1, so Active2 should be ignored in
// calculations.
func (f *A2Filter) MaxEntries() int {
	return f.nrEntriesMax
}

func (f *A2Filter) testCache(cache []byte, hashes []uint32) bool {
	for i := 0; i < f.nrHashes; i++ {
		idx := hashes[i] & f.hashMask
		if 0 == cache[idx/8]&(1<<(idx&7)) {
			// Break out early if there is a miss.
			return false
		}
	}
	return true
}

func (f *A2Filter) addActive1(hashes []uint32) {
	for i := 0; i < f.nrHashes; i++ {
		idx := hashes[i] & f.hashMask
		f.active1[idx/8] |= (1 << (idx & 7))
	}
}

func (f *A2Filter) getHashes(b []byte) []uint32 {
	// Per "Less Hashing, Same Performance: Building a Better Bloom Filter"
	// (Kirsch and Miteznmacher), with a suitably good PRF, only two calls to
	// the hash algorithm are needed.  As SipHash-2-4 returns a 64 bit digest,
	// and we use 32 bit hashes for the filter, this results in only one
	// invocation of SipHash-2-4.

	hashes := make([]uint32, f.nrHashes)
	baseHash := siphash.Hash(f.k1, f.k2, b)
	hashes[0] = uint32(baseHash & math.MaxUint32)
	hashes[1] = uint32(baseHash >> 32)
	for i := 2; i < f.nrHashes; i++ {
		hashes[i] = hashes[0] + uint32(i)*hashes[1]
	}
	return hashes
}
<commit_msg>Take an io.Reader as the entropy source.<commit_after>// a2filter.go - A2 bloom filter
//
// To the extent possible under law, the Yawning Angel waived all copyright
// and related or neighboring rights to a2filter, using the creative
// commons "cc0" public domain dedication. See LICENSE or
// <http://creativecommons.org/publicdomain/zero/1.0/> for full details.

// Package a2filter implements a SipHash-2-4 based Active-Active Bloom Filter.
// It is designed to be stable over time even when filled to max capacity by
// implementing the active-active buffering (A2 buffering) scheme presented in
// "Aging Bloom Filter with Two Active Buffers for Dynamic Sets" (MyungKeun
// Yoon).
//
// Note that none of the operations on the filter are constant time, and the
// the max backing Bloom Filter size is limited to 2^31 bytes.  This package is
// threadsafe.
package a2filter

import (
	"encoding/binary"
	"fmt"
	"io"
	"math"
	"sync"

	"github.com/dchest/siphash"
)

const (
	ln2         = 0.69314718055994529
	ln2Sq       = 0.48045301391820139
	maxMln2     = 31
	maxNrHashes = 32
)

// A2Filter is an Active-Active Bloom Filter.
type A2Filter struct {
	sync.Mutex
	k1, k2 uint64

	nrEntries    int
	nrEntriesMax int

	nrHashes int
	hashMask uint32
	active1  []byte
	active2  []byte
}

// New constructs a new A2Filter with a filter set size 2^mLn2, and false
// postive rate p.  The actual in memory footprint of the datastructure will be
// approximately 2^(mLn2+1) bits due to the double buffered nature of the
// filter.
func New(rand io.Reader, mLn2 int, p float64) (*A2Filter, error) {
	var key [16]byte
	if _, err := io.ReadFull(rand, key[:]); err != nil {
		return nil, err
	}

	if mLn2 > maxMln2 {
		return nil, fmt.Errorf("requested filter too large: %d", mLn2)
	}

	m := 1 << uint32(mLn2)
	n := -1.0 * float64(m) * ln2Sq / math.Log(p)
	k := int((float64(m) * ln2 / n) + 0.5)

	f := new(A2Filter)
	f.k1 = binary.BigEndian.Uint64(key[0:8])
	f.k2 = binary.BigEndian.Uint64(key[8:16])
	f.nrEntriesMax = int(n)
	f.nrHashes = k
	f.hashMask = uint32(m - 1)
	if f.nrHashes < 2 {
		f.nrHashes = 2
	}
	if f.nrHashes > maxNrHashes {
		return nil, fmt.Errorf("requested parameters need too many hashes")
	}
	f.active1 = make([]byte, m/8)
	f.active2 = make([]byte, m/8)
	return f, nil
}

// TestAndSet tests the A2Filter for a given value's membership, adds the
// value to the filter and returns if it was present at the time of the call.
func (f *A2Filter) TestAndSet(b []byte) bool {
	hashes := f.getHashes(b)

	f.Lock()
	defer f.Unlock()

	// If the member is present in Active1, just return.
	if f.testCache(f.active1, hashes) {
		return true
	}

	// Test Active2 for membership, and add the value to Active1.
	ret := f.testCache(f.active2, hashes)
	if f.nrEntries++; f.nrEntries > f.nrEntriesMax {
		// Active1 is full, clear Active2 and swap the buffers, this leaves
		// Active1 empty, and Active2 populated to saturation, immediately
		// after the tested entry will be added to Active1.
		f.active2 = make([]byte, len(f.active2))
		f.active1, f.active2 = f.active2, f.active1
		f.nrEntries = 1
	}
	f.addActive1(hashes)
	return ret
}

// MaxEntries returns the maximum capacity of the A2Filter.  This value is
// usually an underestimate as the filter is double buffered, however entry
// count accounting is only done for Active1, so Active2 should be ignored in
// calculations.
func (f *A2Filter) MaxEntries() int {
	return f.nrEntriesMax
}

func (f *A2Filter) testCache(cache []byte, hashes []uint32) bool {
	for i := 0; i < f.nrHashes; i++ {
		idx := hashes[i] & f.hashMask
		if 0 == cache[idx/8]&(1<<(idx&7)) {
			// Break out early if there is a miss.
			return false
		}
	}
	return true
}

func (f *A2Filter) addActive1(hashes []uint32) {
	for i := 0; i < f.nrHashes; i++ {
		idx := hashes[i] & f.hashMask
		f.active1[idx/8] |= (1 << (idx & 7))
	}
}

func (f *A2Filter) getHashes(b []byte) []uint32 {
	// Per "Less Hashing, Same Performance: Building a Better Bloom Filter"
	// (Kirsch and Miteznmacher), with a suitably good PRF, only two calls to
	// the hash algorithm are needed.  As SipHash-2-4 returns a 64 bit digest,
	// and we use 32 bit hashes for the filter, this results in only one
	// invocation of SipHash-2-4.

	hashes := make([]uint32, f.nrHashes)
	baseHash := siphash.Hash(f.k1, f.k2, b)
	hashes[0] = uint32(baseHash & math.MaxUint32)
	hashes[1] = uint32(baseHash >> 32)
	for i := 2; i < f.nrHashes; i++ {
		hashes[i] = hashes[0] + uint32(i)*hashes[1]
	}
	return hashes
}
<|endoftext|>


<commit_before>package sphere

import (
	"errors"

	"github.com/streamrail/concurrent-map"
)

const (
	// BrokerErrorOverrideOnSubscribe to warn use to override OnSubsribe function
	BrokerErrorOverrideOnSubscribe = "please override OnSubscribe"
	// BrokerErrorOverrideOnUnsubscribe to warn use to override OnUnsubscribe function
	BrokerErrorOverrideOnUnsubscribe = "please override OnUnsubscribe"
	// BrokerErrorOverrideOnPublish to warn use to override OnPublish function
	BrokerErrorOverrideOnPublish = "please override OnPublish"
	// BrokerErrorOverrideOnMessage to warn use to override OnMessage function
	BrokerErrorOverrideOnMessage = "please override OnMessage"
)

// Agent represents Broker instance
type Agent interface {
	ID() string                            // => Broker ID
	ChannelName(string, string) string     // => Broker generate channel name with namespace and channel
	IsSubscribed(string) bool              // => Broker channel subscribe state
	OnSubscribe(*Channel) error            // => Broker OnSubscribe
	OnUnsubscribe(*Channel) error          // => Broker OnUnsubscribe
	OnPublish(*Channel, interface{}) error // => Broker OnPublish
	OnMessage(*Channel, interface{}) error // => Broker OnMessage
}

// ExtendBroker creates a broker instance
func ExtendBroker() *Broker {
	return &Broker{
		id:    guid.String(),
		store: cmap.New(),
	}
}

// Broker allows you to interact directly with Websocket internal data and pub/sub channels
type Broker struct {
	// Broker ID
	id string
	// Channel store
	store cmap.ConcurrentMap
}

// ID returns the unique id for the broker
func (broker *Broker) ID() string {
	return broker.id
}

// ChannelName returns channel name with provided namespace and room name
func (broker *Broker) ChannelName(namespace string, room string) string {
	return namespace + ":" + room
}

// IsSubscribed return the broker state of the channel
func (broker *Broker) IsSubscribed(name string) bool {
	return broker.store.Has(name)
}

// OnSubscribe when websocket subscribes to a channel
func (broker *Broker) OnSubscribe(channel *Channel) error {
	return errors.New(BrokerErrorOverrideOnSubscribe)
}

// OnUnsubscribe when websocket unsubscribes from a channel
func (broker *Broker) OnUnsubscribe(channel *Channel) error {
	return errors.New(BrokerErrorOverrideOnUnsubscribe)
}

// OnPublish when websocket publishes data to a particular channel from the current broker
func (broker *Broker) OnPublish(channel *Channel, data interface{}) error {
	return errors.New(BrokerErrorOverrideOnPublish)
}

// OnMessage when websocket receive data from the broker subscriber
func (broker *Broker) OnMessage(channel *Channel, data interface{}) error {
	return errors.New(BrokerErrorOverrideOnMessage)
}
<commit_msg>use namespace, room format instead of pure name<commit_after>package sphere

import (
	"errors"

	"github.com/streamrail/concurrent-map"
)

const (
	// BrokerErrorOverrideOnSubscribe to warn use to override OnSubsribe function
	BrokerErrorOverrideOnSubscribe = "please override OnSubscribe"
	// BrokerErrorOverrideOnUnsubscribe to warn use to override OnUnsubscribe function
	BrokerErrorOverrideOnUnsubscribe = "please override OnUnsubscribe"
	// BrokerErrorOverrideOnPublish to warn use to override OnPublish function
	BrokerErrorOverrideOnPublish = "please override OnPublish"
	// BrokerErrorOverrideOnMessage to warn use to override OnMessage function
	BrokerErrorOverrideOnMessage = "please override OnMessage"
)

// Agent represents Broker instance
type Agent interface {
	ID() string                            // => Broker ID
	ChannelName(string, string) string     // => Broker generate channel name with namespace and channel
	IsSubscribed(string, string) bool      // => Broker channel subscribe state
	OnSubscribe(*Channel) error            // => Broker OnSubscribe
	OnUnsubscribe(*Channel) error          // => Broker OnUnsubscribe
	OnPublish(*Channel, interface{}) error // => Broker OnPublish
	OnMessage(*Channel, interface{}) error // => Broker OnMessage
}

// ExtendBroker creates a broker instance
func ExtendBroker() *Broker {
	return &Broker{
		id:    guid.String(),
		store: cmap.New(),
	}
}

// Broker allows you to interact directly with Websocket internal data and pub/sub channels
type Broker struct {
	// Broker ID
	id string
	// Channel store
	store cmap.ConcurrentMap
}

// ID returns the unique id for the broker
func (broker *Broker) ID() string {
	return broker.id
}

// ChannelName returns channel name with provided namespace and room name
func (broker *Broker) ChannelName(namespace string, room string) string {
	return namespace + ":" + room
}

// IsSubscribed return the broker state of the channel
func (broker *Broker) IsSubscribed(namespace string, room string) bool {
	return broker.store.Has(broker.ChannelName(namespace, room))
}

// OnSubscribe when websocket subscribes to a channel
func (broker *Broker) OnSubscribe(channel *Channel) error {
	return errors.New(BrokerErrorOverrideOnSubscribe)
}

// OnUnsubscribe when websocket unsubscribes from a channel
func (broker *Broker) OnUnsubscribe(channel *Channel) error {
	return errors.New(BrokerErrorOverrideOnUnsubscribe)
}

// OnPublish when websocket publishes data to a particular channel from the current broker
func (broker *Broker) OnPublish(channel *Channel, data interface{}) error {
	return errors.New(BrokerErrorOverrideOnPublish)
}

// OnMessage when websocket receive data from the broker subscriber
func (broker *Broker) OnMessage(channel *Channel, data interface{}) error {
	return errors.New(BrokerErrorOverrideOnMessage)
}
<|endoftext|>


<commit_before>/*
Copyright 2021 The Vitess Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package semantics

import (
	"vitess.io/vitess/go/vt/key"
	vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
	"vitess.io/vitess/go/vt/sqlparser"
	"vitess.io/vitess/go/vt/vterrors"
	"vitess.io/vitess/go/vt/vtgate/vindexes"
)

// tableCollector is responsible for gathering information about the tables listed in the FROM clause,
// and adding them to the current scope, plus keeping the global list of tables used in the query
type tableCollector struct {
	Tables    []TableInfo
	scoper    *scoper
	si        SchemaInformation
	currentDb string
	org       originable
}

func newTableCollector(scoper *scoper, si SchemaInformation, currentDb string) *tableCollector {
	return &tableCollector{
		scoper:    scoper,
		si:        si,
		currentDb: currentDb,
	}
}

func (tc *tableCollector) up(cursor *sqlparser.Cursor) error {
	node, ok := cursor.Node().(*sqlparser.AliasedTableExpr)
	if !ok {
		return nil
	}

	switch t := node.Expr.(type) {
	case *sqlparser.DerivedTable:
		switch sel := t.Select.(type) {
		case *sqlparser.Select:
			tables := tc.scoper.wScope[sel]
			tableInfo := createDerivedTableForExpressions(sqlparser.GetFirstSelect(sel).SelectExprs, tables.tables, tc.org)
			if err := tableInfo.checkForDuplicates(); err != nil {
				return err
			}

			tableInfo.ASTNode = node
			tableInfo.tableName = node.As.String()

			tc.Tables = append(tc.Tables, tableInfo)
			scope := tc.scoper.currentScope()
			return scope.addTable(tableInfo)

		case *sqlparser.Union:
			firstSelect := sqlparser.GetFirstSelect(sel)
			tables := tc.scoper.wScope[firstSelect]
			tableInfo := createDerivedTableForExpressions(firstSelect.SelectExprs, tables.tables, tc.org)
			if err := tableInfo.checkForDuplicates(); err != nil {
				return err
			}
			tableInfo.ASTNode = node
			tableInfo.tableName = node.As.String()

			tc.Tables = append(tc.Tables, tableInfo)
			scope := tc.scoper.currentScope()
			return scope.addTable(tableInfo)

		default:
			return Gen4NotSupportedF("%T in a derived table", sel)
		}

	case sqlparser.TableName:
		var tbl *vindexes.Table
		var vindex vindexes.Vindex
		var isInfSchema bool
		if sqlparser.SystemSchema(t.Qualifier.String()) {
			isInfSchema = true
		} else {
			var err error
			var target key.Destination
			tbl, vindex, _, _, target, err = tc.si.FindTableOrVindex(t)
			if err != nil {
				return err
			}
			if target != nil {
				return vterrors.Errorf(vtrpcpb.Code_UNIMPLEMENTED, "unsupported: SELECT with a target destination")
			}
			if tbl == nil && vindex != nil {
				tbl = newVindexTable(t.Name)
			}
		}
		scope := tc.scoper.currentScope()
		tableInfo := tc.createTable(t, node, tbl, isInfSchema, vindex)

		tc.Tables = append(tc.Tables, tableInfo)
		return scope.addTable(tableInfo)
	}
	return nil
}

func newVindexTable(t sqlparser.TableIdent) *vindexes.Table {
	vindexCols := []vindexes.Column{
		{Name: sqlparser.NewColIdent("id")},
		{Name: sqlparser.NewColIdent("keyspace_id")},
		{Name: sqlparser.NewColIdent("range_start")},
		{Name: sqlparser.NewColIdent("range_end")},
		{Name: sqlparser.NewColIdent("hex_keyspace_id")},
		{Name: sqlparser.NewColIdent("shard")},
	}

	return &vindexes.Table{
		Name:                    t,
		Columns:                 vindexCols,
		ColumnListAuthoritative: true,
	}
}

// tabletSetFor implements the originable interface, and that is why it lives on the analyser struct.
// The code lives in this file since it is only touching tableCollector data
func (tc *tableCollector) tableSetFor(t *sqlparser.AliasedTableExpr) TableSet {
	for i, t2 := range tc.Tables {
		if t == t2.getExpr() {
			return TableSet(1 << i)
		}
	}
	panic("unknown table")
}

func (tc *tableCollector) createTable(
	t sqlparser.TableName,
	alias *sqlparser.AliasedTableExpr,
	tbl *vindexes.Table,
	isInfSchema bool,
	vindex vindexes.Vindex,
) TableInfo {
	table := &RealTable{
		tableName:   alias.As.String(),
		ASTNode:     alias,
		Table:       tbl,
		isInfSchema: isInfSchema,
	}

	if alias.As.IsEmpty() {
		dbName := t.Qualifier.String()
		if dbName == "" {
			dbName = tc.currentDb
		}

		table.dbName = dbName
		table.tableName = t.Name.String()
	}

	if vindex != nil {
		return &VindexTable{
			Table:  table,
			Vindex: vindex,
		}
	}
	return table
}
<commit_msg>return error than not supported error on derived table query<commit_after>/*
Copyright 2021 The Vitess Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package semantics

import (
	"vitess.io/vitess/go/vt/key"
	vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
	"vitess.io/vitess/go/vt/sqlparser"
	"vitess.io/vitess/go/vt/vterrors"
	"vitess.io/vitess/go/vt/vtgate/vindexes"
)

// tableCollector is responsible for gathering information about the tables listed in the FROM clause,
// and adding them to the current scope, plus keeping the global list of tables used in the query
type tableCollector struct {
	Tables    []TableInfo
	scoper    *scoper
	si        SchemaInformation
	currentDb string
	org       originable
}

func newTableCollector(scoper *scoper, si SchemaInformation, currentDb string) *tableCollector {
	return &tableCollector{
		scoper:    scoper,
		si:        si,
		currentDb: currentDb,
	}
}

func (tc *tableCollector) up(cursor *sqlparser.Cursor) error {
	node, ok := cursor.Node().(*sqlparser.AliasedTableExpr)
	if !ok {
		return nil
	}

	switch t := node.Expr.(type) {
	case *sqlparser.DerivedTable:
		switch sel := t.Select.(type) {
		case *sqlparser.Select:
			tables := tc.scoper.wScope[sel]
			tableInfo := createDerivedTableForExpressions(sqlparser.GetFirstSelect(sel).SelectExprs, tables.tables, tc.org)
			if err := tableInfo.checkForDuplicates(); err != nil {
				return err
			}

			tableInfo.ASTNode = node
			tableInfo.tableName = node.As.String()

			tc.Tables = append(tc.Tables, tableInfo)
			scope := tc.scoper.currentScope()
			return scope.addTable(tableInfo)

		case *sqlparser.Union:
			firstSelect := sqlparser.GetFirstSelect(sel)
			tables := tc.scoper.wScope[firstSelect]
			tableInfo := createDerivedTableForExpressions(firstSelect.SelectExprs, tables.tables, tc.org)
			if err := tableInfo.checkForDuplicates(); err != nil {
				return err
			}
			tableInfo.ASTNode = node
			tableInfo.tableName = node.As.String()

			tc.Tables = append(tc.Tables, tableInfo)
			scope := tc.scoper.currentScope()
			return scope.addTable(tableInfo)

		default:
			return vterrors.Errorf(vtrpcpb.Code_INTERNAL, "[BUG] %T in a derived table", sel)
		}

	case sqlparser.TableName:
		var tbl *vindexes.Table
		var vindex vindexes.Vindex
		var isInfSchema bool
		if sqlparser.SystemSchema(t.Qualifier.String()) {
			isInfSchema = true
		} else {
			var err error
			var target key.Destination
			tbl, vindex, _, _, target, err = tc.si.FindTableOrVindex(t)
			if err != nil {
				return err
			}
			if target != nil {
				return vterrors.Errorf(vtrpcpb.Code_UNIMPLEMENTED, "unsupported: SELECT with a target destination")
			}
			if tbl == nil && vindex != nil {
				tbl = newVindexTable(t.Name)
			}
		}
		scope := tc.scoper.currentScope()
		tableInfo := tc.createTable(t, node, tbl, isInfSchema, vindex)

		tc.Tables = append(tc.Tables, tableInfo)
		return scope.addTable(tableInfo)
	}
	return nil
}

func newVindexTable(t sqlparser.TableIdent) *vindexes.Table {
	vindexCols := []vindexes.Column{
		{Name: sqlparser.NewColIdent("id")},
		{Name: sqlparser.NewColIdent("keyspace_id")},
		{Name: sqlparser.NewColIdent("range_start")},
		{Name: sqlparser.NewColIdent("range_end")},
		{Name: sqlparser.NewColIdent("hex_keyspace_id")},
		{Name: sqlparser.NewColIdent("shard")},
	}

	return &vindexes.Table{
		Name:                    t,
		Columns:                 vindexCols,
		ColumnListAuthoritative: true,
	}
}

// tabletSetFor implements the originable interface, and that is why it lives on the analyser struct.
// The code lives in this file since it is only touching tableCollector data
func (tc *tableCollector) tableSetFor(t *sqlparser.AliasedTableExpr) TableSet {
	for i, t2 := range tc.Tables {
		if t == t2.getExpr() {
			return TableSet(1 << i)
		}
	}
	panic("unknown table")
}

func (tc *tableCollector) createTable(
	t sqlparser.TableName,
	alias *sqlparser.AliasedTableExpr,
	tbl *vindexes.Table,
	isInfSchema bool,
	vindex vindexes.Vindex,
) TableInfo {
	table := &RealTable{
		tableName:   alias.As.String(),
		ASTNode:     alias,
		Table:       tbl,
		isInfSchema: isInfSchema,
	}

	if alias.As.IsEmpty() {
		dbName := t.Qualifier.String()
		if dbName == "" {
			dbName = tc.currentDb
		}

		table.dbName = dbName
		table.tableName = t.Name.String()
	}

	if vindex != nil {
		return &VindexTable{
			Table:  table,
			Vindex: vindex,
		}
	}
	return table
}
<|endoftext|>


<commit_before>package logger

import (
	"fmt"
	"log"
	"os"
)

// Logger is a util class to print log in different level like DEBUG.
// It has 4 level: DEBUG, INFO, WARN, ERROR,
// and 2 exception logger: PANIC and FATAL
type Logger struct {
	Prefix string
	dl     *log.Logger
	il     *log.Logger
	wl     *log.Logger
	el     *log.Logger
	pl     *log.Logger
	fl     *log.Logger
}

// Logger levels
const (
	LevelDebug int = iota
	LevelInfo
	LevelWarn
	LevelError
)

var (
	l = NewLogger("[Logger]")

	currentLevel = LevelDebug
)

// NewLogger create a new top level logger based on prefix.
func NewLogger(prefix string) *Logger {
	return &Logger{
		Prefix: prefix,
		dl:     log.New(os.Stdout, fmt.Sprintf("[%s] %s ", "DEBUG", prefix), log.LstdFlags),
		il:     log.New(os.Stdout, fmt.Sprintf("[%s] %s ", "INFO", prefix), log.LstdFlags),
		wl:     log.New(os.Stdout, fmt.Sprintf("[%s] %s ", "WARN", prefix), log.LstdFlags),
		el:     log.New(os.Stdout, fmt.Sprintf("[%s] %s ", "ERROR", prefix), log.LstdFlags),
		pl:     log.New(os.Stdout, fmt.Sprintf("[%s] %s ", "PANIC", prefix), log.LstdFlags),
		fl:     log.New(os.Stdout, fmt.Sprintf("[%s] %s ", "FATAL", prefix), log.LstdFlags),
	}
}

// Debug print log message as DEBUG level.
// if you set log level higher than LevelDebug, no message will be print.
func (logger *Logger) Debug(data ...interface{}) {
	if currentLevel <= LevelDebug {
		logger.dl.Println(data...)
	}
}

// Info print log message as INFO level.
// If you set log level higher than LevelInfo, no message will be print.
func (logger *Logger) Info(data ...interface{}) {
	if currentLevel <= LevelInfo {
		logger.il.Println(data...)
	}
}

// Warn print log message as WARN level.
// If you set log level higher than LevelWarn, no message will be print.
func (logger *Logger) Warn(data ...interface{}) {
	if currentLevel <= LevelWarn {
		logger.wl.Println(data...)
	}
}

// Error print log message as ERROR level.
// This function do not create panic or fatal, it just print error message.
// If you want get a runtime panic or fatal, use Logger.Panic or Logger.Fatal instead.
func (logger *Logger) Error(data ...interface{}) {
	if currentLevel <= LevelError {
		logger.el.Println(data...)
	}
}

// Panic print log message, and create a panic use the message.
func (logger *Logger) Panic(data ...interface{}) {
	logger.pl.Panicln(data...)
}

// Fatal print log message, and create a fatal use the message.
func (logger *Logger) Fatal(data ...interface{}) {
	logger.fl.Fatalln(data...)
}

// SubLogger create a new logger based on the logger.
// Prefix string of new logger will be concat of old and provided argument.
func (logger *Logger) SubLogger(prefix string) (subLogger *Logger) {
	subLogger = NewLogger(fmt.Sprintf("%s %s", logger.Prefix, prefix))
	return subLogger
}

// SetLevel set the minimum level that message will be print out
func SetLevel(level int) {
	if LevelDebug <= level && level < LevelError {
		currentLevel = level
	} else {
		l.Error("Set logger level", level, "failed, accepted range is", LevelInfo, "to", LevelError)
	}
}
<commit_msg>refactoring logger<commit_after>package logger

import (
	"fmt"
	"log"
	"os"
)

// Logger is a util class to print log in different level like DEBUG.
// It has 4 level: DEBUG, INFO, WARN, ERROR,
// and 2 exception logger: PANIC and FATAL
type Logger struct {
	prefix     string
	trueLogger *log.Logger
}

// Logger levels
const (
	LevelDebug int = iota
	LevelInfo
	LevelWarn
	LevelError
)

var (
	l = NewLogger("[Logger]")

	currentLevel = LevelDebug
)

// NewLogger create a new top level logger based on prefix.
func NewLogger(prefix string) *Logger {
	flag := log.Ldate | log.Ltime | log.Lmicroseconds
	return &Logger{
		prefix:     prefix,
		trueLogger: log.New(os.Stdout, "", flag),
	}
}

// Debug print log message as DEBUG level.
// if you set log level higher than LevelDebug, no message will be print.
func (logger *Logger) Debug(data ...interface{}) {
	if currentLevel <= LevelDebug {
		logger.trueLogger.Print("[DEBUG] ", logger.prefix, " ", fmt.Sprintln(data...))
	}
}

// Info print log message as INFO level.
// If you set log level higher than LevelInfo, no message will be print.
func (logger *Logger) Info(data ...interface{}) {
	if currentLevel <= LevelInfo {
		logger.trueLogger.Print("[ Info] ", logger.prefix, " ", fmt.Sprintln(data...))
	}
}

// Warn print log message as WARN level.
// If you set log level higher than LevelWarn, no message will be print.
func (logger *Logger) Warn(data ...interface{}) {
	if currentLevel <= LevelWarn {
		logger.trueLogger.Print("[ WARN] ", logger.prefix, " ", fmt.Sprintln(data...))
	}
}

// Error print log message as ERROR level.
// This function do not create panic or fatal, it just print error message.
// If you want get a runtime panic or fatal, use Logger.Panic or Logger.Fatal instead.
func (logger *Logger) Error(data ...interface{}) {
	if currentLevel <= LevelError {
		logger.trueLogger.Print("[ERROR] ", logger.prefix, " ", fmt.Sprintln(data...))
	}
}

// Panic print log message, and create a panic use the message.
func (logger *Logger) Panic(data ...interface{}) {
	logger.trueLogger.Panic("[PANIC]", logger.prefix, " ", fmt.Sprint(data...))
}

// Fatal print log message, and create a fatal use the message.
func (logger *Logger) Fatal(data ...interface{}) {
	logger.trueLogger.Fatal("FATAL", logger.prefix, " ", fmt.Sprint(data...))
}

// SubLogger create a new logger based on the logger.
// Prefix string of new logger will be concat of old and provided argument.
func (logger *Logger) SubLogger(prefix string) (subLogger *Logger) {
	return NewLogger(fmt.Sprintf("%s %s", logger.prefix, prefix))
}

// SetLevel set the minimum level that message will be print out
func SetLevel(level int) {
	if LevelDebug <= level && level < LevelError {
		currentLevel = level
	} else {
		l.Error("Set logger level", level, "failed, accepted range is", LevelInfo, "to", LevelError)
	}
}
<|endoftext|>