<commit_before>package provisioning

import (
	"bytes"
	"errors"
	log "github.com/Sirupsen/logrus"
	"os/exec"
	"syscall"
	"time"
)

type taskPID int64

// Local provisioning is responsible for providing the execution environment
// on local machine via exec.Command.
// It runs command as current user.
type Local struct {
}

// NewLocal returns a Local instance.
func NewLocal() Local {
	return Local{}
}

// Run runs the command given as input.
// Returned Task is able to stop & monitor the provisioned process.
func (l Local) Run(command string) (Task, error) {
	statusChannel := make(chan Status)

	log.Debug("Starting ", command)

	cmd := exec.Command("sh", "-c", command)

	// It is important to set additional Process Group ID for parent process and his children
	// to have ability to kill all the children processes.
	cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}

	// Setting Buffer as io.Writer for Command output.
	// TODO: Write to temporary files instead of keeping in memory.
	var stdout bytes.Buffer
	var stderr bytes.Buffer
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr

	err := cmd.Start()
	if err != nil {
		return nil, err
	}

	log.Debug("Started with pid ", cmd.Process.Pid)

	// Wait for local task in goroutine.
	go func() {
		// Wait for task completion.
		// NOTE: Wait() returns an error. We grab the process state in any case
		// (success or failure) below, so the error object matters less in the
		// status handling for now.
		cmd.Wait()

		log.Debug(
			"Ended ", command,
			" with output: ", stdout.String(),
			" with err output: ", stderr.String(),
			" with status code: ",
			(cmd.ProcessState.Sys().(syscall.WaitStatus)).ExitStatus())

		statusChannel <- Status{
			(cmd.ProcessState.Sys().(syscall.WaitStatus)).ExitStatus(),
			stdout.String(),
			stderr.String(),
		}
	}()

	taskPid := taskPID(cmd.Process.Pid)

	t := newlocalTask(taskPid, statusChannel)

	return t, err
}

// localTask implements Task interface.
type localTask struct {
	pid           taskPID
	statusChannel chan Status
	status        Status
	terminated    bool
}

// newlocalTask returns a localTask instance.
func newlocalTask(pid taskPID, statusChannel chan Status) *localTask {
	t := &localTask{
		pid,
		statusChannel,
		Status{},
		false,
	}
	return t
}

func (task *localTask) completeTask(status Status) {
	task.terminated = true
	task.status = status
	task.statusChannel = nil
}

// Stop terminates the local task.
func (task *localTask) Stop() error {
	if task.terminated {
		return errors.New("Task is not running.")
	}

	// We signal the entire process group.
	// The kill syscall interprets a negated PID N as the process group N belongs to.
	log.Debug("Sending SIGTERM to PID ", -task.pid)
	err := syscall.Kill(-int(task.pid), syscall.SIGTERM)
	if err != nil {
		return err
	}

	s := <-task.statusChannel
	task.completeTask(s)

	return err
}

// Status gets status of the local task.
func (task localTask) Status() Status {
	if !task.terminated {
		return Status{code: 0}
	}

	return task.status
}

// Wait blocks until process is terminated or timeout appeared.
// Returns true when process terminates before timeout, otherwise false.
func (task *localTask) Wait(timeoutMs int) bool {
	if task.terminated {
		return true
	}

	if timeoutMs == 0 {
		s := <-task.statusChannel
		task.completeTask(s)
		return true
	}

	timeoutDuration := time.Duration(timeoutMs) * time.Millisecond
	result := true

	select {
	case s := <-task.statusChannel:
		task.completeTask(s)
	case <-time.After(timeoutDuration):
		result = false
	}

	return result
}
<commit_msg>Added note about running exit code<commit_after>package provisioning

import (
	"bytes"
	"errors"
	log "github.com/Sirupsen/logrus"
	"os/exec"
	"syscall"
	"time"
)

type taskPID int64

// Local provisioning is responsible for providing the execution environment
// on local machine via exec.Command.
// It runs command as current user.
type Local struct {
}

// NewLocal returns a Local instance.
func NewLocal() Local {
	return Local{}
}

// Run runs the command given as input.
// Returned Task is able to stop & monitor the provisioned process.
func (l Local) Run(command string) (Task, error) {
	statusChannel := make(chan Status)

	log.Debug("Starting ", command)

	cmd := exec.Command("sh", "-c", command)

	// It is important to set additional Process Group ID for parent process and his children
	// to have ability to kill all the children processes.
	cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}

	// Setting Buffer as io.Writer for Command output.
	// TODO: Write to temporary files instead of keeping in memory.
	var stdout bytes.Buffer
	var stderr bytes.Buffer
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr

	err := cmd.Start()
	if err != nil {
		return nil, err
	}

	log.Debug("Started with pid ", cmd.Process.Pid)

	// Wait for local task in goroutine.
	go func() {
		// Wait for task completion.
		// NOTE: Wait() returns an error. We grab the process state in any case
		// (success or failure) below, so the error object matters less in the
		// status handling for now.
		cmd.Wait()

		log.Debug(
			"Ended ", command,
			" with output: ", stdout.String(),
			" with err output: ", stderr.String(),
			" with status code: ",
			(cmd.ProcessState.Sys().(syscall.WaitStatus)).ExitStatus())

		statusChannel <- Status{
			(cmd.ProcessState.Sys().(syscall.WaitStatus)).ExitStatus(),
			stdout.String(),
			stderr.String(),
		}
	}()

	taskPid := taskPID(cmd.Process.Pid)

	t := newlocalTask(taskPid, statusChannel)

	return t, err
}

// localTask implements Task interface.
type localTask struct {
	pid           taskPID
	statusChannel chan Status
	status        Status
	terminated    bool
}

// newlocalTask returns a localTask instance.
func newlocalTask(pid taskPID, statusChannel chan Status) *localTask {
	t := &localTask{
		pid,
		statusChannel,
		Status{},
		false,
	}
	return t
}

func (task *localTask) completeTask(status Status) {
	task.terminated = true
	task.status = status
	task.statusChannel = nil
}

// Stop terminates the local task.
func (task *localTask) Stop() error {
	if task.terminated {
		return errors.New("Task is not running.")
	}

	// We signal the entire process group.
	// The kill syscall interprets a negated PID N as the process group N belongs to.
	log.Debug("Sending SIGTERM to PID ", -task.pid)
	err := syscall.Kill(-int(task.pid), syscall.SIGTERM)
	if err != nil {
		return err
	}

	s := <-task.statusChannel
	task.completeTask(s)

	return err
}

// Status gets status of the local task.
func (task localTask) Status() Status {
	if !task.terminated {
		// TODO: Represent running as non-presence of an exit code or return
		// tuple with (running, *status)
		return Status{code: 0}
	}

	return task.status
}

// Wait blocks until process is terminated or timeout appeared.
// Returns true when process terminates before timeout, otherwise false.
func (task *localTask) Wait(timeoutMs int) bool {
	if task.terminated {
		return true
	}

	if timeoutMs == 0 {
		s := <-task.statusChannel
		task.completeTask(s)
		return true
	}

	timeoutDuration := time.Duration(timeoutMs) * time.Millisecond
	result := true

	select {
	case s := <-task.statusChannel:
		task.completeTask(s)
	case <-time.After(timeoutDuration):
		result = false
	}

	return result
}
<|endoftext|>


