<commit_before>/*
Copyright 2016 The Kubernetes 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 common

import (
	"fmt"
	"os"
	"path"

	"k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/kubernetes/pkg/api/testapi"
	"k8s.io/kubernetes/test/e2e/framework"

	. "github.com/onsi/ginkgo"
)

//TODO : Consolidate this code with the code for emptyDir.
//This will require some smart.
var _ = framework.KubeDescribe("HostPath", func() {
	f := framework.NewDefaultFramework("hostpath")

	BeforeEach(func() {
		// TODO permission denied cleanup failures
		//cleanup before running the test.
		_ = os.Remove("/tmp/test-file")
	})

	It("should give a volume the correct mode [Conformance] [sig-storage]", func() {
		source := &v1.HostPathVolumeSource{
			Path: "/tmp",
		}
		pod := testPodWithHostVol(volumePath, source)

		pod.Spec.Containers[0].Args = []string{
			fmt.Sprintf("--fs_type=%v", volumePath),
			fmt.Sprintf("--file_mode=%v", volumePath),
		}
		f.TestContainerOutput("hostPath mode", pod, 0, []string{
			"mode of file \"/test-volume\": dtrwxrwxrwx", // we expect the sticky bit (mode flag t) to be set for the dir
		})
	})

	// This test requires mounting a folder into a container with write privileges.
	It("should support r/w [sig-storage]", func() {
		filePath := path.Join(volumePath, "test-file")
		retryDuration := 180
		source := &v1.HostPathVolumeSource{
			Path: "/tmp",
		}
		pod := testPodWithHostVol(volumePath, source)

		pod.Spec.Containers[0].Args = []string{
			fmt.Sprintf("--new_file_0644=%v", filePath),
			fmt.Sprintf("--file_mode=%v", filePath),
		}

		pod.Spec.Containers[1].Args = []string{
			fmt.Sprintf("--file_content_in_loop=%v", filePath),
			fmt.Sprintf("--retry_time=%d", retryDuration),
		}
		//Read the content of the file with the second container to
		//verify volumes  being shared properly among containers within the pod.
		f.TestContainerOutput("hostPath r/w", pod, 1, []string{
			"content of file \"/test-volume/test-file\": mount-tester new file",
		})
	})

	It("should support subPath [sig-storage]", func() {
		subPath := "sub-path"
		fileName := "test-file"
		retryDuration := 180

		filePathInWriter := path.Join(volumePath, fileName)
		filePathInReader := path.Join(volumePath, subPath, fileName)

		source := &v1.HostPathVolumeSource{
			Path: "/tmp",
		}
		pod := testPodWithHostVol(volumePath, source)

		// Write the file in the subPath from container 0
		container := &pod.Spec.Containers[0]
		container.VolumeMounts[0].SubPath = subPath
		container.Args = []string{
			fmt.Sprintf("--new_file_0644=%v", filePathInWriter),
			fmt.Sprintf("--file_mode=%v", filePathInWriter),
		}

		// Read it from outside the subPath from container 1
		pod.Spec.Containers[1].Args = []string{
			fmt.Sprintf("--file_content_in_loop=%v", filePathInReader),
			fmt.Sprintf("--retry_time=%d", retryDuration),
		}

		f.TestContainerOutput("hostPath subPath", pod, 1, []string{
			"content of file \"" + filePathInReader + "\": mount-tester new file",
		})
	})

	It("should support existing directory subPath [sig-storage]", func() {
		framework.SkipUnlessSSHKeyPresent()

		subPath := "sub-path"
		fileName := "test-file"
		retryDuration := 180

		filePathInWriter := path.Join(volumePath, fileName)
		filePathInReader := path.Join(volumePath, subPath, fileName)

		source := &v1.HostPathVolumeSource{
			Path: "/tmp",
		}
		pod := testPodWithHostVol(volumePath, source)
		nodeList := framework.GetReadySchedulableNodesOrDie(f.ClientSet)
		pod.Spec.NodeName = nodeList.Items[0].Name

		// Create the subPath directory on the host
		existing := path.Join(source.Path, subPath)
		result, err := framework.SSH(fmt.Sprintf("mkdir -p %s", existing), framework.GetNodeExternalIP(&nodeList.Items[0]), framework.TestContext.Provider)
		framework.LogSSHResult(result)
		framework.ExpectNoError(err)
		if result.Code != 0 {
			framework.Failf("mkdir returned non-zero")
		}

		// Write the file in the subPath from container 0
		container := &pod.Spec.Containers[0]
		container.VolumeMounts[0].SubPath = subPath
		container.Args = []string{
			fmt.Sprintf("--new_file_0644=%v", filePathInWriter),
			fmt.Sprintf("--file_mode=%v", filePathInWriter),
		}

		// Read it from outside the subPath from container 1
		pod.Spec.Containers[1].Args = []string{
			fmt.Sprintf("--file_content_in_loop=%v", filePathInReader),
			fmt.Sprintf("--retry_time=%d", retryDuration),
		}

		f.TestContainerOutput("hostPath subPath", pod, 1, []string{
			"content of file \"" + filePathInReader + "\": mount-tester new file",
		})
	})

	// TODO consolidate common code of this test and above
	It("should support existing single file subPath [sig-storage]", func() {
		framework.SkipUnlessSSHKeyPresent()

		subPath := "sub-path-test-file"
		retryDuration := 180

		filePathInReader := path.Join(volumePath, subPath)

		source := &v1.HostPathVolumeSource{
			Path: "/tmp",
		}
		pod := testPodWithHostVol(volumePath, source)
		nodeList := framework.GetReadySchedulableNodesOrDie(f.ClientSet)
		pod.Spec.NodeName = nodeList.Items[0].Name

		// Create the subPath file on the host
		existing := path.Join(source.Path, subPath)
		result, err := framework.SSH(fmt.Sprintf("echo \"mount-tester new file\" > %s", existing), framework.GetNodeExternalIP(&nodeList.Items[0]), framework.TestContext.Provider)
		framework.LogSSHResult(result)
		framework.ExpectNoError(err)
		if result.Code != 0 {
			framework.Failf("echo returned non-zero")
		}

		// Mount the file to the subPath in container 0
		container := &pod.Spec.Containers[0]
		container.VolumeMounts[0].SubPath = subPath

		// Read it from outside the subPath from container 1
		pod.Spec.Containers[1].Args = []string{
			fmt.Sprintf("--file_content_in_loop=%v", filePathInReader),
			fmt.Sprintf("--retry_time=%d", retryDuration),
		}

		f.TestContainerOutput("hostPath subPath", pod, 1, []string{
			"content of file \"" + filePathInReader + "\": mount-tester new file",
		})
	})
})

//These constants are borrowed from the other test.
//const volumeName = "test-volume"
const containerName1 = "test-container-1"
const containerName2 = "test-container-2"

func mount(source *v1.HostPathVolumeSource) []v1.Volume {
	return []v1.Volume{
		{
			Name: volumeName,
			VolumeSource: v1.VolumeSource{
				HostPath: source,
			},
		},
	}
}

//TODO: To merge this with the emptyDir tests, we can make source a lambda.
func testPodWithHostVol(path string, source *v1.HostPathVolumeSource) *v1.Pod {
	podName := "pod-host-path-test"
	privileged := true

	return &v1.Pod{
		TypeMeta: metav1.TypeMeta{
			Kind:       "Pod",
			APIVersion: testapi.Groups[v1.GroupName].GroupVersion().String(),
		},
		ObjectMeta: metav1.ObjectMeta{
			Name: podName,
		},
		Spec: v1.PodSpec{
			Containers: []v1.Container{
				{
					Name:  containerName1,
					Image: mountImage,
					VolumeMounts: []v1.VolumeMount{
						{
							Name:      volumeName,
							MountPath: path,
						},
					},
					SecurityContext: &v1.SecurityContext{
						Privileged: &privileged,
					},
				},
				{
					Name:  containerName2,
					Image: mountImage,
					VolumeMounts: []v1.VolumeMount{
						{
							Name:      volumeName,
							MountPath: path,
						},
					},
					SecurityContext: &v1.SecurityContext{
						Privileged: &privileged,
					},
				},
			},
			RestartPolicy: v1.RestartPolicyNever,
			Volumes:       mount(source),
		},
	}
}
<commit_msg>Removes 'rwx' permissions for global users<commit_after>/*
Copyright 2016 The Kubernetes 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 common

import (
	"fmt"
	"os"
	"path"

	"k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/kubernetes/pkg/api/testapi"
	"k8s.io/kubernetes/test/e2e/framework"

	. "github.com/onsi/ginkgo"
)

//TODO : Consolidate this code with the code for emptyDir.
//This will require some smart.
var _ = framework.KubeDescribe("HostPath", func() {
	f := framework.NewDefaultFramework("hostpath")

	BeforeEach(func() {
		// TODO permission denied cleanup failures
		//cleanup before running the test.
		_ = os.Remove("/tmp/test-file")
	})

	It("should give a volume the correct mode [Conformance] [sig-storage]", func() {
		source := &v1.HostPathVolumeSource{
			Path: "/tmp",
		}
		pod := testPodWithHostVol(volumePath, source)

		pod.Spec.Containers[0].Args = []string{
			fmt.Sprintf("--fs_type=%v", volumePath),
			fmt.Sprintf("--file_mode=%v", volumePath),
		}
		f.TestContainerOutput("hostPath mode", pod, 0, []string{
			"mode of file \"/test-volume\": dtrwxrwx", // we expect the sticky bit (mode flag t) to be set for the dir
		})
	})

	// This test requires mounting a folder into a container with write privileges.
	It("should support r/w [sig-storage]", func() {
		filePath := path.Join(volumePath, "test-file")
		retryDuration := 180
		source := &v1.HostPathVolumeSource{
			Path: "/tmp",
		}
		pod := testPodWithHostVol(volumePath, source)

		pod.Spec.Containers[0].Args = []string{
			fmt.Sprintf("--new_file_0644=%v", filePath),
			fmt.Sprintf("--file_mode=%v", filePath),
		}

		pod.Spec.Containers[1].Args = []string{
			fmt.Sprintf("--file_content_in_loop=%v", filePath),
			fmt.Sprintf("--retry_time=%d", retryDuration),
		}
		//Read the content of the file with the second container to
		//verify volumes  being shared properly among containers within the pod.
		f.TestContainerOutput("hostPath r/w", pod, 1, []string{
			"content of file \"/test-volume/test-file\": mount-tester new file",
		})
	})

	It("should support subPath [sig-storage]", func() {
		subPath := "sub-path"
		fileName := "test-file"
		retryDuration := 180

		filePathInWriter := path.Join(volumePath, fileName)
		filePathInReader := path.Join(volumePath, subPath, fileName)

		source := &v1.HostPathVolumeSource{
			Path: "/tmp",
		}
		pod := testPodWithHostVol(volumePath, source)

		// Write the file in the subPath from container 0
		container := &pod.Spec.Containers[0]
		container.VolumeMounts[0].SubPath = subPath
		container.Args = []string{
			fmt.Sprintf("--new_file_0644=%v", filePathInWriter),
			fmt.Sprintf("--file_mode=%v", filePathInWriter),
		}

		// Read it from outside the subPath from container 1
		pod.Spec.Containers[1].Args = []string{
			fmt.Sprintf("--file_content_in_loop=%v", filePathInReader),
			fmt.Sprintf("--retry_time=%d", retryDuration),
		}

		f.TestContainerOutput("hostPath subPath", pod, 1, []string{
			"content of file \"" + filePathInReader + "\": mount-tester new file",
		})
	})

	It("should support existing directory subPath [sig-storage]", func() {
		framework.SkipUnlessSSHKeyPresent()

		subPath := "sub-path"
		fileName := "test-file"
		retryDuration := 180

		filePathInWriter := path.Join(volumePath, fileName)
		filePathInReader := path.Join(volumePath, subPath, fileName)

		source := &v1.HostPathVolumeSource{
			Path: "/tmp",
		}
		pod := testPodWithHostVol(volumePath, source)
		nodeList := framework.GetReadySchedulableNodesOrDie(f.ClientSet)
		pod.Spec.NodeName = nodeList.Items[0].Name

		// Create the subPath directory on the host
		existing := path.Join(source.Path, subPath)
		result, err := framework.SSH(fmt.Sprintf("mkdir -p %s", existing), framework.GetNodeExternalIP(&nodeList.Items[0]), framework.TestContext.Provider)
		framework.LogSSHResult(result)
		framework.ExpectNoError(err)
		if result.Code != 0 {
			framework.Failf("mkdir returned non-zero")
		}

		// Write the file in the subPath from container 0
		container := &pod.Spec.Containers[0]
		container.VolumeMounts[0].SubPath = subPath
		container.Args = []string{
			fmt.Sprintf("--new_file_0644=%v", filePathInWriter),
			fmt.Sprintf("--file_mode=%v", filePathInWriter),
		}

		// Read it from outside the subPath from container 1
		pod.Spec.Containers[1].Args = []string{
			fmt.Sprintf("--file_content_in_loop=%v", filePathInReader),
			fmt.Sprintf("--retry_time=%d", retryDuration),
		}

		f.TestContainerOutput("hostPath subPath", pod, 1, []string{
			"content of file \"" + filePathInReader + "\": mount-tester new file",
		})
	})

	// TODO consolidate common code of this test and above
	It("should support existing single file subPath [sig-storage]", func() {
		framework.SkipUnlessSSHKeyPresent()

		subPath := "sub-path-test-file"
		retryDuration := 180

		filePathInReader := path.Join(volumePath, subPath)

		source := &v1.HostPathVolumeSource{
			Path: "/tmp",
		}
		pod := testPodWithHostVol(volumePath, source)
		nodeList := framework.GetReadySchedulableNodesOrDie(f.ClientSet)
		pod.Spec.NodeName = nodeList.Items[0].Name

		// Create the subPath file on the host
		existing := path.Join(source.Path, subPath)
		result, err := framework.SSH(fmt.Sprintf("echo \"mount-tester new file\" > %s", existing), framework.GetNodeExternalIP(&nodeList.Items[0]), framework.TestContext.Provider)
		framework.LogSSHResult(result)
		framework.ExpectNoError(err)
		if result.Code != 0 {
			framework.Failf("echo returned non-zero")
		}

		// Mount the file to the subPath in container 0
		container := &pod.Spec.Containers[0]
		container.VolumeMounts[0].SubPath = subPath

		// Read it from outside the subPath from container 1
		pod.Spec.Containers[1].Args = []string{
			fmt.Sprintf("--file_content_in_loop=%v", filePathInReader),
			fmt.Sprintf("--retry_time=%d", retryDuration),
		}

		f.TestContainerOutput("hostPath subPath", pod, 1, []string{
			"content of file \"" + filePathInReader + "\": mount-tester new file",
		})
	})
})

//These constants are borrowed from the other test.
//const volumeName = "test-volume"
const containerName1 = "test-container-1"
const containerName2 = "test-container-2"

func mount(source *v1.HostPathVolumeSource) []v1.Volume {
	return []v1.Volume{
		{
			Name: volumeName,
			VolumeSource: v1.VolumeSource{
				HostPath: source,
			},
		},
	}
}

//TODO: To merge this with the emptyDir tests, we can make source a lambda.
func testPodWithHostVol(path string, source *v1.HostPathVolumeSource) *v1.Pod {
	podName := "pod-host-path-test"
	privileged := true

	return &v1.Pod{
		TypeMeta: metav1.TypeMeta{
			Kind:       "Pod",
			APIVersion: testapi.Groups[v1.GroupName].GroupVersion().String(),
		},
		ObjectMeta: metav1.ObjectMeta{
			Name: podName,
		},
		Spec: v1.PodSpec{
			Containers: []v1.Container{
				{
					Name:  containerName1,
					Image: mountImage,
					VolumeMounts: []v1.VolumeMount{
						{
							Name:      volumeName,
							MountPath: path,
						},
					},
					SecurityContext: &v1.SecurityContext{
						Privileged: &privileged,
					},
				},
				{
					Name:  containerName2,
					Image: mountImage,
					VolumeMounts: []v1.VolumeMount{
						{
							Name:      volumeName,
							MountPath: path,
						},
					},
					SecurityContext: &v1.SecurityContext{
						Privileged: &privileged,
					},
				},
			},
			RestartPolicy: v1.RestartPolicyNever,
			Volumes:       mount(source),
		},
	}
}
<|endoftext|>


<commit_before>package test

import (
	"flag"
	"sync"
	"testing"

	"github.com/neptulon/neptulon"
	"github.com/neptulon/neptulon/middleware"
)

var ext = flag.Bool("ext", false, "Run external client test case.")

// Helper method for testing client implementations in other languages.
// Flow of events for this function is:
// * Send a {"method":"echo", "params":{"message": "..."}} request to client upon first 'echo' request from client,
//   and verify that message body is echoed properly in the response body.
// * Echo any incoming request message body as is within a response message.
// * Repeat ad infinitum, until {"method":"close", "params":"{"message": "..."}"} is received. Close message body is logged.
func TestExternalClient(t *testing.T) {
	sh := NewServerHelper(t)
	sh.Server.MiddlewareFunc(middleware.Logger)
	var wg sync.WaitGroup
	m := "Hello from Neptulon server!"

	// handle 'echo' requests via the 'echo middleware'
	srout := middleware.NewRouter()
	sh.Server.Middleware(srout)
	srout.Request("echo", func(ctx *neptulon.ReqCtx) error {
		// send 'echo' request to client upon connection (blocks test if no response is received)
		wg.Add(1)
		ctx.Conn.SendRequest("echo", echoMsg{Message: m}, func(ctx *neptulon.ResCtx) error {
			defer wg.Done()
			var msg echoMsg
			if err := ctx.Result(&msg); err != nil {
				t.Fatal(err)
			}
			if msg.Message != m {
				t.Fatalf("server: expected: %v got: %v", m, msg.Message)
			}
			t.Logf("server: client sent response to our 'echo' request: %v", msg.Message)
			return nil
		})

		// unmarshall incoming message into response directly
		if err := ctx.Params(&ctx.Res); err != nil {
			return err
		}
		return ctx.Next()
	})

	// handle 'close' request (blocks test if no response is received)
	wg.Add(1)
	srout.Request("close", func(ctx *neptulon.ReqCtx) error {
		defer wg.Done()
		if err := ctx.Params(&ctx.Res); err != nil {
			return err
		}
		err := ctx.Next()
		// ctx.Conn.Close() // todo: investigate the error message!!!
		t.Logf("server: closed connection with message from client: %v\n", ctx.Res)
		return err
	})

	defer sh.ListenAndServe().CloseWait()

	if *ext {
		t.Log("Started server and waiting for external client integration test since -ext flag is provided.")
		wg.Wait()
		return
	}

	// use internal conn implementation instead to test the test case itself
	t.Log("Skipping external client integration test since -ext flag is not provided.")
	ch := sh.GetConnHelper()
	ch.Conn.MiddlewareFunc(middleware.Logger)

	// handle 'echo' requests via the 'echo middleware'
	crout := middleware.NewRouter()
	ch.Conn.Middleware(crout)
	crout.Request("echo", middleware.Echo)
	defer ch.Connect().CloseWait()

	// handle 'echo' request and send 'close' request upon echo response
	mc := "Hello from Neptulon Go client!"
	ch.SendRequestSync("echo", echoMsg{Message: mc}, func(ctx *neptulon.ResCtx) error {
		var msg echoMsg
		if err := ctx.Result(&msg); err != nil {
			t.Fatal(err)
		}
		if msg.Message != mc {
			t.Fatalf("client: expected: %v got: %v", mc, msg.Message)
		}
		t.Log("client: server accepted and echoed 'echo' request message body")

		// send close request after getting our echo message back
		mb := "Thanks for echoing! Over and out."
		ch.SendRequestSync("close", echoMsg{Message: mb}, func(ctx *neptulon.ResCtx) error {
			var msg echoMsg
			if err := ctx.Result(&msg); err != nil {
				t.Fatal(err)
			}
			if msg.Message != mb {
				t.Fatalf("client: expected: %v got: %v", mb, msg.Message)
			}
			t.Log("client: server accepted and echoed 'close' request message body. bye!")
			return nil
		})

		return nil
	})
}
<commit_msg>test: make external flag obvious<commit_after>package test

import (
	"flag"
	"sync"
	"testing"

	"github.com/neptulon/neptulon"
	"github.com/neptulon/neptulon/middleware"
)

var extFlog = flag.Bool("ext", false, "Run external client test case.")

// Helper method for testing client implementations in other languages.
// Flow of events for this function is:
// * Send a {"method":"echo", "params":{"message": "..."}} request to client upon first 'echo' request from client,
//   and verify that message body is echoed properly in the response body.
// * Echo any incoming request message body as is within a response message.
// * Repeat ad infinitum, until {"method":"close", "params":"{"message": "..."}"} is received. Close message body is logged.
func TestExternalClient(t *testing.T) {
	sh := NewServerHelper(t)
	sh.Server.MiddlewareFunc(middleware.Logger)
	var wg sync.WaitGroup
	m := "Hello from Neptulon server!"

	// handle 'echo' requests via the 'echo middleware'
	srout := middleware.NewRouter()
	sh.Server.Middleware(srout)
	srout.Request("echo", func(ctx *neptulon.ReqCtx) error {
		// send 'echo' request to client upon connection (blocks test if no response is received)
		wg.Add(1)
		ctx.Conn.SendRequest("echo", echoMsg{Message: m}, func(ctx *neptulon.ResCtx) error {
			defer wg.Done()
			var msg echoMsg
			if err := ctx.Result(&msg); err != nil {
				t.Fatal(err)
			}
			if msg.Message != m {
				t.Fatalf("server: expected: %v got: %v", m, msg.Message)
			}
			t.Logf("server: client sent response to our 'echo' request: %v", msg.Message)
			return nil
		})

		// unmarshall incoming message into response directly
		if err := ctx.Params(&ctx.Res); err != nil {
			return err
		}
		return ctx.Next()
	})

	// handle 'close' request (blocks test if no response is received)
	wg.Add(1)
	srout.Request("close", func(ctx *neptulon.ReqCtx) error {
		defer wg.Done()
		if err := ctx.Params(&ctx.Res); err != nil {
			return err
		}
		err := ctx.Next()
		// ctx.Conn.Close() // todo: investigate the error message!!!
		t.Logf("server: closed connection with message from client: %v\n", ctx.Res)
		return err
	})

	defer sh.ListenAndServe().CloseWait()

	if *extFlog {
		t.Log("Started server and waiting for external client integration test since -ext flag is provided.")
		wg.Wait()
		return
	}

	// use internal conn implementation instead to test the test case itself
	t.Log("Skipping external client integration test since -ext flag is not provided.")
	ch := sh.GetConnHelper()
	ch.Conn.MiddlewareFunc(middleware.Logger)

	// handle 'echo' requests via the 'echo middleware'
	crout := middleware.NewRouter()
	ch.Conn.Middleware(crout)
	crout.Request("echo", middleware.Echo)
	defer ch.Connect().CloseWait()

	// handle 'echo' request and send 'close' request upon echo response
	mc := "Hello from Neptulon Go client!"
	ch.SendRequestSync("echo", echoMsg{Message: mc}, func(ctx *neptulon.ResCtx) error {
		var msg echoMsg
		if err := ctx.Result(&msg); err != nil {
			t.Fatal(err)
		}
		if msg.Message != mc {
			t.Fatalf("client: expected: %v got: %v", mc, msg.Message)
		}
		t.Log("client: server accepted and echoed 'echo' request message body")

		// send close request after getting our echo message back
		mb := "Thanks for echoing! Over and out."
		ch.SendRequestSync("close", echoMsg{Message: mb}, func(ctx *neptulon.ResCtx) error {
			var msg echoMsg
			if err := ctx.Result(&msg); err != nil {
				t.Fatal(err)
			}
			if msg.Message != mb {
				t.Fatalf("client: expected: %v got: %v", mb, msg.Message)
			}
			t.Log("client: server accepted and echoed 'close' request message body. bye!")
			return nil
		})

		return nil
	})
}
<|endoftext|>


<commit_before>package ali_mns

import (
	"github.com/gogap/errors"
)

const (
	ALI_MNS_ERR_NS = "MNS"

	ali_MNS_ERR_TEMPSTR = "ali_mns response status error,code: {{.resp.Code}}, message: {{.resp.Message}}, resource: {{.resource}} request id: {{.resp.RequestId}}, host id: {{.resp.HostId}}"
)

var (
	ERR_SIGN_MESSAGE_FAILED        = errors.TN(ALI_MNS_ERR_NS, 1, "sign message failed, {{.err}}")
	ERR_MARSHAL_MESSAGE_FAILED     = errors.TN(ALI_MNS_ERR_NS, 2, "marshal message filed, {{.err}}")
	ERR_GENERAL_AUTH_HEADER_FAILED = errors.TN(ALI_MNS_ERR_NS, 3, "general auth header failed, {{.err}}")

	ERR_CREATE_NEW_REQUEST_FAILED = errors.TN(ALI_MNS_ERR_NS, 4, "create new request failed, {{.err}}")
	ERR_SEND_REQUEST_FAILED       = errors.TN(ALI_MNS_ERR_NS, 5, "send request failed, {{.err}}")
	ERR_READ_RESPONSE_BODY_FAILED = errors.TN(ALI_MNS_ERR_NS, 6, "read response body failed, {{.err}}")

	ERR_UNMARSHAL_ERROR_RESPONSE_FAILED = errors.TN(ALI_MNS_ERR_NS, 7, "unmarshal error response failed, {{.err}}")
	ERR_UNMARSHAL_RESPONSE_FAILED       = errors.TN(ALI_MNS_ERR_NS, 8, "unmarshal response failed, {{.err}}")
	ERR_DECODE_BODY_FAILED              = errors.TN(ALI_MNS_ERR_NS, 9, "decode body failed, {{.err}}, body: \"{{.body}}\"")
	ERR_GET_BODY_DECODE_ELEMENT_ERROR   = errors.TN(ALI_MNS_ERR_NS, 10, "get body decode element error, local: {{.local}}, error: {{.err}}")

	ERR_MNS_ACCESS_DENIED                = errors.TN(ALI_MNS_ERR_NS, 100, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_INVALID_ACCESS_KEY_ID        = errors.TN(ALI_MNS_ERR_NS, 101, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_INTERNAL_ERROR               = errors.TN(ALI_MNS_ERR_NS, 102, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_INVALID_AUTHORIZATION_HEADER = errors.TN(ALI_MNS_ERR_NS, 103, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_INVALID_DATE_HEADER          = errors.TN(ALI_MNS_ERR_NS, 104, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_INVALID_ARGUMENT             = errors.TN(ALI_MNS_ERR_NS, 105, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_INVALID_DEGIST               = errors.TN(ALI_MNS_ERR_NS, 106, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_INVALID_REQUEST_URL          = errors.TN(ALI_MNS_ERR_NS, 107, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_INVALID_QUERY_STRING         = errors.TN(ALI_MNS_ERR_NS, 108, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_MALFORMED_XML                = errors.TN(ALI_MNS_ERR_NS, 109, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_MISSING_AUTHORIZATION_HEADER = errors.TN(ALI_MNS_ERR_NS, 110, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_MISSING_DATE_HEADER          = errors.TN(ALI_MNS_ERR_NS, 111, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_MISSING_VERSION_HEADER       = errors.TN(ALI_MNS_ERR_NS, 112, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_MISSING_RECEIPT_HANDLE       = errors.TN(ALI_MNS_ERR_NS, 113, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_MISSING_VISIBILITY_TIMEOUT   = errors.TN(ALI_MNS_ERR_NS, 114, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_MESSAGE_NOT_EXIST            = errors.TN(ALI_MNS_ERR_NS, 115, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_QUEUE_DELETED_RECENTLY       = errors.TN(ALI_MNS_ERR_NS, 117, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_INVALID_QUEUE_NAME           = errors.TN(ALI_MNS_ERR_NS, 118, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_INVALID_VERSION_HEADER       = errors.TN(ALI_MNS_ERR_NS, 119, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_INVALID_CONTENT_TYPE         = errors.TN(ALI_MNS_ERR_NS, 120, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_QUEUE_NAME_LENGTH_ERROR      = errors.TN(ALI_MNS_ERR_NS, 121, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_QUEUE_NOT_EXIST              = errors.TN(ALI_MNS_ERR_NS, 122, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_RECEIPT_HANDLE_ERROR         = errors.TN(ALI_MNS_ERR_NS, 123, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_SIGNATURE_DOES_NOT_MATCH     = errors.TN(ALI_MNS_ERR_NS, 124, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_TIME_EXPIRED                 = errors.TN(ALI_MNS_ERR_NS, 125, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_QPS_LIMIT_EXCEEDED           = errors.TN(ALI_MNS_ERR_NS, 134, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_UNKNOWN_CODE                 = errors.TN(ALI_MNS_ERR_NS, 135, ali_MNS_ERR_TEMPSTR)

	ERR_MNS_QUEUE_NAME_IS_TOO_LONG                 = errors.TN(ALI_MNS_ERR_NS, 126, "queue name is too long, the max length is 256")
	ERR_MNS_DELAY_SECONDS_RANGE_ERROR              = errors.TN(ALI_MNS_ERR_NS, 127, "queue delay seconds is not in range of (0~60480)")
	ERR_MNS_MAX_MESSAGE_SIZE_RANGE_ERROR           = errors.TN(ALI_MNS_ERR_NS, 128, "max message size is not in range of (1024~65536)")
	ERR_MNS_MSG_RETENTION_PERIOD_RANGE_ERROR       = errors.TN(ALI_MNS_ERR_NS, 129, "message retention period is not in range of (60~129600)")
	ERR_MNS_MSG_VISIBILITY_TIMEOUT_RANGE_ERROR     = errors.TN(ALI_MNS_ERR_NS, 130, "message visibility timeout is not in range of (1~43200)")
	ERR_MNS_MSG_POOLLING_WAIT_SECONDS_RANGE_ERROR  = errors.TN(ALI_MNS_ERR_NS, 131, "message poolling wait seconds is not in range of (0~30)")
	REE_MNS_GET_QUEUE_RET_NUMBER_RANGE_ERROR       = errors.TN(ALI_MNS_ERR_NS, 132, "get queue list param of ret number is not in range of (1~1000)")
	ERR_MNS_QUEUE_ALREADY_EXIST_AND_HAVE_SAME_ATTR = errors.TN(ALI_MNS_ERR_NS, 133, "mns queue already exist, and the attribute is the same, queue name: {{.name}}")
	ERR_MNS_QUEUE_ALREADY_EXIST                    = errors.TN(ALI_MNS_ERR_NS, 134, "mns queue already exist, and has different attribute, queue name: {{.name}}")
)
<commit_msg>fix error code id of #3<commit_after>package ali_mns

import (
	"github.com/gogap/errors"
)

const (
	ALI_MNS_ERR_NS = "MNS"

	ali_MNS_ERR_TEMPSTR = "ali_mns response status error,code: {{.resp.Code}}, message: {{.resp.Message}}, resource: {{.resource}} request id: {{.resp.RequestId}}, host id: {{.resp.HostId}}"
)

var (
	ERR_SIGN_MESSAGE_FAILED        = errors.TN(ALI_MNS_ERR_NS, 1, "sign message failed, {{.err}}")
	ERR_MARSHAL_MESSAGE_FAILED     = errors.TN(ALI_MNS_ERR_NS, 2, "marshal message filed, {{.err}}")
	ERR_GENERAL_AUTH_HEADER_FAILED = errors.TN(ALI_MNS_ERR_NS, 3, "general auth header failed, {{.err}}")

	ERR_CREATE_NEW_REQUEST_FAILED = errors.TN(ALI_MNS_ERR_NS, 4, "create new request failed, {{.err}}")
	ERR_SEND_REQUEST_FAILED       = errors.TN(ALI_MNS_ERR_NS, 5, "send request failed, {{.err}}")
	ERR_READ_RESPONSE_BODY_FAILED = errors.TN(ALI_MNS_ERR_NS, 6, "read response body failed, {{.err}}")

	ERR_UNMARSHAL_ERROR_RESPONSE_FAILED = errors.TN(ALI_MNS_ERR_NS, 7, "unmarshal error response failed, {{.err}}")
	ERR_UNMARSHAL_RESPONSE_FAILED       = errors.TN(ALI_MNS_ERR_NS, 8, "unmarshal response failed, {{.err}}")
	ERR_DECODE_BODY_FAILED              = errors.TN(ALI_MNS_ERR_NS, 9, "decode body failed, {{.err}}, body: \"{{.body}}\"")
	ERR_GET_BODY_DECODE_ELEMENT_ERROR   = errors.TN(ALI_MNS_ERR_NS, 10, "get body decode element error, local: {{.local}}, error: {{.err}}")

	ERR_MNS_ACCESS_DENIED                = errors.TN(ALI_MNS_ERR_NS, 100, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_INVALID_ACCESS_KEY_ID        = errors.TN(ALI_MNS_ERR_NS, 101, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_INTERNAL_ERROR               = errors.TN(ALI_MNS_ERR_NS, 102, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_INVALID_AUTHORIZATION_HEADER = errors.TN(ALI_MNS_ERR_NS, 103, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_INVALID_DATE_HEADER          = errors.TN(ALI_MNS_ERR_NS, 104, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_INVALID_ARGUMENT             = errors.TN(ALI_MNS_ERR_NS, 105, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_INVALID_DEGIST               = errors.TN(ALI_MNS_ERR_NS, 106, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_INVALID_REQUEST_URL          = errors.TN(ALI_MNS_ERR_NS, 107, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_INVALID_QUERY_STRING         = errors.TN(ALI_MNS_ERR_NS, 108, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_MALFORMED_XML                = errors.TN(ALI_MNS_ERR_NS, 109, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_MISSING_AUTHORIZATION_HEADER = errors.TN(ALI_MNS_ERR_NS, 110, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_MISSING_DATE_HEADER          = errors.TN(ALI_MNS_ERR_NS, 111, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_MISSING_VERSION_HEADER       = errors.TN(ALI_MNS_ERR_NS, 112, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_MISSING_RECEIPT_HANDLE       = errors.TN(ALI_MNS_ERR_NS, 113, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_MISSING_VISIBILITY_TIMEOUT   = errors.TN(ALI_MNS_ERR_NS, 114, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_MESSAGE_NOT_EXIST            = errors.TN(ALI_MNS_ERR_NS, 115, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_QUEUE_DELETED_RECENTLY       = errors.TN(ALI_MNS_ERR_NS, 117, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_INVALID_QUEUE_NAME           = errors.TN(ALI_MNS_ERR_NS, 118, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_INVALID_VERSION_HEADER       = errors.TN(ALI_MNS_ERR_NS, 119, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_INVALID_CONTENT_TYPE         = errors.TN(ALI_MNS_ERR_NS, 120, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_QUEUE_NAME_LENGTH_ERROR      = errors.TN(ALI_MNS_ERR_NS, 121, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_QUEUE_NOT_EXIST              = errors.TN(ALI_MNS_ERR_NS, 122, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_RECEIPT_HANDLE_ERROR         = errors.TN(ALI_MNS_ERR_NS, 123, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_SIGNATURE_DOES_NOT_MATCH     = errors.TN(ALI_MNS_ERR_NS, 124, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_TIME_EXPIRED                 = errors.TN(ALI_MNS_ERR_NS, 125, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_QPS_LIMIT_EXCEEDED           = errors.TN(ALI_MNS_ERR_NS, 134, ali_MNS_ERR_TEMPSTR)
	ERR_MNS_UNKNOWN_CODE                 = errors.TN(ALI_MNS_ERR_NS, 135, ali_MNS_ERR_TEMPSTR)

	ERR_MNS_QUEUE_NAME_IS_TOO_LONG                 = errors.TN(ALI_MNS_ERR_NS, 126, "queue name is too long, the max length is 256")
	ERR_MNS_DELAY_SECONDS_RANGE_ERROR              = errors.TN(ALI_MNS_ERR_NS, 127, "queue delay seconds is not in range of (0~60480)")
	ERR_MNS_MAX_MESSAGE_SIZE_RANGE_ERROR           = errors.TN(ALI_MNS_ERR_NS, 128, "max message size is not in range of (1024~65536)")
	ERR_MNS_MSG_RETENTION_PERIOD_RANGE_ERROR       = errors.TN(ALI_MNS_ERR_NS, 129, "message retention period is not in range of (60~129600)")
	ERR_MNS_MSG_VISIBILITY_TIMEOUT_RANGE_ERROR     = errors.TN(ALI_MNS_ERR_NS, 130, "message visibility timeout is not in range of (1~43200)")
	ERR_MNS_MSG_POOLLING_WAIT_SECONDS_RANGE_ERROR  = errors.TN(ALI_MNS_ERR_NS, 131, "message poolling wait seconds is not in range of (0~30)")
	REE_MNS_GET_QUEUE_RET_NUMBER_RANGE_ERROR       = errors.TN(ALI_MNS_ERR_NS, 132, "get queue list param of ret number is not in range of (1~1000)")
	ERR_MNS_QUEUE_ALREADY_EXIST_AND_HAVE_SAME_ATTR = errors.TN(ALI_MNS_ERR_NS, 133, "mns queue already exist, and the attribute is the same, queue name: {{.name}}")
	ERR_MNS_QUEUE_ALREADY_EXIST                    = errors.TN(ALI_MNS_ERR_NS, 136, "mns queue already exist, and has different attribute, queue name: {{.name}}")
)
<|endoftext|>


<commit_before>package snmpgo

import (
	"fmt"
)

type SNMPError struct{}

type ArgumentError struct {
	Value   interface{}
	Message string
	SNMPError
}

func (e ArgumentError) Error() string {
	return fmt.Sprintf("%s, value `%v`", e.Message, e.Value)
}

type ResponseError struct {
	Cause   error
	Message string
	Detail  string
	SNMPError
}

func (e ResponseError) Error() string {
	if e.Cause == nil {
		return e.Message
	} else {
		return fmt.Sprintf("%s, cause `%v`", e.Message, e.Cause)
	}
}
<commit_msg>remove unused code<commit_after>package snmpgo

import (
	"fmt"
)

type ArgumentError struct {
	Value   interface{}
	Message string
}

func (e ArgumentError) Error() string {
	return fmt.Sprintf("%s, value `%v`", e.Message, e.Value)
}

type ResponseError struct {
	Cause   error
	Message string
	Detail  string
}

func (e ResponseError) Error() string {
	if e.Cause == nil {
		return e.Message
	} else {
		return fmt.Sprintf("%s, cause `%v`", e.Message, e.Cause)
	}
}
<|endoftext|>


<commit_before>package minecraft

import (
	"fmt"
	"github.com/MJKWoolnough/minecraft/nbt"
)

type MissingTagError struct {
	TagName string
}

func (m MissingTagError) Error() string {
	return fmt.Sprintf("minecraft: missing %q tag", m.TagName)
}

type WrongTypeError struct {
	TagName        string
	Expecting, Got nbt.TagId
}

func (w WrongTypeError) Error() string {
	return fmt.Sprintf("minecraft: tag %q is of incorrect type, expecting %q, got %q", w.TagName, w.Expecting, w.Got)
}

type OOB struct{}

func (o OOB) Error() string {
	return "Received Out-of-bounds error"
}

type UnexpectedValue struct {
	TagName, Expecting, Got string
}

func (u UnexpectedValue) Error() string {
	return fmt.Sprintf("minecraft: tag %q was expecting %s, but got %q", u.TagName, u.Expecting, u.Got)
}

type UnknownCompression struct {
	Code byte
}

func (u UnknownCompression) Error() string {
	return fmt.Sprintf("unknown compression code: %d", u.Code)
}

type ExpectedData struct{}

func (e ExpectedData) Error() string {
	return "received nil data stream where non-nil was expected."
}

type NoLock struct{}

func (n NoLock) Error() string {
	return "lost lock on files"
}

type ConflictError struct {
	X, Z int32
}

func (c ConflictError) Error() string {
	return fmt.Sprintf("already setting chunk %d,%d, recall SetChunk to set again", c.X, c.Z)
}
<commit_msg>Removed redundent identifiers<commit_after>package minecraft

import (
	"fmt"
	"github.com/MJKWoolnough/minecraft/nbt"
)

type MissingTagError struct {
	TagName string
}

func (m MissingTagError) Error() string {
	return fmt.Sprintf("minecraft: missing %q tag", m.TagName)
}

type WrongTypeError struct {
	TagName        string
	Expecting, Got nbt.TagId
}

func (w WrongTypeError) Error() string {
	return fmt.Sprintf("minecraft: tag %q is of incorrect type, expecting %q, got %q", w.TagName, w.Expecting, w.Got)
}

type OOB struct{}

func (OOB) Error() string {
	return "Received Out-of-bounds error"
}

type UnexpectedValue struct {
	TagName, Expecting, Got string
}

func (u UnexpectedValue) Error() string {
	return fmt.Sprintf("minecraft: tag %q was expecting %s, but got %q", u.TagName, u.Expecting, u.Got)
}

type UnknownCompression struct {
	Code byte
}

func (u UnknownCompression) Error() string {
	return fmt.Sprintf("unknown compression code: %d", u.Code)
}

type ExpectedData struct{}

func (ExpectedData) Error() string {
	return "received nil data stream where non-nil was expected."
}

type NoLock struct{}

func (NoLock) Error() string {
	return "lost lock on files"
}

type ConflictError struct {
	X, Z int32
}

func (c ConflictError) Error() string {
	return fmt.Sprintf("already setting chunk %d,%d, recall SetChunk to set again", c.X, c.Z)
}
<|endoftext|>


<commit_before>package argparse

import (
	"fmt"
	"strings"
)

type InvalidChoiceErr struct {
	opt Option
	arg string
}

func (err InvalidChoiceErr) Error() string {
	msg := "%s: invalid choice \"%s\" (choose from: %s)"
	return fmt.Sprintf(msg, err.opt.DisplayName(), err.arg, strings.Join(err.opt.ValidChoices, ", "))

}

type InvalidTypeErr struct {
	opt Option
	arg string
}

func (err InvalidTypeErr) Error() string {
	msg := "%s: invalid %s value: \"%s\""
	return fmt.Sprintf(msg, err.opt.DisplayName(), err.opt.ExpectedType.String(), err.arg)
}
<commit_msg>added docstrings<commit_after>package argparse

import (
	"fmt"
	"strings"
)

// InvalidChoiceErr indicates that an argument is not among the valid choices
// for the option.
type InvalidChoiceErr struct {
	opt Option
	arg string
}

// Error will return a string error message for the InvalidChoiceErr
func (err InvalidChoiceErr) Error() string {
	msg := "%s: invalid choice \"%s\" (choose from: %s)"
	return fmt.Sprintf(msg, err.opt.DisplayName(), err.arg, strings.Join(err.opt.ValidChoices, ", "))

}

// InvalidTypeErr indicates that an argument cannot be casted the the option's
// expected type.
type InvalidTypeErr struct {
	opt Option
	arg string
}

// Error will return a string error message for the InvalidTypeErr
func (err InvalidTypeErr) Error() string {
	msg := "%s: invalid %s value: \"%s\""
	return fmt.Sprintf(msg, err.opt.DisplayName(), err.opt.ExpectedType.String(), err.arg)
}
<|endoftext|>


<commit_before>package admin

import (
	"errors"
	"fmt"
	"net/http"

	"html/template"

	"github.com/qor/admin"
	"github.com/qor/banner_editor"
	"github.com/qor/l10n"
	"github.com/qor/media/oss"
	"github.com/qor/qor"
	"github.com/qor/qor-example/app/models"
	"github.com/qor/qor-example/db"
	"github.com/qor/qor/resource"
	"github.com/qor/sorting"
	"github.com/qor/widget"
)

var Widgets *widget.Widgets

type QorWidgetSetting struct {
	widget.QorWidgetSetting
	l10n.Locale
	// publish.Status
	// DeletedAt *time.Time
}

func initWidgets() {
	if Widgets == nil {
		Widgets = widget.New(&widget.Config{DB: db.DB})
		Widgets.WidgetSettingResource = Admin.AddResource(&QorWidgetSetting{}, &admin.Config{Menu: []string{"Site Management"}, Priority: 3})
		Widgets.WidgetSettingResource.Meta(&admin.Meta{Name: "Name", FormattedValuer: func(widget interface{}, ctx *qor.Context) interface{} {
			setting := widget.(*QorWidgetSetting)
			return template.HTML(`<img src="/images/Widget-` + setting.WidgetType + `.png" width="80" height="35" style="margin-right: 12px;"/><span>` + setting.Name + `</span>`)
		}})

		Widgets.RegisterScope(&widget.Scope{
			Name: "From Google",
			Visible: func(context *widget.Context) bool {
				if request, ok := context.Get("Request"); ok {
					_, ok := request.(*http.Request).URL.Query()["from_google"]
					return ok
				}
				return false
			},
		})

		Admin.AddResource(Widgets)

		// Top Banner
		type bannerArgument struct {
			Title           string
			ButtonTitle     string
			Link            string
			BackgroundImage oss.OSS
			Logo            oss.OSS
		}

		Widgets.RegisterWidget(&widget.Widget{
			Name:      "NormalBanner",
			Templates: []string{"banner", "banner2"},
			Setting:   Admin.NewResource(&bannerArgument{}),
			Context: func(context *widget.Context, setting interface{}) *widget.Context {
				context.Options["Setting"] = setting
				return context
			},
		})

		// Banner Editor
		type bannerEditorArgument struct {
			Value string
		}
		type subHeaderSetting struct {
			Text  string
			Color string
		}
		type buttonSetting struct {
			Text string
			Link string
		}
		subHeaderRes := Admin.NewResource(&subHeaderSetting{})
		subHeaderRes.Meta(&admin.Meta{Name: "Text"})
		subHeaderRes.Meta(&admin.Meta{Name: "Color"})

		buttonRes := Admin.NewResource(&buttonSetting{})
		buttonRes.Meta(&admin.Meta{Name: "Text"})
		buttonRes.Meta(&admin.Meta{Name: "Link"})

		banner_editor.RegisterElement(&banner_editor.Element{
			Name:     "Sub Header",
			Template: "{{.Text}}",
			Resource: subHeaderRes,
			Context: func(c *banner_editor.Context, r interface{}) *banner_editor.Context {
				return c
			},
		})
		banner_editor.RegisterElement(&banner_editor.Element{
			Name:     "Button",
			Template: "{{.Text}}",
			Resource: buttonRes,
			Context: func(c *banner_editor.Context, r interface{}) *banner_editor.Context {
				return c
			},
		})
		bannerEditorResource := Admin.NewResource(&bannerEditorArgument{})
		bannerEditorResource.Meta(&admin.Meta{Name: "Value", Config: &banner_editor.BannerEditorConfig{}})

		Widgets.RegisterWidget(&widget.Widget{
			Name:      "BannerEditor",
			Templates: []string{"banner_editor"},
			Setting:   bannerEditorResource,
			Context: func(context *widget.Context, setting interface{}) *widget.Context {
				context.Options["Value"] = template.HTML(setting.(*bannerEditorArgument).Value)
				return context
			},
		})

		type slideImage struct {
			Title string
			Image oss.OSS
		}

		type slideShowArgument struct {
			SlideImages []slideImage
		}
		slideShowResource := Admin.NewResource(&slideShowArgument{})
		slideShowResource.AddProcessor(func(value interface{}, metaValues *resource.MetaValues, context *qor.Context) error {
			if slides, ok := value.(*slideShowArgument); ok {
				for _, slide := range slides.SlideImages {
					if slide.Title == "" {
						return errors.New("slide title is blank")
					}
				}
			}
			return nil
		})

		Widgets.RegisterWidget(&widget.Widget{
			Name:      "SlideShow",
			Templates: []string{"slideshow"},
			Setting:   slideShowResource,
			Context: func(context *widget.Context, setting interface{}) *widget.Context {
				context.Options["Setting"] = setting
				return context
			},
		})

		Widgets.RegisterWidgetsGroup(&widget.WidgetsGroup{
			Name:    "Banner",
			Widgets: []string{"NormalBanner", "SlideShow"},
		})

		// selected Products
		type selectedProductsArgument struct {
			Products       []string
			ProductsSorter sorting.SortableCollection
		}
		selectedProductsResource := Admin.NewResource(&selectedProductsArgument{})
		selectedProductsResource.Meta(&admin.Meta{Name: "Products", Type: "select_many", Collection: func(value interface{}, context *qor.Context) [][]string {
			var collectionValues [][]string
			var products []*models.Product
			context.GetDB().Find(&products)
			for _, product := range products {
				collectionValues = append(collectionValues, []string{fmt.Sprintf("%v", product.ID), product.Name})
			}
			return collectionValues
		}})

		Widgets.RegisterWidget(&widget.Widget{
			Name:      "Products",
			Templates: []string{"products"},
			Setting:   selectedProductsResource,
			Context: func(context *widget.Context, setting interface{}) *widget.Context {
				if setting != nil {
					var products []*models.Product
					context.GetDB().Limit(9).Preload("ColorVariations").Where("id IN (?)", setting.(*selectedProductsArgument).Products).Find(&products)
					setting.(*selectedProductsArgument).ProductsSorter.Sort(&products)
					context.Options["Products"] = products
				}
				return context
			},
		})
	}
}
<commit_msg>update banner edit<commit_after>package admin

import (
	"errors"
	"fmt"
	"net/http"

	"html/template"

	"github.com/qor/admin"
	"github.com/qor/banner_editor"
	"github.com/qor/l10n"
	"github.com/qor/media/oss"
	"github.com/qor/qor"
	"github.com/qor/qor-example/app/models"
	"github.com/qor/qor-example/db"
	"github.com/qor/qor/resource"
	"github.com/qor/sorting"
	"github.com/qor/widget"
)

var Widgets *widget.Widgets

type QorWidgetSetting struct {
	widget.QorWidgetSetting
	l10n.Locale
	// publish.Status
	// DeletedAt *time.Time
}

func initWidgets() {
	if Widgets == nil {
		Widgets = widget.New(&widget.Config{DB: db.DB})
		Widgets.WidgetSettingResource = Admin.AddResource(&QorWidgetSetting{}, &admin.Config{Menu: []string{"Site Management"}, Priority: 3})
		Widgets.WidgetSettingResource.Meta(&admin.Meta{Name: "Name", FormattedValuer: func(widget interface{}, ctx *qor.Context) interface{} {
			setting := widget.(*QorWidgetSetting)
			return template.HTML(`<img src="/images/Widget-` + setting.WidgetType + `.png" width="80" height="35" style="margin-right: 12px;"/><span>` + setting.Name + `</span>`)
		}})

		Widgets.RegisterScope(&widget.Scope{
			Name: "From Google",
			Visible: func(context *widget.Context) bool {
				if request, ok := context.Get("Request"); ok {
					_, ok := request.(*http.Request).URL.Query()["from_google"]
					return ok
				}
				return false
			},
		})

		Admin.AddResource(Widgets)

		// Top Banner
		type bannerArgument struct {
			Title           string
			ButtonTitle     string
			Link            string
			BackgroundImage oss.OSS
			Logo            oss.OSS
		}

		Widgets.RegisterWidget(&widget.Widget{
			Name:      "NormalBanner",
			Templates: []string{"banner", "banner2"},
			Setting:   Admin.NewResource(&bannerArgument{}),
			Context: func(context *widget.Context, setting interface{}) *widget.Context {
				context.Options["Setting"] = setting
				return context
			},
		})

		// Banner Editor
		type bannerEditorArgument struct {
			Value string
		}
		type subHeaderSetting struct {
			Text  string
			Color string
		}
		type headerSetting struct {
			Text  string
			Color string
		}
		type buttonSetting struct {
			Text string
			Link string
		}

		headerRes := Admin.NewResource(&headerSetting{})
		headerRes.Meta(&admin.Meta{Name: "Text"})
		headerRes.Meta(&admin.Meta{Name: "Color"})

		subHeaderRes := Admin.NewResource(&subHeaderSetting{})
		subHeaderRes.Meta(&admin.Meta{Name: "Text"})
		subHeaderRes.Meta(&admin.Meta{Name: "Color"})

		buttonRes := Admin.NewResource(&buttonSetting{})
		buttonRes.Meta(&admin.Meta{Name: "Text"})
		buttonRes.Meta(&admin.Meta{Name: "Link"})

		banner_editor.RegisterElement(&banner_editor.Element{
			Name:     "Add Header",
			Template: "
{{.Text}}
",
			Resource: headerRes,
			Context: func(c *banner_editor.Context, r interface{}) *banner_editor.Context {
				return c
			},
		})
		banner_editor.RegisterElement(&banner_editor.Element{
			Name:     "Add Sub Header",
			Template: "
{{.Text}}
",
			Resource: subHeaderRes,
			Context: func(c *banner_editor.Context, r interface{}) *banner_editor.Context {
				return c
			},
		})
		banner_editor.RegisterElement(&banner_editor.Element{
			Name:     "Add Link",
			Template: "{{.Text}}",
			Resource: buttonRes,
			Context: func(c *banner_editor.Context, r interface{}) *banner_editor.Context {
				return c
			},
		})
		bannerEditorResource := Admin.NewResource(&bannerEditorArgument{})
		bannerEditorResource.Meta(&admin.Meta{Name: "Value", Config: &banner_editor.BannerEditorConfig{}})

		Widgets.RegisterWidget(&widget.Widget{
			Name:      "BannerEditor",
			Templates: []string{"banner_editor"},
			Setting:   bannerEditorResource,
			Context: func(context *widget.Context, setting interface{}) *widget.Context {
				context.Options["Value"] = template.HTML(setting.(*bannerEditorArgument).Value)
				return context
			},
		})

		type slideImage struct {
			Title string
			Image oss.OSS
		}

		type slideShowArgument struct {
			SlideImages []slideImage
		}
		slideShowResource := Admin.NewResource(&slideShowArgument{})
		slideShowResource.AddProcessor(func(value interface{}, metaValues *resource.MetaValues, context *qor.Context) error {
			if slides, ok := value.(*slideShowArgument); ok {
				for _, slide := range slides.SlideImages {
					if slide.Title == "" {
						return errors.New("slide title is blank")
					}
				}
			}
			return nil
		})

		Widgets.RegisterWidget(&widget.Widget{
			Name:      "SlideShow",
			Templates: []string{"slideshow"},
			Setting:   slideShowResource,
			Context: func(context *widget.Context, setting interface{}) *widget.Context {
				context.Options["Setting"] = setting
				return context
			},
		})

		Widgets.RegisterWidgetsGroup(&widget.WidgetsGroup{
			Name:    "Banner",
			Widgets: []string{"NormalBanner", "SlideShow"},
		})

		// selected Products
		type selectedProductsArgument struct {
			Products       []string
			ProductsSorter sorting.SortableCollection
		}
		selectedProductsResource := Admin.NewResource(&selectedProductsArgument{})
		selectedProductsResource.Meta(&admin.Meta{Name: "Products", Type: "select_many", Collection: func(value interface{}, context *qor.Context) [][]string {
			var collectionValues [][]string
			var products []*models.Product
			context.GetDB().Find(&products)
			for _, product := range products {
				collectionValues = append(collectionValues, []string{fmt.Sprintf("%v", product.ID), product.Name})
			}
			return collectionValues
		}})

		Widgets.RegisterWidget(&widget.Widget{
			Name:      "Products",
			Templates: []string{"products"},
			Setting:   selectedProductsResource,
			Context: func(context *widget.Context, setting interface{}) *widget.Context {
				if setting != nil {
					var products []*models.Product
					context.GetDB().Limit(9).Preload("ColorVariations").Where("id IN (?)", setting.(*selectedProductsArgument).Products).Find(&products)
					setting.(*selectedProductsArgument).ProductsSorter.Sort(&products)
					context.Options["Products"] = products
				}
				return context
			},
		})
	}
}
<|endoftext|>


<commit_before>package pull

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"path"

	"github.com/mitchellh/ioprogress"
)

// NewRelease creates a new Release instance
func NewRelease(cache string) *Release {
	return &Release{CacheDir: cache}
}

// Release is a BOSH release with a configurable cache dir
type Release struct {
	CacheDir string
}

// Pull downloads the specified Release to the local cache dir
func (s *Release) Pull(url string) (filename string, err error) {
	name := path.Base(url)
	filename = s.CacheDir + "/" + name

	if _, err = os.Stat(filename); os.IsNotExist(err) {
		fmt.Println("Could not find release in local cache. Downloading now.")
		err = s.download(url, filename)
	}
	return
}

func (s *Release) download(url, local string) (err error) {
	var out *os.File
	out, err = os.Create(local)
	if err != nil {
		return
	}
	var resp *http.Response
	resp, err = http.Get(url)
	if err != nil {
		return
	}
	defer func() {
		if cerr := resp.Body.Close(); cerr != nil {
			err = cerr
		}
	}()

	progressR := &ioprogress.Reader{
		Reader: resp.Body,
		Size:   resp.ContentLength,
	}
	_, err = io.Copy(out, progressR)
	return
}
<commit_msg>Rename release variable receiver from s to r<commit_after>package pull

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"path"

	"github.com/mitchellh/ioprogress"
)

// NewRelease creates a new Release instance
func NewRelease(cache string) *Release {
	return &Release{CacheDir: cache}
}

// Release is a BOSH release with a configurable cache dir
type Release struct {
	CacheDir string
}

// Pull downloads the specified Release to the local cache dir
func (r *Release) Pull(url string) (filename string, err error) {
	name := path.Base(url)
	filename = r.CacheDir + "/" + name

	if _, err = os.Stat(filename); os.IsNotExist(err) {
		fmt.Println("Could not find release in local cache. Downloading now.")
		err = r.download(url, filename)
	}
	return
}

func (r *Release) download(url, local string) (err error) {
	var out *os.File
	out, err = os.Create(local)
	if err != nil {
		return
	}
	var resp *http.Response
	resp, err = http.Get(url)
	if err != nil {
		return
	}
	defer func() {
		if cerr := resp.Body.Close(); cerr != nil {
			err = cerr
		}
	}()

	progressR := &ioprogress.Reader{
		Reader: resp.Body,
		Size:   resp.ContentLength,
	}
	_, err = io.Copy(out, progressR)
	return
}
<|endoftext|>


<commit_before>package gocql

import (
	"log"
	"net"
	"sync"
	"time"
)

type eventDeouncer struct {
	name   string
	timer  *time.Timer
	mu     sync.Mutex
	events []frame

	callback func([]frame)
	quit     chan struct{}
}

func newEventDeouncer(name string, eventHandler func([]frame)) *eventDeouncer {
	e := &eventDeouncer{
		name:     name,
		quit:     make(chan struct{}),
		timer:    time.NewTimer(eventDebounceTime),
		callback: eventHandler,
	}
	e.timer.Stop()
	go e.flusher()

	return e
}

func (e *eventDeouncer) stop() {
	e.quit <- struct{}{} // sync with flusher
	close(e.quit)
}

func (e *eventDeouncer) flusher() {
	for {
		select {
		case <-e.timer.C:
			e.mu.Lock()
			e.flush()
			e.mu.Unlock()
		case <-e.quit:
			return
		}
	}
}

const (
	eventBufferSize   = 1000
	eventDebounceTime = 1 * time.Second
)

// flush must be called with mu locked
func (e *eventDeouncer) flush() {
	if len(e.events) == 0 {
		return
	}

	// if the flush interval is faster than the callback then we will end up calling
	// the callback multiple times, probably a bad idea. In this case we could drop
	// frames?
	go e.callback(e.events)
	e.events = make([]frame, 0, eventBufferSize)
}

func (e *eventDeouncer) debounce(frame frame) {
	e.mu.Lock()
	e.timer.Reset(eventDebounceTime)

	// TODO: probably need a warning to track if this threshold is too low
	if len(e.events) < eventBufferSize {
		e.events = append(e.events, frame)
	} else {
		log.Printf("%s: buffer full, dropping event frame: %s", e.name, frame)
	}

	e.mu.Unlock()
}

func (s *Session) handleNodeEvent(frames []frame) {
	type nodeEvent struct {
		change string
		host   net.IP
		port   int
	}

	events := make(map[string]*nodeEvent)

	for _, frame := range frames {
		// TODO: can we be sure the order of events in the buffer is correct?
		switch f := frame.(type) {
		case *topologyChangeEventFrame:
			event, ok := events[f.host.String()]
			if !ok {
				event = &nodeEvent{change: f.change, host: f.host, port: f.port}
				events[f.host.String()] = event
			}
			event.change = f.change

		case *statusChangeEventFrame:
			event, ok := events[f.host.String()]
			if !ok {
				event = &nodeEvent{change: f.change, host: f.host, port: f.port}
				events[f.host.String()] = event
			}
			event.change = f.change
		}
	}

	for _, f := range events {
		log.Printf("debouncing event %+v\n", f)
		switch f.change {
		case "NEW_NODE":
			s.handleNewNode(f.host, f.port, true)
		case "REMOVED_NODE":
			s.handleRemovedNode(f.host, f.port)
		case "MOVED_NODE":
		// java-driver handles this, not mentioned in the spec
		// TODO(zariel): refresh token map
		case "UP":
			s.handleNodeUp(f.host, f.port, true)
		case "DOWN":
			s.handleNodeDown(f.host, f.port)
		}
	}
}

func (s *Session) handleEvent(framer *framer) {
	// TODO(zariel): need to debounce events frames, and possible also events
	defer framerPool.Put(framer)

	frame, err := framer.parseFrame()
	if err != nil {
		// TODO: logger
		log.Printf("gocql: unable to parse event frame: %v\n", err)
		return
	}
	log.Println(frame)

	// TODO: handle medatadata events
	switch f := frame.(type) {
	case *schemaChangeKeyspace:
	case *schemaChangeFunction:
	case *schemaChangeTable:
	case *topologyChangeEventFrame, *statusChangeEventFrame:
		s.nodeEvents.debounce(frame)
	default:
		log.Printf("gocql: invalid event frame (%T): %v\n", f, f)
	}

}

func (s *Session) handleNewNode(host net.IP, port int, waitForBinary bool) {
	// TODO(zariel): need to be able to filter discovered nodes

	var hostInfo *HostInfo
	if s.control != nil {
		var err error
		hostInfo, err = s.control.fetchHostInfo(host, port)
		if err != nil {
			log.Printf("gocql: events: unable to fetch host info for %v: %v\n", host, err)
			return
		}

	} else {
		hostInfo = &HostInfo{peer: host.String(), port: port, state: NodeUp}
	}

	if t := hostInfo.Version().nodeUpDelay(); t > 0 && waitForBinary {
		time.Sleep(t)
	}

	// should this handle token moving?
	if existing, ok := s.ring.addHostIfMissing(hostInfo); !ok {
		existing.update(hostInfo)
		hostInfo = existing
	}

	s.pool.addHost(hostInfo)

	if s.control != nil {
		s.hostSource.refreshRing()
	}
}

func (s *Session) handleRemovedNode(ip net.IP, port int) {
	// we remove all nodes but only add ones which pass the filter
	addr := ip.String()
	s.pool.removeHost(addr)
	s.ring.removeHost(addr)

	s.hostSource.refreshRing()
}

func (s *Session) handleNodeUp(ip net.IP, port int, waitForBinary bool) {
	addr := ip.String()
	host := s.ring.getHost(addr)
	if host != nil {
		if t := host.Version().nodeUpDelay(); t > 0 && waitForBinary {
			time.Sleep(t)
		}

		host.setState(NodeUp)
		s.pool.hostUp(host)
		return
	}

	s.handleNewNode(ip, port, waitForBinary)
}

func (s *Session) handleNodeDown(ip net.IP, port int) {
	addr := ip.String()
	host := s.ring.getHost(addr)
	if host != nil {
		host.setState(NodeDown)
	}

	s.pool.hostDown(addr)
}
<commit_msg>remove debug logging<commit_after>package gocql

import (
	"log"
	"net"
	"sync"
	"time"
)

type eventDeouncer struct {
	name   string
	timer  *time.Timer
	mu     sync.Mutex
	events []frame

	callback func([]frame)
	quit     chan struct{}
}

func newEventDeouncer(name string, eventHandler func([]frame)) *eventDeouncer {
	e := &eventDeouncer{
		name:     name,
		quit:     make(chan struct{}),
		timer:    time.NewTimer(eventDebounceTime),
		callback: eventHandler,
	}
	e.timer.Stop()
	go e.flusher()

	return e
}

func (e *eventDeouncer) stop() {
	e.quit <- struct{}{} // sync with flusher
	close(e.quit)
}

func (e *eventDeouncer) flusher() {
	for {
		select {
		case <-e.timer.C:
			e.mu.Lock()
			e.flush()
			e.mu.Unlock()
		case <-e.quit:
			return
		}
	}
}

const (
	eventBufferSize   = 1000
	eventDebounceTime = 1 * time.Second
)

// flush must be called with mu locked
func (e *eventDeouncer) flush() {
	if len(e.events) == 0 {
		return
	}

	// if the flush interval is faster than the callback then we will end up calling
	// the callback multiple times, probably a bad idea. In this case we could drop
	// frames?
	go e.callback(e.events)
	e.events = make([]frame, 0, eventBufferSize)
}

func (e *eventDeouncer) debounce(frame frame) {
	e.mu.Lock()
	e.timer.Reset(eventDebounceTime)

	// TODO: probably need a warning to track if this threshold is too low
	if len(e.events) < eventBufferSize {
		e.events = append(e.events, frame)
	} else {
		log.Printf("%s: buffer full, dropping event frame: %s", e.name, frame)
	}

	e.mu.Unlock()
}

func (s *Session) handleNodeEvent(frames []frame) {
	type nodeEvent struct {
		change string
		host   net.IP
		port   int
	}

	events := make(map[string]*nodeEvent)

	for _, frame := range frames {
		// TODO: can we be sure the order of events in the buffer is correct?
		switch f := frame.(type) {
		case *topologyChangeEventFrame:
			event, ok := events[f.host.String()]
			if !ok {
				event = &nodeEvent{change: f.change, host: f.host, port: f.port}
				events[f.host.String()] = event
			}
			event.change = f.change

		case *statusChangeEventFrame:
			event, ok := events[f.host.String()]
			if !ok {
				event = &nodeEvent{change: f.change, host: f.host, port: f.port}
				events[f.host.String()] = event
			}
			event.change = f.change
		}
	}

	for _, f := range events {
		switch f.change {
		case "NEW_NODE":
			s.handleNewNode(f.host, f.port, true)
		case "REMOVED_NODE":
			s.handleRemovedNode(f.host, f.port)
		case "MOVED_NODE":
		// java-driver handles this, not mentioned in the spec
		// TODO(zariel): refresh token map
		case "UP":
			s.handleNodeUp(f.host, f.port, true)
		case "DOWN":
			s.handleNodeDown(f.host, f.port)
		}
	}
}

func (s *Session) handleEvent(framer *framer) {
	// TODO(zariel): need to debounce events frames, and possible also events
	defer framerPool.Put(framer)

	frame, err := framer.parseFrame()
	if err != nil {
		// TODO: logger
		log.Printf("gocql: unable to parse event frame: %v\n", err)
		return
	}

	// TODO: handle medatadata events
	switch f := frame.(type) {
	case *schemaChangeKeyspace:
	case *schemaChangeFunction:
	case *schemaChangeTable:
	case *topologyChangeEventFrame, *statusChangeEventFrame:
		s.nodeEvents.debounce(frame)
	default:
		log.Printf("gocql: invalid event frame (%T): %v\n", f, f)
	}

}

func (s *Session) handleNewNode(host net.IP, port int, waitForBinary bool) {
	// TODO(zariel): need to be able to filter discovered nodes

	var hostInfo *HostInfo
	if s.control != nil {
		var err error
		hostInfo, err = s.control.fetchHostInfo(host, port)
		if err != nil {
			log.Printf("gocql: events: unable to fetch host info for %v: %v\n", host, err)
			return
		}

	} else {
		hostInfo = &HostInfo{peer: host.String(), port: port, state: NodeUp}
	}

	if t := hostInfo.Version().nodeUpDelay(); t > 0 && waitForBinary {
		time.Sleep(t)
	}

	// should this handle token moving?
	if existing, ok := s.ring.addHostIfMissing(hostInfo); !ok {
		existing.update(hostInfo)
		hostInfo = existing
	}

	s.pool.addHost(hostInfo)

	if s.control != nil {
		s.hostSource.refreshRing()
	}
}

func (s *Session) handleRemovedNode(ip net.IP, port int) {
	// we remove all nodes but only add ones which pass the filter
	addr := ip.String()
	s.pool.removeHost(addr)
	s.ring.removeHost(addr)

	s.hostSource.refreshRing()
}

func (s *Session) handleNodeUp(ip net.IP, port int, waitForBinary bool) {
	addr := ip.String()
	host := s.ring.getHost(addr)
	if host != nil {
		if t := host.Version().nodeUpDelay(); t > 0 && waitForBinary {
			time.Sleep(t)
		}

		host.setState(NodeUp)
		s.pool.hostUp(host)
		return
	}

	s.handleNewNode(ip, port, waitForBinary)
}

func (s *Session) handleNodeDown(ip net.IP, port int) {
	addr := ip.String()
	host := s.ring.getHost(addr)
	if host != nil {
		host.setState(NodeDown)
	}

	s.pool.hostDown(addr)
}
<|endoftext|>


<commit_before>package xweb

import (
	"sync"
)

var Events *EventsInstance = NewEvents()

func NewEvents() *EventsInstance {
	return &EventsInstance{
		listeners: make(map[string][]func(interface{}, func(bool))),
		lock:      new(sync.RWMutex),
	}
}

//并发执行事件
func GoEvent(eventName string, session interface{}, next func(bool)) {
	Events.GoExecute(eventName, session, next)
}

//顺序执行事件
func Event(eventName string, session interface{}, next func(bool)) {
	Events.Execute(eventName, session, next)
}

//添加事件
func AddEvent(eventName string, handler func(interface{}, func(bool))) {
	Events.Register(eventName, handler)
}

type EventsInstance struct {
	listeners map[string][]func(interface{}, func(bool))
	lock      *sync.RWMutex
}

/*
注册事件
[Examle:]
Events.Register("AfterResponse", func(session interface{}, next func(bool)) {
	log.Println("Got AfterResponse event!")
	isSuccess := true
	next(isSuccess) //这里的next函数无论什么情况下必须执行。
})

采用不同的方式执行事件时，此处的next函数的作用也是不同的：
1、在并发执行事件的时候，next函数的作用是通知程序我已经执行完了(不理会这一步是否执行成功)；
2、在顺序执行事件的时候，next函数的作用是通知程序是否继续执行下一步，next(true)是继续执行下一步，next(false)是终止执行下一步
*/
func (e *EventsInstance) Register(eventName string, handler func(interface{}, func(bool))) {
	e.lock.Lock()
	defer e.lock.Unlock()
	if e.listeners == nil {
		e.listeners = make(map[string][]func(interface{}, func(bool)))
	}
	_, ok := e.listeners[eventName]
	if !ok {
		e.listeners[eventName] = make([]func(interface{}, func(bool)), 0)
	}
	e.listeners[eventName] = append(e.listeners[eventName], handler)
}

