<commit_before>/*
Copyright 2014 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 skipper

import (
	"bufio"
	"bytes"
	"context"
	"fmt"
	"regexp"
	"runtime"
	"runtime/debug"
	"strings"

	"github.com/onsi/ginkgo"

	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime/schema"
	utilversion "k8s.io/apimachinery/pkg/util/version"
	utilfeature "k8s.io/apiserver/pkg/util/feature"
	"k8s.io/client-go/discovery"
	"k8s.io/client-go/dynamic"
	clientset "k8s.io/client-go/kubernetes"
	"k8s.io/kubernetes/pkg/features"
	"k8s.io/kubernetes/test/e2e/framework"
	e2essh "k8s.io/kubernetes/test/e2e/framework/ssh"
)

// TestContext should be used by all tests to access common context data.
var TestContext framework.TestContextType

func skipInternalf(caller int, format string, args ...interface{}) {
	msg := fmt.Sprintf(format, args...)
	framework.Logf(msg)
	skip(msg, caller+1)
}

// SkipPanic is the value that will be panicked from Skip.
type SkipPanic struct {
	Message        string // The failure message passed to Fail
	Filename       string // The filename that is the source of the failure
	Line           int    // The line number of the filename that is the source of the failure
	FullStackTrace string // A full stack trace starting at the source of the failure
}

// String makes SkipPanic look like the old Ginkgo panic when printed.
func (SkipPanic) String() string { return ginkgo.GINKGO_PANIC }

// Skip wraps ginkgo.Skip so that it panics with more useful
// information about why the test is being skipped. This function will
// panic with a SkipPanic.
func skip(message string, callerSkip ...int) {
	skip := 1
	if len(callerSkip) > 0 {
		skip += callerSkip[0]
	}

	_, file, line, _ := runtime.Caller(skip)
	sp := SkipPanic{
		Message:        message,
		Filename:       file,
		Line:           line,
		FullStackTrace: pruneStack(skip),
	}

	defer func() {
		e := recover()
		if e != nil {
			panic(sp)
		}
	}()

	ginkgo.Skip(message, skip)
}

// ginkgo adds a lot of test running infrastructure to the stack, so
// we filter those out
var stackSkipPattern = regexp.MustCompile(`onsi/ginkgo`)

func pruneStack(skip int) string {
	skip += 2 // one for pruneStack and one for debug.Stack
	stack := debug.Stack()
	scanner := bufio.NewScanner(bytes.NewBuffer(stack))
	var prunedStack []string

	// skip the top of the stack
	for i := 0; i < 2*skip+1; i++ {
		scanner.Scan()
	}

	for scanner.Scan() {
		if stackSkipPattern.Match(scanner.Bytes()) {
			scanner.Scan() // these come in pairs
		} else {
			prunedStack = append(prunedStack, scanner.Text())
			scanner.Scan() // these come in pairs
			prunedStack = append(prunedStack, scanner.Text())
		}
	}

	return strings.Join(prunedStack, "\n")
}

// Skipf skips with information about why the test is being skipped.
func Skipf(format string, args ...interface{}) {
	skipInternalf(1, format, args...)
}

// SkipUnlessAtLeast skips if the value is less than the minValue.
func SkipUnlessAtLeast(value int, minValue int, message string) {
	if value < minValue {
		skipInternalf(1, message)
	}
}

// SkipUnlessLocalEphemeralStorageEnabled skips if the LocalStorageCapacityIsolation is not enabled.
func SkipUnlessLocalEphemeralStorageEnabled() {
	if !utilfeature.DefaultFeatureGate.Enabled(features.LocalStorageCapacityIsolation) {
		skipInternalf(1, "Only supported when %v feature is enabled", features.LocalStorageCapacityIsolation)
	}
}

// SkipIfMissingResource skips if the gvr resource is missing.
func SkipIfMissingResource(dynamicClient dynamic.Interface, gvr schema.GroupVersionResource, namespace string) {
	resourceClient := dynamicClient.Resource(gvr).Namespace(namespace)
	_, err := resourceClient.List(context.TODO(), metav1.ListOptions{})
	if err != nil {
		// not all resources support list, so we ignore those
		if apierrors.IsMethodNotSupported(err) || apierrors.IsNotFound(err) || apierrors.IsForbidden(err) {
			skipInternalf(1, "Could not find %s resource, skipping test: %#v", gvr, err)
		}
		framework.Failf("Unexpected error getting %v: %v", gvr, err)
	}
}

// SkipUnlessNodeCountIsAtLeast skips if the number of nodes is less than the minNodeCount.
func SkipUnlessNodeCountIsAtLeast(minNodeCount int) {
	if TestContext.CloudConfig.NumNodes < minNodeCount {
		skipInternalf(1, "Requires at least %d nodes (not %d)", minNodeCount, TestContext.CloudConfig.NumNodes)
	}
}

// SkipUnlessNodeCountIsAtMost skips if the number of nodes is greater than the maxNodeCount.
func SkipUnlessNodeCountIsAtMost(maxNodeCount int) {
	if TestContext.CloudConfig.NumNodes > maxNodeCount {
		skipInternalf(1, "Requires at most %d nodes (not %d)", maxNodeCount, TestContext.CloudConfig.NumNodes)
	}
}

// SkipIfProviderIs skips if the provider is included in the unsupportedProviders.
func SkipIfProviderIs(unsupportedProviders ...string) {
	if framework.ProviderIs(unsupportedProviders...) {
		skipInternalf(1, "Not supported for providers %v (found %s)", unsupportedProviders, TestContext.Provider)
	}
}

// SkipUnlessProviderIs skips if the provider is not included in the supportedProviders.
func SkipUnlessProviderIs(supportedProviders ...string) {
	if !framework.ProviderIs(supportedProviders...) {
		skipInternalf(1, "Only supported for providers %v (not %s)", supportedProviders, TestContext.Provider)
	}
}

// SkipUnlessMultizone skips if the cluster does not have multizone.
func SkipUnlessMultizone(c clientset.Interface) {
	zones, err := framework.GetClusterZones(c)
	if err != nil {
		skipInternalf(1, "Error listing cluster zones")
	}
	if zones.Len() <= 1 {
		skipInternalf(1, "Requires more than one zone")
	}
}

// SkipIfMultizone skips if the cluster has multizone.
func SkipIfMultizone(c clientset.Interface) {
	zones, err := framework.GetClusterZones(c)
	if err != nil {
		skipInternalf(1, "Error listing cluster zones")
	}
	if zones.Len() > 1 {
		skipInternalf(1, "Requires at most one zone")
	}
}

// SkipUnlessMasterOSDistroIs skips if the master OS distro is not included in the supportedMasterOsDistros.
func SkipUnlessMasterOSDistroIs(supportedMasterOsDistros ...string) {
	if !framework.MasterOSDistroIs(supportedMasterOsDistros...) {
		skipInternalf(1, "Only supported for master OS distro %v (not %s)", supportedMasterOsDistros, TestContext.MasterOSDistro)
	}
}

// SkipUnlessNodeOSDistroIs skips if the node OS distro is not included in the supportedNodeOsDistros.
func SkipUnlessNodeOSDistroIs(supportedNodeOsDistros ...string) {
	if !framework.NodeOSDistroIs(supportedNodeOsDistros...) {
		skipInternalf(1, "Only supported for node OS distro %v (not %s)", supportedNodeOsDistros, TestContext.NodeOSDistro)
	}
}

// SkipIfNodeOSDistroIs skips if the node OS distro is included in the unsupportedNodeOsDistros.
func SkipIfNodeOSDistroIs(unsupportedNodeOsDistros ...string) {
	if framework.NodeOSDistroIs(unsupportedNodeOsDistros...) {
		skipInternalf(1, "Not supported for node OS distro %v (is %s)", unsupportedNodeOsDistros, TestContext.NodeOSDistro)
	}
}

// SkipUnlessServerVersionGTE skips if the server version is less than v.
func SkipUnlessServerVersionGTE(v *utilversion.Version, c discovery.ServerVersionInterface) {
	gte, err := serverVersionGTE(v, c)
	if err != nil {
		framework.Failf("Failed to get server version: %v", err)
	}
	if !gte {
		skipInternalf(1, "Not supported for server versions before %q", v)
	}
}

// SkipUnlessSSHKeyPresent skips if no SSH key is found.
func SkipUnlessSSHKeyPresent() {
	if _, err := e2essh.GetSigner(TestContext.Provider); err != nil {
		skipInternalf(1, "No SSH Key for provider %s: '%v'", TestContext.Provider, err)
	}
}

// serverVersionGTE returns true if v is greater than or equal to the server version.
func serverVersionGTE(v *utilversion.Version, c discovery.ServerVersionInterface) (bool, error) {
	serverVersion, err := c.ServerVersion()
	if err != nil {
		return false, fmt.Errorf("Unable to get server version: %v", err)
	}
	sv, err := utilversion.ParseSemantic(serverVersion.GitVersion)
	if err != nil {
		return false, fmt.Errorf("Unable to parse server version %q: %v", serverVersion.GitVersion, err)
	}
	return sv.AtLeast(v), nil
}

// AppArmorDistros are distros with AppArmor support
var AppArmorDistros = []string{"gci", "ubuntu"}

// SkipIfAppArmorNotSupported skips if the AppArmor is not supported by the node OS distro.
func SkipIfAppArmorNotSupported() {
	SkipUnlessNodeOSDistroIs(AppArmorDistros...)
}

// RunIfContainerRuntimeIs runs if the container runtime is included in the runtimes.
func RunIfContainerRuntimeIs(runtimes ...string) {
	for _, containerRuntime := range runtimes {
		if containerRuntime == TestContext.ContainerRuntime {
			return
		}
	}
	skipInternalf(1, "Skipped because container runtime %q is not in %s", TestContext.ContainerRuntime, runtimes)
}

// RunIfSystemSpecNameIs runs if the system spec name is included in the names.
func RunIfSystemSpecNameIs(names ...string) {
	for _, name := range names {
		if name == TestContext.SystemSpecName {
			return
		}
	}
	skipInternalf(1, "Skipped because system spec name %q is not in %v", TestContext.SystemSpecName, names)
}
<commit_msg>UPSTREAM: 90707: Fix references to TestContext in e2e skippers<commit_after>/*
Copyright 2014 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 skipper

import (
	"bufio"
	"bytes"
	"context"
	"fmt"
	"regexp"
	"runtime"
	"runtime/debug"
	"strings"

	"github.com/onsi/ginkgo"

	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime/schema"
	utilversion "k8s.io/apimachinery/pkg/util/version"
	utilfeature "k8s.io/apiserver/pkg/util/feature"
	"k8s.io/client-go/discovery"
	"k8s.io/client-go/dynamic"
	clientset "k8s.io/client-go/kubernetes"
	"k8s.io/kubernetes/pkg/features"
	"k8s.io/kubernetes/test/e2e/framework"
	e2essh "k8s.io/kubernetes/test/e2e/framework/ssh"
)

func skipInternalf(caller int, format string, args ...interface{}) {
	msg := fmt.Sprintf(format, args...)
	framework.Logf(msg)
	skip(msg, caller+1)
}

// SkipPanic is the value that will be panicked from Skip.
type SkipPanic struct {
	Message        string // The failure message passed to Fail
	Filename       string // The filename that is the source of the failure
	Line           int    // The line number of the filename that is the source of the failure
	FullStackTrace string // A full stack trace starting at the source of the failure
}

// String makes SkipPanic look like the old Ginkgo panic when printed.
func (SkipPanic) String() string { return ginkgo.GINKGO_PANIC }

// Skip wraps ginkgo.Skip so that it panics with more useful
// information about why the test is being skipped. This function will
// panic with a SkipPanic.
func skip(message string, callerSkip ...int) {
	skip := 1
	if len(callerSkip) > 0 {
		skip += callerSkip[0]
	}

	_, file, line, _ := runtime.Caller(skip)
	sp := SkipPanic{
		Message:        message,
		Filename:       file,
		Line:           line,
		FullStackTrace: pruneStack(skip),
	}

	defer func() {
		e := recover()
		if e != nil {
			panic(sp)
		}
	}()

	ginkgo.Skip(message, skip)
}

// ginkgo adds a lot of test running infrastructure to the stack, so
// we filter those out
var stackSkipPattern = regexp.MustCompile(`onsi/ginkgo`)

func pruneStack(skip int) string {
	skip += 2 // one for pruneStack and one for debug.Stack
	stack := debug.Stack()
	scanner := bufio.NewScanner(bytes.NewBuffer(stack))
	var prunedStack []string

	// skip the top of the stack
	for i := 0; i < 2*skip+1; i++ {
		scanner.Scan()
	}

	for scanner.Scan() {
		if stackSkipPattern.Match(scanner.Bytes()) {
			scanner.Scan() // these come in pairs
		} else {
			prunedStack = append(prunedStack, scanner.Text())
			scanner.Scan() // these come in pairs
			prunedStack = append(prunedStack, scanner.Text())
		}
	}

	return strings.Join(prunedStack, "\n")
}

// Skipf skips with information about why the test is being skipped.
func Skipf(format string, args ...interface{}) {
	skipInternalf(1, format, args...)
}

// SkipUnlessAtLeast skips if the value is less than the minValue.
func SkipUnlessAtLeast(value int, minValue int, message string) {
	if value < minValue {
		skipInternalf(1, message)
	}
}

// SkipUnlessLocalEphemeralStorageEnabled skips if the LocalStorageCapacityIsolation is not enabled.
func SkipUnlessLocalEphemeralStorageEnabled() {
	if !utilfeature.DefaultFeatureGate.Enabled(features.LocalStorageCapacityIsolation) {
		skipInternalf(1, "Only supported when %v feature is enabled", features.LocalStorageCapacityIsolation)
	}
}

// SkipIfMissingResource skips if the gvr resource is missing.
func SkipIfMissingResource(dynamicClient dynamic.Interface, gvr schema.GroupVersionResource, namespace string) {
	resourceClient := dynamicClient.Resource(gvr).Namespace(namespace)
	_, err := resourceClient.List(context.TODO(), metav1.ListOptions{})
	if err != nil {
		// not all resources support list, so we ignore those
		if apierrors.IsMethodNotSupported(err) || apierrors.IsNotFound(err) || apierrors.IsForbidden(err) {
			skipInternalf(1, "Could not find %s resource, skipping test: %#v", gvr, err)
		}
		framework.Failf("Unexpected error getting %v: %v", gvr, err)
	}
}

// SkipUnlessNodeCountIsAtLeast skips if the number of nodes is less than the minNodeCount.
func SkipUnlessNodeCountIsAtLeast(minNodeCount int) {
	if framework.TestContext.CloudConfig.NumNodes < minNodeCount {
		skipInternalf(1, "Requires at least %d nodes (not %d)", minNodeCount, framework.TestContext.CloudConfig.NumNodes)
	}
}

// SkipUnlessNodeCountIsAtMost skips if the number of nodes is greater than the maxNodeCount.
func SkipUnlessNodeCountIsAtMost(maxNodeCount int) {
	if framework.TestContext.CloudConfig.NumNodes > maxNodeCount {
		skipInternalf(1, "Requires at most %d nodes (not %d)", maxNodeCount, framework.TestContext.CloudConfig.NumNodes)
	}
}

// SkipIfProviderIs skips if the provider is included in the unsupportedProviders.
func SkipIfProviderIs(unsupportedProviders ...string) {
	if framework.ProviderIs(unsupportedProviders...) {
		skipInternalf(1, "Not supported for providers %v (found %s)", unsupportedProviders, framework.TestContext.Provider)
	}
}

// SkipUnlessProviderIs skips if the provider is not included in the supportedProviders.
func SkipUnlessProviderIs(supportedProviders ...string) {
	if !framework.ProviderIs(supportedProviders...) {
		skipInternalf(1, "Only supported for providers %v (not %s)", supportedProviders, framework.TestContext.Provider)
	}
}

// SkipUnlessMultizone skips if the cluster does not have multizone.
func SkipUnlessMultizone(c clientset.Interface) {
	zones, err := framework.GetClusterZones(c)
	if err != nil {
		skipInternalf(1, "Error listing cluster zones")
	}
	if zones.Len() <= 1 {
		skipInternalf(1, "Requires more than one zone")
	}
}

// SkipIfMultizone skips if the cluster has multizone.
func SkipIfMultizone(c clientset.Interface) {
	zones, err := framework.GetClusterZones(c)
	if err != nil {
		skipInternalf(1, "Error listing cluster zones")
	}
	if zones.Len() > 1 {
		skipInternalf(1, "Requires at most one zone")
	}
}

// SkipUnlessMasterOSDistroIs skips if the master OS distro is not included in the supportedMasterOsDistros.
func SkipUnlessMasterOSDistroIs(supportedMasterOsDistros ...string) {
	if !framework.MasterOSDistroIs(supportedMasterOsDistros...) {
		skipInternalf(1, "Only supported for master OS distro %v (not %s)", supportedMasterOsDistros, framework.TestContext.MasterOSDistro)
	}
}

// SkipUnlessNodeOSDistroIs skips if the node OS distro is not included in the supportedNodeOsDistros.
func SkipUnlessNodeOSDistroIs(supportedNodeOsDistros ...string) {
	if !framework.NodeOSDistroIs(supportedNodeOsDistros...) {
		skipInternalf(1, "Only supported for node OS distro %v (not %s)", supportedNodeOsDistros, framework.TestContext.NodeOSDistro)
	}
}

// SkipIfNodeOSDistroIs skips if the node OS distro is included in the unsupportedNodeOsDistros.
func SkipIfNodeOSDistroIs(unsupportedNodeOsDistros ...string) {
	if framework.NodeOSDistroIs(unsupportedNodeOsDistros...) {
		skipInternalf(1, "Not supported for node OS distro %v (is %s)", unsupportedNodeOsDistros, framework.TestContext.NodeOSDistro)
	}
}

// SkipUnlessServerVersionGTE skips if the server version is less than v.
func SkipUnlessServerVersionGTE(v *utilversion.Version, c discovery.ServerVersionInterface) {
	gte, err := serverVersionGTE(v, c)
	if err != nil {
		framework.Failf("Failed to get server version: %v", err)
	}
	if !gte {
		skipInternalf(1, "Not supported for server versions before %q", v)
	}
}

// SkipUnlessSSHKeyPresent skips if no SSH key is found.
func SkipUnlessSSHKeyPresent() {
	if _, err := e2essh.GetSigner(framework.TestContext.Provider); err != nil {
		skipInternalf(1, "No SSH Key for provider %s: '%v'", framework.TestContext.Provider, err)
	}
}

// serverVersionGTE returns true if v is greater than or equal to the server version.
func serverVersionGTE(v *utilversion.Version, c discovery.ServerVersionInterface) (bool, error) {
	serverVersion, err := c.ServerVersion()
	if err != nil {
		return false, fmt.Errorf("Unable to get server version: %v", err)
	}
	sv, err := utilversion.ParseSemantic(serverVersion.GitVersion)
	if err != nil {
		return false, fmt.Errorf("Unable to parse server version %q: %v", serverVersion.GitVersion, err)
	}
	return sv.AtLeast(v), nil
}

// AppArmorDistros are distros with AppArmor support
var AppArmorDistros = []string{"gci", "ubuntu"}

// SkipIfAppArmorNotSupported skips if the AppArmor is not supported by the node OS distro.
func SkipIfAppArmorNotSupported() {
	SkipUnlessNodeOSDistroIs(AppArmorDistros...)
}

// RunIfContainerRuntimeIs runs if the container runtime is included in the runtimes.
func RunIfContainerRuntimeIs(runtimes ...string) {
	for _, containerRuntime := range runtimes {
		if containerRuntime == framework.TestContext.ContainerRuntime {
			return
		}
	}
	skipInternalf(1, "Skipped because container runtime %q is not in %s", framework.TestContext.ContainerRuntime, runtimes)
}

// RunIfSystemSpecNameIs runs if the system spec name is included in the names.
func RunIfSystemSpecNameIs(names ...string) {
	for _, name := range names {
		if name == framework.TestContext.SystemSpecName {
			return
		}
	}
	skipInternalf(1, "Skipped because system spec name %q is not in %v", framework.TestContext.SystemSpecName, names)
}
<|endoftext|>


<commit_before>package qemu
<commit_msg>add network test but still have not running<commit_after>package qemu

import (
	"net"
	"testing"

	"code.cloudfoundry.org/bytefmt"
	"github.com/n0stack/n0core/module/iproute2"
	uuid "github.com/satori/go.uuid"
)

func TestAttachTap(t *testing.T) {
	b, err := iproute2.NewBridge("br-test")
	if err != nil {
		t.Fatalf("Failed to create bridge: err='%s'", err.Error())
	}
	defer b.Delete()

	i, err := iproute2.NewTap("tap-test")
	if err != nil {
		t.Fatalf("Failed to create tap: err='%s'", err.Error())
	}
	defer i.Delete()

	i.SetMaster(b)

	id, _ := uuid.FromString("5fd6c569-172f-4b25-84cd-b76cc336cfdd")
	q, err := OpenQemu(&id)
	if err != nil {
		t.Fatalf("Failed to open qemu: err='%s'", err.Error())
	}
	defer q.Kill()

	m, _ := bytefmt.ToBytes("512M")
	if err := q.StartProcess("test", "monitor.sock", 10000, 1, m); err != nil {
		t.Fatalf("Failed to start process: err='%s'", err.Error())
	}

	hw, _ := net.ParseMAC("52:54:01:23:45:67")
	if err := q.AttachTap("test", i.Name(), hw); err != nil {
		t.Errorf("Failed to attach tap: err='%s'", err.Error())
	}

	if err := q.Boot(); err != nil {
		t.Errorf("Failed to boot: err='%s'", err.Error())
	}

	s, err := q.Status()
	if err != nil {
		t.Errorf("Failed to get status: err='%s'", err.Error())
	}
	if s != StatusRunning {
		t.Errorf("Status is mismatch: want='%v', have='%v'", StatusRunning, s)
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2014 Couchbase, Inc.
// 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 indexer

import (
	"encoding/json"
	"fmt"
	"github.com/couchbase/indexing/secondary/common"
	"github.com/couchbase/indexing/secondary/logging"
	"github.com/couchbase/indexing/secondary/platform"
	"github.com/couchbase/indexing/secondary/stats"
	"net/http"
	"runtime"
	"sync"
	"time"
	"unsafe"
)

type BucketStats struct {
	bucket     string
	indexCount int

	mutationQueueSize stats.Int64Val
}

func (s *BucketStats) Init() {
	s.mutationQueueSize.Init()
}

type IndexStats struct {
	name, bucket string

	scanDuration     stats.Int64Val
	insertBytes      stats.Int64Val
	numDocsPending   stats.Int64Val
	scanWaitDuration stats.Int64Val
	numDocsIndexed   stats.Int64Val
	numRequests      stats.Int64Val
	numRowsReturned  stats.Int64Val
	diskSize         stats.Int64Val
	buildProgress    stats.Int64Val
	numDocsQueued    stats.Int64Val
	deleteBytes      stats.Int64Val
	dataSize         stats.Int64Val
	scanBytesRead    stats.Int64Val
	getBytes         stats.Int64Val
	itemsCount       stats.Int64Val
	numCommits       stats.Int64Val
	numSnapshots     stats.Int64Val
	numCompactions   stats.Int64Val
	flushQueueSize   stats.Int64Val

	avgTsInterval stats.Int64Val
	lastTsTime    stats.Int64Val
}

type IndexerStatsHolder struct {
	ptr unsafe.Pointer
}

func (h IndexerStatsHolder) Get() *IndexerStats {
	return (*IndexerStats)(platform.LoadPointer(&h.ptr))
}

func (h *IndexerStatsHolder) Set(s *IndexerStats) {
	platform.StorePointer(&h.ptr, unsafe.Pointer(s))
}

func (s *IndexStats) Init() {
	s.scanDuration.Init()
	s.insertBytes.Init()
	s.numDocsPending.Init()
	s.scanWaitDuration.Init()
	s.numDocsIndexed.Init()
	s.numRequests.Init()
	s.numRowsReturned.Init()
	s.diskSize.Init()
	s.buildProgress.Init()
	s.numDocsQueued.Init()
	s.deleteBytes.Init()
	s.dataSize.Init()
	s.scanBytesRead.Init()
	s.getBytes.Init()
	s.itemsCount.Init()
	s.avgTsInterval.Init()
	s.lastTsTime.Init()
	s.numCommits.Init()
	s.numSnapshots.Init()
	s.numCompactions.Init()
	s.flushQueueSize.Init()
}

type IndexerStats struct {
	indexes map[common.IndexInstId]*IndexStats
	buckets map[string]*BucketStats

	numConnections stats.Int64Val
	memoryQuota    stats.Int64Val
	memoryUsed     stats.Int64Val
	needsRestart   stats.BoolVal
}

func (s *IndexerStats) Init() {
	s.indexes = make(map[common.IndexInstId]*IndexStats)
	s.buckets = make(map[string]*BucketStats)
	s.numConnections.Init()
	s.memoryQuota.Init()
	s.memoryUsed.Init()
	s.needsRestart.Init()
}

func (s *IndexerStats) AddIndex(id common.IndexInstId, bucket string, name string) {
	idxStats := &IndexStats{name: name, bucket: bucket}
	idxStats.Init()
	s.indexes[id] = idxStats

	b, ok := s.buckets[bucket]
	if !ok {
		b = &BucketStats{bucket: bucket}
		b.Init()
		s.buckets[bucket] = b
	}

	b.indexCount++
}

func (s *IndexerStats) RemoveIndex(id common.IndexInstId) {
	idx := s.indexes[id]
	delete(s.indexes, id)
	b := s.buckets[idx.bucket]
	b.indexCount--
	if b.indexCount == 0 {
		delete(s.buckets, idx.bucket)
	}
}

func (is IndexerStats) MarshalJSON() ([]byte, error) {
	var prefix string

	statsMap := make(map[string]interface{})
	addStat := func(k string, v interface{}) {
		statsMap[fmt.Sprintf("%s%s", prefix, k)] = v
	}

	addStat("num_connections", is.numConnections.Value())
	addStat("memory_quota", is.memoryQuota.Value())
	addStat("memory_used", is.memoryUsed.Value())
	addStat("needs_restart", is.needsRestart.Value())

	for _, s := range is.indexes {
		prefix = fmt.Sprintf("%s:%s:", s.bucket, s.name)
		addStat("total_scan_duration", s.scanDuration.Value())
		addStat("insert_bytes", s.insertBytes.Value())
		addStat("num_docs_pending", s.numDocsPending.Value())
		addStat("scan_wait_duration", s.scanWaitDuration.Value())
		addStat("num_docs_indexed", s.numDocsIndexed.Value())
		addStat("num_requests", s.numRequests.Value())
		addStat("num_rows_returned", s.numRowsReturned.Value())
		addStat("disk_size", s.diskSize.Value())
		addStat("build_progress", s.buildProgress.Value())
		addStat("num_docs_queued", s.numDocsQueued.Value())
		addStat("delete_bytes", s.deleteBytes.Value())
		addStat("data_size", s.dataSize.Value())
		addStat("scan_bytes_read", s.scanBytesRead.Value())
		addStat("get_bytes", s.getBytes.Value())
		addStat("items_count", s.itemsCount.Value())
		addStat("avg_ts_interval", s.avgTsInterval.Value())
		addStat("num_commits", s.numCommits.Value())
		addStat("num_snapshots", s.numSnapshots.Value())
		addStat("num_compactions", s.numCompactions.Value())
		addStat("flush_queue_size", s.flushQueueSize.Value())
	}

	for _, s := range is.buckets {
		prefix = fmt.Sprintf("%s:", s.bucket)
		addStat("mutation_queue_size", s.mutationQueueSize.Value())
	}

	return json.Marshal(statsMap)
}

func (s IndexerStats) Clone() *IndexerStats {
	var clone IndexerStats
	clone = s
	clone.indexes = make(map[common.IndexInstId]*IndexStats)
	for k, v := range s.indexes {
		clone.indexes[k] = v
	}

	return &clone
}

func NewIndexerStats() *IndexerStats {
	s := &IndexerStats{}
	s.Init()
	return s
}

type statsManager struct {
	sync.Mutex
	conf                  common.Config
	stats                 IndexerStatsHolder
	supvCmdch             MsgChannel
	supvMsgch             MsgChannel
	lastStatTime          time.Time
	cacheUpdateInProgress bool
}

func NewStatsManager(supvCmdch MsgChannel,
	supvMsgch MsgChannel, config common.Config) (statsManager, Message) {
	s := statsManager{
		conf:         config,
		supvCmdch:    supvCmdch,
		supvMsgch:    supvMsgch,
		lastStatTime: time.Unix(0, 0),
	}

	http.HandleFunc("/stats", s.handleStatsReq)
	http.HandleFunc("/stats/mem", s.handleMemStatsReq)
	go s.run()
	return s, &MsgSuccess{}
}

func (s *statsManager) tryUpdateStats(sync bool) {
	waitCh := make(chan struct{})
	timeout := time.Millisecond * time.Duration(s.conf["stats_cache_timeout"].Uint64())

	s.Lock()
	cacheTime := s.lastStatTime
	shouldUpdate := !s.cacheUpdateInProgress

	if s.lastStatTime.Unix() == 0 {
		sync = true
	}

	// Refresh cache if cache ttl has expired
	if shouldUpdate && time.Now().Sub(cacheTime) > timeout || sync {
		s.cacheUpdateInProgress = true
		s.Unlock()

		go func() {
			stats_list := []MsgType{STORAGE_STATS, SCAN_STATS, INDEX_PROGRESS_STATS, INDEXER_STATS}
			for _, t := range stats_list {
				ch := make(chan bool)
				msg := &MsgStatsRequest{
					mType:  t,
					respch: ch,
				}

				s.supvMsgch <- msg
				<-ch
			}

			s.Lock()
			s.lastStatTime = time.Now()
			s.cacheUpdateInProgress = false
			s.Unlock()
			close(waitCh)
		}()

		if sync {
			<-waitCh
		}
	} else {
		s.Unlock()
	}
}

func (s *statsManager) handleStatsReq(w http.ResponseWriter, r *http.Request) {
	sync := false
	if r.Method == "POST" || r.Method == "GET" {
		if r.URL.Query().Get("async") == "false" {
			sync = true
		}
		s.tryUpdateStats(sync)
		s.Lock()
		stats := s.stats.Get()
		bytes, _ := stats.MarshalJSON()
		s.Unlock()
		w.WriteHeader(200)
		w.Write(bytes)
	} else {
		w.WriteHeader(400)
		w.Write([]byte("Unsupported method"))
	}
}

func (s *statsManager) handleMemStatsReq(w http.ResponseWriter, r *http.Request) {
	stats := new(runtime.MemStats)
	if r.Method == "POST" || r.Method == "GET" {
		runtime.ReadMemStats(stats)
		bytes, _ := json.Marshal(stats)
		w.WriteHeader(200)
		w.Write(bytes)
	} else {
		w.WriteHeader(400)
		w.Write([]byte("Unsupported method"))
	}
}

func (s *statsManager) run() {
loop:
	for {
		select {
		case cmd, ok := <-s.supvCmdch:
			if ok {
				switch cmd.GetMsgType() {
				case STORAGE_MGR_SHUTDOWN:
					logging.Infof("SettingsManager::run Shutting Down")
					s.supvCmdch <- &MsgSuccess{}
					break loop
				case UPDATE_INDEX_INSTANCE_MAP:
					s.handleIndexInstanceUpdate(cmd)
				}
			} else {
				break loop
			}
		}
	}
}

func (s *statsManager) handleIndexInstanceUpdate(cmd Message) {
	req := cmd.(*MsgUpdateInstMap)
	s.stats.Set(req.GetStatsObject())
	s.supvCmdch <- &MsgSuccess{}
}
<commit_msg>MB-14373 indexer: Add scan latency stats<commit_after>// Copyright (c) 2014 Couchbase, Inc.
// 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 indexer

import (
	"encoding/json"
	"fmt"
	"github.com/couchbase/indexing/secondary/common"
	"github.com/couchbase/indexing/secondary/logging"
	"github.com/couchbase/indexing/secondary/platform"
	"github.com/couchbase/indexing/secondary/stats"
	"net/http"
	"runtime"
	"sync"
	"time"
	"unsafe"
)

type BucketStats struct {
	bucket     string
	indexCount int

	mutationQueueSize stats.Int64Val
}

func (s *BucketStats) Init() {
	s.mutationQueueSize.Init()
}

type IndexStats struct {
	name, bucket string

	scanDuration     stats.Int64Val
	insertBytes      stats.Int64Val
	numDocsPending   stats.Int64Val
	scanWaitDuration stats.Int64Val
	numDocsIndexed   stats.Int64Val
	numRequests      stats.Int64Val
	numRowsReturned  stats.Int64Val
	diskSize         stats.Int64Val
	buildProgress    stats.Int64Val
	numDocsQueued    stats.Int64Val
	deleteBytes      stats.Int64Val
	dataSize         stats.Int64Val
	scanBytesRead    stats.Int64Val
	getBytes         stats.Int64Val
	itemsCount       stats.Int64Val
	numCommits       stats.Int64Val
	numSnapshots     stats.Int64Val
	numCompactions   stats.Int64Val
	flushQueueSize   stats.Int64Val
	avgTsInterval    stats.Int64Val
	lastTsTime       stats.Int64Val
}

type IndexerStatsHolder struct {
	ptr unsafe.Pointer
}

func (h IndexerStatsHolder) Get() *IndexerStats {
	return (*IndexerStats)(platform.LoadPointer(&h.ptr))
}

func (h *IndexerStatsHolder) Set(s *IndexerStats) {
	platform.StorePointer(&h.ptr, unsafe.Pointer(s))
}

func (s *IndexStats) Init() {
	s.scanDuration.Init()
	s.insertBytes.Init()
	s.numDocsPending.Init()
	s.scanWaitDuration.Init()
	s.numDocsIndexed.Init()
	s.numRequests.Init()
	s.numRowsReturned.Init()
	s.diskSize.Init()
	s.buildProgress.Init()
	s.numDocsQueued.Init()
	s.deleteBytes.Init()
	s.dataSize.Init()
	s.scanBytesRead.Init()
	s.getBytes.Init()
	s.itemsCount.Init()
	s.avgTsInterval.Init()
	s.lastTsTime.Init()
	s.numCommits.Init()
	s.numSnapshots.Init()
	s.numCompactions.Init()
	s.flushQueueSize.Init()
}

type IndexerStats struct {
	indexes map[common.IndexInstId]*IndexStats
	buckets map[string]*BucketStats

	numConnections stats.Int64Val
	memoryQuota    stats.Int64Val
	memoryUsed     stats.Int64Val
	needsRestart   stats.BoolVal
}

func (s *IndexerStats) Init() {
	s.indexes = make(map[common.IndexInstId]*IndexStats)
	s.buckets = make(map[string]*BucketStats)
	s.numConnections.Init()
	s.memoryQuota.Init()
	s.memoryUsed.Init()
	s.needsRestart.Init()
}

func (s *IndexerStats) AddIndex(id common.IndexInstId, bucket string, name string) {
	idxStats := &IndexStats{name: name, bucket: bucket}
	idxStats.Init()
	s.indexes[id] = idxStats

	b, ok := s.buckets[bucket]
	if !ok {
		b = &BucketStats{bucket: bucket}
		b.Init()
		s.buckets[bucket] = b
	}

	b.indexCount++
}

func (s *IndexerStats) RemoveIndex(id common.IndexInstId) {
	idx := s.indexes[id]
	delete(s.indexes, id)
	b := s.buckets[idx.bucket]
	b.indexCount--
	if b.indexCount == 0 {
		delete(s.buckets, idx.bucket)
	}
}

func (is IndexerStats) MarshalJSON() ([]byte, error) {
	var prefix string

	statsMap := make(map[string]interface{})
	addStat := func(k string, v interface{}) {
		statsMap[fmt.Sprintf("%s%s", prefix, k)] = v
	}

	addStat("num_connections", is.numConnections.Value())
	addStat("memory_quota", is.memoryQuota.Value())
	addStat("memory_used", is.memoryUsed.Value())
	addStat("needs_restart", is.needsRestart.Value())

	for _, s := range is.indexes {
		prefix = fmt.Sprintf("%s:%s:", s.bucket, s.name)
		addStat("total_scan_duration", s.scanDuration.Value())
		addStat("insert_bytes", s.insertBytes.Value())
		addStat("num_docs_pending", s.numDocsPending.Value())
		addStat("scan_wait_duration", s.scanWaitDuration.Value())
		addStat("num_docs_indexed", s.numDocsIndexed.Value())
		addStat("num_requests", s.numRequests.Value())
		addStat("num_rows_returned", s.numRowsReturned.Value())
		addStat("disk_size", s.diskSize.Value())
		addStat("build_progress", s.buildProgress.Value())
		addStat("num_docs_queued", s.numDocsQueued.Value())
		addStat("delete_bytes", s.deleteBytes.Value())
		addStat("data_size", s.dataSize.Value())
		addStat("scan_bytes_read", s.scanBytesRead.Value())
		addStat("get_bytes", s.getBytes.Value())
		addStat("items_count", s.itemsCount.Value())
		addStat("avg_ts_interval", s.avgTsInterval.Value())
		addStat("num_commits", s.numCommits.Value())
		addStat("num_snapshots", s.numSnapshots.Value())
		addStat("num_compactions", s.numCompactions.Value())
		addStat("flush_queue_size", s.flushQueueSize.Value())
		addStat("avg_scan_latency", s.scanDuration.Value()/s.numRequests.Value())
		addStat("avg_scan_wait_latency", s.scanWaitDuration.Value()/s.numRequests.Value())
	}

	for _, s := range is.buckets {
		prefix = fmt.Sprintf("%s:", s.bucket)
		addStat("mutation_queue_size", s.mutationQueueSize.Value())
	}

	return json.Marshal(statsMap)
}

func (s IndexerStats) Clone() *IndexerStats {
	var clone IndexerStats
	clone = s
	clone.indexes = make(map[common.IndexInstId]*IndexStats)
	for k, v := range s.indexes {
		clone.indexes[k] = v
	}

	return &clone
}

func NewIndexerStats() *IndexerStats {
	s := &IndexerStats{}
	s.Init()
	return s
}

type statsManager struct {
	sync.Mutex
	conf                  common.Config
	stats                 IndexerStatsHolder
	supvCmdch             MsgChannel
	supvMsgch             MsgChannel
	lastStatTime          time.Time
	cacheUpdateInProgress bool
}

func NewStatsManager(supvCmdch MsgChannel,
	supvMsgch MsgChannel, config common.Config) (statsManager, Message) {
	s := statsManager{
		conf:         config,
		supvCmdch:    supvCmdch,
		supvMsgch:    supvMsgch,
		lastStatTime: time.Unix(0, 0),
	}

	http.HandleFunc("/stats", s.handleStatsReq)
	http.HandleFunc("/stats/mem", s.handleMemStatsReq)
	go s.run()
	return s, &MsgSuccess{}
}

func (s *statsManager) tryUpdateStats(sync bool) {
	waitCh := make(chan struct{})
	timeout := time.Millisecond * time.Duration(s.conf["stats_cache_timeout"].Uint64())

	s.Lock()
	cacheTime := s.lastStatTime
	shouldUpdate := !s.cacheUpdateInProgress

	if s.lastStatTime.Unix() == 0 {
		sync = true
	}

	// Refresh cache if cache ttl has expired
	if shouldUpdate && time.Now().Sub(cacheTime) > timeout || sync {
		s.cacheUpdateInProgress = true
		s.Unlock()

		go func() {
			stats_list := []MsgType{STORAGE_STATS, SCAN_STATS, INDEX_PROGRESS_STATS, INDEXER_STATS}
			for _, t := range stats_list {
				ch := make(chan bool)
				msg := &MsgStatsRequest{
					mType:  t,
					respch: ch,
				}

				s.supvMsgch <- msg
				<-ch
			}

			s.Lock()
			s.lastStatTime = time.Now()
			s.cacheUpdateInProgress = false
			s.Unlock()
			close(waitCh)
		}()

		if sync {
			<-waitCh
		}
	} else {
		s.Unlock()
	}
}

func (s *statsManager) handleStatsReq(w http.ResponseWriter, r *http.Request) {
	sync := false
	if r.Method == "POST" || r.Method == "GET" {
		if r.URL.Query().Get("async") == "false" {
			sync = true
		}
		s.tryUpdateStats(sync)
		s.Lock()
		stats := s.stats.Get()
		bytes, _ := stats.MarshalJSON()
		s.Unlock()
		w.WriteHeader(200)
		w.Write(bytes)
	} else {
		w.WriteHeader(400)
		w.Write([]byte("Unsupported method"))
	}
}

func (s *statsManager) handleMemStatsReq(w http.ResponseWriter, r *http.Request) {
	stats := new(runtime.MemStats)
	if r.Method == "POST" || r.Method == "GET" {
		runtime.ReadMemStats(stats)
		bytes, _ := json.Marshal(stats)
		w.WriteHeader(200)
		w.Write(bytes)
	} else {
		w.WriteHeader(400)
		w.Write([]byte("Unsupported method"))
	}
}

func (s *statsManager) run() {
loop:
	for {
		select {
		case cmd, ok := <-s.supvCmdch:
			if ok {
				switch cmd.GetMsgType() {
				case STORAGE_MGR_SHUTDOWN:
					logging.Infof("SettingsManager::run Shutting Down")
					s.supvCmdch <- &MsgSuccess{}
					break loop
				case UPDATE_INDEX_INSTANCE_MAP:
					s.handleIndexInstanceUpdate(cmd)
				}
			} else {
				break loop
			}
		}
	}
}

func (s *statsManager) handleIndexInstanceUpdate(cmd Message) {
	req := cmd.(*MsgUpdateInstMap)
	s.stats.Set(req.GetStatsObject())
	s.supvCmdch <- &MsgSuccess{}
}
<|endoftext|>


<commit_before>package views

import (
	"fmt"
	"path"

	log "github.com/Sirupsen/logrus"
	"github.com/go-martini/martini"
	"github.com/ikeikeikeike/godic/middlewares/html"
	"github.com/ikeikeikeike/godic/models/dict"
	"github.com/ikeikeikeike/godic/modules/git"
	"github.com/ikeikeikeike/godic/views/forms"
	"github.com/martini-contrib/binding"
	"github.com/martini-contrib/render"
)

type APIResponse struct {
	Ok  bool   `json:"ok"`
	Sha string `json:"sha"`
	Msg string `json:"msg"`
}

func UpdateDict(params martini.Params, commit forms.Commit, errs binding.Errors, r render.Render) {
	log.Debugln("UpdateDict action !!!!!")

	if len(errs) > 0 {
		msg := fmt.Sprintf("valid error (%d):\n%+v", len(errs), errs)
		r.JSON(400, APIResponse{Ok: false, Msg: msg})
		log.Warn(msg)
		return
	}

	m := dict.UpdateByCommit(commit)

	repo := git.NewRepo()
	repo.Init(path.Join(RepoPath, m.GetPrefix()))

	sha1, err := repo.SaveFile(m.Name, commit.Content, commit.Message)
	if err != nil {
		msg := fmt.Sprintf("Update file error: %s", err)
		r.JSON(400, APIResponse{Ok: false, Msg: msg})
		log.Warn(msg)
		return
	}

	r.JSON(200, APIResponse{Ok: true, Sha: sha1.String()})
}

func CreateDict(params martini.Params, commit forms.Commit, errs binding.Errors, r render.Render) {
	log.Debugln("CreateDict action !!!!!")

	if len(errs) > 0 {
		msg := fmt.Sprintf("valid error (%d):\n%+v", len(errs), errs)
		r.JSON(400, APIResponse{Ok: false, Msg: msg}) // TODO: Now this error message is used in javascript alert, next time must be change to japanese.
		log.Warn(msg)
		return
	}

	m, created, err := dict.FirstOrCreateByCommit(commit)
	if !created || err != nil {
		msg := fmt.Sprintf("%[1]sは既に存在します: > %[1]s", m.Name)
		r.JSON(400, APIResponse{Ok: false, Msg: msg})
		log.Warn(msg, err)
		return
	}

	repo := git.NewRepo()
	repo.Init(path.Join(RepoPath, m.GetPrefix()))

	// Create
	sha1, err := repo.SaveFile(m.Name, commit.Content, commit.Message)
	if err != nil {
		msg := fmt.Sprintf("Create file error: %s", err)
		r.JSON(400, APIResponse{Ok: false, Msg: msg})
		log.Warn(msg)
		return
	}

	r.JSON(200, APIResponse{Ok: true, Sha: sha1.String()})
}

func DeleteDict(params martini.Params, html html.HTMLContext, r render.Render) {
	log.Debugln("DeleteDict action !!!!!")

	if params["name"] == "" {
		r.JSON(404, APIResponse{Ok: false, Msg: "Invalid name"})
		return
	}

	html["Name"] = params["name"]
	html["Content"] = ""

	r.HTML(200, "dict/edit", html)
}
<commit_msg>rename<commit_after>package views

import (
	"fmt"
	"path"

	log "github.com/Sirupsen/logrus"
	"github.com/go-martini/martini"
	"github.com/ikeikeikeike/godic/middlewares/html"
	"github.com/ikeikeikeike/godic/models/dict"
	"github.com/ikeikeikeike/godic/modules/git"
	"github.com/ikeikeikeike/godic/views/forms"
	"github.com/martini-contrib/binding"
	"github.com/martini-contrib/render"
)

type APIResponse struct {
	Ok  bool   `json:"ok"`
	Sha string `json:"sha"`
	Msg string `json:"msg"`
}

func UpdateDicts(params martini.Params, commit forms.Commit, errs binding.Errors, r render.Render) {
	log.Debugln("UpdateDict action !!!!!")

	if len(errs) > 0 {
		msg := fmt.Sprintf("valid error (%d):\n%+v", len(errs), errs)
		r.JSON(400, APIResponse{Ok: false, Msg: msg})
		log.Warn(msg)
		return
	}

	m := dict.UpdateByCommit(commit)

	repo := git.NewRepo()
	repo.Init(path.Join(RepoPath, m.GetPrefix()))

	sha1, err := repo.SaveFile(m.Name, commit.Content, commit.Message)
	if err != nil {
		msg := fmt.Sprintf("Update file error: %s", err)
		r.JSON(400, APIResponse{Ok: false, Msg: msg})
		log.Warn(msg)
		return
	}

	r.JSON(200, APIResponse{Ok: true, Sha: sha1.String()})
}

func CreateDicts(params martini.Params, commit forms.Commit, errs binding.Errors, r render.Render) {
	log.Debugln("CreateDict action !!!!!")

	if len(errs) > 0 {
		msg := fmt.Sprintf("valid error (%d):\n%+v", len(errs), errs)
		r.JSON(400, APIResponse{Ok: false, Msg: msg}) // TODO: Now this error message is used in javascript alert, next time must be change to japanese.
		log.Warn(msg)
		return
	}

	m, created, err := dict.FirstOrCreateByCommit(commit)
	if !created || err != nil {
		msg := fmt.Sprintf("%[1]sは既に存在します: > %[1]s", m.Name)
		r.JSON(400, APIResponse{Ok: false, Msg: msg})
		log.Warn(msg, err)
		return
	}

	repo := git.NewRepo()
	repo.Init(path.Join(RepoPath, m.GetPrefix()))

	// Create
	sha1, err := repo.SaveFile(m.Name, commit.Content, commit.Message)
	if err != nil {
		msg := fmt.Sprintf("Create file error: %s", err)
		r.JSON(400, APIResponse{Ok: false, Msg: msg})
		log.Warn(msg)
		return
	}

	r.JSON(200, APIResponse{Ok: true, Sha: sha1.String()})
}

func DeleteDicts(params martini.Params, html html.HTMLContext, r render.Render) {
	log.Debugln("DeleteDict action !!!!!")

	if params["name"] == "" {
		r.JSON(404, APIResponse{Ok: false, Msg: "Invalid name"})
		return
	}

	html["Name"] = params["name"]
	html["Content"] = ""

	r.HTML(200, "dict/edit", html)
}
<|endoftext|>


<commit_before>// Copyright 2020 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

// +build !gogit

package git

import (
	"bufio"
	"io"
	"strconv"
	"strings"

	gitea_log "code.gitea.io/gitea/modules/log"
)

// Blob represents a Git object.
type Blob struct {
	ID SHA1

	gotSize  bool
	size     int64
	repoPath string
	name     string
}

// DataAsync gets a ReadCloser for the contents of a blob without reading it all.
// Calling the Close function on the result will discard all unread output.
func (b *Blob) DataAsync() (io.ReadCloser, error) {
	stdoutReader, stdoutWriter := io.Pipe()

	go func() {
		stderr := &strings.Builder{}
		err := NewCommand("cat-file", "--batch").RunInDirFullPipeline(b.repoPath, stdoutWriter, stderr, strings.NewReader(b.ID.String()+"\n"))
		if err != nil {
			err = ConcatenateError(err, stderr.String())
			gitea_log.Error("Blob.DataAsync Error: %v", err)
			_ = stdoutWriter.CloseWithError(err)
		} else {
			_ = stdoutWriter.Close()
		}
	}()

	bufReader := bufio.NewReader(stdoutReader)
	_, _, size, err := ReadBatchLine(bufReader)
	if err != nil {
		stdoutReader.Close()
		return nil, err
	}

	return &LimitedReaderCloser{
		R: bufReader,
		C: stdoutReader,
		N: size,
	}, nil
}

// Size returns the uncompressed size of the blob
func (b *Blob) Size() int64 {
	if b.gotSize {
		return b.size
	}

	size, err := NewCommand("cat-file", "-s", b.ID.String()).RunInDir(b.repoPath)
	if err != nil {
		log("error whilst reading size for %s in %s. Error: %v", b.ID.String(), b.repoPath, err)
		return 0
	}

	b.size, err = strconv.ParseInt(size[:len(size)-1], 10, 64)
	if err != nil {
		log("error whilst parsing size %s for %s in %s. Error: %v", size, b.ID.String(), b.repoPath, err)
		return 0
	}
	b.gotSize = true

	return b.size
}
<commit_msg>Remove spurious DataAsync Error logging (#14599)<commit_after>// Copyright 2020 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

// +build !gogit

package git

import (
	"bufio"
	"io"
	"strconv"
	"strings"
)

// Blob represents a Git object.
type Blob struct {
	ID SHA1

	gotSize  bool
	size     int64
	repoPath string
	name     string
}

// DataAsync gets a ReadCloser for the contents of a blob without reading it all.
// Calling the Close function on the result will discard all unread output.
func (b *Blob) DataAsync() (io.ReadCloser, error) {
	stdoutReader, stdoutWriter := io.Pipe()

	go func() {
		stderr := &strings.Builder{}
		err := NewCommand("cat-file", "--batch").RunInDirFullPipeline(b.repoPath, stdoutWriter, stderr, strings.NewReader(b.ID.String()+"\n"))
		if err != nil {
			err = ConcatenateError(err, stderr.String())
			_ = stdoutWriter.CloseWithError(err)
		} else {
			_ = stdoutWriter.Close()
		}
	}()

	bufReader := bufio.NewReader(stdoutReader)
	_, _, size, err := ReadBatchLine(bufReader)
	if err != nil {
		stdoutReader.Close()
		return nil, err
	}

	return &LimitedReaderCloser{
		R: bufReader,
		C: stdoutReader,
		N: size,
	}, nil
}

// Size returns the uncompressed size of the blob
func (b *Blob) Size() int64 {
	if b.gotSize {
		return b.size
	}

	size, err := NewCommand("cat-file", "-s", b.ID.String()).RunInDir(b.repoPath)
	if err != nil {
		log("error whilst reading size for %s in %s. Error: %v", b.ID.String(), b.repoPath, err)
		return 0
	}

	b.size, err = strconv.ParseInt(size[:len(size)-1], 10, 64)
	if err != nil {
		log("error whilst parsing size %s for %s in %s. Error: %v", size, b.ID.String(), b.repoPath, err)
		return 0
	}
	b.gotSize = true

	return b.size
}
<|endoftext|>


<commit_before>// Copyright 2020 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package repository

import (
	"fmt"
	"os"
	"path/filepath"

	"code.gitea.io/gitea/modules/git"
	"code.gitea.io/gitea/modules/setting"
	"code.gitea.io/gitea/modules/util"
)

func getHookTemplates() (hookNames, hookTpls, giteaHookTpls []string) {
	hookNames = []string{"pre-receive", "update", "post-receive"}
	hookTpls = []string{
		// for pre-receive
		fmt.Sprintf(`#!/usr/bin/env %s
# AUTO GENERATED BY GITEA, DO NOT MODIFY
data=$(cat)
exitcodes=""
hookname=$(basename $0)
GIT_DIR=${GIT_DIR:-$(dirname $0)/..}

for hook in ${GIT_DIR}/hooks/${hookname}.d/*; do
  test -x "${hook}" && test -f "${hook}" || continue
  echo "${data}" | "${hook}"
  exitcodes="${exitcodes} $?"
done

for i in ${exitcodes}; do
  [ ${i} -eq 0 ] || exit ${i}
done
`, setting.ScriptType),

		// for update
		fmt.Sprintf(`#!/usr/bin/env %s
# AUTO GENERATED BY GITEA, DO NOT MODIFY
exitcodes=""
hookname=$(basename $0)
GIT_DIR=${GIT_DIR:-$(dirname $0/..)}

for hook in ${GIT_DIR}/hooks/${hookname}.d/*; do
  test -x "${hook}" && test -f "${hook}" || continue
  "${hook}" $1 $2 $3
  exitcodes="${exitcodes} $?"
done

for i in ${exitcodes}; do
  [ ${i} -eq 0 ] || exit ${i}
done
`, setting.ScriptType),

		// for post-receive
		fmt.Sprintf(`#!/usr/bin/env %s
# AUTO GENERATED BY GITEA, DO NOT MODIFY
data=$(cat)
exitcodes=""
hookname=$(basename $0)
GIT_DIR=${GIT_DIR:-$(dirname $0)/..}

for hook in ${GIT_DIR}/hooks/${hookname}.d/*; do
  test -x "${hook}" && test -f "${hook}" || continue
  echo "${data}" | "${hook}"
  exitcodes="${exitcodes} $?"
done

for i in ${exitcodes}; do
  [ ${i} -eq 0 ] || exit ${i}
done
`, setting.ScriptType),
	}

	giteaHookTpls = []string{
		// for pre-receive
		fmt.Sprintf(`#!/usr/bin/env %s
# AUTO GENERATED BY GITEA, DO NOT MODIFY
%s hook --config=%s pre-receive
`, setting.ScriptType, util.ShellEscape(setting.AppPath), util.ShellEscape(setting.CustomConf)),

		// for update
		fmt.Sprintf(`#!/usr/bin/env %s
# AUTO GENERATED BY GITEA, DO NOT MODIFY
%s hook --config=%s update $1 $2 $3
`, setting.ScriptType, util.ShellEscape(setting.AppPath), util.ShellEscape(setting.CustomConf)),

		// for post-receive
		fmt.Sprintf(`#!/usr/bin/env %s
# AUTO GENERATED BY GITEA, DO NOT MODIFY
%s hook --config=%s post-receive
`, setting.ScriptType, util.ShellEscape(setting.AppPath), util.ShellEscape(setting.CustomConf)),
	}

	if git.SupportProcReceive {
		hookNames = append(hookNames, "proc-receive")
		hookTpls = append(hookTpls,
			fmt.Sprintf(`#!/usr/bin/env %s
# AUTO GENERATED BY GITEA, DO NOT MODIFY
%s hook --config=%s proc-receive
`, setting.ScriptType, util.ShellEscape(setting.AppPath), util.ShellEscape(setting.CustomConf)))
		giteaHookTpls = append(giteaHookTpls, "")
	}

	return hookNames, hookTpls, giteaHookTpls
}

// CreateDelegateHooks creates all the hooks scripts for the repo
func CreateDelegateHooks(repoPath string) error {
	return createDelegateHooks(repoPath)
}

// createDelegateHooks creates all the hooks scripts for the repo
func createDelegateHooks(repoPath string) (err error) {
	hookNames, hookTpls, giteaHookTpls := getHookTemplates()
	hookDir := filepath.Join(repoPath, "hooks")

	for i, hookName := range hookNames {
		oldHookPath := filepath.Join(hookDir, hookName)
		newHookPath := filepath.Join(hookDir, hookName+".d", "gitea")

		if err := os.MkdirAll(filepath.Join(hookDir, hookName+".d"), os.ModePerm); err != nil {
			return fmt.Errorf("create hooks dir '%s': %v", filepath.Join(hookDir, hookName+".d"), err)
		}

		// WARNING: This will override all old server-side hooks
		if err = util.Remove(oldHookPath); err != nil && !os.IsNotExist(err) {
			return fmt.Errorf("unable to pre-remove old hook file '%s' prior to rewriting: %v ", oldHookPath, err)
		}
		if err = os.WriteFile(oldHookPath, []byte(hookTpls[i]), 0o777); err != nil {
			return fmt.Errorf("write old hook file '%s': %v", oldHookPath, err)
		}

		if err = ensureExecutable(oldHookPath); err != nil {
			return fmt.Errorf("Unable to set %s executable. Error %v", oldHookPath, err)
		}

		if err = util.Remove(newHookPath); err != nil && !os.IsNotExist(err) {
			return fmt.Errorf("unable to pre-remove new hook file '%s' prior to rewriting: %v", newHookPath, err)
		}
		if err = os.WriteFile(newHookPath, []byte(giteaHookTpls[i]), 0o777); err != nil {
			return fmt.Errorf("write new hook file '%s': %v", newHookPath, err)
		}

		if err = ensureExecutable(newHookPath); err != nil {
			return fmt.Errorf("Unable to set %s executable. Error %v", oldHookPath, err)
		}
	}

	return nil
}

func checkExecutable(filename string) bool {
	fileInfo, err := os.Stat(filename)
	if err != nil {
		return false
	}
	return (fileInfo.Mode() & 0o100) > 0
}

func ensureExecutable(filename string) error {
	fileInfo, err := os.Stat(filename)
	if err != nil {
		return err
	}
	if (fileInfo.Mode() & 0o100) > 0 {
		return nil
	}
	mode := fileInfo.Mode() | 0o100
	return os.Chmod(filename, mode)
}

// CheckDelegateHooks checks the hooks scripts for the repo
func CheckDelegateHooks(repoPath string) ([]string, error) {
	hookNames, hookTpls, giteaHookTpls := getHookTemplates()

	hookDir := filepath.Join(repoPath, "hooks")
	results := make([]string, 0, 10)

	for i, hookName := range hookNames {
		oldHookPath := filepath.Join(hookDir, hookName)
		newHookPath := filepath.Join(hookDir, hookName+".d", "gitea")

		cont := false
		isExist, err := util.IsExist(oldHookPath)
		if err != nil {
			results = append(results, fmt.Sprintf("unable to check if %s exists. Error: %v", oldHookPath, err))
		}
		if err == nil && !isExist {
			results = append(results, fmt.Sprintf("old hook file %s does not exist", oldHookPath))
			cont = true
		}
		isExist, err = util.IsExist(oldHookPath + ".d")
		if err != nil {
			results = append(results, fmt.Sprintf("unable to check if %s exists. Error: %v", oldHookPath+".d", err))
		}
		if err == nil && !isExist {
			results = append(results, fmt.Sprintf("hooks directory %s does not exist", oldHookPath+".d"))
			cont = true
		}
		isExist, err = util.IsExist(newHookPath)
		if err != nil {
			results = append(results, fmt.Sprintf("unable to check if %s exists. Error: %v", newHookPath, err))
		}
		if err == nil && !isExist {
			results = append(results, fmt.Sprintf("new hook file %s does not exist", newHookPath))
			cont = true
		}
		if cont {
			continue
		}
		contents, err := os.ReadFile(oldHookPath)
		if err != nil {
			return results, err
		}
		if string(contents) != hookTpls[i] {
			results = append(results, fmt.Sprintf("old hook file %s is out of date", oldHookPath))
		}
		if !checkExecutable(oldHookPath) {
			results = append(results, fmt.Sprintf("old hook file %s is not executable", oldHookPath))
		}
		contents, err = os.ReadFile(newHookPath)
		if err != nil {
			return results, err
		}
		if string(contents) != giteaHookTpls[i] {
			results = append(results, fmt.Sprintf("new hook file %s is out of date", newHookPath))
		}
		if !checkExecutable(newHookPath) {
			results = append(results, fmt.Sprintf("new hook file %s is not executable", newHookPath))
		}
	}
	return results, nil
}
<commit_msg>Executable check always returns true for windows (#20637)<commit_after>// Copyright 2020 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package repository

import (
	"fmt"
	"os"
	"path/filepath"
	"runtime"

	"code.gitea.io/gitea/modules/git"
	"code.gitea.io/gitea/modules/setting"
	"code.gitea.io/gitea/modules/util"
)

func getHookTemplates() (hookNames, hookTpls, giteaHookTpls []string) {
	hookNames = []string{"pre-receive", "update", "post-receive"}
	hookTpls = []string{
		// for pre-receive
		fmt.Sprintf(`#!/usr/bin/env %s
# AUTO GENERATED BY GITEA, DO NOT MODIFY
data=$(cat)
exitcodes=""
hookname=$(basename $0)
GIT_DIR=${GIT_DIR:-$(dirname $0)/..}

for hook in ${GIT_DIR}/hooks/${hookname}.d/*; do
  test -x "${hook}" && test -f "${hook}" || continue
  echo "${data}" | "${hook}"
  exitcodes="${exitcodes} $?"
done

for i in ${exitcodes}; do
  [ ${i} -eq 0 ] || exit ${i}
done
`, setting.ScriptType),

		// for update
		fmt.Sprintf(`#!/usr/bin/env %s
# AUTO GENERATED BY GITEA, DO NOT MODIFY
exitcodes=""
hookname=$(basename $0)
GIT_DIR=${GIT_DIR:-$(dirname $0/..)}

for hook in ${GIT_DIR}/hooks/${hookname}.d/*; do
  test -x "${hook}" && test -f "${hook}" || continue
  "${hook}" $1 $2 $3
  exitcodes="${exitcodes} $?"
done

for i in ${exitcodes}; do
  [ ${i} -eq 0 ] || exit ${i}
done
`, setting.ScriptType),

		// for post-receive
		fmt.Sprintf(`#!/usr/bin/env %s
# AUTO GENERATED BY GITEA, DO NOT MODIFY
data=$(cat)
exitcodes=""
hookname=$(basename $0)
GIT_DIR=${GIT_DIR:-$(dirname $0)/..}

for hook in ${GIT_DIR}/hooks/${hookname}.d/*; do
  test -x "${hook}" && test -f "${hook}" || continue
  echo "${data}" | "${hook}"
  exitcodes="${exitcodes} $?"
done

for i in ${exitcodes}; do
  [ ${i} -eq 0 ] || exit ${i}
done
`, setting.ScriptType),
	}

	giteaHookTpls = []string{
		// for pre-receive
		fmt.Sprintf(`#!/usr/bin/env %s
# AUTO GENERATED BY GITEA, DO NOT MODIFY
%s hook --config=%s pre-receive
`, setting.ScriptType, util.ShellEscape(setting.AppPath), util.ShellEscape(setting.CustomConf)),

		// for update
		fmt.Sprintf(`#!/usr/bin/env %s
# AUTO GENERATED BY GITEA, DO NOT MODIFY
%s hook --config=%s update $1 $2 $3
`, setting.ScriptType, util.ShellEscape(setting.AppPath), util.ShellEscape(setting.CustomConf)),

		// for post-receive
		fmt.Sprintf(`#!/usr/bin/env %s
# AUTO GENERATED BY GITEA, DO NOT MODIFY
%s hook --config=%s post-receive
`, setting.ScriptType, util.ShellEscape(setting.AppPath), util.ShellEscape(setting.CustomConf)),
	}

	if git.SupportProcReceive {
		hookNames = append(hookNames, "proc-receive")
		hookTpls = append(hookTpls,
			fmt.Sprintf(`#!/usr/bin/env %s
# AUTO GENERATED BY GITEA, DO NOT MODIFY
%s hook --config=%s proc-receive
`, setting.ScriptType, util.ShellEscape(setting.AppPath), util.ShellEscape(setting.CustomConf)))
		giteaHookTpls = append(giteaHookTpls, "")
	}

	return hookNames, hookTpls, giteaHookTpls
}

// CreateDelegateHooks creates all the hooks scripts for the repo
func CreateDelegateHooks(repoPath string) error {
	return createDelegateHooks(repoPath)
}

// createDelegateHooks creates all the hooks scripts for the repo
func createDelegateHooks(repoPath string) (err error) {
	hookNames, hookTpls, giteaHookTpls := getHookTemplates()
	hookDir := filepath.Join(repoPath, "hooks")

	for i, hookName := range hookNames {
		oldHookPath := filepath.Join(hookDir, hookName)
		newHookPath := filepath.Join(hookDir, hookName+".d", "gitea")

		if err := os.MkdirAll(filepath.Join(hookDir, hookName+".d"), os.ModePerm); err != nil {
			return fmt.Errorf("create hooks dir '%s': %v", filepath.Join(hookDir, hookName+".d"), err)
		}

		// WARNING: This will override all old server-side hooks
		if err = util.Remove(oldHookPath); err != nil && !os.IsNotExist(err) {
			return fmt.Errorf("unable to pre-remove old hook file '%s' prior to rewriting: %v ", oldHookPath, err)
		}
		if err = os.WriteFile(oldHookPath, []byte(hookTpls[i]), 0o777); err != nil {
			return fmt.Errorf("write old hook file '%s': %v", oldHookPath, err)
		}

		if err = ensureExecutable(oldHookPath); err != nil {
			return fmt.Errorf("Unable to set %s executable. Error %v", oldHookPath, err)
		}

		if err = util.Remove(newHookPath); err != nil && !os.IsNotExist(err) {
			return fmt.Errorf("unable to pre-remove new hook file '%s' prior to rewriting: %v", newHookPath, err)
		}
		if err = os.WriteFile(newHookPath, []byte(giteaHookTpls[i]), 0o777); err != nil {
			return fmt.Errorf("write new hook file '%s': %v", newHookPath, err)
		}

		if err = ensureExecutable(newHookPath); err != nil {
			return fmt.Errorf("Unable to set %s executable. Error %v", oldHookPath, err)
		}
	}

	return nil
}

func checkExecutable(filename string) bool {
	// windows has no concept of a executable bit
	if runtime.GOOS == "windows" {
		return true
	}
	fileInfo, err := os.Stat(filename)
	if err != nil {
		return false
	}
	return (fileInfo.Mode() & 0o100) > 0
}

func ensureExecutable(filename string) error {
	fileInfo, err := os.Stat(filename)
	if err != nil {
		return err
	}
	if (fileInfo.Mode() & 0o100) > 0 {
		return nil
	}
	mode := fileInfo.Mode() | 0o100
	return os.Chmod(filename, mode)
}

// CheckDelegateHooks checks the hooks scripts for the repo
func CheckDelegateHooks(repoPath string) ([]string, error) {
	hookNames, hookTpls, giteaHookTpls := getHookTemplates()

	hookDir := filepath.Join(repoPath, "hooks")
	results := make([]string, 0, 10)

	for i, hookName := range hookNames {
		oldHookPath := filepath.Join(hookDir, hookName)
		newHookPath := filepath.Join(hookDir, hookName+".d", "gitea")

		cont := false
		isExist, err := util.IsExist(oldHookPath)
		if err != nil {
			results = append(results, fmt.Sprintf("unable to check if %s exists. Error: %v", oldHookPath, err))
		}
		if err == nil && !isExist {
			results = append(results, fmt.Sprintf("old hook file %s does not exist", oldHookPath))
			cont = true
		}
		isExist, err = util.IsExist(oldHookPath + ".d")
		if err != nil {
			results = append(results, fmt.Sprintf("unable to check if %s exists. Error: %v", oldHookPath+".d", err))
		}
		if err == nil && !isExist {
			results = append(results, fmt.Sprintf("hooks directory %s does not exist", oldHookPath+".d"))
			cont = true
		}
		isExist, err = util.IsExist(newHookPath)
		if err != nil {
			results = append(results, fmt.Sprintf("unable to check if %s exists. Error: %v", newHookPath, err))
		}
		if err == nil && !isExist {
			results = append(results, fmt.Sprintf("new hook file %s does not exist", newHookPath))
			cont = true
		}
		if cont {
			continue
		}
		contents, err := os.ReadFile(oldHookPath)
		if err != nil {
			return results, err
		}
		if string(contents) != hookTpls[i] {
			results = append(results, fmt.Sprintf("old hook file %s is out of date", oldHookPath))
		}
		if !checkExecutable(oldHookPath) {
			results = append(results, fmt.Sprintf("old hook file %s is not executable", oldHookPath))
		}
		contents, err = os.ReadFile(newHookPath)
		if err != nil {
			return results, err
		}
		if string(contents) != giteaHookTpls[i] {
			results = append(results, fmt.Sprintf("new hook file %s is out of date", newHookPath))
		}
		if !checkExecutable(newHookPath) {
			results = append(results, fmt.Sprintf("new hook file %s is not executable", newHookPath))
		}
	}
	return results, nil
}
<|endoftext|>


<commit_before>// Copyright 2016 tsuru-autoscale authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package web

import (
	"net/http"
	"net/http/httptest"

	"github.com/tsuru/tsuru-autoscale/alarm"
	"gopkg.in/check.v1"
)

func (s *S) TestAlarmEnable(c *check.C) {
	a := &alarm.Alarm{Name: "myalarm", Enabled: false}
	err := alarm.NewAlarm(a)
	c.Assert(err, check.IsNil)
	recorder := httptest.NewRecorder()
	request, err := http.NewRequest("GET", "/alarm/myalarm/enable", nil)
	c.Assert(err, check.IsNil)
	server(recorder, request)
	c.Assert(recorder.Code, check.Equals, http.StatusFound)
	a, err = alarm.FindAlarmByName("myalarm")
	c.Assert(err, check.IsNil)
	c.Assert(a.Enabled, check.Equals, true)
}

func (s *S) TestAlarmDisable(c *check.C) {
	a := &alarm.Alarm{Name: "myalarm", Enabled: true}
	err := alarm.NewAlarm(a)
	c.Assert(err, check.IsNil)
	recorder := httptest.NewRecorder()
	request, err := http.NewRequest("GET", "/alarm/myalarm/disable", nil)
	c.Assert(err, check.IsNil)
	server(recorder, request)
	c.Assert(recorder.Code, check.Equals, http.StatusFound)
	a, err = alarm.FindAlarmByName("myalarm")
	c.Assert(err, check.IsNil)
	c.Assert(a.Enabled, check.Equals, false)
}
<commit_msg>web: add test for alarm remove<commit_after>// Copyright 2016 tsuru-autoscale authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package web

import (
	"net/http"
	"net/http/httptest"

	"github.com/tsuru/tsuru-autoscale/alarm"
	"gopkg.in/check.v1"
)

func (s *S) TestAlarmEnable(c *check.C) {
	a := &alarm.Alarm{Name: "myalarm", Enabled: false}
	err := alarm.NewAlarm(a)
	c.Assert(err, check.IsNil)
	recorder := httptest.NewRecorder()
	request, err := http.NewRequest("GET", "/alarm/myalarm/enable", nil)
	c.Assert(err, check.IsNil)
	server(recorder, request)
	c.Assert(recorder.Code, check.Equals, http.StatusFound)
	a, err = alarm.FindAlarmByName("myalarm")
	c.Assert(err, check.IsNil)
	c.Assert(a.Enabled, check.Equals, true)
}

func (s *S) TestAlarmDisable(c *check.C) {
	a := &alarm.Alarm{Name: "myalarm", Enabled: true}
	err := alarm.NewAlarm(a)
	c.Assert(err, check.IsNil)
	recorder := httptest.NewRecorder()
	request, err := http.NewRequest("GET", "/alarm/myalarm/disable", nil)
	c.Assert(err, check.IsNil)
	server(recorder, request)
	c.Assert(recorder.Code, check.Equals, http.StatusFound)
	a, err = alarm.FindAlarmByName("myalarm")
	c.Assert(err, check.IsNil)
	c.Assert(a.Enabled, check.Equals, false)
}

func (s *S) TestAlarmRemove(c *check.C) {
	a := &alarm.Alarm{Name: "myalarm"}
	err := alarm.NewAlarm(a)
	c.Assert(err, check.IsNil)
	recorder := httptest.NewRecorder()
	request, err := http.NewRequest("GET", "/alarm/myalarm/delete", nil)
	c.Assert(err, check.IsNil)
	server(recorder, request)
	c.Assert(recorder.Code, check.Equals, http.StatusFound)
	_, err = alarm.FindAlarmByName("myalarm")
	c.Assert(err, check.NotNil)
}
<|endoftext|>


<commit_before>package NH

// #cgo CFLAGS: -m32 -Wall -O1
// #include <stdio.h>
// #include <stdlib.h>
// #include "./wmca_type.h"
// #include "./trio_inv.h"
// #include "./trio_ord.h"
import "C"

import (
	공용 "github.com/ghts/ghts/common"

	"reflect"
	//"time"
	"unsafe"
)

//export OnTrData_Go
func OnTrData_Go(c데이터 *C.OUTDATABLOCK) {
	defer C.free(unsafe.Pointer(c데이터))

	데이터 := (*OutDataBlock)(unsafe.Pointer(c데이터))

	TR구분번호 := 데이터.TrIndex
    공용.F문자열_출력("TR회신 데이터 수신. %v", TR구분번호)

    공용.F메모("TR구분번호를 TR코드로 변경하는 기능이 필요함.")

    switch TR구분번호 {
	case 1:	// TRID_c1101: 주식 현재가 조회. 임시로 1로 정함.
		블록_이름 := C.GoString((*C.char)(데이터.DataStruct.BlockName))

		switch 블록_이름 {
		case "c1101OutBlock":	// 단순출력 처리 방식
			블록 := (*Tc1101OutBlock)(unsafe.Pointer(데이터.DataStruct.DataString))
			공용.F문자열_출력(">>  주식현재가조회 - 현재가")
			공용.F문자열_출력(공용.F2문자열(블록.QuoteTime))
			공용.F문자열_출력(공용.F2문자열(블록.Code))
			공용.F문자열_출력(공용.F2문자열(블록.Title))
			공용.F문자열_출력(공용.F2문자열(블록.MarketPrice))
			공용.F문자열_출력(공용.F2문자열(블록.Volume))
		case "c1101OutBlock2":	// 반복가능한 출력 처리 방식
			// C배열을 Go슬라이스로 전환
			길이 := int(데이터.DataStruct.Length / int32(unsafe.Sizeof(Tc1101OutBlock2{})))
			슬라이스_헤더 := reflect.SliceHeader{
				Data: uintptr(unsafe.Pointer(데이터.DataStruct.DataString)),
				Len: 길이,
				Cap: 길이,
			}

			슬라이스 := *(*[]C.Tc1101OutBlock2)(unsafe.Pointer(&슬라이스_헤더))

			공용.F문자열_출력(">>  주식 현재가 조회 - 변동거래량")

			for i:=0 ; i < 길이 ; i++ {
				c개별_데이터 := 슬라이스[i]
				개별_데이터 := *((*Tc1101OutBlock2)(unsafe.Pointer(&c개별_데이터)))
				공용.F문자열_출력(공용.F2문자열(개별_데이터.Time))
				공용.F문자열_출력(공용.F2문자열(개별_데이터.MarketPrice))
				공용.F문자열_출력(공용.F2문자열(개별_데이터.Diff))
				공용.F문자열_출력(공용.F2문자열(개별_데이터.OfferPrice))
				공용.F문자열_출력(공용.F2문자열(개별_데이터.BidPrice))
				공용.F문자열_출력(공용.F2문자열(개별_데이터.DiffVolume))
				공용.F문자열_출력(공용.F2문자열(개별_데이터.Volume))
			}
		case "c1101OutBlock3":	// 동시 호가
			// TODO
		default:
			에러 := 공용.F에러_생성("예상치 못한 구조체 이름. %v", 블록_이름)
			panic(에러)
		}
	case 2:	// TRID_c1151: ETF 현재가 조회
		블록_이름 := C.GoString((*C.char)(데이터.DataStruct.BlockName))

		switch 블록_이름 {
		case "c1151OutBlock":
			// TODO
		case "c1151OutBlock2":
			// TODO
		case "c1151OutBlock3":
			// TODO
		case "c1151OutBlock4":
			// TODO
		case "c1151OutBlock5":
			// TODO
		default:
			에러 := 공용.F에러_생성("예상치 못한 구조체 이름. %v", 블록_이름)
			panic(에러)
		}
	}
}

//export OnRealTimeData_Go
func OnRealTimeData_Go(c데이터 *C.OUTDATABLOCK) {
    공용.F문자열_출력("Realtime Data Go.");
}

//export OnConnected_Go
func OnConnected_Go(c데이터 *C.LOGINBLOCK) {
	defer C.free(unsafe.Pointer(c데이터))

	데이터 := (*LoginBlock)(unsafe.Pointer(c데이터))

    // 로그인이 성공하면, 접속시각 및 계좌번호 정보를 받아 적절히 보관/출력합니다.
	// 계좌번호에 대한 순서(인덱스)는 계좌관련 서비스 호출시 사용되므로 중요합니다.

	// 예제코드 기능만 Go언어로 이식함.
	// 넘겨받은 구조체에 다른 정보가 많이 있으니 필요에 따라 사용할 것.
	// 모든 정보를 포함한 새로 만드는 것도 생각해 볼 것.

	TR구분번호 := 데이터.TrIndex
	공용.F문자열_출력("접속되었습니다. %v", TR구분번호);

	로그인_정보 := 데이터.LoginInfo

	// 시간 형식은 나중에 수정할 것.
	공용.F문자열_출력(공용.F2문자열(로그인_정보.Date))
	//접속시각, 에러 := time.Parse(공용.F2문자열(로그인_정보.Date), "2006-01-02T15:04:05.999999999Z07:00")
	//공용.F에러_패닉(에러)

	계좌_수량, 에러 := 공용.F2정수(공용.F2문자열(로그인_정보.AccountCount))
	공용.F에러_패닉(에러)

	계좌번호_모음 := make([]string, 계좌_수량)
	for i:=0 ; i < 계좌_수량 ; i++ {
		계좌_정보 := 로그인_정보.Accountlist[i]

		// 계좌번호 인덱스는 1부터 시작하는 데, 저장되는 슬라이스의 인덱스는 0부터 시작하니 주의.
		계좌번호_모음[i] = 공용.F2문자열(계좌_정보.AccountNo)
	}
}

//export OnMessage_Go
func OnMessage_Go(c데이터 *C.OUTDATABLOCK) {
	defer C.free(unsafe.Pointer(c데이터))

	데이터 := (*OutDataBlock)(unsafe.Pointer(c데이터))

	TR구분번호 := 데이터.TrIndex
	공용.F문자열_출력("메시지 수신. %v", TR구분번호);

	메시지_구조체 := (*MsgHeader)(unsafe.Pointer(데이터.DataStruct.DataString))
	메시지_코드 := 공용.F2문자열(메시지_구조체.MsgCode)
	메시지_내용 := 공용.F2문자열(메시지_구조체.UsrMsg)

	공용.F문자열_출력("%v : %v : %v", TR구분번호, 메시지_코드, 메시지_내용)
}

//export OnComplete_Go
func OnComplete_Go(c데이터 *C.OUTDATABLOCK) {
    공용.F문자열_출력("완료 메시지 수신.");

    defer C.free(unsafe.Pointer(c데이터))

    데이터 := (*OutDataBlock)(unsafe.Pointer(c데이터))

    TR구분번호 := 데이터.TrIndex

    // 그냥 예를 든 것임.
	switch TR구분번호 {
	case 1:	//TRID_c1101: 임시로 1로 정함.
		공용.F문자열_출력("주식 현재가 조회 완료");
	case 2:	//TRID_c8201: 임시로 2로 정함.
		공용.F문자열_출력("계좌 잔고 조회 완료");
	}
}

//export OnError_Go
func OnError_Go(c데이터 *C.OUTDATABLOCK) {
	defer C.free(unsafe.Pointer(c데이터))

    데이터 := (*OutDataBlock)(unsafe.Pointer(c데이터))

    TR구분번호 := 데이터.TrIndex
    공용.F문자열_출력("서비스 호출 실패. 에러 발생. %v", TR구분번호);

    //데이터_구조체 := (*Received)(데이터.DataStruct)
    //에러_내역 := C.GoString((*C.char)(데이터_구조체.DataString))
    에러_내역 := C.GoString((*C.char)(데이터.DataStruct.DataString))

    공용.F에러_출력(공용.F에러_생성(에러_내역))
}

//export OnSocketError_Go
func OnSocketError_Go(에러_코드 C.int) {
    공용.F문자열_출력("소켓 에러 발생. 에러 코드 : %v", int(에러_코드));
}

//export OnDisconnected_Go
func OnDisconnected_Go() {
    공용.F문자열_출력("접속이 끊겼습니다.");
}<commit_msg>int8 -> byte 변환으로 인한 컴파일 에러 수정<commit_after>package NH

// #cgo CFLAGS: -m32 -Wall -O1
// #include <stdio.h>
// #include <stdlib.h>
// #include "./wmca_type.h"
// #include "./trio_inv.h"
// #include "./trio_ord.h"
import "C"

import (
	공용 "github.com/ghts/ghts/common"

	"reflect"
	//"time"
	"unsafe"
)

//export OnTrData_Go
func OnTrData_Go(c데이터 *C.OUTDATABLOCK) {
	defer C.free(unsafe.Pointer(c데이터))

	데이터 := (*OutDataBlock)(unsafe.Pointer(c데이터))

	TR구분번호 := 데이터.TrIndex
    공용.F문자열_출력("TR회신 데이터 수신. %v", TR구분번호)

    공용.F메모("TR구분번호를 TR코드로 변경하는 기능이 필요함.")

    switch TR구분번호 {
	case 1:	// TRID_c1101: 주식 현재가 조회. 임시로 1로 정함.
		블록_이름 := 공용.F2문자열(데이터.DataStruct.BlockName)

		switch 블록_이름 {
		case "c1101OutBlock":	// 단순출력 처리 방식
			블록 := (*Tc1101OutBlock)(unsafe.Pointer(데이터.DataStruct.DataString))
			공용.F문자열_출력(">>  주식현재가조회 - 현재가")
			공용.F문자열_출력(공용.F2문자열(블록.QuoteTime))
			공용.F문자열_출력(공용.F2문자열(블록.Code))
			공용.F문자열_출력(공용.F2문자열(블록.Title))
			공용.F문자열_출력(공용.F2문자열(블록.MarketPrice))
			공용.F문자열_출력(공용.F2문자열(블록.Volume))
		case "c1101OutBlock2":	// 반복가능한 출력 처리 방식
			// C배열을 Go슬라이스로 전환
			길이 := int(데이터.DataStruct.Length / int32(unsafe.Sizeof(Tc1101OutBlock2{})))
			슬라이스_헤더 := reflect.SliceHeader{
				Data: uintptr(unsafe.Pointer(데이터.DataStruct.DataString)),
				Len: 길이,
				Cap: 길이,
			}

			슬라이스 := *(*[]C.Tc1101OutBlock2)(unsafe.Pointer(&슬라이스_헤더))

			공용.F문자열_출력(">>  주식 현재가 조회 - 변동거래량")

			for i:=0 ; i < 길이 ; i++ {
				c개별_데이터 := 슬라이스[i]
				개별_데이터 := *((*Tc1101OutBlock2)(unsafe.Pointer(&c개별_데이터)))
				공용.F문자열_출력(공용.F2문자열(개별_데이터.Time))
				공용.F문자열_출력(공용.F2문자열(개별_데이터.MarketPrice))
				공용.F문자열_출력(공용.F2문자열(개별_데이터.Diff))
				공용.F문자열_출력(공용.F2문자열(개별_데이터.OfferPrice))
				공용.F문자열_출력(공용.F2문자열(개별_데이터.BidPrice))
				공용.F문자열_출력(공용.F2문자열(개별_데이터.DiffVolume))
				공용.F문자열_출력(공용.F2문자열(개별_데이터.Volume))
			}
		case "c1101OutBlock3":	// 동시 호가
			// TODO
		default:
			에러 := 공용.F에러_생성("예상치 못한 구조체 이름. %v", 블록_이름)
			panic(에러)
		}
	case 2:	// TRID_c1151: ETF 현재가 조회
		블록_이름 := 공용.F2문자열(데이터.DataStruct.BlockName)

		switch 블록_이름 {
		case "c1151OutBlock":
			// TODO
		case "c1151OutBlock2":
			// TODO
		case "c1151OutBlock3":
			// TODO
		case "c1151OutBlock4":
			// TODO
		case "c1151OutBlock5":
			// TODO
		default:
			에러 := 공용.F에러_생성("예상치 못한 구조체 이름. %v", 블록_이름)
			panic(에러)
		}
	}
}

//export OnRealTimeData_Go
func OnRealTimeData_Go(c데이터 *C.OUTDATABLOCK) {
    공용.F문자열_출력("Realtime Data Go.");
}

//export OnConnected_Go
func OnConnected_Go(c데이터 *C.LOGINBLOCK) {
	defer C.free(unsafe.Pointer(c데이터))

	데이터 := (*LoginBlock)(unsafe.Pointer(c데이터))

    // 로그인이 성공하면, 접속시각 및 계좌번호 정보를 받아 적절히 보관/출력합니다.
	// 계좌번호에 대한 순서(인덱스)는 계좌관련 서비스 호출시 사용되므로 중요합니다.

	// 예제코드 기능만 Go언어로 이식함.
	// 넘겨받은 구조체에 다른 정보가 많이 있으니 필요에 따라 사용할 것.
	// 모든 정보를 포함한 새로 만드는 것도 생각해 볼 것.

	TR구분번호 := 데이터.TrIndex
	공용.F문자열_출력("접속되었습니다. %v", TR구분번호);

	로그인_정보 := 데이터.LoginInfo

	// 시간 형식은 나중에 수정할 것.
	공용.F문자열_출력(공용.F2문자열(로그인_정보.Date))
	//접속시각, 에러 := time.Parse(공용.F2문자열(로그인_정보.Date), "2006-01-02T15:04:05.999999999Z07:00")
	//공용.F에러_패닉(에러)

	계좌_수량, 에러 := 공용.F2정수(공용.F2문자열(로그인_정보.AccountCount))
	공용.F에러_패닉(에러)

	계좌번호_모음 := make([]string, 계좌_수량)
	for i:=0 ; i < 계좌_수량 ; i++ {
		계좌_정보 := 로그인_정보.Accountlist[i]

		// 계좌번호 인덱스는 1부터 시작하는 데, 저장되는 슬라이스의 인덱스는 0부터 시작하니 주의.
		계좌번호_모음[i] = 공용.F2문자열(계좌_정보.AccountNo)
	}
}

//export OnMessage_Go
func OnMessage_Go(c데이터 *C.OUTDATABLOCK) {
	defer C.free(unsafe.Pointer(c데이터))

	데이터 := (*OutDataBlock)(unsafe.Pointer(c데이터))

	TR구분번호 := 데이터.TrIndex
	공용.F문자열_출력("메시지 수신. %v", TR구분번호);

	메시지_구조체 := (*MsgHeader)(unsafe.Pointer(데이터.DataStruct.DataString))
	메시지_코드 := 공용.F2문자열(메시지_구조체.MsgCode)
	메시지_내용 := 공용.F2문자열(메시지_구조체.UsrMsg)

	공용.F문자열_출력("%v : %v : %v", TR구분번호, 메시지_코드, 메시지_내용)
}

//export OnComplete_Go
func OnComplete_Go(c데이터 *C.OUTDATABLOCK) {
    공용.F문자열_출력("완료 메시지 수신.");

    defer C.free(unsafe.Pointer(c데이터))

    데이터 := (*OutDataBlock)(unsafe.Pointer(c데이터))

    TR구분번호 := 데이터.TrIndex

    // 그냥 예를 든 것임.
	switch TR구분번호 {
	case 1:	//TRID_c1101: 임시로 1로 정함.
		공용.F문자열_출력("주식 현재가 조회 완료");
	case 2:	//TRID_c8201: 임시로 2로 정함.
		공용.F문자열_출력("계좌 잔고 조회 완료");
	}
}

//export OnError_Go
func OnError_Go(c데이터 *C.OUTDATABLOCK) {
	defer C.free(unsafe.Pointer(c데이터))

    데이터 := (*OutDataBlock)(unsafe.Pointer(c데이터))

    TR구분번호 := 데이터.TrIndex
    공용.F문자열_출력("서비스 호출 실패. 에러 발생. %v", TR구분번호);

    //데이터_구조체 := (*Received)(데이터.DataStruct)
    //에러_내역 := C.GoString((*C.char)(데이터_구조체.DataString))
    에러_내역 := 공용.F2문자열(데이터.DataStruct.DataString)

    공용.F에러_출력(공용.F에러_생성(에러_내역))
}

//export OnSocketError_Go
func OnSocketError_Go(에러_코드 C.int) {
    공용.F문자열_출력("소켓 에러 발생. 에러 코드 : %v", int(에러_코드));
}

//export OnDisconnected_Go
func OnDisconnected_Go() {
    공용.F문자열_출력("접속이 끊겼습니다.");
}<|endoftext|>


<commit_before>package bomberman_test

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"time"

	"code.cloudfoundry.org/garden"
	fakes "code.cloudfoundry.org/garden/gardenfakes"
	"code.cloudfoundry.org/garden/server/bomberman"
)

var _ = Describe("Bomberman", func() {
	It("straps a bomb to the given container with the container's grace time as the countdown", func() {
		detonated := make(chan garden.Container)

		backend := new(fakes.FakeBackend)
		backend.GraceTimeReturns(100 * time.Millisecond)

		bomberman := bomberman.New(backend, func(container garden.Container) {
			detonated <- container
		})

		container := new(fakes.FakeContainer)
		container.HandleReturns("doomed")

		bomberman.Strap(container)

		select {
		case <-detonated:
		case <-time.After(backend.GraceTime(container) * 2):
			Fail("did not detonate!")
		}
	})

	Context("when the container has a grace time of 0", func() {
		It("never detonates", func() {
			detonated := make(chan garden.Container)

			backend := new(fakes.FakeBackend)
			backend.GraceTimeReturns(0)

			bomberman := bomberman.New(backend, func(container garden.Container) {
				detonated <- container
			})

			container := new(fakes.FakeContainer)
			container.HandleReturns("doomed")

			bomberman.Strap(container)

			select {
			case <-detonated:
				Fail("detonated!")
			case <-time.After(backend.GraceTime(container) + 50*time.Millisecond):
			}
		})
	})

	Describe("pausing a container's timebomb", func() {
		It("prevents it from detonating", func() {
			detonated := make(chan garden.Container)

			backend := new(fakes.FakeBackend)
			backend.GraceTimeReturns(100 * time.Millisecond)

			bomberman := bomberman.New(backend, func(container garden.Container) {
				detonated <- container
			})

			container := new(fakes.FakeContainer)
			container.HandleReturns("doomed")

			bomberman.Strap(container)
			bomberman.Pause("doomed")

			select {
			case <-detonated:
				Fail("detonated!")
			case <-time.After(backend.GraceTime(container) + 50*time.Millisecond):
			}
		})

		Context("when the handle is invalid", func() {
			It("doesn't launch any missiles or anything like that", func() {
				bomberman := bomberman.New(new(fakes.FakeBackend), func(container garden.Container) {
					panic("dont call me")
				})

				bomberman.Pause("BOOM?!")
			})
		})

		Describe("and then unpausing it", func() {
			It("causes it to detonate after the countdown", func() {
				detonated := make(chan garden.Container)

				backend := new(fakes.FakeBackend)
				backend.GraceTimeReturns(100 * time.Millisecond)

				bomberman := bomberman.New(backend, func(container garden.Container) {
					detonated <- container
				})

				container := new(fakes.FakeContainer)
				container.HandleReturns("doomed")

				bomberman.Strap(container)
				bomberman.Pause("doomed")

				before := time.Now()
				bomberman.Unpause("doomed")

				select {
				case <-detonated:
					Ω(time.Since(before)).Should(BeNumerically(">=", 100*time.Millisecond))
				case <-time.After(backend.GraceTime(container) + 50*time.Millisecond):
					Fail("did not detonate!")
				}
			})

			Context("when the handle is invalid", func() {
				It("doesn't launch any missiles or anything like that", func() {
					bomberman := bomberman.New(new(fakes.FakeBackend), func(container garden.Container) {
						panic("dont call me")
					})

					bomberman.Unpause("BOOM?!")
				})
			})
		})
	})

	Describe("defusing a container's timebomb", func() {
		It("prevents it from detonating", func() {
			detonated := make(chan garden.Container)

			backend := new(fakes.FakeBackend)
			backend.GraceTimeReturns(100 * time.Millisecond)

			bomberman := bomberman.New(backend, func(container garden.Container) {
				detonated <- container
			})

			container := new(fakes.FakeContainer)
			container.HandleReturns("doomed")

			bomberman.Strap(container)
			bomberman.Defuse("doomed")

			select {
			case <-detonated:
				Fail("detonated!")
			case <-time.After(backend.GraceTime(container) + 50*time.Millisecond):
			}
		})

		Context("when the handle is invalid", func() {
			It("doesn't launch any missiles or anything like that", func() {
				bomberman := bomberman.New(new(fakes.FakeBackend), func(container garden.Container) {
					panic("dont call me")
				})

				bomberman.Defuse("BOOM?!")
			})
		})
	})
})
<commit_msg>Increases timeout on bomberman tests<commit_after>package bomberman_test

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"time"

	"code.cloudfoundry.org/garden"
	fakes "code.cloudfoundry.org/garden/gardenfakes"
	"code.cloudfoundry.org/garden/server/bomberman"
)

var _ = Describe("Bomberman", func() {
	It("straps a bomb to the given container with the container's grace time as the countdown", func() {
		detonated := make(chan garden.Container)

		backend := new(fakes.FakeBackend)
		backend.GraceTimeReturns(100 * time.Millisecond)

		bomberman := bomberman.New(backend, func(container garden.Container) {
			detonated <- container
		})

		container := new(fakes.FakeContainer)
		container.HandleReturns("doomed")

		bomberman.Strap(container)

		select {
		case <-detonated:
		case <-time.After(backend.GraceTime(container) * 2):
			Fail("did not detonate!")
		}
	})

	Context("when the container has a grace time of 0", func() {
		It("never detonates", func() {
			detonated := make(chan garden.Container)

			backend := new(fakes.FakeBackend)
			backend.GraceTimeReturns(0)

			bomberman := bomberman.New(backend, func(container garden.Container) {
				detonated <- container
			})

			container := new(fakes.FakeContainer)
			container.HandleReturns("doomed")

			bomberman.Strap(container)

			select {
			case <-detonated:
				Fail("detonated!")
			case <-time.After(backend.GraceTime(container) * 2):
			}
		})
	})

	Describe("pausing a container's timebomb", func() {
		It("prevents it from detonating", func() {
			detonated := make(chan garden.Container)

			backend := new(fakes.FakeBackend)
			backend.GraceTimeReturns(100 * time.Millisecond)

			bomberman := bomberman.New(backend, func(container garden.Container) {
				detonated <- container
			})

			container := new(fakes.FakeContainer)
			container.HandleReturns("doomed")

			bomberman.Strap(container)
			bomberman.Pause("doomed")

			select {
			case <-detonated:
				Fail("detonated!")
			case <-time.After(backend.GraceTime(container) * 2):
			}
		})

		Context("when the handle is invalid", func() {
			It("doesn't launch any missiles or anything like that", func() {
				bomberman := bomberman.New(new(fakes.FakeBackend), func(container garden.Container) {
					panic("dont call me")
				})

				bomberman.Pause("BOOM?!")
			})
		})

		Describe("and then unpausing it", func() {
			It("causes it to detonate after the countdown", func() {
				detonated := make(chan garden.Container)

				backend := new(fakes.FakeBackend)
				backend.GraceTimeReturns(100 * time.Millisecond)

				bomberman := bomberman.New(backend, func(container garden.Container) {
					detonated <- container
				})

				container := new(fakes.FakeContainer)
				container.HandleReturns("doomed")

				bomberman.Strap(container)
				bomberman.Pause("doomed")

				before := time.Now()
				bomberman.Unpause("doomed")

				select {
				case <-detonated:
					Expect(time.Since(before)).To(BeNumerically(">=", 100*time.Millisecond))
				case <-time.After(backend.GraceTime(container) * 2):
					Fail("did not detonate!")
				}
			})

			Context("when the handle is invalid", func() {
				It("doesn't launch any missiles or anything like that", func() {
					bomberman := bomberman.New(new(fakes.FakeBackend), func(container garden.Container) {
						panic("dont call me")
					})

					bomberman.Unpause("BOOM?!")
				})
			})
		})
	})

	Describe("defusing a container's timebomb", func() {
		It("prevents it from detonating", func() {
			detonated := make(chan garden.Container)

			backend := new(fakes.FakeBackend)
			backend.GraceTimeReturns(100 * time.Millisecond)

			bomberman := bomberman.New(backend, func(container garden.Container) {
				detonated <- container
			})

			container := new(fakes.FakeContainer)
			container.HandleReturns("doomed")

			bomberman.Strap(container)
			bomberman.Defuse("doomed")

			select {
			case <-detonated:
				Fail("detonated!")
			case <-time.After(backend.GraceTime(container) * 2):
			}
		})

		Context("when the handle is invalid", func() {
			It("doesn't launch any missiles or anything like that", func() {
				bomberman := bomberman.New(new(fakes.FakeBackend), func(container garden.Container) {
					panic("dont call me")
				})

				bomberman.Defuse("BOOM?!")
			})
		})
	})
})
<|endoftext|>


<commit_before>package consumergroup

import (
	"errors"
	"fmt"
	"strconv"

	"github.com/Shopify/sarama"
)

// Keeps track of the status of a consumergroup, i.e. how far the processing is behind
// on the events that are available in Kafka.
type Monitor struct {
	zookeeperConnection *ZK            // The zookeeper connection that gets the current offsets of the consumergroup.
	zookeeperPath       string         // The path in zookeeper on which to find the current offsets for a consumergroup
	kafkaConnection     *sarama.Client // The kafka connection that gets the available offsets.
}

type TopicProcessingLag map[int32]int64                       // The number of messages behind latest in Kafka for every partition in a topic
type ConsumerGroupProcessingLag map[string]TopicProcessingLag // The number of messages behind latest in Kafka for every topic the consumergroup is consuming.

// Instantiates a new consumergroup monitor. Retuns the number of messages the consumergroup is behind
// the latest offset in Kafka for every topic/partition the consumergroup is consuming.
func NewMonitor(name string, consumergroup string, zookeeper []string, config *ConsumerGroupConfig) (*Monitor, error) {
	if config == nil {
		config = NewConsumerGroupConfig()
	}

	zkConn, err := NewZK(zookeeper, config.ZookeeperTimeout)
	if err != nil {
		return nil, err
	}

	kafkaBrokers, err := zkConn.Brokers()
	if err != nil {
		return nil, err
	}

	saramaClient, err := sarama.NewClient(name, kafkaBrokers, config.KafkaClientConfig)
	if err != nil {
		return nil, err
	}

	return &Monitor{
		zookeeperConnection: zkConn,
		zookeeperPath:       fmt.Sprintf("/consumers/%s/offsets", consumergroup),
		kafkaConnection:     saramaClient,
	}, nil
}

// Returns the processing lag of the consumergroup.
func (m *Monitor) ProcessingLag() (ConsumerGroupProcessingLag, error) {
	eventsBehindLatest := make(ConsumerGroupProcessingLag)

	topics, err := m.getTopics()
	if err != nil {
		return nil, errors.New(fmt.Sprintf("Error getting topics: %s", err))
	}

	for _, topic := range topics {
		eventsBehindLatest[topic] = make(TopicProcessingLag)

		partitions, err := m.getPartitions(topic)
		if err != nil {
			return nil, errors.New(fmt.Sprintf("Error getting partitions for %s: %s", topic, err))
		}

		for _, partition := range partitions {
			currentOffset, _, err := m.zookeeperConnection.Get(fmt.Sprintf("%s/%s/%d", m.zookeeperPath, topic, partition))
			if err != nil {
				return nil, err
			}

			currentOffsetInt, err := strconv.ParseInt(string(currentOffset), 10, 64)
			if err != nil {
				return nil, err
			}

			latestOffsetInt, err := m.kafkaConnection.GetOffset(topic, partition, sarama.LatestOffsets)
			if err != nil {
				return nil, err
			}

			eventsBehindLatest[topic][partition] = latestOffsetInt - currentOffsetInt - 1
		}
	}
	return eventsBehindLatest, nil
}

func (m *Monitor) getTopics() ([]string, error) {
	topics, _, zkErr := m.zookeeperConnection.Children(m.zookeeperPath)
	if zkErr != nil {
		return nil, zkErr
	}

	return topics, nil
}

func (m *Monitor) getPartitions(topic string) ([]int32, error) {
	partitions, _, err := m.zookeeperConnection.Children(fmt.Sprintf("/%s", m.zookeeperPath, topic))
	if err != nil {
		return nil, err
	}

	if len(partitions) == 0 {
		return nil, errors.New("No committed partitions for consumer group on topic")
	}

	partitionsInt := make([]int32, 0, len(partitions))
	for _, partition := range partitions {
		partitionInt, err := strconv.ParseInt(string(partition), 10, 32)
		if err != nil {
			return nil, err
		}
		partitionsInt = append(partitionsInt, int32(partitionInt))
	}

	return partitionsInt, nil
}
<commit_msg>Small fix<commit_after>package consumergroup

import (
	"errors"
	"fmt"
	"strconv"

	"github.com/Shopify/sarama"
)

// Keeps track of the status of a consumergroup, i.e. how far the processing is behind
// on the events that are available in Kafka.
type Monitor struct {
	zookeeperConnection *ZK            // The zookeeper connection that gets the current offsets of the consumergroup.
	zookeeperPath       string         // The path in zookeeper on which to find the current offsets for a consumergroup
	kafkaConnection     *sarama.Client // The kafka connection that gets the available offsets.
}

type TopicProcessingLag map[int32]int64                       // The number of messages behind latest in Kafka for every partition in a topic
type ConsumerGroupProcessingLag map[string]TopicProcessingLag // The number of messages behind latest in Kafka for every topic the consumergroup is consuming.

// Instantiates a new consumergroup monitor. Retuns the number of messages the consumergroup is behind
// the latest offset in Kafka for every topic/partition the consumergroup is consuming.
func NewMonitor(name string, consumergroup string, zookeeper []string, config *ConsumerGroupConfig) (*Monitor, error) {
	if config == nil {
		config = NewConsumerGroupConfig()
	}

	zkConn, err := NewZK(zookeeper, config.ZookeeperTimeout)
	if err != nil {
		return nil, err
	}

	kafkaBrokers, err := zkConn.Brokers()
	if err != nil {
		return nil, err
	}

	saramaClient, err := sarama.NewClient(name, kafkaBrokers, config.KafkaClientConfig)
	if err != nil {
		return nil, err
	}

	return &Monitor{
		zookeeperConnection: zkConn,
		zookeeperPath:       fmt.Sprintf("/consumers/%s/offsets", consumergroup),
		kafkaConnection:     saramaClient,
	}, nil
}

// Returns the processing lag of the consumergroup.
func (m *Monitor) ProcessingLag() (ConsumerGroupProcessingLag, error) {
	eventsBehindLatest := make(ConsumerGroupProcessingLag)

	topics, err := m.getTopics()
	if err != nil {
		return nil, errors.New(fmt.Sprintf("Error getting topics: %s", err))
	}

	for _, topic := range topics {
		eventsBehindLatest[topic] = make(TopicProcessingLag)

		partitions, err := m.getPartitions(topic)
		if err != nil {
			return nil, errors.New(fmt.Sprintf("Error getting partitions for %s: %s", topic, err))
		}

		for _, partition := range partitions {
			currentOffset, _, err := m.zookeeperConnection.Get(fmt.Sprintf("%s/%s/%d", m.zookeeperPath, topic, partition))
			if err != nil {
				return nil, err
			}

			currentOffsetInt, err := strconv.ParseInt(string(currentOffset), 10, 64)
			if err != nil {
				return nil, err
			}

			latestOffsetInt, err := m.kafkaConnection.GetOffset(topic, partition, sarama.LatestOffsets)
			if err != nil {
				return nil, err
			}

			eventsBehindLatest[topic][partition] = latestOffsetInt - currentOffsetInt - 1
		}
	}
	return eventsBehindLatest, nil
}

func (m *Monitor) getTopics() ([]string, error) {
	topics, _, zkErr := m.zookeeperConnection.Children(m.zookeeperPath)
	if zkErr != nil {
		return nil, zkErr
	}

	return topics, nil
}

func (m *Monitor) getPartitions(topic string) ([]int32, error) {
	partitions, _, err := m.zookeeperConnection.Children(fmt.Sprintf("%s/%s", m.zookeeperPath, topic))
	if err != nil {
		return nil, err
	}

	if len(partitions) == 0 {
		return nil, errors.New("No committed partitions for consumer group on topic")
	}

	partitionsInt := make([]int32, 0, len(partitions))
	for _, partition := range partitions {
		partitionInt, err := strconv.ParseInt(string(partition), 10, 32)
		if err != nil {
			return nil, err
		}
		partitionsInt = append(partitionsInt, int32(partitionInt))
	}

	return partitionsInt, nil
}
<|endoftext|>