<commit_before>/*
Copyright 2018 the Heptio Ark contributors.

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 restic

import (
	"sort"
	"testing"

	"github.com/stretchr/testify/require"

	"github.com/stretchr/testify/assert"

	corev1api "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	corev1listers "k8s.io/client-go/listers/core/v1"
	"k8s.io/client-go/tools/cache"

	arkv1api "github.com/heptio/ark/pkg/apis/ark/v1"
	"github.com/heptio/ark/pkg/generated/clientset/versioned/fake"
	informers "github.com/heptio/ark/pkg/generated/informers/externalversions"
	arktest "github.com/heptio/ark/pkg/util/test"
)

func TestPodHasSnapshotAnnotation(t *testing.T) {
	tests := []struct {
		name        string
		annotations map[string]string
		expected    bool
	}{
		{
			name:        "nil annotations",
			annotations: nil,
			expected:    false,
		},
		{
			name:        "empty annotations",
			annotations: make(map[string]string),
			expected:    false,
		},
		{
			name:        "non-empty map, no snapshot annotation",
			annotations: map[string]string{"foo": "bar"},
			expected:    false,
		},
		{
			name:        "has snapshot annotation only, no suffix",
			annotations: map[string]string{podAnnotationPrefix: "bar"},
			expected:    true,
		},
		{
			name:        "has snapshot annotation only, with suffix",
			annotations: map[string]string{podAnnotationPrefix + "foo": "bar"},
			expected:    true,
		},
		{
			name:        "has snapshot annotation, with suffix",
			annotations: map[string]string{"foo": "bar", podAnnotationPrefix + "foo": "bar"},
			expected:    true,
		},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			pod := &corev1api.Pod{}
			pod.Annotations = test.annotations
			assert.Equal(t, test.expected, PodHasSnapshotAnnotation(pod))
		})
	}
}

func TestGetPodSnapshotAnnotations(t *testing.T) {
	tests := []struct {
		name        string
		annotations map[string]string
		expected    map[string]string
	}{
		{
			name:        "nil annotations",
			annotations: nil,
			expected:    nil,
		},
		{
			name:        "empty annotations",
			annotations: make(map[string]string),
			expected:    nil,
		},
		{
			name:        "non-empty map, no snapshot annotation",
			annotations: map[string]string{"foo": "bar"},
			expected:    nil,
		},
		{
			name:        "has snapshot annotation only, no suffix",
			annotations: map[string]string{podAnnotationPrefix: "bar"},
			expected:    map[string]string{"": "bar"},
		},
		{
			name:        "has snapshot annotation only, with suffix",
			annotations: map[string]string{podAnnotationPrefix + "foo": "bar"},
			expected:    map[string]string{"foo": "bar"},
		},
		{
			name:        "has snapshot annotation, with suffix",
			annotations: map[string]string{"x": "y", podAnnotationPrefix + "foo": "bar", podAnnotationPrefix + "abc": "123"},
			expected:    map[string]string{"foo": "bar", "abc": "123"},
		},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			pod := &corev1api.Pod{}
			pod.Annotations = test.annotations
			assert.Equal(t, test.expected, GetPodSnapshotAnnotations(pod))
		})
	}
}

func TestSetPodSnapshotAnnotation(t *testing.T) {
	tests := []struct {
		name        string
		annotations map[string]string
		volumeName  string
		snapshotID  string
		expected    map[string]string
	}{
		{
			name:        "set snapshot annotation on pod with no annotations",
			annotations: nil,
			volumeName:  "foo",
			snapshotID:  "bar",
			expected:    map[string]string{podAnnotationPrefix + "foo": "bar"},
		},
		{
			name:        "set snapshot annotation on pod with existing annotations",
			annotations: map[string]string{"existing": "annotation"},
			volumeName:  "foo",
			snapshotID:  "bar",
			expected:    map[string]string{"existing": "annotation", podAnnotationPrefix + "foo": "bar"},
		},
		{
			name:        "snapshot annotation is overwritten if already exists",
			annotations: map[string]string{podAnnotationPrefix + "foo": "existing"},
			volumeName:  "foo",
			snapshotID:  "bar",
			expected:    map[string]string{podAnnotationPrefix + "foo": "bar"},
		},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			pod := &corev1api.Pod{}
			pod.Annotations = test.annotations

			SetPodSnapshotAnnotation(pod, test.volumeName, test.snapshotID)
			assert.Equal(t, test.expected, pod.Annotations)
		})
	}
}

func TestGetVolumesToBackup(t *testing.T) {
	tests := []struct {
		name        string
		annotations map[string]string
		expected    []string
	}{
		{
			name:        "nil annotations",
			annotations: nil,
			expected:    nil,
		},
		{
			name:        "no volumes to backup",
			annotations: map[string]string{"foo": "bar"},
			expected:    nil,
		},
		{
			name:        "one volume to backup",
			annotations: map[string]string{"foo": "bar", volumesToBackupAnnotation: "volume-1"},
			expected:    []string{"volume-1"},
		},
		{
			name:        "multiple volumes to backup",
			annotations: map[string]string{"foo": "bar", volumesToBackupAnnotation: "volume-1,volume-2,volume-3"},
			expected:    []string{"volume-1", "volume-2", "volume-3"},
		},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			pod := &corev1api.Pod{}
			pod.Annotations = test.annotations

			res := GetVolumesToBackup(pod)

			// sort to ensure good compare of slices
			sort.Strings(test.expected)
			sort.Strings(res)

			assert.Equal(t, test.expected, res)
		})
	}
}

func TestGetSnapshotsInBackup(t *testing.T) {
	tests := []struct {
		name             string
		podVolumeBackups []arkv1api.PodVolumeBackup
		expected         []SnapshotIdentifier
	}{
		{
			name:             "no pod volume backups",
			podVolumeBackups: nil,
			expected:         nil,
		},
		{
			name: "no pod volume backups with matching label",
			podVolumeBackups: []arkv1api.PodVolumeBackup{
				{
					ObjectMeta: metav1.ObjectMeta{Name: "foo", Labels: map[string]string{arkv1api.BackupNameLabel: "non-matching-backup-1"}},
					Spec: arkv1api.PodVolumeBackupSpec{
						Pod: corev1api.ObjectReference{Name: "pod-1", Namespace: "ns-1"},
					},
					Status: arkv1api.PodVolumeBackupStatus{SnapshotID: "snap-1"},
				},
				{
					ObjectMeta: metav1.ObjectMeta{Name: "bar", Labels: map[string]string{arkv1api.BackupNameLabel: "non-matching-backup-2"}},
					Spec: arkv1api.PodVolumeBackupSpec{
						Pod: corev1api.ObjectReference{Name: "pod-2", Namespace: "ns-2"},
					},
					Status: arkv1api.PodVolumeBackupStatus{SnapshotID: "snap-2"},
				},
			},
			expected: nil,
		},
		{
			name: "some pod volume backups with matching label",
			podVolumeBackups: []arkv1api.PodVolumeBackup{
				{
					ObjectMeta: metav1.ObjectMeta{Name: "foo", Labels: map[string]string{arkv1api.BackupNameLabel: "non-matching-backup-1"}},
					Spec: arkv1api.PodVolumeBackupSpec{
						Pod: corev1api.ObjectReference{Name: "pod-1", Namespace: "ns-1"},
					},
					Status: arkv1api.PodVolumeBackupStatus{SnapshotID: "snap-1"},
				},
				{
					ObjectMeta: metav1.ObjectMeta{Name: "bar", Labels: map[string]string{arkv1api.BackupNameLabel: "non-matching-backup-2"}},
					Spec: arkv1api.PodVolumeBackupSpec{
						Pod: corev1api.ObjectReference{Name: "pod-2", Namespace: "ns-2"},
					},
					Status: arkv1api.PodVolumeBackupStatus{SnapshotID: "snap-2"},
				},
				{
					ObjectMeta: metav1.ObjectMeta{Name: "completed-pvb", Labels: map[string]string{arkv1api.BackupNameLabel: "backup-1"}},
					Spec: arkv1api.PodVolumeBackupSpec{
						Pod: corev1api.ObjectReference{Name: "pod-1", Namespace: "ns-1"},
					},
					Status: arkv1api.PodVolumeBackupStatus{SnapshotID: "snap-3"},
				},
				{
					ObjectMeta: metav1.ObjectMeta{Name: "completed-pvb-2", Labels: map[string]string{arkv1api.BackupNameLabel: "backup-1"}},
					Spec: arkv1api.PodVolumeBackupSpec{
						Pod: corev1api.ObjectReference{Name: "pod-1", Namespace: "ns-1"},
					},
					Status: arkv1api.PodVolumeBackupStatus{SnapshotID: "snap-4"},
				},
				{
					ObjectMeta: metav1.ObjectMeta{Name: "incomplete-or-failed-pvb", Labels: map[string]string{arkv1api.BackupNameLabel: "backup-1"}},
					Spec: arkv1api.PodVolumeBackupSpec{
						Pod: corev1api.ObjectReference{Name: "pod-1", Namespace: "ns-2"},
					},
					Status: arkv1api.PodVolumeBackupStatus{SnapshotID: ""},
				},
			},
			expected: []SnapshotIdentifier{
				{
					Repo:       "ns-1",
					SnapshotID: "snap-3",
				},
				{
					Repo:       "ns-1",
					SnapshotID: "snap-4",
				},
			},
		},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			var (
				client          = fake.NewSimpleClientset()
				sharedInformers = informers.NewSharedInformerFactory(client, 0)
				pvbInformer     = sharedInformers.Ark().V1().PodVolumeBackups()
				arkBackup       = &arkv1api.Backup{}
			)

			arkBackup.Name = "backup-1"

			for _, pvb := range test.podVolumeBackups {
				require.NoError(t, pvbInformer.Informer().GetStore().Add(pvb.DeepCopy()))
			}

			res, err := GetSnapshotsInBackup(arkBackup, pvbInformer.Lister())
			assert.NoError(t, err)

			// sort to ensure good compare of slices
			less := func(snapshots []SnapshotIdentifier) func(i, j int) bool {
				return func(i, j int) bool {
					return snapshots[i].Repo < snapshots[j].Repo &&
						snapshots[i].SnapshotID < snapshots[j].SnapshotID
				}

			}
			sort.Slice(test.expected, less(test.expected))
			sort.Slice(res, less(res))

			assert.Equal(t, test.expected, res)
		})
	}
}

func TestTempCredentialsFile(t *testing.T) {
	var (
		secretInformer = cache.NewSharedIndexInformer(nil, new(corev1api.Secret), 0, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc})
		secretLister   = corev1listers.NewSecretLister(secretInformer.GetIndexer())
		fs             = arktest.NewFakeFileSystem()
		secret         = &corev1api.Secret{
			ObjectMeta: metav1.ObjectMeta{
				Namespace: "heptio-ark",
				Name:      CredentialsSecretName,
			},
			Data: map[string][]byte{
				CredentialsKey: []byte("passw0rd"),
			},
		}
	)

	// secret not in lister: expect an error
	fileName, err := TempCredentialsFile(secretLister, "heptio-ark", "default", fs)
	assert.Error(t, err)

	// now add secret to lister
	require.NoError(t, secretInformer.GetStore().Add(secret))

	// secret in lister: expect temp file to be created with password
	fileName, err = TempCredentialsFile(secretLister, "heptio-ark", "default", fs)
	require.NoError(t, err)

	contents, err := fs.ReadFile(fileName)
	require.NoError(t, err)

	assert.Equal(t, "passw0rd", string(contents))
}
<commit_msg>Fix test sorting function<commit_after>/*
Copyright 2018 the Heptio Ark contributors.

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 restic

import (
	"sort"
	"testing"

	"github.com/stretchr/testify/require"

	"github.com/stretchr/testify/assert"

	corev1api "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	corev1listers "k8s.io/client-go/listers/core/v1"
	"k8s.io/client-go/tools/cache"

	arkv1api "github.com/heptio/ark/pkg/apis/ark/v1"
	"github.com/heptio/ark/pkg/generated/clientset/versioned/fake"
	informers "github.com/heptio/ark/pkg/generated/informers/externalversions"
	arktest "github.com/heptio/ark/pkg/util/test"
)

func TestPodHasSnapshotAnnotation(t *testing.T) {
	tests := []struct {
		name        string
		annotations map[string]string
		expected    bool
	}{
		{
			name:        "nil annotations",
			annotations: nil,
			expected:    false,
		},
		{
			name:        "empty annotations",
			annotations: make(map[string]string),
			expected:    false,
		},
		{
			name:        "non-empty map, no snapshot annotation",
			annotations: map[string]string{"foo": "bar"},
			expected:    false,
		},
		{
			name:        "has snapshot annotation only, no suffix",
			annotations: map[string]string{podAnnotationPrefix: "bar"},
			expected:    true,
		},
		{
			name:        "has snapshot annotation only, with suffix",
			annotations: map[string]string{podAnnotationPrefix + "foo": "bar"},
			expected:    true,
		},
		{
			name:        "has snapshot annotation, with suffix",
			annotations: map[string]string{"foo": "bar", podAnnotationPrefix + "foo": "bar"},
			expected:    true,
		},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			pod := &corev1api.Pod{}
			pod.Annotations = test.annotations
			assert.Equal(t, test.expected, PodHasSnapshotAnnotation(pod))
		})
	}
}

func TestGetPodSnapshotAnnotations(t *testing.T) {
	tests := []struct {
		name        string
		annotations map[string]string
		expected    map[string]string
	}{
		{
			name:        "nil annotations",
			annotations: nil,
			expected:    nil,
		},
		{
			name:        "empty annotations",
			annotations: make(map[string]string),
			expected:    nil,
		},
		{
			name:        "non-empty map, no snapshot annotation",
			annotations: map[string]string{"foo": "bar"},
			expected:    nil,
		},
		{
			name:        "has snapshot annotation only, no suffix",
			annotations: map[string]string{podAnnotationPrefix: "bar"},
			expected:    map[string]string{"": "bar"},
		},
		{
			name:        "has snapshot annotation only, with suffix",
			annotations: map[string]string{podAnnotationPrefix + "foo": "bar"},
			expected:    map[string]string{"foo": "bar"},
		},
		{
			name:        "has snapshot annotation, with suffix",
			annotations: map[string]string{"x": "y", podAnnotationPrefix + "foo": "bar", podAnnotationPrefix + "abc": "123"},
			expected:    map[string]string{"foo": "bar", "abc": "123"},
		},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			pod := &corev1api.Pod{}
			pod.Annotations = test.annotations
			assert.Equal(t, test.expected, GetPodSnapshotAnnotations(pod))
		})
	}
}

func TestSetPodSnapshotAnnotation(t *testing.T) {
	tests := []struct {
		name        string
		annotations map[string]string
		volumeName  string
		snapshotID  string
		expected    map[string]string
	}{
		{
			name:        "set snapshot annotation on pod with no annotations",
			annotations: nil,
			volumeName:  "foo",
			snapshotID:  "bar",
			expected:    map[string]string{podAnnotationPrefix + "foo": "bar"},
		},
		{
			name:        "set snapshot annotation on pod with existing annotations",
			annotations: map[string]string{"existing": "annotation"},
			volumeName:  "foo",
			snapshotID:  "bar",
			expected:    map[string]string{"existing": "annotation", podAnnotationPrefix + "foo": "bar"},
		},
		{
			name:        "snapshot annotation is overwritten if already exists",
			annotations: map[string]string{podAnnotationPrefix + "foo": "existing"},
			volumeName:  "foo",
			snapshotID:  "bar",
			expected:    map[string]string{podAnnotationPrefix + "foo": "bar"},
		},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			pod := &corev1api.Pod{}
			pod.Annotations = test.annotations

			SetPodSnapshotAnnotation(pod, test.volumeName, test.snapshotID)
			assert.Equal(t, test.expected, pod.Annotations)
		})
	}
}

func TestGetVolumesToBackup(t *testing.T) {
	tests := []struct {
		name        string
		annotations map[string]string
		expected    []string
	}{
		{
			name:        "nil annotations",
			annotations: nil,
			expected:    nil,
		},
		{
			name:        "no volumes to backup",
			annotations: map[string]string{"foo": "bar"},
			expected:    nil,
		},
		{
			name:        "one volume to backup",
			annotations: map[string]string{"foo": "bar", volumesToBackupAnnotation: "volume-1"},
			expected:    []string{"volume-1"},
		},
		{
			name:        "multiple volumes to backup",
			annotations: map[string]string{"foo": "bar", volumesToBackupAnnotation: "volume-1,volume-2,volume-3"},
			expected:    []string{"volume-1", "volume-2", "volume-3"},
		},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			pod := &corev1api.Pod{}
			pod.Annotations = test.annotations

			res := GetVolumesToBackup(pod)

			// sort to ensure good compare of slices
			sort.Strings(test.expected)
			sort.Strings(res)

			assert.Equal(t, test.expected, res)
		})
	}
}

func TestGetSnapshotsInBackup(t *testing.T) {
	tests := []struct {
		name             string
		podVolumeBackups []arkv1api.PodVolumeBackup
		expected         []SnapshotIdentifier
	}{
		{
			name:             "no pod volume backups",
			podVolumeBackups: nil,
			expected:         nil,
		},
		{
			name: "no pod volume backups with matching label",
			podVolumeBackups: []arkv1api.PodVolumeBackup{
				{
					ObjectMeta: metav1.ObjectMeta{Name: "foo", Labels: map[string]string{arkv1api.BackupNameLabel: "non-matching-backup-1"}},
					Spec: arkv1api.PodVolumeBackupSpec{
						Pod: corev1api.ObjectReference{Name: "pod-1", Namespace: "ns-1"},
					},
					Status: arkv1api.PodVolumeBackupStatus{SnapshotID: "snap-1"},
				},
				{
					ObjectMeta: metav1.ObjectMeta{Name: "bar", Labels: map[string]string{arkv1api.BackupNameLabel: "non-matching-backup-2"}},
					Spec: arkv1api.PodVolumeBackupSpec{
						Pod: corev1api.ObjectReference{Name: "pod-2", Namespace: "ns-2"},
					},
					Status: arkv1api.PodVolumeBackupStatus{SnapshotID: "snap-2"},
				},
			},
			expected: nil,
		},
		{
			name: "some pod volume backups with matching label",
			podVolumeBackups: []arkv1api.PodVolumeBackup{
				{
					ObjectMeta: metav1.ObjectMeta{Name: "foo", Labels: map[string]string{arkv1api.BackupNameLabel: "non-matching-backup-1"}},
					Spec: arkv1api.PodVolumeBackupSpec{
						Pod: corev1api.ObjectReference{Name: "pod-1", Namespace: "ns-1"},
					},
					Status: arkv1api.PodVolumeBackupStatus{SnapshotID: "snap-1"},
				},
				{
					ObjectMeta: metav1.ObjectMeta{Name: "bar", Labels: map[string]string{arkv1api.BackupNameLabel: "non-matching-backup-2"}},
					Spec: arkv1api.PodVolumeBackupSpec{
						Pod: corev1api.ObjectReference{Name: "pod-2", Namespace: "ns-2"},
					},
					Status: arkv1api.PodVolumeBackupStatus{SnapshotID: "snap-2"},
				},
				{
					ObjectMeta: metav1.ObjectMeta{Name: "completed-pvb", Labels: map[string]string{arkv1api.BackupNameLabel: "backup-1"}},
					Spec: arkv1api.PodVolumeBackupSpec{
						Pod: corev1api.ObjectReference{Name: "pod-1", Namespace: "ns-1"},
					},
					Status: arkv1api.PodVolumeBackupStatus{SnapshotID: "snap-3"},
				},
				{
					ObjectMeta: metav1.ObjectMeta{Name: "completed-pvb-2", Labels: map[string]string{arkv1api.BackupNameLabel: "backup-1"}},
					Spec: arkv1api.PodVolumeBackupSpec{
						Pod: corev1api.ObjectReference{Name: "pod-1", Namespace: "ns-1"},
					},
					Status: arkv1api.PodVolumeBackupStatus{SnapshotID: "snap-4"},
				},
				{
					ObjectMeta: metav1.ObjectMeta{Name: "incomplete-or-failed-pvb", Labels: map[string]string{arkv1api.BackupNameLabel: "backup-1"}},
					Spec: arkv1api.PodVolumeBackupSpec{
						Pod: corev1api.ObjectReference{Name: "pod-1", Namespace: "ns-2"},
					},
					Status: arkv1api.PodVolumeBackupStatus{SnapshotID: ""},
				},
			},
			expected: []SnapshotIdentifier{
				{
					Repo:       "ns-1",
					SnapshotID: "snap-3",
				},
				{
					Repo:       "ns-1",
					SnapshotID: "snap-4",
				},
			},
		},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			var (
				client          = fake.NewSimpleClientset()
				sharedInformers = informers.NewSharedInformerFactory(client, 0)
				pvbInformer     = sharedInformers.Ark().V1().PodVolumeBackups()
				arkBackup       = &arkv1api.Backup{}
			)

			arkBackup.Name = "backup-1"

			for _, pvb := range test.podVolumeBackups {
				require.NoError(t, pvbInformer.Informer().GetStore().Add(pvb.DeepCopy()))
			}

			res, err := GetSnapshotsInBackup(arkBackup, pvbInformer.Lister())
			assert.NoError(t, err)

			// sort to ensure good compare of slices
			less := func(snapshots []SnapshotIdentifier) func(i, j int) bool {
				return func(i, j int) bool {
					if snapshots[i].Repo == snapshots[j].Repo {
						return snapshots[i].SnapshotID < snapshots[j].SnapshotID
					}
					return snapshots[i].Repo < snapshots[j].Repo
				}

			}

			sort.Slice(test.expected, less(test.expected))
			sort.Slice(res, less(res))

			assert.Equal(t, test.expected, res)
		})
	}
}

func TestTempCredentialsFile(t *testing.T) {
	var (
		secretInformer = cache.NewSharedIndexInformer(nil, new(corev1api.Secret), 0, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc})
		secretLister   = corev1listers.NewSecretLister(secretInformer.GetIndexer())
		fs             = arktest.NewFakeFileSystem()
		secret         = &corev1api.Secret{
			ObjectMeta: metav1.ObjectMeta{
				Namespace: "heptio-ark",
				Name:      CredentialsSecretName,
			},
			Data: map[string][]byte{
				CredentialsKey: []byte("passw0rd"),
			},
		}
	)

	// secret not in lister: expect an error
	fileName, err := TempCredentialsFile(secretLister, "heptio-ark", "default", fs)
	assert.Error(t, err)

	// now add secret to lister
	require.NoError(t, secretInformer.GetStore().Add(secret))

	// secret in lister: expect temp file to be created with password
	fileName, err = TempCredentialsFile(secretLister, "heptio-ark", "default", fs)
	require.NoError(t, err)

	contents, err := fs.ReadFile(fileName)
	require.NoError(t, err)

	assert.Equal(t, "passw0rd", string(contents))
}
<|endoftext|>


<commit_before>package calculators

import (
	"github.com/NumberXNumbers/GoCalculate/utils/parsers"
	gcf "github.com/NumberXNumbers/types/gc/functions"
)

var (
	// C style order of opertations. Mod is of same level as multiplication and division
	orderOfOperations = map[string]uint{
		"exp": 3,
		"*":   2,
		"x":   2,
		"/":   2,
		"%":   2,
		"+":   1,
		"-":   1,
	}
)

// InfixCalculator will calculate an infix calculation
func InfixCalculator(args []string) gcf.Const {
	var argsForCalculation []interface{}

	for _, arg := range args {
		if v, e := parsers.Value(arg); e == nil {
			argsForCalculation = append(argsForCalculation, v)
		} else {
			argsForCalculation = append(argsForCalculation, arg)
		}
	}

	calculation := gcf.MustCalculate(argsForCalculation...)

	return calculation
}
<commit_msg>update due to refactor<commit_after>package calculators

import (
	"github.com/NumberXNumbers/GoCalculate/utils/parsers"
	gcf "github.com/NumberXNumbers/types/gc/functions"
	gcfargs "github.com/NumberXNumbers/types/gc/functions/arguments"
)

var (
	// C style order of opertations. Mod is of same level as multiplication and division
	orderOfOperations = map[string]uint{
		"exp": 3,
		"*":   2,
		"x":   2,
		"/":   2,
		"%":   2,
		"+":   1,
		"-":   1,
	}
)

// InfixCalculator will calculate an infix calculation
func InfixCalculator(args []string) gcfargs.Const {
	var argsForCalculation []interface{}

	for _, arg := range args {
		if v, e := parsers.Value(arg); e == nil {
			argsForCalculation = append(argsForCalculation, v)
		} else {
			argsForCalculation = append(argsForCalculation, arg)
		}
	}

	calculation := gcf.MustCalculate(argsForCalculation...)

	return calculation
}
<|endoftext|>


<commit_before>// Package Enchant provides simplified bindings to Enchant spell checking library.
package enchant

/*
#cgo LDFLAGS: -lenchant
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include "enchant/enchant.h"

static size_t getLength(char ** c) {
	return sizeof(c);
}

static char* getString(char ** c, int i) {
    return c[i];
}
*/
import "C"