/*
并发执行事件
[Examle 1:]
Events.GoExecute("AfterHandler", session, func(_ bool) {//此匿名函数在本事件的最后执行
	session.Response.Send()
	session.Response.Close()
})

[Examle 2:]
Events.Execute("AfterResponse", session, func(_ bool) {})
*/
func (e *EventsInstance) GoExecute(eventName string, session interface{}, next func(bool)) {
	if e.listeners == nil {
		next(true)
		return
	}
	c := make(chan int)
	n := 0
	e.lock.RLock()
	defer e.lock.RUnlock()
	if l, ok := e.listeners[eventName]; ok {
		if len(l) > 0 {
			for _, h := range l {
				n++
				//h 的原型为 func(interface{}, func(bool))
				go h(session, func(_ bool) {
					c <- 1
				})
			}
		}
	}
	for n > 0 {
		i := <-c
		if i == 1 {
			n--
		}
	}
	next(true)
}

/**
 * 顺序执行事件
 */
func (e *EventsInstance) Execute(eventName string, session interface{}, next func(bool)) {
	if e.listeners == nil {
		next(true)
		return
	}
	e.lock.RLock()
	defer e.lock.RUnlock()
	var nextStep bool = false
	if l, ok := e.listeners[eventName]; ok {
		if len(l) > 0 {
			for _, h := range l {
				h(session, func(ok bool) {
					nextStep = ok
				})
				//一旦传入false，后面的全部忽略执行
				if !nextStep {
					break
				}
			}
		} else {
			nextStep = true
		}
	} else {
		nextStep = true
	}
	next(nextStep)
}
<commit_msg>支持删除事件<commit_after>package xweb

import (
	"sync"
)

var Events *EventsInstance = NewEvents()

func NewEvents() *EventsInstance {
	return &EventsInstance{
		listeners: make(map[string][]func(interface{}, func(bool))),
		lock:      new(sync.RWMutex),
	}
}

//并发执行事件
func GoEvent(eventName string, session interface{}, next func(bool)) {
	Events.GoExecute(eventName, session, next)
}

//顺序执行事件
func Event(eventName string, session interface{}, next func(bool)) {
	Events.Execute(eventName, session, next)
}

//删除事件
func DelEvent(eventName string) {
	Events.Delete(eventName)
}

//添加事件
func AddEvent(eventName string, handler func(interface{}, func(bool))) {
	Events.Register(eventName, handler)
}

type EventsInstance struct {
	listeners map[string][]func(interface{}, func(bool))
	lock      *sync.RWMutex
}

/*
注册事件
[Examle:]
Events.Register("AfterResponse", func(session interface{}, next func(bool)) {
	log.Println("Got AfterResponse event!")
	isSuccess := true
	next(isSuccess) //这里的next函数无论什么情况下必须执行。
})

采用不同的方式执行事件时，此处的next函数的作用也是不同的：
1、在并发执行事件的时候，next函数的作用是通知程序我已经执行完了(不理会这一步是否执行成功)；
2、在顺序执行事件的时候，next函数的作用是通知程序是否继续执行下一步，next(true)是继续执行下一步，next(false)是终止执行下一步
*/
func (e *EventsInstance) Register(eventName string, handler func(interface{}, func(bool))) {
	e.lock.Lock()
	defer e.lock.Unlock()
	if e.listeners == nil {
		e.listeners = make(map[string][]func(interface{}, func(bool)))
	}
	_, ok := e.listeners[eventName]
	if !ok {
		e.listeners[eventName] = make([]func(interface{}, func(bool)), 0)
	}
	e.listeners[eventName] = append(e.listeners[eventName], handler)
}