import (
	"unsafe"
)

// Enchant is a type that encapsulates Enchant internals
type Enchant struct {
	broker *C.EnchantBroker
	dict   *C.EnchantDict
}

// NewEnchant creates a new Enchant instance for access
// to the rest of the Enchant API.
//
// The returned value is an Enchant struct.
//
// Example usage:
//
// 		enchant, err := enchant.NewEnchant()
// 		if err != nil {
// 			panic("Enchant error: " + err.Error())
// 		}
// 		defer enchant.Free()
//      fmt.Println(enchant.DictExists("zh"))
//
// Because the Enchant package is a binding to Enchant C library, memory
// allocated by the NewEnchant() call has to be disposed explicitly.
// This is why the above example contains a deferred call to Free().
func NewEnchant() (e *Enchant, err error) {
	broker := C.enchant_broker_init()
	e = &Enchant{broker, nil}
	// we don't return errors at the moment, but we might in the future
	return e, nil
}

// Free frees the Enchant broker and dictionary, and needs
// to be called when use of the library is no longer needed
// to prevent memory leaks.
func (e *Enchant) Free() {
	if e.dict != nil {
		C.enchant_broker_free_dict(e.broker, e.dict)
	}
	C.enchant_broker_free(e.broker)
}

// DictExists wraps enchant_broker_dict_exists.
// It takes a language code name, such as "en_GB", as string
// argument, and it returns whether or not such a dictionary
// is installed on the system.
func (e *Enchant) DictExists(name string) bool {
	cName := C.CString(name)
	defer C.free(unsafe.Pointer(cName))

	exists := C.enchant_broker_dict_exists(e.broker, cName)
	return exists > 0
}

// LoadDict wraps enchant_broker_request_dict, and adds
// the loaded dictionary to the Enchant instance.
// It takes a language code name, such as "en_GB", as string
// argument, and it returns a EnchantDict representation
// of this dictionary.
func (e *Enchant) LoadDict(name string) {
	cName := C.CString(name)
	defer C.free(unsafe.Pointer(cName))

	if e.dict != nil {
		C.enchant_broker_free_dict(e.broker, e.dict)
	}
	dict := C.enchant_broker_request_dict(e.broker, cName)
	e.dict = dict
}

// Check whether a given word is in the currently loaded dictionary.
// This wraps enchant_dict_check.
// It returns a boolean value: true if the word is in the dictionary,
// false otherwise.
func (e *Enchant) Check(word string) bool {
	if len(word) == 0 {
		return true
	}

	cWord := C.CString(word)
	defer C.free(unsafe.Pointer(cWord))

	size := uintptr(len(word))
	s := (*C.ssize_t)(unsafe.Pointer(&size))

	return C.enchant_dict_check(e.dict, cWord, *s) == 0
}