func (e *EventsInstance) Delete(eventName string) {
	e.lock.Lock()
	defer e.lock.Unlock()
	if e.listeners == nil {
		return
	}
	_, ok := e.listeners[eventName]
	if ok {
		delete(e.listeners, eventName)
	}
}

/*
并发执行事件
[Examle 1:]
Events.GoExecute("AfterHandler", session, func(_ bool) {//此匿名函数在本事件的最后执行
	session.Response.Send()
	session.Response.Close()
})

[Examle 2:]
Events.Execute("AfterResponse", session, func(_ bool) {})
*/
func (e *EventsInstance) GoExecute(eventName string, session interface{}, next func(bool)) {
	if e.listeners == nil {
		next(true)
		return
	}
	c := make(chan int)
	n := 0
	e.lock.RLock()
	defer e.lock.RUnlock()
	if l, ok := e.listeners[eventName]; ok {
		if len(l) > 0 {
			for _, h := range l {
				n++
				//h 的原型为 func(interface{}, func(bool))
				go h(session, func(_ bool) {
					c <- 1
				})
			}
		}
	}
	for n > 0 {
		i := <-c
		if i == 1 {
			n--
		}
	}
	next(true)
}

/**
 * 顺序执行事件
 */
func (e *EventsInstance) Execute(eventName string, session interface{}, next func(bool)) {
	if e.listeners == nil {
		next(true)
		return
	}
	e.lock.RLock()
	defer e.lock.RUnlock()
	var nextStep bool = false
	if l, ok := e.listeners[eventName]; ok {
		if len(l) > 0 {
			for _, h := range l {
				h(session, func(ok bool) {
					nextStep = ok
				})
				//一旦传入false，后面的全部忽略执行
				if !nextStep {
					break
				}
			}
		} else {
			nextStep = true
		}
	} else {
		nextStep = true
	}
	next(nextStep)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"os"
	"os/exec"
	"strings"
	"unicode"
)

// generates snake case json tags so that you won't need to write them. Can be also exteded to xml or sql tags
func main() {
	fset := token.NewFileSet() // positions are relative to fset
	args := os.Args[1:]
	if len(args) < 2 {
		fmt.Println("Usage : easytags {file_name} {tag_name} {debug (true/false)} \n example: easytags file.go json true")
		return
	}
	debug := false
	if len(args) == 3 {
		if args[2] == "true" {
			debug = true
		}
	}
	tagName := args[1]
	// Parse the file given in arguments
	f, err := parser.ParseFile(fset, args[0], nil, parser.ParseComments)
	if err != nil {
		fmt.Println("Error")
		fmt.Println(err)
		return
	}
	// read entire source file as a slice of lines
	lines, err := readLines(args[0])
	if err != nil {
		fmt.Printf("Error reading file %v \n ", err)
		return
	}
	// range over the objects in the scope of this generated AST and check for StructType. Then range over fields
	// contained in that struct.
	for _, d := range f.Scope.Objects {
		if d.Kind == ast.Typ {
			ts, ok := d.Decl.(*ast.TypeSpec)
			if !ok {
				fmt.Printf("Unknown type without TypeSec: %v", d)
				return
			}

			x, ok := ts.Type.(*ast.StructType)
			if !ok {
				continue
			}
			for _, field := range x.Fields.List {
				line := fset.File(field.Pos()).Line(field.Pos())
				line = line - 1
				// if tag for field doesn't exists, create one
				if field.Tag == nil {
					name := field.Names[0].String()
					if debug {
						fmt.Printf("Replacing line %s \n ", lines[line])
					}
					lines[line] = fmt.Sprintf("%s %v `%s:\"%s\"`", name, field.Type, tagName, ToSnake(name))
					if debug {
						fmt.Printf("By line : %s \n", lines[line])
					}
				} else if !strings.Contains(field.Tag.Value, fmt.Sprintf("%s:", tagName)) {
					// if tag exists, but doesn't contain target tag
					name := field.Names[0].String()
					if debug {
						fmt.Printf("Replacing line %s \n ", lines[line])
					}
					lines[line] = fmt.Sprintf("%s %v `%s:\"%s\" %s`", name, field.Type, tagName, ToSnake(name), strings.Replace(field.Tag.Value, "`", "", 2))
					if debug {
						fmt.Printf("By line : %s \n", lines[line])
					}

				}

			}
		}
	}
	// overwrite the file with modified version of lines.
	writeLines(lines, args[0])
	cmd := exec.Command("go", "fmt", args[0])
	cmd.Run()
}