// Suggest words based on the given word.
// This is a wrapper for enchant_dict_suggest.
// It returns a slice of suggestion strings.
func (e *Enchant) Suggest(word string) (suggestions []string) {
	if len(word) == 0 {
		return suggestions
	}

	cWord := C.CString(word)
	defer C.free(unsafe.Pointer(cWord))

	size := uintptr(len(word))
	s := (*C.ssize_t)(unsafe.Pointer(&size))

	var n int
	nSugg := uintptr(n)
	ns := (*C.size_t)(unsafe.Pointer(&nSugg))

	// get the suggestions; ns will be modified to store the
	// number of suggestions returned
	response := C.enchant_dict_suggest(e.dict, cWord, *s, ns)

	for i := 0; i < int(*ns); i++ {
		ci := C.int(i)
		suggestions = append(suggestions, C.GoString(C.getString(response, ci)))
	}

	return suggestions
}
<commit_msg>Remove unused getLength function<commit_after>// Package Enchant provides simplified bindings to Enchant spell checking library.
package enchant

/*
#cgo LDFLAGS: -lenchant
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include "enchant/enchant.h"

static char* getString(char ** c, int i) {
    return c[i];
}
*/
import "C"

import (
	"unsafe"
)

// Enchant is a type that encapsulates Enchant internals
type Enchant struct {
	broker *C.EnchantBroker
	dict   *C.EnchantDict
}

// NewEnchant creates a new Enchant instance for access
// to the rest of the Enchant API.
//
// The returned value is an Enchant struct.
//
// Example usage:
//
// 		enchant, err := enchant.NewEnchant()
// 		if err != nil {
// 			panic("Enchant error: " + err.Error())
// 		}
// 		defer enchant.Free()
//      fmt.Println(enchant.DictExists("zh"))
//
// Because the Enchant package is a binding to Enchant C library, memory
// allocated by the NewEnchant() call has to be disposed explicitly.
// This is why the above example contains a deferred call to Free().
func NewEnchant() (e *Enchant, err error) {
	broker := C.enchant_broker_init()
	e = &Enchant{broker, nil}
	// we don't return errors at the moment, but we might in the future
	return e, nil
}

// Free frees the Enchant broker and dictionary, and needs
// to be called when use of the library is no longer needed
// to prevent memory leaks.
func (e *Enchant) Free() {
	if e.dict != nil {
		C.enchant_broker_free_dict(e.broker, e.dict)
	}
	C.enchant_broker_free(e.broker)
}

// DictExists wraps enchant_broker_dict_exists.
// It takes a language code name, such as "en_GB", as string
// argument, and it returns whether or not such a dictionary
// is installed on the system.
func (e *Enchant) DictExists(name string) bool {
	cName := C.CString(name)
	defer C.free(unsafe.Pointer(cName))

	exists := C.enchant_broker_dict_exists(e.broker, cName)
	return exists > 0
}

// LoadDict wraps enchant_broker_request_dict, and adds
// the loaded dictionary to the Enchant instance.
// It takes a language code name, such as "en_GB", as string
// argument, and it returns a EnchantDict representation
// of this dictionary.
func (e *Enchant) LoadDict(name string) {
	cName := C.CString(name)
	defer C.free(unsafe.Pointer(cName))

	if e.dict != nil {
		C.enchant_broker_free_dict(e.broker, e.dict)
	}
	dict := C.enchant_broker_request_dict(e.broker, cName)
	e.dict = dict
}

// Check whether a given word is in the currently loaded dictionary.
// This wraps enchant_dict_check.
// It returns a boolean value: true if the word is in the dictionary,
// false otherwise.
func (e *Enchant) Check(word string) bool {
	if len(word) == 0 {
		return true
	}

	cWord := C.CString(word)
	defer C.free(unsafe.Pointer(cWord))

	size := uintptr(len(word))
	s := (*C.ssize_t)(unsafe.Pointer(&size))

	return C.enchant_dict_check(e.dict, cWord, *s) == 0
}

// Suggest words based on the given word.
// This is a wrapper for enchant_dict_suggest.
// It returns a slice of suggestion strings.
func (e *Enchant) Suggest(word string) (suggestions []string) {
	if len(word) == 0 {
		return suggestions
	}

	cWord := C.CString(word)
	defer C.free(unsafe.Pointer(cWord))

	size := uintptr(len(word))
	s := (*C.ssize_t)(unsafe.Pointer(&size))

	var n int
	nSugg := uintptr(n)
	ns := (*C.size_t)(unsafe.Pointer(&nSugg))

	// get the suggestions; ns will be modified to store the
	// number of suggestions returned
	response := C.enchant_dict_suggest(e.dict, cWord, *s, ns)

	for i := 0; i < int(*ns); i++ {
		ci := C.int(i)
		suggestions = append(suggestions, C.GoString(C.getString(response, ci)))
	}

	return suggestions
}
<|endoftext|>


<commit_before>package restruct

import (
	"encoding/binary"
	"fmt"
	"math"
	"reflect"
)

// Packer is a type capable of packing a native value into a binary
// representation. The Pack function is expected to overwrite a number of
// bytes in buf then return a slice of the remaining buffer. Note that you
// must also implement SizeOf, and returning an incorrect SizeOf will cause
// the encoder to crash. The SizeOf should be equal to the number of bytes
// consumed from the buffer slice in Pack. You may use a pointer receiver even
// if the type is used by value.
type Packer interface {
	Sizer
	Pack(buf []byte, order binary.ByteOrder) ([]byte, error)
}

type encoder struct {
	order      binary.ByteOrder
	buf        []byte
	struc      reflect.Value
	sfields    []field
	bitCounter uint8
	realSize   uint64
	initBuf    []byte
}

func (e *encoder) assignBuffer(in []byte) {
	e.buf = in
	e.initBuf = in
}

func (e *encoder) writeBits(f field, inBuf []byte) {

	var inputLength uint8 = uint8(len(inBuf))

	if f.BitSize == 0 {
		// Having problems with complex64 type ... so we asume we want to read all
		//f.BitSize = uint8(f.Type.Bits())
		f.BitSize = 8 * inputLength
	}
	// destPos: Destination position ( in the result ) of the first bit in the first byte
	var destPos uint8 = 8 - e.bitCounter

	// originPos: Original position of the first bit in the first byte
	var originPos uint8 = f.BitSize % 8
	if originPos == 0 {
		originPos = 8
	}

	// numBytes: number of complete bytes to hold the result
	var numBytes uint8 = f.BitSize / 8

	// numBits: number of remaining bits in the first non-complete byte of the result
	var numBits uint8 = f.BitSize % 8

	// number of positions we have to shift the bytes to get the result
	var shift uint8
	if originPos > destPos {
		shift = originPos - destPos
	} else {
		shift = destPos - originPos
	}
	shift = shift % 8

	var inputInitialIdx uint8 = inputLength - numBytes
	if numBits > 0 {
		inputInitialIdx = inputInitialIdx - 1
	}

	if originPos < destPos {
		// shift left
		carry := func(idx uint8) uint8 {
			if (idx + 1) < inputLength {
				return (inBuf[idx + 1] >> (8 - shift))
			}
			return 0x00

		}
		mask := func(idx uint8) uint8{
			if idx == 0 {
				return (0x01<<destPos)-1
			}
			return 0xFF
		}
		var idx uint8 = 0
		for inIdx := inputInitialIdx; inIdx < inputLength; inIdx++ {
			e.buf[idx] |= ((inBuf[inIdx] << shift) | carry(inIdx) ) & mask(idx)
			idx++
		}

	} else {
		// originPos >= destPos => shift right
		var idx uint8 = 0
		// carry : is a little bit tricky in this case because of the first case
		// when idx == 0 and there is no carry at all
		carry := func(idx uint8) uint8 {
			if idx == 0 {
				return 0x00
			}
			return (inBuf[idx-1] << (8 - shift))
		}
		mask := func(idx uint8) uint8{
			if idx == 0 {
				return (0x01<<destPos)-1
			}
			return 0xFF
		}
		inIdx := inputInitialIdx
		for ; inIdx < inputLength; inIdx++ {
			//note: Should the mask be done BEFORE the OR with carry?
			e.buf[idx] |= ((inBuf[inIdx] >> shift) | carry(inIdx)) & mask(idx)
			idx++
		}
		if ((e.bitCounter + f.BitSize) % 8) > 0 {
			e.buf[idx] |= carry(inIdx)
		}
	}

        //now we should update buffer and bitCounter
	e.bitCounter = (e.bitCounter + f.BitSize) % 8

	// move the head to the next non-complete byte used
	headerUpdate := func() uint8 {
		if (e.bitCounter == 0) && ((f.BitSize % 8) != 0) {
			return (numBytes + 1)
		}
		return numBytes
	}
	e.buf = e.buf[headerUpdate():]
	return
}

func (e *encoder) write8(f field, x uint8) {
	typeSize := uint8(reflect.TypeOf(x).Size())

	b := make([]byte, typeSize)
	b[0] = x
	e.writeBits(f, b)
}

func (e *encoder) write16(f field, x uint16) {
	typeSize := uint8(reflect.TypeOf(x).Size())

	b := make([]byte, typeSize)
	e.order.PutUint16(b[0:typeSize], x)

	e.writeBits(f, b)
}

func (e *encoder) write32(f field, x uint32) {
	typeSize := uint8(reflect.TypeOf(x).Size())

	b := make([]byte, typeSize)
	e.order.PutUint32(b[0:typeSize], x)

	e.writeBits(f, b)
}

func (e *encoder) write64(f field, x uint64) {
	typeSize := uint8(reflect.TypeOf(x).Size())

	b := make([]byte, typeSize)
	e.order.PutUint64(b[0:typeSize], x)

	e.writeBits(f, b)
}

func (e *encoder) writeS8(f field, x int8) { e.write8(f, uint8(x)) }

func (e *encoder) writeS16(f field, x int16) { e.write16(f, uint16(x)) }

func (e *encoder) writeS32(f field, x int32) { e.write32(f, uint32(x)) }

func (e *encoder) writeS64(f field, x int64) { e.write64(f, uint64(x)) }

func (e *encoder) skipn(count int) {
	e.buf = e.buf[count:]
}

func (e *encoder) skip(f field, v reflect.Value) {
	e.skipn(f.SizeOf(v))
}

func (e *encoder) packer(v reflect.Value) (Packer, bool) {
	if s, ok := v.Interface().(Packer); ok {
		return s, true
	}

	if !v.CanAddr() {
		return nil, false
	}

	if s, ok := v.Addr().Interface().(Packer); ok {
		return s, true
	}

	return nil, false
}