// readLines reads a whole file into memory
// and returns a slice of its lines.
// original source : http://stackoverflow.com/questions/5884154/golang-read-text-file-into-string-array-and-write
func readLines(path string) ([]string, error) {
	file, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	var lines []string
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		lines = append(lines, scanner.Text())
	}
	return lines, scanner.Err()
}

// writeLines writes the lines to the given file.
func writeLines(lines []string, path string) error {
	file, err := os.Create(path)
	if err != nil {
		return err
	}
	defer file.Close()

	w := bufio.NewWriter(file)
	for _, line := range lines {
		fmt.Fprintln(w, line)
	}
	return w.Flush()
}

// ToSnake convert the given string to snake case following the Golang format:
// acronyms are converted to lower-case and preceded by an underscore.
// Original source : https://gist.github.com/elwinar/14e1e897fdbe4d3432e1
func ToSnake(in string) string {
	runes := []rune(in)
	length := len(runes)

	var out []rune
	for i := 0; i < length; i++ {
		if i > 0 && unicode.IsUpper(runes[i]) && ((i+1 < length && unicode.IsLower(runes[i+1])) || unicode.IsLower(runes[i-1])) {
			out = append(out, '_')
		}
		out = append(out, unicode.ToLower(runes[i]))
	}

	return string(out)
}
<commit_msg>Fixes panic with embedded structs. See example https://gist.github.com/GeorgeErickson/d9bf40237ccb1cffb410<commit_after>package main

import (
	"bufio"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"os"
	"os/exec"
	"strings"
	"unicode"
)

// generates snake case json tags so that you won't need to write them. Can be also exteded to xml or sql tags
func main() {
	fset := token.NewFileSet() // positions are relative to fset
	args := os.Args[1:]
	if len(args) < 2 {
		fmt.Println("Usage : easytags {file_name} {tag_name} {debug (true/false)} \n example: easytags file.go json true")
		return
	}
	debug := false
	if len(args) == 3 {
		if args[2] == "true" {
			debug = true
		}
	}
	tagName := args[1]
	// Parse the file given in arguments
	f, err := parser.ParseFile(fset, args[0], nil, parser.ParseComments)
	if err != nil {
		fmt.Println("Error")
		fmt.Println(err)
		return
	}
	// read entire source file as a slice of lines
	lines, err := readLines(args[0])
	if err != nil {
		fmt.Printf("Error reading file %v \n ", err)
		return
	}
	// range over the objects in the scope of this generated AST and check for StructType. Then range over fields
	// contained in that struct.
	for _, d := range f.Scope.Objects {
		if d.Kind == ast.Typ {
			ts, ok := d.Decl.(*ast.TypeSpec)
			if !ok {
				fmt.Printf("Unknown type without TypeSec: %v", d)
				return
			}

			x, ok := ts.Type.(*ast.StructType)
			if !ok {
				continue
			}
			for _, field := range x.Fields.List {
				line := fset.File(field.Pos()).Line(field.Pos())
				line = line - 1
				if len(field.Names) == 0 {
					continue
				}
				// if tag for field doesn't exists, create one
				if field.Tag == nil {
					name := field.Names[0].String()
					if debug {
						fmt.Printf("Replacing line %s \n ", lines[line])
					}
					lines[line] = fmt.Sprintf("%s %v `%s:\"%s\"`", name, field.Type, tagName, ToSnake(name))
					if debug {
						fmt.Printf("By line : %s \n", lines[line])
					}
				} else if !strings.Contains(field.Tag.Value, fmt.Sprintf("%s:", tagName)) {
					// if tag exists, but doesn't contain target tag
					name := field.Names[0].String()
					if debug {
						fmt.Printf("Replacing line %s \n ", lines[line])
					}
					lines[line] = fmt.Sprintf("%s %v `%s:\"%s\" %s`", name, field.Type, tagName, ToSnake(name), strings.Replace(field.Tag.Value, "`", "", 2))
					if debug {
						fmt.Printf("By line : %s \n", lines[line])
					}

				}

			}
		}
	}
	// overwrite the file with modified version of lines.
	writeLines(lines, args[0])
	cmd := exec.Command("go", "fmt", args[0])
	cmd.Run()
}

// readLines reads a whole file into memory
// and returns a slice of its lines.
// original source : http://stackoverflow.com/questions/5884154/golang-read-text-file-into-string-array-and-write
func readLines(path string) ([]string, error) {
	file, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	var lines []string
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		lines = append(lines, scanner.Text())
	}
	return lines, scanner.Err()
}

// writeLines writes the lines to the given file.
func writeLines(lines []string, path string) error {
	file, err := os.Create(path)
	if err != nil {
		return err
	}
	defer file.Close()

	w := bufio.NewWriter(file)
	for _, line := range lines {
		fmt.Fprintln(w, line)
	}
	return w.Flush()
}

// ToSnake convert the given string to snake case following the Golang format:
// acronyms are converted to lower-case and preceded by an underscore.
// Original source : https://gist.github.com/elwinar/14e1e897fdbe4d3432e1
func ToSnake(in string) string {
	runes := []rune(in)
	length := len(runes)

	var out []rune
	for i := 0; i < length; i++ {
		if i > 0 && unicode.IsUpper(runes[i]) && ((i+1 < length && unicode.IsLower(runes[i+1])) || unicode.IsLower(runes[i-1])) {
			out = append(out, '_')
		}
		out = append(out, unicode.ToLower(runes[i]))
	}

	return string(out)
}
<|endoftext|>


<commit_before>// Copyright 2014 Manu Martinez-Almeida.  All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.

package ego

import (
	"fmt"
	"html/template"
	"io/ioutil"
	"net/http"
	"reflect"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
)

func formatAsDate(t time.Time) string {
	year, month, day := t.Date()
	return fmt.Sprintf("%d/%02d/%02d", year, month, day)
}

func setupHTMLFiles(t *testing.T) func() {
	go func() {
		// SetMode(TestMode)
		router := New()
		router.Delims("{[{", "}]}")
		router.SetFuncMap(template.FuncMap{
			"formatAsDate": formatAsDate,
		})
		router.LoadHTMLFiles("./test/basic/hello.tmpl", "./test/basic/raw.tmpl")
		router.GET("/test", func(c *Context) {
			c.HTML(http.StatusOK, "hello.tmpl", map[string]string{"name": "world"})
		})
		router.GET("/raw", func(c *Context) {
			c.HTML(http.StatusOK, "raw.tmpl", map[string]interface{}{
				"now": time.Date(2017, 07, 01, 0, 0, 0, 0, time.UTC),
			})
		})
		router.Run(":8888")
	}()
	t.Log("waiting 1 second for server startup")
	time.Sleep(1 * time.Second)
	return func() {}
}

func setupHTMLGlob(t *testing.T) func() {
	go func() {
		// SetMode(DebugMode)
		router := New()
		router.Delims("{[{", "}]}")
		router.SetFuncMap(template.FuncMap{
			"formatAsDate": formatAsDate,
		})
		router.LoadHTMLGlob("./test/basic/*")
		router.GET("/test", func(c *Context) {
			c.HTML(http.StatusOK, "hello.tmpl", map[string]string{"name": "world"})
		})
		router.GET("/raw", func(c *Context) {
			c.HTML(http.StatusOK, "raw.tmpl", map[string]interface{}{
				"now": time.Date(2017, 07, 01, 0, 0, 0, 0, time.UTC),
			})
		})
		router.Run(":8888")
	}()
	t.Log("waiting 1 second for server startup")
	time.Sleep(1 * time.Second)
	return func() {}
}