func (e *encoder) write(f field, v reflect.Value) {
	if f.Name != "_" {
		if s, ok := e.packer(v); ok {
			var err error
			e.buf, err = s.Pack(e.buf, e.order)
			if err != nil {
				panic(err)
			}
			return
		}
	} else {
		e.skipn(f.SizeOf(v))
		return
	}

	struc := e.struc
	sfields := e.sfields
	order := e.order

	if f.Order != nil {
		e.order = f.Order
		defer func() { e.order = order }()
	}

	if f.Skip != 0 {
		e.skipn(f.Skip)
	}

	// If this is a sizeof field, pull the current slice length into it.
	if f.SIndex != -1 {
		sv := struc.Field(f.SIndex)

		switch f.DefType.Kind() {
		case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			v.SetInt(int64(sv.Len()))
		case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
			v.SetUint(uint64(sv.Len()))
		default:
			panic(fmt.Errorf("unsupported sizeof type %s", f.DefType.String()))
		}
	}

	switch f.Type.Kind() {
	case reflect.Array, reflect.Slice, reflect.String:
		switch f.DefType.Kind() {
		case reflect.Array, reflect.Slice, reflect.String:
			ef := f.Elem()
			l := v.Len()
			for i := 0; i < l; i++ {
				e.write(ef, v.Index(i))
			}
		default:
			panic(fmt.Errorf("invalid array cast type: %s", f.DefType.String()))
		}

	case reflect.Struct:
		e.struc = v
		e.sfields = cachedFieldsFromStruct(f.Type)
		l := len(e.sfields)
		for i := 0; i < l; i++ {
			f := e.sfields[i]
			v := v.Field(f.Index)
			if v.CanSet() {
				e.write(f, v)
			} else {
				e.skip(f, v)
			}
		}
		e.sfields = sfields
		e.struc = struc

	case reflect.Int8:
		e.writeS8(f, int8(v.Int()))
	case reflect.Int16:
		e.writeS16(f, int16(v.Int()))
	case reflect.Int32:
		e.writeS32(f, int32(v.Int()))
	case reflect.Int64:
		e.writeS64(f, int64(v.Int()))

	case reflect.Uint8:
		e.write8(f, uint8(v.Uint()))
	case reflect.Uint16:
		e.write16(f, uint16(v.Uint()))
	case reflect.Uint32:
		e.write32(f, uint32(v.Uint()))
	case reflect.Uint64:
		e.write64(f, uint64(v.Uint()))

	case reflect.Float32:
		e.write32(f, math.Float32bits(float32(v.Float())))
	case reflect.Float64:
		e.write64(f, math.Float64bits(float64(v.Float())))

	case reflect.Complex64:
		x := v.Complex()
		e.write32(f, math.Float32bits(float32(real(x))))
		e.write32(f, math.Float32bits(float32(imag(x))))
	case reflect.Complex128:
		x := v.Complex()
		e.write64(f, math.Float64bits(float64(real(x))))
		e.write64(f, math.Float64bits(float64(imag(x))))
	}
}
<commit_msg>Fix linting errors in encoder.go.<commit_after>package restruct

import (
	"encoding/binary"
	"fmt"
	"math"
	"reflect"
)

// Packer is a type capable of packing a native value into a binary
// representation. The Pack function is expected to overwrite a number of
// bytes in buf then return a slice of the remaining buffer. Note that you
// must also implement SizeOf, and returning an incorrect SizeOf will cause
// the encoder to crash. The SizeOf should be equal to the number of bytes
// consumed from the buffer slice in Pack. You may use a pointer receiver even
// if the type is used by value.
type Packer interface {
	Sizer
	Pack(buf []byte, order binary.ByteOrder) ([]byte, error)
}

type encoder struct {
	order      binary.ByteOrder
	buf        []byte
	struc      reflect.Value
	sfields    []field
	bitCounter uint8
	realSize   uint64
	initBuf    []byte
}

func (e *encoder) assignBuffer(in []byte) {
	e.buf = in
	e.initBuf = in
}

func (e *encoder) writeBits(f field, inBuf []byte) {

	var inputLength = uint8(len(inBuf))

	if f.BitSize == 0 {
		// Having problems with complex64 type ... so we asume we want to read all
		//f.BitSize = uint8(f.Type.Bits())
		f.BitSize = 8 * inputLength
	}
	// destPos: Destination position ( in the result ) of the first bit in the first byte
	var destPos = 8 - e.bitCounter

	// originPos: Original position of the first bit in the first byte
	var originPos = f.BitSize % 8
	if originPos == 0 {
		originPos = 8
	}

	// numBytes: number of complete bytes to hold the result
	var numBytes = f.BitSize / 8

	// numBits: number of remaining bits in the first non-complete byte of the result
	var numBits = f.BitSize % 8

	// number of positions we have to shift the bytes to get the result
	var shift uint8
	if originPos > destPos {
		shift = originPos - destPos
	} else {
		shift = destPos - originPos
	}
	shift = shift % 8

	var inputInitialIdx = inputLength - numBytes
	if numBits > 0 {
		inputInitialIdx = inputInitialIdx - 1
	}

	if originPos < destPos {
		// shift left
		carry := func(idx uint8) uint8 {
			if (idx + 1) < inputLength {
				return (inBuf[idx+1] >> (8 - shift))
			}
			return 0x00

		}
		mask := func(idx uint8) uint8 {
			if idx == 0 {
				return (0x01 << destPos) - 1
			}
			return 0xFF
		}
		var idx uint8
		for inIdx := inputInitialIdx; inIdx < inputLength; inIdx++ {
			e.buf[idx] |= ((inBuf[inIdx] << shift) | carry(inIdx)) & mask(idx)
			idx++
		}

	} else {
		// originPos >= destPos => shift right
		var idx uint8
		// carry : is a little bit tricky in this case because of the first case
		// when idx == 0 and there is no carry at all
		carry := func(idx uint8) uint8 {
			if idx == 0 {
				return 0x00
			}
			return (inBuf[idx-1] << (8 - shift))
		}
		mask := func(idx uint8) uint8 {
			if idx == 0 {
				return (0x01 << destPos) - 1
			}
			return 0xFF
		}
		inIdx := inputInitialIdx
		for ; inIdx < inputLength; inIdx++ {
			//note: Should the mask be done BEFORE the OR with carry?
			e.buf[idx] |= ((inBuf[inIdx] >> shift) | carry(inIdx)) & mask(idx)
			idx++
		}
		if ((e.bitCounter + f.BitSize) % 8) > 0 {
			e.buf[idx] |= carry(inIdx)
		}
	}

	//now we should update buffer and bitCounter
	e.bitCounter = (e.bitCounter + f.BitSize) % 8

	// move the head to the next non-complete byte used
	headerUpdate := func() uint8 {
		if (e.bitCounter == 0) && ((f.BitSize % 8) != 0) {
			return (numBytes + 1)
		}
		return numBytes
	}
	e.buf = e.buf[headerUpdate():]
	return
}

func (e *encoder) write8(f field, x uint8) {
	typeSize := uint8(reflect.TypeOf(x).Size())

	b := make([]byte, typeSize)
	b[0] = x
	e.writeBits(f, b)
}

func (e *encoder) write16(f field, x uint16) {
	typeSize := uint8(reflect.TypeOf(x).Size())

	b := make([]byte, typeSize)
	e.order.PutUint16(b[0:typeSize], x)

	e.writeBits(f, b)
}

func (e *encoder) write32(f field, x uint32) {
	typeSize := uint8(reflect.TypeOf(x).Size())

	b := make([]byte, typeSize)
	e.order.PutUint32(b[0:typeSize], x)

	e.writeBits(f, b)
}

func (e *encoder) write64(f field, x uint64) {
	typeSize := uint8(reflect.TypeOf(x).Size())

	b := make([]byte, typeSize)
	e.order.PutUint64(b[0:typeSize], x)

	e.writeBits(f, b)
}

func (e *encoder) writeS8(f field, x int8) { e.write8(f, uint8(x)) }

func (e *encoder) writeS16(f field, x int16) { e.write16(f, uint16(x)) }

func (e *encoder) writeS32(f field, x int32) { e.write32(f, uint32(x)) }

func (e *encoder) writeS64(f field, x int64) { e.write64(f, uint64(x)) }

func (e *encoder) skipn(count int) {
	e.buf = e.buf[count:]
}

func (e *encoder) skip(f field, v reflect.Value) {
	e.skipn(f.SizeOf(v))
}

func (e *encoder) packer(v reflect.Value) (Packer, bool) {
	if s, ok := v.Interface().(Packer); ok {
		return s, true
	}

	if !v.CanAddr() {
		return nil, false
	}

	if s, ok := v.Addr().Interface().(Packer); ok {
		return s, true
	}

	return nil, false
}

func (e *encoder) write(f field, v reflect.Value) {
	if f.Name != "_" {
		if s, ok := e.packer(v); ok {
			var err error
			e.buf, err = s.Pack(e.buf, e.order)
			if err != nil {
				panic(err)
			}
			return
		}
	} else {
		e.skipn(f.SizeOf(v))
		return
	}

	struc := e.struc
	sfields := e.sfields
	order := e.order

	if f.Order != nil {
		e.order = f.Order
		defer func() { e.order = order }()
	}

	if f.Skip != 0 {
		e.skipn(f.Skip)
	}

	// If this is a sizeof field, pull the current slice length into it.
	if f.SIndex != -1 {
		sv := struc.Field(f.SIndex)

		switch f.DefType.Kind() {
		case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			v.SetInt(int64(sv.Len()))
		case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
			v.SetUint(uint64(sv.Len()))
		default:
			panic(fmt.Errorf("unsupported sizeof type %s", f.DefType.String()))
		}
	}

	switch f.Type.Kind() {
	case reflect.Array, reflect.Slice, reflect.String:
		switch f.DefType.Kind() {
		case reflect.Array, reflect.Slice, reflect.String:
			ef := f.Elem()
			l := v.Len()
			for i := 0; i < l; i++ {
				e.write(ef, v.Index(i))
			}
		default:
			panic(fmt.Errorf("invalid array cast type: %s", f.DefType.String()))
		}

	case reflect.Struct:
		e.struc = v
		e.sfields = cachedFieldsFromStruct(f.Type)
		l := len(e.sfields)
		for i := 0; i < l; i++ {
			sf := e.sfields[i]
			sv := v.Field(sf.Index)
			if sv.CanSet() {
				e.write(sf, sv)
			} else {
				e.skip(sf, sv)
			}
		}
		e.sfields = sfields
		e.struc = struc

	case reflect.Int8:
		e.writeS8(f, int8(v.Int()))
	case reflect.Int16:
		e.writeS16(f, int16(v.Int()))
	case reflect.Int32:
		e.writeS32(f, int32(v.Int()))
	case reflect.Int64:
		e.writeS64(f, int64(v.Int()))

	case reflect.Uint8:
		e.write8(f, uint8(v.Uint()))
	case reflect.Uint16:
		e.write16(f, uint16(v.Uint()))
	case reflect.Uint32:
		e.write32(f, uint32(v.Uint()))
	case reflect.Uint64:
		e.write64(f, uint64(v.Uint()))

	case reflect.Float32:
		e.write32(f, math.Float32bits(float32(v.Float())))
	case reflect.Float64:
		e.write64(f, math.Float64bits(float64(v.Float())))

	case reflect.Complex64:
		x := v.Complex()
		e.write32(f, math.Float32bits(float32(real(x))))
		e.write32(f, math.Float32bits(float32(imag(x))))
	case reflect.Complex128:
		x := v.Complex()
		e.write64(f, math.Float64bits(float64(real(x))))
		e.write64(f, math.Float64bits(float64(imag(x))))
	}
}
<|endoftext|>


<commit_before>package fox

import (
	"encoding/hex"
	"errors"
	"net"
	"strconv"
	"strings"
)

const (
	ORIGINAL_QUERY = "666f7820612031202d3120666f782068656c6c6f0a7b0a" +
		"666f782e76657273696f6e3d733a312e300a69643d693a310a686f73744e" +
		"616d653d733a7870766d2d306f6d64633031786d790a686f737441646472" +
		"6573733d733a3139322e3136382e312e3132350a6170702e6e616d653d73" +
		"3a576f726b62656e63680a6170702e76657273696f6e3d733a332e372e34" +
		"340a766d2e6e616d653d733a4a61766120486f7453706f7428544d292053" +
		"657276657220564d0a766d2e76657273696f6e3d733a32302e342d623032" +
		"0a6f732e6e616d653d733a57696e646f77732058500a6f732e7665727369" +
		"6f6e3d733a352e310a6c616e673d733a656e0a74696d655a6f6e653d733a" +
		"416d65726963612f4c6f735f416e67656c65733b2d32383830303030303b" +
		"333630303030303b30323a30303a30302e3030302c77616c6c2c6d617263" +
		"682c382c6f6e206f722061667465722c73756e6461792c756e646566696e" +
		"65643b30323a30303a30302e3030302c77616c6c2c6e6f76656d6265722c" +
		"312c6f6e206f722061667465722c73756e6461792c756e646566696e6564" +
		"0a686f737449643d733a57696e2d393943422d443439442d353434322d30" +
		"3742420a766d557569643d733a38623533306263382d373663352d343133" +
		"392d613265612d3066616264333934643330350a6272616e6449643d733a" +
		"76796b6f6e0a7d3b3b0a"
	RESPONSE_PREFIX = "fox a 0 -1 fox hello"
)

func GetFoxBanner(logStruct *FoxLog, connection net.Conn) error {
	queryBytes, err := hex.DecodeString(ORIGINAL_QUERY)
	if err != nil {
		return err
	}

	bytesWritten, err := connection.Write(queryBytes)
	if bytesWritten != len(queryBytes) {
		return errors.New("Unable to write all Fox query bytes...")
	}
	if err != nil {
		return err
	}

	readBuffer := make([]byte, 8196)
	bytesRead, err := connection.Read(readBuffer)
	if bytesRead == len(readBuffer) {
		return errors.New("Need a bigger buffer to read Fox response")
	}
	if err != nil {
		return err
	}

	responseString := string(readBuffer[0:bytesRead])
	output := strings.Split(responseString, string(0x0a))

	if strings.HasPrefix(responseString, RESPONSE_PREFIX) {
		logStruct.IsFox = true

		for _, value := range output {
			if strings.HasPrefix(value, "fox.version") && strings.Contains(value, ":") {
				logStruct.Version = strings.Split(value, ":")[1]
			} else if strings.HasPrefix(value, "id") && strings.Contains(value, ":") {
				id, err := strconv.ParseUint(strings.Split(value, ":")[1], 10, 32)
				if err != nil {
					return err
				}
				logStruct.Id = uint32(id)
			} else if strings.HasPrefix(value, "hostAddress") && strings.Contains(value, ":") {
				logStruct.Hostname = strings.Split(value, ":")[1]
			} else if strings.HasPrefix(value, "hostName") && strings.Contains(value, ":") {
				logStruct.HostAddress = strings.Split(value, ":")[1]
			} else if strings.HasPrefix(value, "app.name") && strings.Contains(value, ":") {
				logStruct.AppName = strings.Split(value, ":")[1]
			} else if strings.HasPrefix(value, "app.version") && strings.Contains(value, ":") {
				logStruct.AppVersion = strings.Split(value, ":")[1]
			} else if strings.HasPrefix(value, "vm.name") && strings.Contains(value, ":") {
				logStruct.VMName = strings.Split(value, ":")[1]
			} else if strings.HasPrefix(value, "vm.version") && strings.Contains(value, ":") {
				logStruct.VMVersion = strings.Split(value, ":")[1]
			} else if strings.HasPrefix(value, "os.name") && strings.Contains(value, ":") {
				logStruct.OSName = strings.Split(value, ":")[1]
			} else if strings.HasPrefix(value, "os.version") && strings.Contains(value, ":") {
				logStruct.OSVersion = strings.Split(value, ":")[1]
			} else if strings.HasPrefix(value, "station.name") && strings.Contains(value, ":") {
				logStruct.StationName = strings.Split(value, ":")[1]
			} else if strings.HasPrefix(value, "lang") && strings.Contains(value, ":") {
				logStruct.Language = strings.Split(value, ":")[1]
			} else if strings.HasPrefix(value, "timeZone") && strings.Contains(value, ":") {
				timeZone := strings.Split(value, ":")[1]
				if strings.Contains(timeZone, ";") {
					timeZone = strings.Split(timeZone, ";")[0]
				}
				logStruct.TimeZone = timeZone
			} else if strings.HasPrefix(value, "hostId") && strings.Contains(value, ":") {
				logStruct.HostId = strings.Split(value, ":")[1]
			} else if strings.HasPrefix(value, "vmUuid") && strings.Contains(value, ":") {
				logStruct.VMUuid = strings.Split(value, ":")[1]
			} else if strings.HasPrefix(value, "brandId") && strings.Contains(value, ":") {
				logStruct.BrandId = strings.Split(value, ":")[1]
			} else if strings.HasPrefix(value, "sysInfo") && strings.Contains(value, ":") {
				logStruct.SysInfo = strings.Split(value, ":")[1]
			} else if strings.HasPrefix(value, "authAgentTypeSpecs") && strings.Contains(value, ":") {
				logStruct.AuthAgentType = strings.Split(value, ":")[1]
			}
		}
	}

	return nil
}
<commit_msg>switch hostname / address<commit_after>package fox

import (
	"encoding/hex"
	"errors"
	"net"
	"strconv"
	"strings"
)

const (
	ORIGINAL_QUERY = "666f7820612031202d3120666f782068656c6c6f0a7b0a" +
		"666f782e76657273696f6e3d733a312e300a69643d693a310a686f73744e" +
		"616d653d733a7870766d2d306f6d64633031786d790a686f737441646472" +
		"6573733d733a3139322e3136382e312e3132350a6170702e6e616d653d73" +
		"3a576f726b62656e63680a6170702e76657273696f6e3d733a332e372e34" +
		"340a766d2e6e616d653d733a4a61766120486f7453706f7428544d292053" +
		"657276657220564d0a766d2e76657273696f6e3d733a32302e342d623032" +
		"0a6f732e6e616d653d733a57696e646f77732058500a6f732e7665727369" +
		"6f6e3d733a352e310a6c616e673d733a656e0a74696d655a6f6e653d733a" +
		"416d65726963612f4c6f735f416e67656c65733b2d32383830303030303b" +
		"333630303030303b30323a30303a30302e3030302c77616c6c2c6d617263" +
		"682c382c6f6e206f722061667465722c73756e6461792c756e646566696e" +
		"65643b30323a30303a30302e3030302c77616c6c2c6e6f76656d6265722c" +
		"312c6f6e206f722061667465722c73756e6461792c756e646566696e6564" +
		"0a686f737449643d733a57696e2d393943422d443439442d353434322d30" +
		"3742420a766d557569643d733a38623533306263382d373663352d343133" +
		"392d613265612d3066616264333934643330350a6272616e6449643d733a" +
		"76796b6f6e0a7d3b3b0a"
	RESPONSE_PREFIX = "fox a 0 -1 fox hello"
)