func TestLoadHTMLGlob(t *testing.T) {
	td := setupHTMLGlob(t)
	res, err := http.Get("http://127.0.0.1:8888/test")
	if err != nil {
		fmt.Println(err)
	}

	resp, _ := ioutil.ReadAll(res.Body)
	assert.Equal(t, "
Hello world
", string(resp[:]))

	td()
}

func TestLoadHTMLGlobFromFuncMap(t *testing.T) {
	time.Now()
	td := setupHTMLGlob(t)
	res, err := http.Get("http://127.0.0.1:8888/raw")
	if err != nil {
		fmt.Println(err)
	}

	resp, _ := ioutil.ReadAll(res.Body)
	assert.Equal(t, "Date: 2017/07/01\n", string(resp[:]))

	td()
}

//TODO
// func (engine *Engine) LoadHTMLFiles(files ...string) {
// func (engine *Engine) RunTLS(addr, cert, key string) error {

func init() {
	SetMode(TestMode)
}
func TestCreateEngine(t *testing.T) {
	router := New()
	assert.Equal(t, "/", router.basePath)
	assert.Equal(t, router.engine, router)
	assert.Empty(t, router.Handlers)
}

// func TestLoadHTMLDebugMode(t *testing.T) {
// 	router := New()
// 	SetMode(DebugMode)
// 	router.LoadHTMLGlob("*.testtmpl")
// 	r := router.HTMLRender.(render.HTMLDebug)
// 	assert.Empty(t, r.Files)
// 	assert.Equal(t, r.Glob, "*.testtmpl")
//
// 	router.LoadHTMLFiles("index.html.testtmpl", "login.html.testtmpl")
// 	r = router.HTMLRender.(render.HTMLDebug)
// 	assert.Empty(t, r.Glob)
// 	assert.Equal(t, r.Files, []string{"index.html", "login.html"})
// 	SetMode(TestMode)
// }

func TestLoadHTMLFiles(t *testing.T) {
	td := setupHTMLFiles(t)
	res, err := http.Get("http://127.0.0.1:8888/test")
	if err != nil {
		fmt.Println(err)
	}

	resp, _ := ioutil.ReadAll(res.Body)
	assert.Equal(t, "
Hello world
", string(resp[:]))
	td()
}

func TestLoadHTMLFilesFuncMap(t *testing.T) {
	time.Now()
	td := setupHTMLFiles(t)
	res, err := http.Get("http://127.0.0.1:8888/raw")
	if err != nil {
		fmt.Println(err)
	}

	resp, _ := ioutil.ReadAll(res.Body)
	assert.Equal(t, "Date: 2017/07/01\n", string(resp[:]))

	td()
}

func TestLoadHTMLReleaseMode(t *testing.T) {

}

func TestAddRoute(t *testing.T) {
	router := New()
	router.addRoute("GET", "/", HandlersChain{func(_ *Context) {}})

	assert.Len(t, router.trees, 1)
	assert.NotNil(t, router.trees.get("GET"))
	assert.Nil(t, router.trees.get("POST"))

	router.addRoute("POST", "/", HandlersChain{func(_ *Context) {}})

	assert.Len(t, router.trees, 2)
	assert.NotNil(t, router.trees.get("GET"))
	assert.NotNil(t, router.trees.get("POST"))

	router.addRoute("POST", "/post", HandlersChain{func(_ *Context) {}})
	assert.Len(t, router.trees, 2)
}

func TestAddRouteFails(t *testing.T) {
	router := New()
	assert.Panics(t, func() { router.addRoute("", "/", HandlersChain{func(_ *Context) {}}) })
	assert.Panics(t, func() { router.addRoute("GET", "a", HandlersChain{func(_ *Context) {}}) })
	assert.Panics(t, func() { router.addRoute("GET", "/", HandlersChain{}) })

	router.addRoute("POST", "/post", HandlersChain{func(_ *Context) {}})
	assert.Panics(t, func() {
		router.addRoute("POST", "/post", HandlersChain{func(_ *Context) {}})
	})
}

func TestCreateDefaultRouter(t *testing.T) {
	router := Default()
	assert.Len(t, router.Handlers, 2)
}

func TestNoRouteWithoutGlobalHandlers(t *testing.T) {
	var middleware0 HandlerFunc = func(c *Context) {}
	var middleware1 HandlerFunc = func(c *Context) {}

	router := New()

	router.NoRoute(middleware0)
	assert.Nil(t, router.Handlers)
	assert.Len(t, router.noRoute, 1)
	assert.Len(t, router.allNoRoute, 1)
	compareFunc(t, router.noRoute[0], middleware0)
	compareFunc(t, router.allNoRoute[0], middleware0)

	router.NoRoute(middleware1, middleware0)
	assert.Len(t, router.noRoute, 2)
	assert.Len(t, router.allNoRoute, 2)
	compareFunc(t, router.noRoute[0], middleware1)
	compareFunc(t, router.allNoRoute[0], middleware1)
	compareFunc(t, router.noRoute[1], middleware0)
	compareFunc(t, router.allNoRoute[1], middleware0)
}

func TestNoRouteWithGlobalHandlers(t *testing.T) {
	var middleware0 HandlerFunc = func(c *Context) {}
	var middleware1 HandlerFunc = func(c *Context) {}
	var middleware2 HandlerFunc = func(c *Context) {}

	router := New()
	router.Use(middleware2)

	router.NoRoute(middleware0)
	assert.Len(t, router.allNoRoute, 2)
	assert.Len(t, router.Handlers, 1)
	assert.Len(t, router.noRoute, 1)

	compareFunc(t, router.Handlers[0], middleware2)
	compareFunc(t, router.noRoute[0], middleware0)
	compareFunc(t, router.allNoRoute[0], middleware2)
	compareFunc(t, router.allNoRoute[1], middleware0)

	router.Use(middleware1)
	assert.Len(t, router.allNoRoute, 3)
	assert.Len(t, router.Handlers, 2)
	assert.Len(t, router.noRoute, 1)

	compareFunc(t, router.Handlers[0], middleware2)
	compareFunc(t, router.Handlers[1], middleware1)
	compareFunc(t, router.noRoute[0], middleware0)
	compareFunc(t, router.allNoRoute[0], middleware2)
	compareFunc(t, router.allNoRoute[1], middleware1)
	compareFunc(t, router.allNoRoute[2], middleware0)
}

func TestNoMethodWithoutGlobalHandlers(t *testing.T) {
	var middleware0 HandlerFunc = func(c *Context) {}
	var middleware1 HandlerFunc = func(c *Context) {}

	router := New()

	router.NoMethod(middleware0)
	assert.Empty(t, router.Handlers)
	assert.Len(t, router.noMethod, 1)
	assert.Len(t, router.allNoMethod, 1)
	compareFunc(t, router.noMethod[0], middleware0)
	compareFunc(t, router.allNoMethod[0], middleware0)

	router.NoMethod(middleware1, middleware0)
	assert.Len(t, router.noMethod, 2)
	assert.Len(t, router.allNoMethod, 2)
	compareFunc(t, router.noMethod[0], middleware1)
	compareFunc(t, router.allNoMethod[0], middleware1)
	compareFunc(t, router.noMethod[1], middleware0)
	compareFunc(t, router.allNoMethod[1], middleware0)
}

func TestRebuild404Handlers(t *testing.T) {

}

func TestNoMethodWithGlobalHandlers(t *testing.T) {
	var middleware0 HandlerFunc = func(c *Context) {}
	var middleware1 HandlerFunc = func(c *Context) {}
	var middleware2 HandlerFunc = func(c *Context) {}

	router := New()
	router.Use(middleware2)

	router.NoMethod(middleware0)
	assert.Len(t, router.allNoMethod, 2)
	assert.Len(t, router.Handlers, 1)
	assert.Len(t, router.noMethod, 1)

	compareFunc(t, router.Handlers[0], middleware2)
	compareFunc(t, router.noMethod[0], middleware0)
	compareFunc(t, router.allNoMethod[0], middleware2)
	compareFunc(t, router.allNoMethod[1], middleware0)

	router.Use(middleware1)
	assert.Len(t, router.allNoMethod, 3)
	assert.Len(t, router.Handlers, 2)
	assert.Len(t, router.noMethod, 1)

	compareFunc(t, router.Handlers[0], middleware2)
	compareFunc(t, router.Handlers[1], middleware1)
	compareFunc(t, router.noMethod[0], middleware0)
	compareFunc(t, router.allNoMethod[0], middleware2)
	compareFunc(t, router.allNoMethod[1], middleware1)
	compareFunc(t, router.allNoMethod[2], middleware0)
}

func compareFunc(t *testing.T, a, b interface{}) {
	sf1 := reflect.ValueOf(a)
	sf2 := reflect.ValueOf(b)
	if sf1.Pointer() != sf2.Pointer() {
		t.Error("different functions")
	}
}

func TestListOfRoutes(t *testing.T) {
	router := New()
	router.GET("/favicon.ico", handlerTest1)
	router.GET("/", handlerTest1)
	group := router.Group("/users")
	{
		group.GET("/", handlerTest2)
		group.GET("/:id", handlerTest1)
		group.POST("/:id", handlerTest2)
	}
	router.Static("/static", ".")

	list := router.Routes()

	assert.Len(t, list, 7)
	assertRoutePresent(t, list, RouteInfo{
		Method:  "GET",
		Path:    "/favicon.ico",
		Handler: "^(.*/vendor/)?github.com/go-ego/ego.handlerTest1$",
	})
	assertRoutePresent(t, list, RouteInfo{
		Method:  "GET",
		Path:    "/",
		Handler: "^(.*/vendor/)?github.com/go-ego/ego.handlerTest1$",
	})
	assertRoutePresent(t, list, RouteInfo{
		Method:  "GET",
		Path:    "/users/",
		Handler: "^(.*/vendor/)?github.com/go-ego/ego.handlerTest2$",
	})
	assertRoutePresent(t, list, RouteInfo{
		Method:  "GET",
		Path:    "/users/:id",
		Handler: "^(.*/vendor/)?github.com/go-ego/ego.handlerTest1$",
	})
	assertRoutePresent(t, list, RouteInfo{
		Method:  "POST",
		Path:    "/users/:id",
		Handler: "^(.*/vendor/)?github.com/go-ego/ego.handlerTest2$",
	})
}

func assertRoutePresent(t *testing.T, gotRoutes RoutesInfo, wantRoute RouteInfo) {
	for _, gotRoute := range gotRoutes {
		if gotRoute.Path == wantRoute.Path && gotRoute.Method == wantRoute.Method {
			assert.Regexp(t, wantRoute.Handler, gotRoute.Handler)
			return
		}
	}
	t.Errorf("route not found: %v", wantRoute)
}

func handlerTest1(c *Context) {}
func handlerTest2(c *Context) {}
<commit_msg>Update test<commit_after>// Copyright 2014 Manu Martinez-Almeida.  All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.

package ego

import (
	"fmt"
	"html/template"
	"io/ioutil"
	"net/http"
	"reflect"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
)

func formatAsDate(t time.Time) string {
	year, month, day := t.Date()
	return fmt.Sprintf("%d/%02d/%02d", year, month, day)
}

func setupHTMLFiles(t *testing.T) func() {
	go func() {
		SetMode(TestMode)
		router := New()
		router.Delims("{[{", "}]}")
		router.SetFuncMap(template.FuncMap{
			"formatAsDate": formatAsDate,
		})
		router.LoadHTMLFiles("./test/basic/hello.tmpl", "./test/basic/raw.tmpl")
		router.GET("/test", func(c *Context) {
			c.HTML(http.StatusOK, "hello.tmpl", map[string]string{"name": "world"})
		})
		router.GET("/raw", func(c *Context) {
			c.HTML(http.StatusOK, "raw.tmpl", map[string]interface{}{
				"now": time.Date(2017, 07, 01, 0, 0, 0, 0, time.UTC),
			})
		})
		router.Run(":8888")
	}()
	t.Log("waiting 1 second for server startup")
	time.Sleep(1 * time.Second)
	return func() {}
}

func setupHTMLGlob(t *testing.T) func() {
	go func() {
		SetMode(DebugMode)
		router := New()
		router.Delims("{[{", "}]}")
		router.SetFuncMap(template.FuncMap{
			"formatAsDate": formatAsDate,
		})
		router.LoadHTMLGlob("./test/basic/*")
		router.GET("/test", func(c *Context) {
			c.HTML(http.StatusOK, "hello.tmpl", map[string]string{"name": "world"})
		})
		router.GET("/raw", func(c *Context) {
			c.HTML(http.StatusOK, "raw.tmpl", map[string]interface{}{
				"now": time.Date(2017, 07, 01, 0, 0, 0, 0, time.UTC),
			})
		})
		router.Run(":8888")
	}()
	t.Log("waiting 1 second for server startup")
	time.Sleep(1 * time.Second)
	return func() {}
}

func TestLoadHTMLGlob(t *testing.T) {
	td := setupHTMLGlob(t)
	res, err := http.Get("http://127.0.0.1:8888/test")
	if err != nil {
		fmt.Println(err)
	}

	resp, _ := ioutil.ReadAll(res.Body)
	assert.Equal(t, "
Hello world
", string(resp[:]))

	td()
}

func TestLoadHTMLGlobFromFuncMap(t *testing.T) {
	time.Now()
	td := setupHTMLGlob(t)
	res, err := http.Get("http://127.0.0.1:8888/raw")
	if err != nil {
		fmt.Println(err)
	}

	resp, _ := ioutil.ReadAll(res.Body)
	assert.Equal(t, "Date: 2017/07/01\n", string(resp[:]))

	td()
}

//TODO
// func (engine *Engine) LoadHTMLFiles(files ...string) {
// func (engine *Engine) RunTLS(addr, cert, key string) error {

func init() {
	SetMode(TestMode)
}
func TestCreateEngine(t *testing.T) {
	router := New()
	assert.Equal(t, "/", router.basePath)
	assert.Equal(t, router.engine, router)
	assert.Empty(t, router.Handlers)
}

// func TestLoadHTMLDebugMode(t *testing.T) {
// 	router := New()
// 	SetMode(DebugMode)
// 	router.LoadHTMLGlob("*.testtmpl")
// 	r := router.HTMLRender.(render.HTMLDebug)
// 	assert.Empty(t, r.Files)
// 	assert.Equal(t, r.Glob, "*.testtmpl")
//
// 	router.LoadHTMLFiles("index.html.testtmpl", "login.html.testtmpl")
// 	r = router.HTMLRender.(render.HTMLDebug)
// 	assert.Empty(t, r.Glob)
// 	assert.Equal(t, r.Files, []string{"index.html", "login.html"})
// 	SetMode(TestMode)
// }

func TestLoadHTMLFiles(t *testing.T) {
	td := setupHTMLFiles(t)
	res, err := http.Get("http://127.0.0.1:8888/test")
	if err != nil {
		fmt.Println(err)
	}

	resp, _ := ioutil.ReadAll(res.Body)
	assert.Equal(t, "
Hello world
", string(resp[:]))
	td()
}

func TestLoadHTMLFilesFuncMap(t *testing.T) {
	time.Now()
	td := setupHTMLFiles(t)
	res, err := http.Get("http://127.0.0.1:8888/raw")
	if err != nil {
		fmt.Println(err)
	}

	resp, _ := ioutil.ReadAll(res.Body)
	assert.Equal(t, "Date: 2017/07/01\n", string(resp[:]))

	td()
}

func TestLoadHTMLReleaseMode(t *testing.T) {

}

func TestAddRoute(t *testing.T) {
	router := New()
	router.addRoute("GET", "/", HandlersChain{func(_ *Context) {}})

	assert.Len(t, router.trees, 1)
	assert.NotNil(t, router.trees.get("GET"))
	assert.Nil(t, router.trees.get("POST"))

	router.addRoute("POST", "/", HandlersChain{func(_ *Context) {}})

	assert.Len(t, router.trees, 2)
	assert.NotNil(t, router.trees.get("GET"))
	assert.NotNil(t, router.trees.get("POST"))

	router.addRoute("POST", "/post", HandlersChain{func(_ *Context) {}})
	assert.Len(t, router.trees, 2)
}

func TestAddRouteFails(t *testing.T) {
	router := New()
	assert.Panics(t, func() { router.addRoute("", "/", HandlersChain{func(_ *Context) {}}) })
	assert.Panics(t, func() { router.addRoute("GET", "a", HandlersChain{func(_ *Context) {}}) })
	assert.Panics(t, func() { router.addRoute("GET", "/", HandlersChain{}) })

	router.addRoute("POST", "/post", HandlersChain{func(_ *Context) {}})
	assert.Panics(t, func() {
		router.addRoute("POST", "/post", HandlersChain{func(_ *Context) {}})
	})
}

func TestCreateDefaultRouter(t *testing.T) {
	router := Default()
	assert.Len(t, router.Handlers, 2)
}

func TestNoRouteWithoutGlobalHandlers(t *testing.T) {
	var middleware0 HandlerFunc = func(c *Context) {}
	var middleware1 HandlerFunc = func(c *Context) {}

	router := New()

	router.NoRoute(middleware0)
	assert.Nil(t, router.Handlers)
	assert.Len(t, router.noRoute, 1)
	assert.Len(t, router.allNoRoute, 1)
	compareFunc(t, router.noRoute[0], middleware0)
	compareFunc(t, router.allNoRoute[0], middleware0)

	router.NoRoute(middleware1, middleware0)
	assert.Len(t, router.noRoute, 2)
	assert.Len(t, router.allNoRoute, 2)
	compareFunc(t, router.noRoute[0], middleware1)
	compareFunc(t, router.allNoRoute[0], middleware1)
	compareFunc(t, router.noRoute[1], middleware0)
	compareFunc(t, router.allNoRoute[1], middleware0)
}

func TestNoRouteWithGlobalHandlers(t *testing.T) {
	var middleware0 HandlerFunc = func(c *Context) {}
	var middleware1 HandlerFunc = func(c *Context) {}
	var middleware2 HandlerFunc = func(c *Context) {}

	router := New()
	router.Use(middleware2)

	router.NoRoute(middleware0)
	assert.Len(t, router.allNoRoute, 2)
	assert.Len(t, router.Handlers, 1)
	assert.Len(t, router.noRoute, 1)

	compareFunc(t, router.Handlers[0], middleware2)
	compareFunc(t, router.noRoute[0], middleware0)
	compareFunc(t, router.allNoRoute[0], middleware2)
	compareFunc(t, router.allNoRoute[1], middleware0)

	router.Use(middleware1)
	assert.Len(t, router.allNoRoute, 3)
	assert.Len(t, router.Handlers, 2)
	assert.Len(t, router.noRoute, 1)

	compareFunc(t, router.Handlers[0], middleware2)
	compareFunc(t, router.Handlers[1], middleware1)
	compareFunc(t, router.noRoute[0], middleware0)
	compareFunc(t, router.allNoRoute[0], middleware2)
	compareFunc(t, router.allNoRoute[1], middleware1)
	compareFunc(t, router.allNoRoute[2], middleware0)
}

func TestNoMethodWithoutGlobalHandlers(t *testing.T) {
	var middleware0 HandlerFunc = func(c *Context) {}
	var middleware1 HandlerFunc = func(c *Context) {}

	router := New()

	router.NoMethod(middleware0)
	assert.Empty(t, router.Handlers)
	assert.Len(t, router.noMethod, 1)
	assert.Len(t, router.allNoMethod, 1)
	compareFunc(t, router.noMethod[0], middleware0)
	compareFunc(t, router.allNoMethod[0], middleware0)

	router.NoMethod(middleware1, middleware0)
	assert.Len(t, router.noMethod, 2)
	assert.Len(t, router.allNoMethod, 2)
	compareFunc(t, router.noMethod[0], middleware1)
	compareFunc(t, router.allNoMethod[0], middleware1)
	compareFunc(t, router.noMethod[1], middleware0)
	compareFunc(t, router.allNoMethod[1], middleware0)
}

func TestRebuild404Handlers(t *testing.T) {

}

func TestNoMethodWithGlobalHandlers(t *testing.T) {
	var middleware0 HandlerFunc = func(c *Context) {}
	var middleware1 HandlerFunc = func(c *Context) {}
	var middleware2 HandlerFunc = func(c *Context) {}

	router := New()
	router.Use(middleware2)

	router.NoMethod(middleware0)
	assert.Len(t, router.allNoMethod, 2)
	assert.Len(t, router.Handlers, 1)
	assert.Len(t, router.noMethod, 1)

	compareFunc(t, router.Handlers[0], middleware2)
	compareFunc(t, router.noMethod[0], middleware0)
	compareFunc(t, router.allNoMethod[0], middleware2)
	compareFunc(t, router.allNoMethod[1], middleware0)

	router.Use(middleware1)
	assert.Len(t, router.allNoMethod, 3)
	assert.Len(t, router.Handlers, 2)
	assert.Len(t, router.noMethod, 1)

	compareFunc(t, router.Handlers[0], middleware2)
	compareFunc(t, router.Handlers[1], middleware1)
	compareFunc(t, router.noMethod[0], middleware0)
	compareFunc(t, router.allNoMethod[0], middleware2)
	compareFunc(t, router.allNoMethod[1], middleware1)
	compareFunc(t, router.allNoMethod[2], middleware0)
}

func compareFunc(t *testing.T, a, b interface{}) {
	sf1 := reflect.ValueOf(a)
	sf2 := reflect.ValueOf(b)
	if sf1.Pointer() != sf2.Pointer() {
		t.Error("different functions")
	}
}

func TestListOfRoutes(t *testing.T) {
	router := New()
	router.GET("/favicon.ico", handlerTest1)
	router.GET("/", handlerTest1)
	group := router.Group("/users")
	{
		group.GET("/", handlerTest2)
		group.GET("/:id", handlerTest1)
		group.POST("/:id", handlerTest2)
	}
	router.Static("/static", ".")

	list := router.Routes()

	assert.Len(t, list, 7)
	assertRoutePresent(t, list, RouteInfo{
		Method:  "GET",
		Path:    "/favicon.ico",
		Handler: "^(.*/vendor/)?github.com/go-ego/ego.handlerTest1$",
	})
	assertRoutePresent(t, list, RouteInfo{
		Method:  "GET",
		Path:    "/",
		Handler: "^(.*/vendor/)?github.com/go-ego/ego.handlerTest1$",
	})
	assertRoutePresent(t, list, RouteInfo{
		Method:  "GET",
		Path:    "/users/",
		Handler: "^(.*/vendor/)?github.com/go-ego/ego.handlerTest2$",
	})
	assertRoutePresent(t, list, RouteInfo{
		Method:  "GET",
		Path:    "/users/:id",
		Handler: "^(.*/vendor/)?github.com/go-ego/ego.handlerTest1$",
	})
	assertRoutePresent(t, list, RouteInfo{
		Method:  "POST",
		Path:    "/users/:id",
		Handler: "^(.*/vendor/)?github.com/go-ego/ego.handlerTest2$",
	})
}

func assertRoutePresent(t *testing.T, gotRoutes RoutesInfo, wantRoute RouteInfo) {
	for _, gotRoute := range gotRoutes {
		if gotRoute.Path == wantRoute.Path && gotRoute.Method == wantRoute.Method {
			assert.Regexp(t, wantRoute.Handler, gotRoute.Handler)
			return
		}
	}
	t.Errorf("route not found: %v", wantRoute)
}

func handlerTest1(c *Context) {}
func handlerTest2(c *Context) {}
<|endoftext|>