func GetFoxBanner(logStruct *FoxLog, connection net.Conn) error {
	queryBytes, err := hex.DecodeString(ORIGINAL_QUERY)
	if err != nil {
		return err
	}

	bytesWritten, err := connection.Write(queryBytes)
	if bytesWritten != len(queryBytes) {
		return errors.New("Unable to write all Fox query bytes...")
	}
	if err != nil {
		return err
	}

	readBuffer := make([]byte, 8196)
	bytesRead, err := connection.Read(readBuffer)
	if bytesRead == len(readBuffer) {
		return errors.New("Need a bigger buffer to read Fox response")
	}
	if err != nil {
		return err
	}

	responseString := string(readBuffer[0:bytesRead])
	output := strings.Split(responseString, string(0x0a))

	if strings.HasPrefix(responseString, RESPONSE_PREFIX) {
		logStruct.IsFox = true

		for _, value := range output {
			if strings.HasPrefix(value, "fox.version") && strings.Contains(value, ":") {
				logStruct.Version = strings.Split(value, ":")[1]
			} else if strings.HasPrefix(value, "id") && strings.Contains(value, ":") {
				id, err := strconv.ParseUint(strings.Split(value, ":")[1], 10, 32)
				if err != nil {
					return err
				}
				logStruct.Id = uint32(id)
			} else if strings.HasPrefix(value, "hostAddress") && strings.Contains(value, ":") {
				logStruct.HostAddress = strings.Split(value, ":")[1]
			} else if strings.HasPrefix(value, "hostName") && strings.Contains(value, ":") {
				logStruct.Hostname = strings.Split(value, ":")[1]
			} else if strings.HasPrefix(value, "app.name") && strings.Contains(value, ":") {
				logStruct.AppName = strings.Split(value, ":")[1]
			} else if strings.HasPrefix(value, "app.version") && strings.Contains(value, ":") {
				logStruct.AppVersion = strings.Split(value, ":")[1]
			} else if strings.HasPrefix(value, "vm.name") && strings.Contains(value, ":") {
				logStruct.VMName = strings.Split(value, ":")[1]
			} else if strings.HasPrefix(value, "vm.version") && strings.Contains(value, ":") {
				logStruct.VMVersion = strings.Split(value, ":")[1]
			} else if strings.HasPrefix(value, "os.name") && strings.Contains(value, ":") {
				logStruct.OSName = strings.Split(value, ":")[1]
			} else if strings.HasPrefix(value, "os.version") && strings.Contains(value, ":") {
				logStruct.OSVersion = strings.Split(value, ":")[1]
			} else if strings.HasPrefix(value, "station.name") && strings.Contains(value, ":") {
				logStruct.StationName = strings.Split(value, ":")[1]
			} else if strings.HasPrefix(value, "lang") && strings.Contains(value, ":") {
				logStruct.Language = strings.Split(value, ":")[1]
			} else if strings.HasPrefix(value, "timeZone") && strings.Contains(value, ":") {
				timeZone := strings.Split(value, ":")[1]
				if strings.Contains(timeZone, ";") {
					timeZone = strings.Split(timeZone, ";")[0]
				}
				logStruct.TimeZone = timeZone
			} else if strings.HasPrefix(value, "hostId") && strings.Contains(value, ":") {
				logStruct.HostId = strings.Split(value, ":")[1]
			} else if strings.HasPrefix(value, "vmUuid") && strings.Contains(value, ":") {
				logStruct.VMUuid = strings.Split(value, ":")[1]
			} else if strings.HasPrefix(value, "brandId") && strings.Contains(value, ":") {
				logStruct.BrandId = strings.Split(value, ":")[1]
			} else if strings.HasPrefix(value, "sysInfo") && strings.Contains(value, ":") {
				logStruct.SysInfo = strings.Split(value, ":")[1]
			} else if strings.HasPrefix(value, "authAgentTypeSpecs") && strings.Contains(value, ":") {
				logStruct.AuthAgentType = strings.Split(value, ":")[1]
			}
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package common

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"strings"

	"github.com/Sirupsen/logrus"
)

type textFormatter struct {
}

// Based off logrus.TextFormatter, which behaves completely
// differently when you don't want colored output
func (f *textFormatter) Format(entry *logrus.Entry) ([]byte, error) {
	b := &bytes.Buffer{}

	levelText := strings.ToUpper(entry.Level.String())[0:4]
	timeStamp := entry.Time.Format("2006/01/02 15:04:05.000000")
	fmt.Fprintf(b, "%s: %s %-44s ", levelText, timeStamp, entry.Message)
	for k, v := range entry.Data {
		fmt.Fprintf(b, " %s=%v", k, v)
	}

	b.WriteByte('\n')
	return b.Bytes(), nil
}

var (
	standardTextFormatter = &textFormatter{}
)

var (
	Log    *logrus.Logger
	Info   *logrus.Logger
	debugF bool
)

func InitLogging(debugHandle io.Writer,
	infoHandle io.Writer,
	warningHandle io.Writer,
	errorHandle io.Writer) {

	Info = &logrus.Logger{
		Out:       infoHandle,
		Formatter: standardTextFormatter,
		Hooks:     make(logrus.LevelHooks),
		Level:     logrus.InfoLevel,
	}
	Log = Info
}

func InitDefaultLogging(debug bool) {
	if debug == debugF {
		return
	}
	debugF = debug
	debugOut := ioutil.Discard
	if debug {
		debugOut = os.Stderr
	}
	InitLogging(debugOut, os.Stdout, os.Stdout, os.Stderr)
}
<commit_msg>Adjust logrus feature of padding all lines less than 44 chars with spaces at the end<commit_after>package common

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"strings"

	"github.com/Sirupsen/logrus"
)

type textFormatter struct {
}

// Based off logrus.TextFormatter, which behaves completely
// differently when you don't want colored output
func (f *textFormatter) Format(entry *logrus.Entry) ([]byte, error) {
	b := &bytes.Buffer{}

	levelText := strings.ToUpper(entry.Level.String())[0:4]
	timeStamp := entry.Time.Format("2006/01/02 15:04:05.000000")
	if len(entry.Data) > 0 {
		fmt.Fprintf(b, "%s: %s %-44s ", levelText, timeStamp, entry.Message)
		for k, v := range entry.Data {
			fmt.Fprintf(b, " %s=%v", k, v)
		}
	} else {
		// No padding when there's no fields
		fmt.Fprintf(b, "%s: %s %s", levelText, timeStamp, entry.Message)
	}

	b.WriteByte('\n')
	return b.Bytes(), nil
}

var (
	standardTextFormatter = &textFormatter{}
)

var (
	Log    *logrus.Logger
	Info   *logrus.Logger
	debugF bool
)

func InitLogging(debugHandle io.Writer,
	infoHandle io.Writer,
	warningHandle io.Writer,
	errorHandle io.Writer) {

	Info = &logrus.Logger{
		Out:       infoHandle,
		Formatter: standardTextFormatter,
		Hooks:     make(logrus.LevelHooks),
		Level:     logrus.InfoLevel,
	}
	Log = Info
}

func InitDefaultLogging(debug bool) {
	if debug == debugF {
		return
	}
	debugF = debug
	debugOut := ioutil.Discard
	if debug {
		debugOut = os.Stderr
	}
	InitLogging(debugOut, os.Stdout, os.Stdout, os.Stderr)
}
<|endoftext|>


<commit_before>// Copyright 2015 Hajime Hoshi
//
// 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.

// +build js

package driver

import (
	"errors"
	"strings"

	"github.com/gopherjs/gopherjs/js"
)

type Player struct {
	sampleRate        int
	channelNum        int
	bytesPerSample    int
	positionInSamples int64
	bufferedData      []byte
	context           *js.Object
}

func isIOS() bool {
	ua := js.Global.Get("navigator").Get("userAgent").String()
	if !strings.Contains(ua, "iPhone") {
		return false
	}
	return true
}

func NewPlayer(sampleRate, channelNum, bytesPerSample int) (*Player, error) {
	class := js.Global.Get("AudioContext")
	if class == js.Undefined {
		class = js.Global.Get("webkitAudioContext")
	}
	if class == js.Undefined {
		return nil, errors.New("driver: audio couldn't be initialized")
	}
	p := &Player{
		sampleRate:     sampleRate,
		channelNum:     channelNum,
		bytesPerSample: bytesPerSample,
		bufferedData:   []byte{},
		context:        class.New(),
	}
	// iOS requires touch event to use AudioContext.
	if isIOS() {
		js.Global.Get("document").Call("addEventListener", "touchend", func() {
			p.context.Call("createBufferSource").Call("start", 0)
			p.positionInSamples = int64(p.context.Get("currentTime").Float() * float64(p.sampleRate))
		})
	}
	p.positionInSamples = int64(p.context.Get("currentTime").Float() * float64(p.sampleRate))
	return p, nil
}

func toLR(data []byte) ([]int16, []int16) {
	l := make([]int16, len(data)/4)
	r := make([]int16, len(data)/4)
	for i := 0; i < len(data)/4; i++ {
		l[i] = int16(data[4*i]) | int16(data[4*i+1])<<8
		r[i] = int16(data[4*i+2]) | int16(data[4*i+3])<<8
	}
	return l, r
}

func (p *Player) Proceed(data []byte) error {
	p.bufferedData = append(p.bufferedData, data...)
	c := int64(p.context.Get("currentTime").Float() * float64(p.sampleRate))
	if p.positionInSamples < c {
		p.positionInSamples = c
	}
	// Looks like low sample rate (e.g. 22050) requires a quite long buffer (#205).
	// 4096 is not perfect but it reduce noise to some extent.
	const dataSize = 4096
	for dataSize <= len(p.bufferedData) {
		data := p.bufferedData[:dataSize]
		size := len(data) / p.bytesPerSample / p.channelNum
		// TODO: size must be const or you'll get noise (e.g. sample rate is 22050)
		buf := p.context.Call("createBuffer", p.channelNum, size, p.sampleRate)
		l := buf.Call("getChannelData", 0)
		r := buf.Call("getChannelData", 1)
		il, ir := toLR(data)
		const max = 1 << 15
		for i := 0; i < len(il); i++ {
			l.SetIndex(i, float64(il[i])/max)
			r.SetIndex(i, float64(ir[i])/max)
		}
		s := p.context.Call("createBufferSource")
		s.Set("buffer", buf)
		s.Call("connect", p.context.Get("destination"))
		s.Call("start", float64(p.positionInSamples)/float64(p.sampleRate))
		p.positionInSamples += int64(len(il))
		p.bufferedData = p.bufferedData[dataSize:]
	}
	return nil
}

func (p *Player) Close() error {
	return nil
}
<commit_msg>audio: Bug fix: Touch is required by Chrome 55+ on Android<commit_after>// Copyright 2015 Hajime Hoshi
//
// 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.

// +build js

package driver

import (
	"errors"
	"strings"

	"github.com/gopherjs/gopherjs/js"
)

type Player struct {
	sampleRate        int
	channelNum        int
	bytesPerSample    int
	positionInSamples int64
	bufferedData      []byte
	context           *js.Object
}

func isIOS() bool {
	ua := js.Global.Get("navigator").Get("userAgent").String()
	if !strings.Contains(ua, "iPhone") {
		return false
	}
	return true
}

func isAndroidChrome() bool {
	ua := js.Global.Get("navigator").Get("userAgent").String()
	if !strings.Contains(ua, "Android") {
		return false
	}
	if !strings.Contains(ua, "Chrome") {
		return false
	}
	return true
}

func NewPlayer(sampleRate, channelNum, bytesPerSample int) (*Player, error) {
	class := js.Global.Get("AudioContext")
	if class == js.Undefined {
		class = js.Global.Get("webkitAudioContext")
	}
	if class == js.Undefined {
		return nil, errors.New("driver: audio couldn't be initialized")
	}
	p := &Player{
		sampleRate:     sampleRate,
		channelNum:     channelNum,
		bytesPerSample: bytesPerSample,
		bufferedData:   []byte{},
		context:        class.New(),
	}
	// iOS and Android Chrome requires touch event to use AudioContext.
	if isIOS() || isAndroidChrome() {
		js.Global.Get("document").Call("addEventListener", "touchend", func() {
			// Resuming is necessary as of Chrome 55+ in some cases like different
			// domain page in an iframe.
			p.context.Call("resume")
			p.context.Call("createBufferSource").Call("start", 0)
			p.positionInSamples = int64(p.context.Get("currentTime").Float() * float64(p.sampleRate))
		})
	}
	p.positionInSamples = int64(p.context.Get("currentTime").Float() * float64(p.sampleRate))
	return p, nil
}

func toLR(data []byte) ([]int16, []int16) {
	l := make([]int16, len(data)/4)
	r := make([]int16, len(data)/4)
	for i := 0; i < len(data)/4; i++ {
		l[i] = int16(data[4*i]) | int16(data[4*i+1])<<8
		r[i] = int16(data[4*i+2]) | int16(data[4*i+3])<<8
	}
	return l, r
}

func (p *Player) Proceed(data []byte) error {
	p.bufferedData = append(p.bufferedData, data...)
	c := int64(p.context.Get("currentTime").Float() * float64(p.sampleRate))
	if p.positionInSamples < c {
		p.positionInSamples = c
	}
	// Looks like low sample rate (e.g. 22050) requires a quite long buffer (#205).
	// 4096 is not perfect but it reduce noise to some extent.
	const dataSize = 4096
	for dataSize <= len(p.bufferedData) {
		data := p.bufferedData[:dataSize]
		size := len(data) / p.bytesPerSample / p.channelNum
		// TODO: size must be const or you'll get noise (e.g. sample rate is 22050)
		buf := p.context.Call("createBuffer", p.channelNum, size, p.sampleRate)
		l := buf.Call("getChannelData", 0)
		r := buf.Call("getChannelData", 1)
		il, ir := toLR(data)
		const max = 1 << 15
		for i := 0; i < len(il); i++ {
			l.SetIndex(i, float64(il[i])/max)
			r.SetIndex(i, float64(ir[i])/max)
		}
		s := p.context.Call("createBufferSource")
		s.Set("buffer", buf)
		s.Call("connect", p.context.Get("destination"))
		s.Call("start", float64(p.positionInSamples)/float64(p.sampleRate))
		p.positionInSamples += int64(len(il))
		p.bufferedData = p.bufferedData[dataSize:]
	}
	return nil
}

func (p *Player) Close() error {
	return nil
}
<|endoftext|>


<commit_before>package availability_test

import (
	"fmt"
	"sync"
	"time"

	"availability/helpers"

	vegeta "github.com/tsenart/vegeta/lib"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

const (
	availabilityTestRate             = 10
	availabilityTestMaxDuration      = 2 * time.Hour
	availabilityTestMaxLatency       = 300 * time.Millisecond
	availabilityTestMaxErrors        = 0
	availabilitySuccessRateThreshold = 99.9
	minimumTestDuration              = 15 * time.Second
	maximumErrorRate                 = 0.5

	vegetaRunForever = 0 * time.Second
	vegetaKeepAlive  = true
)

func loadTest(appUri string, endpoint string, rate uint64) (*vegeta.Attacker, <-chan *vegeta.Result) {
	targeter := vegeta.NewStaticTargeter(vegeta.Target{
		Method: "GET",
		URL:    appUri,
	})

	attacker := vegeta.NewAttacker(vegeta.KeepAlive(vegetaKeepAlive))
	res := attacker.Attack(targeter, rate, vegetaRunForever)

	return attacker, res
}

func errorRateThreshold(metrics *vegeta.Metrics, minimumTestDuration time.Duration, maximumErrorRate float64) bool {
	// metrics.Close() does trigger the computation of metrics, but does not stop any process
	metrics.Close()

	fmt.Printf(
		" - Duration: %s, Requests: %d, Non 200 Requests: %d, Success Rate: %.2f%%\n",
		metrics.Duration,
		metrics.Requests,
		metrics.Requests-uint64(metrics.StatusCodes["200"]),
		metrics.Success*100,
	)

	if metrics.Duration > minimumTestDuration {
		if metrics.Success < (1 - maximumErrorRate) {
			return true
		}
	}
	return false
}

var _ = Describe("Availability test", func() {

	var metrics vegeta.Metrics
	var metricsLock sync.Mutex
	var stopAttackCriteria func() bool

	Context("when runs (until the deployment is finished or error rate > 50%)", func() {
		var attacker *vegeta.Attacker
		var resultChannel <-chan *vegeta.Result

		BeforeEach(func() {
			stopAttackCriteria = func() bool {
				if helpers.DeploymentHasFinishedInConcourse() {
					return true
				}
				metricsLock.Lock()
				defer metricsLock.Unlock()
				if errorRateThreshold(&metrics, minimumTestDuration, maximumErrorRate) {
					return true
				}
				return false
			}
		})

		It(fmt.Sprintf("does not get request success rate less than %.2f%%", availabilitySuccessRateThreshold), func() {
			appUri := "https://healthcheck." + helpers.GetAppsDomainZoneName() + "/?availability-test=" + helpers.GetResourceVersion()

			attacker, resultChannel = loadTest(appUri, "/", availabilityTestRate)
			defer attacker.Stop()

			var wg sync.WaitGroup
			wg.Add(1)
			go func() {
				defer wg.Done()
				for res := range resultChannel {
					metricsLock.Lock()
					metrics.Add(res)
					metricsLock.Unlock()
				}
			}()

			Eventually(
				stopAttackCriteria,
				availabilityTestMaxDuration,
				5*time.Second,
			).Should(BeTrue(), "Deployment did not finish in the expected time")

			attacker.Stop()
			wg.Wait() // Ensure all results have been collected.

			metrics.Close()
			Expect(metrics.Success*100).To(
				BeNumerically(">=", availabilitySuccessRateThreshold),
				"Errors detected during the attack: %v", metrics.Errors,
			)
		})
	})

})
<commit_msg>Increase required request success ratio to 100%<commit_after>package availability_test

import (
	"fmt"
	"sync"
	"time"

	"availability/helpers"

	vegeta "github.com/tsenart/vegeta/lib"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

const (
	availabilityTestRate             = 10
	availabilityTestMaxDuration      = 2 * time.Hour
	availabilityTestMaxLatency       = 300 * time.Millisecond
	availabilityTestMaxErrors        = 0
	availabilitySuccessRateThreshold = 100.0
	minimumTestDuration              = 15 * time.Second
	maximumErrorRate                 = 0.5

	vegetaRunForever = 0 * time.Second
	vegetaKeepAlive  = true
)

func loadTest(appUri string, endpoint string, rate uint64) (*vegeta.Attacker, <-chan *vegeta.Result) {
	targeter := vegeta.NewStaticTargeter(vegeta.Target{
		Method: "GET",
		URL:    appUri,
	})

	attacker := vegeta.NewAttacker(vegeta.KeepAlive(vegetaKeepAlive))
	res := attacker.Attack(targeter, rate, vegetaRunForever)

	return attacker, res
}

func errorRateThreshold(metrics *vegeta.Metrics, minimumTestDuration time.Duration, maximumErrorRate float64) bool {
	// metrics.Close() does trigger the computation of metrics, but does not stop any process
	metrics.Close()

	fmt.Printf(
		" - Duration: %s, Requests: %d, Non 200 Requests: %d, Success Rate: %.2f%%\n",
		metrics.Duration,
		metrics.Requests,
		metrics.Requests-uint64(metrics.StatusCodes["200"]),
		metrics.Success*100,
	)

	if metrics.Duration > minimumTestDuration {
		if metrics.Success < (1 - maximumErrorRate) {
			return true
		}
	}
	return false
}

var _ = Describe("Availability test", func() {

	var metrics vegeta.Metrics
	var metricsLock sync.Mutex
	var stopAttackCriteria func() bool

	Context("when runs (until the deployment is finished or error rate > 50%)", func() {
		var attacker *vegeta.Attacker
		var resultChannel <-chan *vegeta.Result

		BeforeEach(func() {
			stopAttackCriteria = func() bool {
				if helpers.DeploymentHasFinishedInConcourse() {
					return true
				}
				metricsLock.Lock()
				defer metricsLock.Unlock()
				if errorRateThreshold(&metrics, minimumTestDuration, maximumErrorRate) {
					return true
				}
				return false
			}
		})

		It(fmt.Sprintf("does not get request success rate less than %.2f%%", availabilitySuccessRateThreshold), func() {
			appUri := "https://healthcheck." + helpers.GetAppsDomainZoneName() + "/?availability-test=" + helpers.GetResourceVersion()

			attacker, resultChannel = loadTest(appUri, "/", availabilityTestRate)
			defer attacker.Stop()

			var wg sync.WaitGroup
			wg.Add(1)
			go func() {
				defer wg.Done()
				for res := range resultChannel {
					metricsLock.Lock()
					metrics.Add(res)
					metricsLock.Unlock()
				}
			}()

			Eventually(
				stopAttackCriteria,
				availabilityTestMaxDuration,
				5*time.Second,
			).Should(BeTrue(), "Deployment did not finish in the expected time")

			attacker.Stop()
			wg.Wait() // Ensure all results have been collected.

			metrics.Close()
			Expect(metrics.Success*100).To(
				BeNumerically(">=", availabilitySuccessRateThreshold),
				"Errors detected during the attack: %v", metrics.Errors,
			)
		})
	})

})
<|endoftext|>


<commit_before>// Title：表格，及其下属控件
//
// Description:
//
// Author:black
//
// Createtime:2013-08-08 09:29
//
// Version:1.0
//
// 修改历史:版本号 修改日期 修改人 修改说明
//
// 1.0 2013-08-08 09:29 black 创建文档
package lessgo

import (
	"bytes"
	"text/template"
)

type gridPanel struct {
	Entity      string       `xml:"entity,attr"`
	PageSize    int          `xml:"pageSize,attr"`
	LoadUrl     string       `xml:"loadUrl,attr"`
	Id          string       `xml:"id,attr"`
	Title       string       `xml:"title,attr"`
	Width       string       `xml:"width,attr"`
	Height      string       `xml:"height,attr"`
	MutiSelect  string       `xml:"mutiSelect,attr"`
	Columns     []column     `xml:"column"`
	Actions     []action     `xml:"action"`
	Searchs     []search     `xml:"search"`
	ToolActions []toolaction `xml:"toolaction"`
}

//link目前可以支持，直接跳转，打开浏览器新窗口跳转，iframe弹窗，询问提示窗
//linkType=currentPage，
//以下为通用配置
//url 必填
//iconUrl 选填 如果有配置iconUrl，则会生成一个可点击的图标
//loadParamName 选填，不填就不带参数
//loadParamValue 如果loadParamName有值，则此配置必填，可取值为id 或者 this
type column struct {
	Field     string `xml:"field,attr"`
	Desc      string `xml:"desc,attr"`
	Hidden    string `xml:"hidden,attr"`
	Formatter string `xml:"formatter"`
}

type action struct {
	Desc         string `xml:"desc,attr"`
	Url          string `xml:"url,attr"`
	ActionParams string `xml:"actionParams,attr"`
	LinkType     string `xml:"linkType,attr"`
	Width        string `xml:"width,attr"`
	Height       string `xml:"height,attr"`
	Title        string `xml:"title,attr"`
}

type toolaction struct {
	Desc       string `xml:"desc,attr"`
	Url        string `xml:"url,attr"`
	LinkType   string `xml:"linkType,attr"`
	ColorClass string `xml:"colorClass,attr"`

	//for iframeWindow
	Width  string `xml:"width,attr"`
	Height string `xml:"height,attr"`
	Title  string `xml:"title,attr"`

	//for mutiSelect
	ConfirmMsg string `xml:"confirmMsg,attr"`
	Params     string `xml:"params,attr"`
}

type search struct {
	Field      string `xml:"field,attr"`
	SearchType string `xml:"searchType,attr"`
	InputType  string `xml:"inputType,attr"`
	LocalData  string `xml:"localData,attr"`
	Desc       string `xml:"desc,attr"`
	Url        string `xml:"url,attr"`
	ValueField string `xml:"valueField,attr"`
	DescField  string `xml:"descField,attr"`
	//存储实际的搜索值
	Value string
}

func (gridpanel gridPanel) generate(entity Entity, terminal, packageName string) []byte {

	var t *template.Template

	var buf bytes.Buffer

	gridpanel.Id = packageName + "." + gridpanel.Id

	runtimeComponentContain[gridpanel.Id] = gridpanel

	t = template.New("gridpanel.html")

	t = t.Funcs(template.FuncMap{
		"getComponentId": getComponentId,
		"compareInt":     CompareInt,
		"compareString":  CompareString,
	})

	t, err := t.ParseFiles("../lessgo/template/component/" + terminal + "/gridpanel.html")

	if err != nil {
		Log.Error(err.Error())
		return []byte{}
	}

	data := make(map[string]interface{})

	data["Gridpanel"] = gridpanel
	data["Entity"] = entity
	data["Terminal"] = terminal
	data["SearchLength"] = len(gridpanel.Searchs)
	data["ActionLength"] = len(gridpanel.Actions)

	err = t.Execute(&buf, data)

	if err != nil {
		Log.Error(err.Error())
		return []byte{}
	}

	return buf.Bytes()

}
<commit_msg>弹窗大小自己调整到最大，弹窗状态下菜单可以点击，弹窗中的按钮固定位置，避免保存的时候要上下翻动<commit_after>// Title：表格，及其下属控件
//
// Description:
//
// Author:black
//
// Createtime:2013-08-08 09:29
//
// Version:1.0
//
// 修改历史:版本号 修改日期 修改人 修改说明
//
// 1.0 2013-08-08 09:29 black 创建文档
package lessgo

import (
	"bytes"
	"text/template"
)

type gridPanel struct {
	Entity      string       `xml:"entity,attr"`
	PageSize    int          `xml:"pageSize,attr"`
	LoadUrl     string       `xml:"loadUrl,attr"`
	Id          string       `xml:"id,attr"`
	Title       string       `xml:"title,attr"`
	Width       string       `xml:"width,attr"`
	Height      string       `xml:"height,attr"`
	MutiSelect  string       `xml:"mutiSelect,attr"`
	Columns     []column     `xml:"column"`
	Actions     []action     `xml:"action"`
	Searchs     []search     `xml:"search"`
	ToolActions []toolaction `xml:"toolaction"`
}

//link目前可以支持，直接跳转，打开浏览器新窗口跳转，iframe弹窗，询问提示窗
//linkType=currentPage，
//以下为通用配置
//url 必填
//iconUrl 选填 如果有配置iconUrl，则会生成一个可点击的图标
//loadParamName 选填，不填就不带参数
//loadParamValue 如果loadParamName有值，则此配置必填，可取值为id 或者 this
type column struct {
	Field     string `xml:"field,attr"`
	Desc      string `xml:"desc,attr"`
	Hidden    string `xml:"hidden,attr"`
	Formatter string `xml:"formatter"`
}

type action struct {
	Desc         string `xml:"desc,attr"`
	Url          string `xml:"url,attr"`
	ActionParams string `xml:"actionParams,attr"`
	LinkType     string `xml:"linkType,attr"`
}

type toolaction struct {
	Desc       string `xml:"desc,attr"`
	Url        string `xml:"url,attr"`
	LinkType   string `xml:"linkType,attr"`
	ColorClass string `xml:"colorClass,attr"`

	//for mutiSelect
	ConfirmMsg string `xml:"confirmMsg,attr"`
	Params     string `xml:"params,attr"`
}

type search struct {
	Field      string `xml:"field,attr"`
	SearchType string `xml:"searchType,attr"`
	InputType  string `xml:"inputType,attr"`
	LocalData  string `xml:"localData,attr"`
	Desc       string `xml:"desc,attr"`
	Url        string `xml:"url,attr"`
	ValueField string `xml:"valueField,attr"`
	DescField  string `xml:"descField,attr"`
	//存储实际的搜索值
	Value string
}

func (gridpanel gridPanel) generate(entity Entity, terminal, packageName string) []byte {

	var t *template.Template

	var buf bytes.Buffer

	gridpanel.Id = packageName + "." + gridpanel.Id

	runtimeComponentContain[gridpanel.Id] = gridpanel

	t = template.New("gridpanel.html")

	t = t.Funcs(template.FuncMap{
		"getComponentId": getComponentId,
		"compareInt":     CompareInt,
		"compareString":  CompareString,
	})

	t, err := t.ParseFiles("../lessgo/template/component/" + terminal + "/gridpanel.html")

	if err != nil {
		Log.Error(err.Error())
		return []byte{}
	}

	data := make(map[string]interface{})

	data["Gridpanel"] = gridpanel
	data["Entity"] = entity
	data["Terminal"] = terminal
	data["SearchLength"] = len(gridpanel.Searchs)
	data["ActionLength"] = len(gridpanel.Actions)

	err = t.Execute(&buf, data)

	if err != nil {
		Log.Error(err.Error())
		return []byte{}
	}

	return buf.Bytes()

}
<|endoftext|>