<commit_before>package main

import "testing"

func Test_findUniversalAPKPair(t *testing.T) {
	tests := []struct {
		name string
		aab  string
		apks []string
		want string
	}{
		{
			name: "Only universal apk can be the pair",
			aab:  "app-minApi21-demo-debug-bitrise-signed.aab",
			apks: []string{"app-minApi21-demo-debug.apk"},
			want: "",
		},
		{
			name: "Finds if aab is bitrise-signed",
			aab:  "app-minApi21-demo-debug-bitrise-signed.aab",
			apks: []string{"app-minApi21-demo-universal-debug.apk"},
			want: "app-minApi21-demo-universal-debug.apk",
		},
		{
			name: "Finds if aab is bitrise-signed, even if apk is unsigned",
			aab:  "app-minApi21-demo-debug-bitrise-signed.aab",
			apks: []string{"app-minApi21-demo-universal-debug-unsigned.apk"},
			want: "app-minApi21-demo-universal-debug-unsigned.apk",
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := findUniversalAPKPair(tt.aab, tt.apks); got != tt.want {
				t.Errorf("findUniversalAPKPair() = %v, want %v", got, tt.want)
			}
		})
	}
}
<commit_msg>Test that output is formatted correctly if too many artifacts are deployed (#130)<commit_after>package main

import (
	"html/template"
	"testing"
)

func Test_findUniversalAPKPair(t *testing.T) {
	tests := []struct {
		name string
		aab  string
		apks []string
		want string
	}{
		{
			name: "Only universal apk can be the pair",
			aab:  "app-minApi21-demo-debug-bitrise-signed.aab",
			apks: []string{"app-minApi21-demo-debug.apk"},
			want: "",
		},
		{
			name: "Finds if aab is bitrise-signed",
			aab:  "app-minApi21-demo-debug-bitrise-signed.aab",
			apks: []string{"app-minApi21-demo-universal-debug.apk"},
			want: "app-minApi21-demo-universal-debug.apk",
		},
		{
			name: "Finds if aab is bitrise-signed, even if apk is unsigned",
			aab:  "app-minApi21-demo-debug-bitrise-signed.aab",
			apks: []string{"app-minApi21-demo-universal-debug-unsigned.apk"},
			want: "app-minApi21-demo-universal-debug-unsigned.apk",
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := findUniversalAPKPair(tt.aab, tt.apks); got != tt.want {
				t.Errorf("findUniversalAPKPair() = %v, want %v", got, tt.want)
			}
		})
	}
}

func Test_generateUrlOutputWithTemplate(t *testing.T) {
	defaultTemplate := "{{range $index, $element := .}}{{if $index}}|{{end}}{{$element.File}}=>{{$element.URL}}{{end}}"
	temp := template.New("test")
	temp, err := temp.Parse(defaultTemplate)
	if err != nil {
		t.Errorf("error during parsing: %s", err)
	}
	tests := []struct {
		name         string
		pages        []PublicInstallPage
		maxEnvLength int
		want         string
		wantWarn     bool
	}{
		{
			name:         "Empty list gives empty value",
			pages:        []PublicInstallPage{},
			maxEnvLength: 100,
			want:         "",
		},
		{
			name: "All content fits the variable",
			pages: []PublicInstallPage{
				{
					File: "Foo",
					URL:  "Bar",
				},
			},
			maxEnvLength: 100,
			want:         "Foo=>Bar",
		},
		{
			name: "One item doesn't fit",
			pages: []PublicInstallPage{
				{
					File: "Foo",
					URL:  "Bar",
				},
				{
					File: "Baz",
					URL:  "Qux",
				},
			},
			maxEnvLength: 10,
			want:         "Foo=>Bar",
			wantWarn:     true,
		},
		{
			name: "Multiple items doesn't fit",
			pages: []PublicInstallPage{
				{
					File: "Foo",
					URL:  "Bar",
				},
				{
					File: "Baz",
					URL:  "Qux",
				},
				{
					File: "Apple",
					URL:  "Pear",
				},
				{
					File: "Peach",
					URL:  "Grapes",
				},
			},
			maxEnvLength: 20,
			want:         "Foo=>Bar|Baz=>Qux",
			wantWarn:     true,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got, gotWarn, err := applyTemplateWithMaxSize(temp, tt.pages, tt.maxEnvLength)
			if err != nil {
				t.Errorf("applyTemplateWithMaxSize() error: %s", err)
			}
			if gotWarn != tt.wantWarn {
				t.Errorf("applyTemplateWithMaxSize() warning = %v, want %v", gotWarn, tt.wantWarn)
			}
			if got != tt.want {
				t.Errorf("applyTemplateWithMaxSize() = %v, want %v", got, tt.want)
			}
		})
	}
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"os/exec"
	"testing"
)

func TestInit(t *testing.T) {
	err := os.Setenv("LHCBPROJECTPATH", "testdata/projects")
	if err != nil {
		t.Fatalf("error setting LHCBPROJECTPATH: %v\n", err)
	}

	_ = os.RemoveAll("GaudiDev_trunk")

	cmd := exec.Command("lbx", "init", "-lvl=-2", "gaudi")
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err = cmd.Run()
	if err != nil {
		t.Fatalf("error running lbx-init: %v\n", err)
	}
}
<commit_msg>test: cleanup tests hierarchy<commit_after>package main

import (
	"os"
	"os/exec"
	"testing"
)

func TestInit(t *testing.T) {
	err := os.Setenv("LHCBPROJECTPATH", "testdata/projects")
	if err != nil {
		t.Fatalf("error setting LHCBPROJECTPATH: %v\n", err)
	}

	_ = os.RemoveAll("testdata/test-init")

	cmd := exec.Command("lbx", "init", "-lvl=-2", "-user-area=testdata/test-init", "gaudi")
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err = cmd.Run()
	if err != nil {
		t.Fatalf("error running lbx-init: %v\n", err)
	}

	_ = os.RemoveAll("testdata/test-init")
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"testing"
)

func TestReadWriterPing(t *testing.T) {
	priv, pub := &[32]byte{'p', 'r', 'i', 'v'}, &[32]byte{'p', 'u', 'b'}

	r, w := io.Pipe()
	secureR := NewSecureReader(r, priv, pub)
	secureW := NewSecureWriter(w, priv, pub)

	// Encrypt hello world
	go func() {
		fmt.Fprintf(secureW, "hello world\n")
		w.Close()
	}()

	// Decrypt message
	buf := make([]byte, 1024)
	n, err := secureR.Read(buf)
	if err != nil && err != io.EOF {
		t.Fatal(err)
	}
	buf = buf[:n]

	// Make sure we have hello world back
	if res := string(buf); res != "hello world\n" {
		t.Fatalf("Unexpected result: %s != %s", res, "hello world")
	}
}

func TestSecureWriter(t *testing.T) {
	priv, pub := &[32]byte{'p', 'r', 'i', 'v'}, &[32]byte{'p', 'u', 'b'}

	r, w := io.Pipe()
	secureW := NewSecureWriter(w, priv, pub)

	// Make sure we are secure
	// Encrypt hello world
	go func() {
		fmt.Fprintf(secureW, "hello world\n")
		w.Close()
	}()

	// Read from the underlying transport instead of the decoder
	buf, err := ioutil.ReadAll(r)
	if err != nil {
		t.Fatal(err)
	}
	// Make sure we dont' read the plain text message.
	if res := string(buf); res == "hello world\n" {
		t.Fatal("Unexpected result. The message is not encrypted.")
	}

	r, w = io.Pipe()
	secureW = NewSecureWriter(w, priv, pub)

	// Make sure we are unique
	// Encrypt hello world
	go func() {
		fmt.Fprintf(secureW, "hello world\n")
		w.Close()
	}()

	// Read from the underlying transport instead of the decoder
	buf2, err := ioutil.ReadAll(r)
	if err != nil {
		t.Fatal(err)
	}
	// Make sure we dont' read the plain text message.
	if string(buf) == string(buf2) {
		t.Fatal("Unexpected result. The encrypted message is not unique.")
	}

}

func TestSecureEchoServer(t *testing.T) {
	// Create a random listener
	l, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		t.Fatal(err)
	}
	defer l.Close()

	// Start the server
	go Serve(l)

	conn, err := Dial(l.Addr().String())
	if err != nil {
		t.Fatal(err)
	}
	defer conn.Close()

	expected := "hello world 2\n"
	fmt.Println("wir rufen den rwc auf")
	if _, err := fmt.Fprintf(conn, expected); err != nil {
		t.Fatal(err)
	}

	buf := make([]byte, 2048)
	n, err := conn.Read(buf)
	if err != nil && err != io.EOF {
		t.Fatal(err)
	}
	fmt.Printf("das erwarte ich %v\n", []byte(expected))
	fmt.Printf("das bekomme ich als bytes %v\n", buf[:n])
	fmt.Printf("das bekomme ich %v\n", string(buf[:n]))
	if got := string(buf[:n]); got != expected {
		t.Fatalf("Unexpected result:\nGot:\t\t%s\nExpected:\t%s\n", got, expected)
	}
}

func TestSecureServe(t *testing.T) {
	// Create a random listener
	l, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		t.Fatal(err)
	}
	defer l.Close()

	// Start the server
	go Serve(l)

	conn, err := net.Dial("tcp", l.Addr().String())
	if err != nil {
		t.Fatal(err)
	}
	unexpected := "hello world 3\n"
	if _, err := fmt.Fprintf(conn, unexpected); err != nil {
		t.Fatal(err)
	}
	buf := make([]byte, 2048)
	n, err := conn.Read(buf)
	if err != nil && err != io.EOF {
		t.Fatal(err)
	}
	if got := string(buf[:n]); got == unexpected {
		t.Fatalf("Unexpected result:\nGot raw data instead of serialized key")
	}
}
<commit_msg>wir encrypten aber es funktioniert immernoch kein schlussel austausch<commit_after>package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"testing"
)

func TestReadWriterPing(t *testing.T) {
	priv, pub := &[32]byte{'p', 'r', 'i', 'v'}, &[32]byte{'p', 'u', 'b'}

	r, w := io.Pipe()
	secureR := NewSecureReader(r, priv, pub)
	secureW := NewSecureWriter(w, priv, pub)

	// Encrypt hello world
	go func() {
		fmt.Fprintf(secureW, "hello world\n")
		w.Close()
	}()

	// Decrypt message
	buf := make([]byte, 1024)
	n, err := secureR.Read(buf)
	if err != nil && err != io.EOF {
		t.Fatal(err)
	}
	buf = buf[:n]

	// Make sure we have hello world back
	if res := string(buf); res != "hello world\n" {
		t.Fatalf("Unexpected result: %s != %s", res, "hello world")
	}
}

func TestSecureWriter(t *testing.T) {
	priv, pub := &[32]byte{'p', 'r', 'i', 'v'}, &[32]byte{'p', 'u', 'b'}

	r, w := io.Pipe()
	secureW := NewSecureWriter(w, priv, pub)

	// Make sure we are secure
	// Encrypt hello world
	go func() {
		fmt.Fprintf(secureW, "hello world\n")
		w.Close()
	}()

	// Read from the underlying transport instead of the decoder
	buf, err := ioutil.ReadAll(r)
	if err != nil {
		t.Fatal(err)
	}
	// Make sure we dont' read the plain text message.
	if res := string(buf); res == "hello world\n" {
		t.Fatal("Unexpected result. The message is not encrypted.")
	}

	r, w = io.Pipe()
	secureW = NewSecureWriter(w, priv, pub)

	// Make sure we are unique
	// Encrypt hello world
	go func() {
		fmt.Fprintf(secureW, "hello world\n")
		w.Close()
	}()

	// Read from the underlying transport instead of the decoder
	buf2, err := ioutil.ReadAll(r)
	if err != nil {
		t.Fatal(err)
	}
	// Make sure we dont' read the plain text message.
	if string(buf) == string(buf2) {
		t.Fatal("Unexpected result. The encrypted message is not unique.")
	}

}

func TestSecureEchoServer(t *testing.T) {
	// Create a random listener
	l, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		t.Fatal(err)
	}
	defer l.Close()

	// Start the server
	go Serve(l)

	conn, err := Dial(l.Addr().String())
	if err != nil {
		t.Fatal(err)
	}
	defer conn.Close()

	expected := "hello world 2\n"
	fmt.Println("wir rufen den rwc auf")
	if _, err := fmt.Fprintf(conn, expected); err != nil {
		t.Fatal(err)
	}

	buf := make([]byte, 2048)
	n, err := conn.Read(buf)
	if err != nil && err != io.EOF {
		t.Fatal(err)
	}
	// 	fmt.Printf("das erwarte ich %v\n", []byte(expected))
	// 	fmt.Printf("das bekomme ich als bytes %v\n", buf[:n])
	// 	fmt.Printf("das bekomme ich %v\n", string(buf[:n]))
	if got := string(buf[:n]); got != expected {
		t.Fatalf("Unexpected result:\nGot:\t\t%s\nExpected:\t%s\n", got, expected)
	}
}

func TestSecureServe(t *testing.T) {
	// Create a random listener
	l, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		t.Fatal(err)
	}
	defer l.Close()

	// Start the server
	go Serve(l)

	conn, err := net.Dial("tcp", l.Addr().String())
	if err != nil {
		t.Fatal(err)
	}
	unexpected := "hello world 3\n"
	if _, err := fmt.Fprintf(conn, unexpected); err != nil {
		t.Fatal(err)
	}
	buf := make([]byte, 2048)
	n, err := conn.Read(buf)
	if err != nil && err != io.EOF {
		t.Fatal(err)
	}
	if got := string(buf[:n]); got == unexpected {
		t.Fatalf("Unexpected result:\nGot raw data instead of serialized key")
	}
}
<|endoftext|>


<commit_before>// Copyright 2017 Vector Creations Ltd
//
// 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 internal

import (
	"context"
	"fmt"
	"io"
	"net/http"
	"os"
	"path"
	"path/filepath"
	"runtime"
	"strings"

	"github.com/matrix-org/util"

	"github.com/matrix-org/dendrite/setup/config"
	"github.com/matrix-org/dugong"
	"github.com/sirupsen/logrus"
)

type utcFormatter struct {
	logrus.Formatter
}

func (f utcFormatter) Format(entry *logrus.Entry) ([]byte, error) {
	entry.Time = entry.Time.UTC()
	return f.Formatter.Format(entry)
}

// Logrus hook which wraps another hook and filters log entries according to their level.
// (Note that we cannot use solely logrus.SetLevel, because Dendrite supports multiple
// levels of logging at the same time.)
type logLevelHook struct {
	level logrus.Level
	logrus.Hook
}

// Levels returns all the levels supported by this hook.
func (h *logLevelHook) Levels() []logrus.Level {
	levels := make([]logrus.Level, 0)

	for _, level := range logrus.AllLevels {
		if level <= h.level {
			levels = append(levels, level)
		}
	}

	return levels
}

// callerPrettyfier is a function that given a runtime.Frame object, will
// extract the calling function's name and file, and return them in a nicely
// formatted way
func callerPrettyfier(f *runtime.Frame) (string, string) {
	// Retrieve just the function name
	s := strings.Split(f.Function, ".")
	funcname := s[len(s)-1]

	// Append a newline + tab to it to move the actual log content to its own line
	funcname += "\n\t"

	// Use a shortened file path which just has the filename to avoid having lots of redundant
	// directories which contribute significantly to overall log sizes!
	filename := fmt.Sprintf(" [%s:%d]", path.Base(f.File), f.Line)

	return funcname, filename
}

// SetupPprof starts a pprof listener. We use the DefaultServeMux here because it is
// simplest, and it gives us the freedom to run pprof on a separate port.
func SetupPprof() {
	if hostPort := os.Getenv("PPROFLISTEN"); hostPort != "" {
		logrus.Warn("Starting pprof on ", hostPort)
		go func() {
			logrus.WithError(http.ListenAndServe(hostPort, nil)).Error("Failed to setup pprof listener")
		}()
	}
}

// SetupStdLogging configures the logging format to standard output. Typically, it is called when the config is not yet loaded.
func SetupStdLogging() {
	logrus.SetReportCaller(true)
	logrus.SetFormatter(&utcFormatter{
		&logrus.TextFormatter{
			TimestampFormat:  "2006-01-02T15:04:05.000000000Z07:00",
			FullTimestamp:    true,
			DisableColors:    false,
			DisableTimestamp: false,
			QuoteEmptyFields: true,
			CallerPrettyfier: callerPrettyfier,
		},
	})
}

// SetupHookLogging configures the logging hooks defined in the configuration.
// If something fails here it means that the logging was improperly configured,
// so we just exit with the error
func SetupHookLogging(hooks []config.LogrusHook, componentName string) {
	logrus.SetReportCaller(true)
	for _, hook := range hooks {
		// Check we received a proper logging level
		level, err := logrus.ParseLevel(hook.Level)
		if err != nil {
			logrus.Fatalf("Unrecognised logging level %s: %q", hook.Level, err)
		}

		// Perform a first filter on the logs according to the lowest level of all
		// (Eg: If we have hook for info and above, prevent logrus from processing debug logs)
		if logrus.GetLevel() < level {
			logrus.SetLevel(level)
		}

		switch hook.Type {
		case "file":
			checkFileHookParams(hook.Params)
			setupFileHook(hook, level, componentName)
		default:
			logrus.Fatalf("Unrecognised logging hook type: %s", hook.Type)
		}
	}
}

// File type hooks should be provided a path to a directory to store log files
func checkFileHookParams(params map[string]interface{}) {
	path, ok := params["path"]
	if !ok {
		logrus.Fatalf("Expecting a parameter \"path\" for logging hook of type \"file\"")
	}

	if _, ok := path.(string); !ok {
		logrus.Fatalf("Parameter \"path\" for logging hook of type \"file\" should be a string")
	}
}

// Add a new FSHook to the logger. Each component will log in its own file
func setupFileHook(hook config.LogrusHook, level logrus.Level, componentName string) {
	dirPath := (hook.Params["path"]).(string)
	fullPath := filepath.Join(dirPath, componentName+".log")

	if err := os.MkdirAll(path.Dir(fullPath), os.ModePerm); err != nil {
		logrus.Fatalf("Couldn't create directory %s: %q", path.Dir(fullPath), err)
	}

	logrus.AddHook(&logLevelHook{
		level,
		dugong.NewFSHook(
			fullPath,
			&utcFormatter{
				&logrus.TextFormatter{
					TimestampFormat:  "2006-01-02T15:04:05.000000000Z07:00",
					DisableColors:    true,
					DisableTimestamp: false,
					DisableSorting:   false,
					QuoteEmptyFields: true,
				},
			},
			&dugong.DailyRotationSchedule{GZip: true},
		),
	})
}

//CloseAndLogIfError Closes io.Closer and logs the error if any
func CloseAndLogIfError(ctx context.Context, closer io.Closer, message string) {
	if closer == nil {
		return
	}
	err := closer.Close()
	if ctx == nil {
		ctx = context.TODO()
	}
	if err != nil {
		util.GetLogger(ctx).WithError(err).Error(message)
	}
}
<commit_msg>Syslog integration (#1952)<commit_after>// Copyright 2017 Vector Creations Ltd
//
// 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 internal

import (
	"context"
	"fmt"
	"io"
	"log/syslog"
	"net/http"
	"os"
	"path"
	"path/filepath"
	"runtime"
	"strings"

	"github.com/matrix-org/util"

	"github.com/matrix-org/dendrite/setup/config"
	"github.com/matrix-org/dugong"
	"github.com/sirupsen/logrus"
	lSyslog "github.com/sirupsen/logrus/hooks/syslog"
)

type utcFormatter struct {
	logrus.Formatter
}

func (f utcFormatter) Format(entry *logrus.Entry) ([]byte, error) {
	entry.Time = entry.Time.UTC()
	return f.Formatter.Format(entry)
}

// Logrus hook which wraps another hook and filters log entries according to their level.
// (Note that we cannot use solely logrus.SetLevel, because Dendrite supports multiple
// levels of logging at the same time.)
type logLevelHook struct {
	level logrus.Level
	logrus.Hook
}

// Levels returns all the levels supported by this hook.
func (h *logLevelHook) Levels() []logrus.Level {
	levels := make([]logrus.Level, 0)

	for _, level := range logrus.AllLevels {
		if level <= h.level {
			levels = append(levels, level)
		}
	}

	return levels
}

// callerPrettyfier is a function that given a runtime.Frame object, will
// extract the calling function's name and file, and return them in a nicely
// formatted way
func callerPrettyfier(f *runtime.Frame) (string, string) {
	// Retrieve just the function name
	s := strings.Split(f.Function, ".")
	funcname := s[len(s)-1]

	// Append a newline + tab to it to move the actual log content to its own line
	funcname += "\n\t"

	// Use a shortened file path which just has the filename to avoid having lots of redundant
	// directories which contribute significantly to overall log sizes!
	filename := fmt.Sprintf(" [%s:%d]", path.Base(f.File), f.Line)

	return funcname, filename
}

// SetupPprof starts a pprof listener. We use the DefaultServeMux here because it is
// simplest, and it gives us the freedom to run pprof on a separate port.
func SetupPprof() {
	if hostPort := os.Getenv("PPROFLISTEN"); hostPort != "" {
		logrus.Warn("Starting pprof on ", hostPort)
		go func() {
			logrus.WithError(http.ListenAndServe(hostPort, nil)).Error("Failed to setup pprof listener")
		}()
	}
}

// SetupStdLogging configures the logging format to standard output. Typically, it is called when the config is not yet loaded.
func SetupStdLogging() {
	logrus.SetReportCaller(true)
	logrus.SetFormatter(&utcFormatter{
		&logrus.TextFormatter{
			TimestampFormat:  "2006-01-02T15:04:05.000000000Z07:00",
			FullTimestamp:    true,
			DisableColors:    false,
			DisableTimestamp: false,
			QuoteEmptyFields: true,
			CallerPrettyfier: callerPrettyfier,
		},
	})
}

// SetupHookLogging configures the logging hooks defined in the configuration.
// If something fails here it means that the logging was improperly configured,
// so we just exit with the error
func SetupHookLogging(hooks []config.LogrusHook, componentName string) {
	logrus.SetReportCaller(true)
	for _, hook := range hooks {
		// Check we received a proper logging level
		level, err := logrus.ParseLevel(hook.Level)
		if err != nil {
			logrus.Fatalf("Unrecognised logging level %s: %q", hook.Level, err)
		}

		// Perform a first filter on the logs according to the lowest level of all
		// (Eg: If we have hook for info and above, prevent logrus from processing debug logs)
		if logrus.GetLevel() < level {
			logrus.SetLevel(level)
		}

		switch hook.Type {
		case "file":
			checkFileHookParams(hook.Params)
			setupFileHook(hook, level, componentName)
		case "syslog":
			checkSyslogHookParams(hook.Params)
			setupSyslogHook(hook, level, componentName)
		default:
			logrus.Fatalf("Unrecognised logging hook type: %s", hook.Type)
		}
	}
}

// File type hooks should be provided a path to a directory to store log files
func checkFileHookParams(params map[string]interface{}) {
	path, ok := params["path"]
	if !ok {
		logrus.Fatalf("Expecting a parameter \"path\" for logging hook of type \"file\"")
	}

	if _, ok := path.(string); !ok {
		logrus.Fatalf("Parameter \"path\" for logging hook of type \"file\" should be a string")
	}
}

// Add a new FSHook to the logger. Each component will log in its own file
func setupFileHook(hook config.LogrusHook, level logrus.Level, componentName string) {
	dirPath := (hook.Params["path"]).(string)
	fullPath := filepath.Join(dirPath, componentName+".log")

	if err := os.MkdirAll(path.Dir(fullPath), os.ModePerm); err != nil {
		logrus.Fatalf("Couldn't create directory %s: %q", path.Dir(fullPath), err)
	}

	logrus.AddHook(&logLevelHook{
		level,
		dugong.NewFSHook(
			fullPath,
			&utcFormatter{
				&logrus.TextFormatter{
					TimestampFormat:  "2006-01-02T15:04:05.000000000Z07:00",
					DisableColors:    true,
					DisableTimestamp: false,
					DisableSorting:   false,
					QuoteEmptyFields: true,
				},
			},
			&dugong.DailyRotationSchedule{GZip: true},
		),
	})
}

func checkSyslogHookParams(params map[string]interface{}) {
	addr, ok := params["address"]
	if !ok {
		logrus.Fatalf("Expecting a parameter \"address\" for logging hook of type \"syslog\"")
	}

	if _, ok := addr.(string); !ok {
		logrus.Fatalf("Parameter \"address\" for logging hook of type \"syslog\" should be a string")
	}

	proto, ok2 := params["protocol"]
	if !ok2 {
		logrus.Fatalf("Expecting a parameter \"protocol\" for logging hook of type \"syslog\"")
	}

	if _, ok2 := proto.(string); !ok2 {
		logrus.Fatalf("Parameter \"protocol\" for logging hook of type \"syslog\" should be a string")
	}

}

func setupSyslogHook(hook config.LogrusHook, level logrus.Level, componentName string) {
	syslogHook, err := lSyslog.NewSyslogHook(hook.Params["protocol"].(string), hook.Params["address"].(string), syslog.LOG_INFO, componentName)
	if err == nil {
		logrus.AddHook(&logLevelHook{level, syslogHook})
	}
}

//CloseAndLogIfError Closes io.Closer and logs the error if any
func CloseAndLogIfError(ctx context.Context, closer io.Closer, message string) {
	if closer == nil {
		return
	}
	err := closer.Close()
	if ctx == nil {
		ctx = context.TODO()
	}
	if err != nil {
		util.GetLogger(ctx).WithError(err).Error(message)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/rand"
	"encoding/base64"
	"flag"
	"fmt"
	"time"

	"github.com/dronemill/eventsocket-client-go"
)

var ticker = flag.Bool("ticker", false, "Do we write to the websocket connection as we tick?")
var requester = flag.Bool("requester", false, "Do we write to the websocket connection?")
var requestClientId = flag.String("requestClientId", "", "The clientId to send a request to")

func main() {
	flag.Parse()

	client, err := eventsocketclient.NewClient("127.0.0.1:8080")
	if err != nil {
		panic(err)
	}

	if err := client.DialWs(); err != nil {
		panic(err)
	}

	fmt.Printf("Connected! ClientId: %s\n", client.Id)

	if *ticker {
		go tick(client)
	}

	if *requester {
		go makeRequest(client)
	}

	go client.Recv()

	subChan, err := client.Suscribe("foo")
	if err != nil {
		panic(err)
	}

	for {
		select {
		case m := <-client.RecvBroadcast:
			if m.Err != nil {
				panic(m.Err)
			}
			fmt.Printf("BROADCAST err:%v :: %+v\n", m.Err, m.Message.Payload)
		case m := <-subChan:
			if m.Err != nil {
				panic(m.Err)
			}
			fmt.Printf("Foo: err:%v :: %+v\n", m.Err, m.Message.Payload)
		case m := <-client.RecvRequest:
			if m.Err != nil {
				panic(m.Err)
			}
			fmt.Printf("REQUEST err:%v :: %+v\n", m.Err, m.Message.Payload)
			p := eventsocketclient.NewPayload()
			p["I_SEE_YOU"] = randomString(32)
			if err := client.Reply(m.Message.RequestId, m.Message.ReplyClientId, &p); err != nil {
				panic(err)
			}
		}
	}
}

func makeRequest(client *eventsocketclient.Client) {
	p := eventsocketclient.NewPayload()
	p["PEEK_ABOO"] = randomString(32)

	res, err := client.Request(*requestClientId, &p)
	if err != nil {
		panic(err)
	}

	m := <-res

	fmt.Printf("REPLY err:%v :: %+v\n", m.Err, m.Message.Payload)
}

func tick(client *eventsocketclient.Client) {
	tickChan := time.NewTicker(time.Second).C

	for {
		select {
		case <-tickChan:
			p := eventsocketclient.NewPayload()
			p["awesomeValue"] = randomString(32)

			if err := client.Emit("foo", &p); err != nil {
				panic(err)
			}

			p = make(eventsocketclient.Payload)
			p["value"] = randomString(32)

			if err := client.Broadcast(&p); err != nil {
				panic(err)
			}
		}
	}
}

func randomString(size int) string {
	rb := make([]byte, size)
	_, err := rand.Read(rb)

	if err != nil {
		fmt.Println(err)
	}

	return base64.URLEncoding.EncodeToString(rb)
}
<commit_msg>examples.basic.client: handle general receive errors<commit_after>package main

import (
	"crypto/rand"
	"encoding/base64"
	"flag"
	"fmt"
	"time"

	"github.com/dronemill/eventsocket-client-go"
)

var ticker = flag.Bool("ticker", false, "Do we write to the websocket connection as we tick?")
var requester = flag.Bool("requester", false, "Do we write to the websocket connection?")
var requestClientId = flag.String("requestClientId", "", "The clientId to send a request to")

func main() {
	flag.Parse()

	client, err := eventsocketclient.NewClient("127.0.0.1:8080")
	if err != nil {
		panic(err)
	}

	if err := client.DialWs(); err != nil {
		panic(err)
	}

	fmt.Printf("Connected! ClientId: %s\n", client.Id)

	if *ticker {
		go tick(client)
	}

	if *requester {
		go makeRequest(client)
	}

	go client.Recv()

	subChan, err := client.Suscribe("foo")
	if err != nil {
		panic(err)
	}

	for {
		select {
		case m := <-client.RecvBroadcast:
			if m.Err != nil {
				panic(m.Err)
			}
			fmt.Printf("BROADCAST err:%v :: %+v\n", m.Err, m.Message.Payload)
		case m := <-subChan:
			if m.Err != nil {
				panic(m.Err)
			}
			fmt.Printf("Foo: err:%v :: %+v\n", m.Err, m.Message.Payload)
		case m := <-client.RecvRequest:
			if m.Err != nil {
				panic(m.Err)
			}
			fmt.Printf("REQUEST err:%v :: %+v\n", m.Err, m.Message.Payload)
			p := eventsocketclient.NewPayload()
			p["I_SEE_YOU"] = randomString(32)
			if err := client.Reply(m.Message.RequestId, m.Message.ReplyClientId, &p); err != nil {
				panic(err)
			}
		case err := <-client.RecvError:
			panic(err)
		}
	}
}

func makeRequest(client *eventsocketclient.Client) {
	p := eventsocketclient.NewPayload()
	p["PEEK_ABOO"] = randomString(32)

	res, err := client.Request(*requestClientId, &p)
	if err != nil {
		panic(err)
	}

	m := <-res

	fmt.Printf("REPLY err:%v :: %+v\n", m.Err, m.Message.Payload)
}

func tick(client *eventsocketclient.Client) {
	tickChan := time.NewTicker(time.Second).C

	for {
		select {
		case <-tickChan:
			p := eventsocketclient.NewPayload()
			p["awesomeValue"] = randomString(32)

			if err := client.Emit("foo", &p); err != nil {
				panic(err)
			}

			p = make(eventsocketclient.Payload)
			p["value"] = randomString(32)

			if err := client.Broadcast(&p); err != nil {
				panic(err)
			}
		}
	}
}

func randomString(size int) string {
	rb := make([]byte, size)
	_, err := rand.Read(rb)

	if err != nil {
		fmt.Println(err)
	}

	return base64.URLEncoding.EncodeToString(rb)
}
<|endoftext|>


<commit_before>package keymap

import (
	"github.com/Bredgren/game1/game/keymap/button"
	"github.com/hajimehoshi/ebiten"
)

// Action is a name/label for an action.
type Action string

// ButtonHandler is a function that handles a button state. The parameter down is true
// if the button is pressed. It should return true if no later handlers should be called
// for the same button.
type ButtonHandler func(down bool) (stopPropagation bool)

// AxisHandler is a function that handles gamepad axis state. The function will directly
// be given the result of ebiten.GamepadAxis. It should return true if no later handlers
// should be called for the same axis.
type AxisHandler func(val float64) (stopPropagation bool)

// ActionHanderMap maps an Action to its handler.
type ActionHandlerMap map[Action]ButtonHandler

// AxisActionHandlerMap maps an Action to its axis handler.
type AxisActionHandlerMap map[Action]AxisHandler

// KeyMap maps a Button to an Action.
type KeyMap map[button.Button]Action

// StoppedBtnSet holds a set of Buttons that stopped propagation.
type StoppedBtnSet map[button.Button]bool

// Update calls the handler for all buttons that haven't been stopped. A button is stopped
// if it maps to true in stoppedBtns. The stoppedBtns map is updated according to the
// the return values of the handlers that are executed.
func (km KeyMap) Update(ahm ActionHandlerMap, stoppedBtns StoppedBtnSet) {
	gamepadId := 0 // Assume one gamepad for now

	for btn, action := range km {
		if stoppedBtns[btn] {
			continue
		}

		if actionFn, ok := ahm[action]; ok {
			var down bool
			if k, ok := btn.Key(); ok {
				down = ebiten.IsKeyPressed(k)
			} else if gb, ok := btn.GamepadButton(); ok {
				down = ebiten.IsGamepadButtonPressed(gamepadId, gb)
			} else if mb, ok := btn.MouseButton(); ok {
				down = ebiten.IsMouseButtonPressed(mb)
			}
			stoppedBtns[btn] = actionFn(down)
		}
	}
}

// AxisMap maps an axis id to an Action.
type AxisMap map[int]Action

// StoppedAxisSet holds a set of axis that stopped propagation.
type StoppedAxisSet map[int]bool

// Update calls the handler for all axes that haven't been stopped. An axis is stopped
// if it maps to true in stoppedAxis. The stoppedAxis map is updated according to the
// the return values of the handlers that are executed.
func (am AxisMap) Update(ahm AxisActionHandlerMap, stoppedAxis StoppedAxisSet) {
	gamepadId := 0 // Assume one gamepad for now

	for axis, action := range am {
		if stoppedAxis[axis] {
			continue
		}

		if actionFn, ok := ahm[action]; ok {
			stoppedAxis[axis] = actionFn(ebiten.GamepadAxis(gamepadId, axis))
		}
	}
}

// Map combines KeyMap and AxisMap.
type Map struct {
	KeyMap
	AxisMap
}

//ActionMap groups the handler map types.
type ActionMap struct {
	ActionHandlerMap
	AxisActionHandlerMap
}

// Layers is a slice of Maps. This can be used to combine and use multiple Maps at once.
// Maps are handled in order and if more than one KeyMap has a handler for the same Button
// then ther earlier ones have the option to stop propagation to later handlers.
type Layers []Map

func (l Layers) Update(am ActionMap) {
	stoppedBtns := StoppedBtnSet{}
	stoppedAxis := StoppedAxisSet{}

	for _, m := range l {
		m.KeyMap.Update(am.ActionHandlerMap, stoppedBtns)
		m.AxisMap.Update(am.AxisActionHandlerMap, stoppedAxis)
	}
}
<commit_msg>Fix typos. Add NewMap.<commit_after>package keymap

import (
	"github.com/Bredgren/game1/game/keymap/button"
	"github.com/hajimehoshi/ebiten"
)

// Action is a name/label for an action.
type Action string

// ButtonHandler is a function that handles a button state. The parameter down is true
// if the button is pressed. It should return true if no later handlers should be called
// for the same button.
type ButtonHandler func(down bool) (stopPropagation bool)

// AxisHandler is a function that handles gamepad axis state. The function will directly
// be given the result of ebiten.GamepadAxis. It should return true if no later handlers
// should be called for the same axis.
type AxisHandler func(val float64) (stopPropagation bool)

// ActionHandlerMap maps an Action to its handler.
type ActionHandlerMap map[Action]ButtonHandler

// AxisActionHandlerMap maps an Action to its axis handler.
type AxisActionHandlerMap map[Action]AxisHandler

// KeyMap maps a Button to an Action.
type KeyMap map[button.Button]Action

// StoppedBtnSet holds a set of Buttons that stopped propagation.
type StoppedBtnSet map[button.Button]bool

// Update calls the handler for all buttons that haven't been stopped. A button is stopped
// if it maps to true in stoppedBtns. The stoppedBtns map is updated according to the
// the return values of the handlers that are executed.
func (km KeyMap) Update(ahm ActionHandlerMap, stoppedBtns StoppedBtnSet) {
	gamepadID := 0 // Assume one gamepad for now

	for btn, action := range km {
		if stoppedBtns[btn] {
			continue
		}

		if actionFn, ok := ahm[action]; ok {
			var down bool
			if k, ok := btn.Key(); ok {
				down = ebiten.IsKeyPressed(k)
			} else if gb, ok := btn.GamepadButton(); ok {
				down = ebiten.IsGamepadButtonPressed(gamepadID, gb)
			} else if mb, ok := btn.MouseButton(); ok {
				down = ebiten.IsMouseButtonPressed(mb)
			}
			stoppedBtns[btn] = actionFn(down)
		}
	}
}

// AxisMap maps an axis id to an Action.
type AxisMap map[int]Action

// StoppedAxisSet holds a set of axis that stopped propagation.
type StoppedAxisSet map[int]bool

// Update calls the handler for all axes that haven't been stopped. An axis is stopped
// if it maps to true in stoppedAxis. The stoppedAxis map is updated according to the
// the return values of the handlers that are executed.
func (am AxisMap) Update(ahm AxisActionHandlerMap, stoppedAxis StoppedAxisSet) {
	gamepadID := 0 // Assume one gamepad for now

	for axis, action := range am {
		if stoppedAxis[axis] {
			continue
		}

		if actionFn, ok := ahm[action]; ok {
			stoppedAxis[axis] = actionFn(ebiten.GamepadAxis(gamepadID, axis))
		}
	}
}

// Map combines KeyMap and AxisMap.
type Map struct {
	KeyMap
	AxisMap
}

// NewMap creates a new Map type with empty KeyMap and AxisMap.
func NewMap() Map {
	return Map{
		KeyMap:  make(KeyMap),
		AxisMap: make(AxisMap),
	}
}

//ActionMap groups the handler map types.
type ActionMap struct {
	ActionHandlerMap
	AxisActionHandlerMap
}

// Layers is a slice of Maps. This can be used to combine and use multiple Maps at once.
// Maps are handled in order and if more than one KeyMap has a handler for the same Button
// then their earlier ones have the option to stop propagation to later handlers.
type Layers []Map

// Update calls the Update methods for each Map type in the list.
func (l Layers) Update(am ActionMap) {
	stoppedBtns := StoppedBtnSet{}
	stoppedAxis := StoppedAxisSet{}

	for _, m := range l {
		m.KeyMap.Update(am.ActionHandlerMap, stoppedBtns)
		m.AxisMap.Update(am.AxisActionHandlerMap, stoppedAxis)
	}
}
<|endoftext|>


<commit_before>// Package afutil includes utility functions for afto.
package afutil

import (
	"errors"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strconv"

	"github.com/hako/afto/deb"
	"github.com/hako/afto/release"
)

var (
	debFilesNotFound = "No .deb file(s) found. Unable to continue."
	debFileNotFound  = " not found. Unable to continue."
)

// ParseDir checks to see if a directory has the required files for a cydia repo.
// might move to separate util package.
func ParseDir(indir string) (bool, error) {
	var reqfiles = []string{"Packages", "Release"}
	var valid = false
	var reqcount = 0

	files, err := ioutil.ReadDir(indir)
	if err != nil {
		return valid, errors.New("directory " + indir + " not found or valid.")
	}
	for _, file := range files {
		for _, reqfile := range reqfiles {
			if file.Name() == reqfile {
				reqcount++
			}
		}
	}

	if reqcount < len(reqfiles) {
		count := len(reqfiles) - reqcount
		return valid, errors.New(strconv.Itoa(count) + " required files missing. (Need Packages and Release)")
	}
	valid = true
	return valid, nil
}

// CheckDPKG checks the host system has the dpkg command installed.
func CheckDPKG() error {
	_, err := exec.LookPath("dpkg")
	if err != nil {
		return errors.New("Unable to find required command 'dpkg'")
	}
	return nil
}

// CheckBzip2 checks the host system has the bzip2 command installed. (Sometimes this happens.)
func CheckBzip2() error {
	_, err := exec.LookPath("bzip2")
	if err != nil {
		return errors.New("Unable to find required command 'bzip2'")
	}
	return nil
}

// GetRepo checks if the string dir matches a valid repo in the current directory.
// This can be from a name or a path.
func GetRepo(dir string) (string, error) {
	// Check if the input directory has the valid files for a cydia repo.
	_, direrr := ParseDir(dir)
	if direrr != nil {
		return "", errors.New(direrr.Error())
	}

	// Get the absolute path from dir.
	finalPath, abserr := filepath.Abs(dir)
	if abserr != nil {
		return "", errors.New(abserr.Error())
	}

	return finalPath, nil
}

// ParseDeb parses a deb file and returns a *deb.Control struct.
func ParseDeb(debName string) (*deb.Control, error) {
	// Run dpkg --field *.deb
	fields, parseerr := exec.Command("dpkg", "-f", debName).Output()
	if parseerr != nil {
		return nil, parseerr
	}
	c := deb.NewControl()
	controlFile, errs := c.ParseString(string(fields))
	if errs != nil {
		return nil, errs
	}

	return controlFile, nil
}

// BzipPackages compresses the 'Packages' file Pacakges.bz2.
// Note: The stlib package "compress/bzip2" does not support compression.
func BzipPackages() error {
	// Run bzip2 -kf Packages.
	_, bzcmderr := exec.Command("bzip2", "-kf", "Packages").Output()
	if bzcmderr != nil {
		return bzcmderr
	}
	return nil
}

// CheckDeb checks if the user has deb files ready to go to the repo.
func CheckDeb() ([]string, error) {
	cwdir, err := os.Getwd()
	if err != nil {
		return nil, err
	}

	files, err := ioutil.ReadDir(cwdir)
	if err != nil {
		return nil, err
	}

	var deb []string
	for _, file := range files {
		if IsDeb(file.Name()) == true {
			deb = append(deb, file.Name())
		}
	}
	// Return error if ultimately no deb files are found.
	if len(deb) == 0 {
		return nil, errors.New(debFilesNotFound)
	}
	return deb, nil
}

// CheckDebWithPath is like CheckDeb but a path is required.
func CheckDebWithPath(path string) ([]string, error) {
	files, err := ioutil.ReadDir(path)
	if err != nil {
		return nil, err
	}

	var deb []string
	for _, file := range files {
		if IsDeb(file.Name()) == true {
			deb = append(deb, file.Name())
		}
	}
	// Return error if ultimately no deb files are found.
	if len(deb) == 0 {
		return nil, errors.New(debFilesNotFound)
	}
	return deb, nil
}

// CheckDebWithFile is like CheckDeb but a filepath is required.
func CheckDebWithFile(fp string) (string, error) {
	path, fperr := filepath.Abs(fp)
	if fperr != nil {
		return "", errors.New("\"" + fp + "\"" + debFileNotFound)
	}

	// Return error if the deb does not exist.
	if IsDeb(path) != true {
		return "", errors.New("\"" + fp + "\"" + debFileNotFound)
	}
	return path, nil
}

// SignRepo signs the repo's Packages and Packages.bz2 using devs' GPG key.
func SignRepo(fp string) error {
	repo, fperr := GetRepo(fp)
	if fperr != nil {
		return fperr
	}
	releaseFile := repo + "/Release"
	outputFile := repo + "/Release.gpg"
	_, err := ioutil.ReadFile(releaseFile)
	if err != nil {
		return err
	}
	_, gpgerr := exec.Command("gpg", "-abs", "-o", outputFile, releaseFile).Output()
	if gpgerr != nil {
		return gpgerr
	}
	return nil
}

// IsDeb returns whether the string is a deb file with regex.
func IsDeb(filename string) bool {
	re := regexp.MustCompile(`(\.deb)`)
	return re.MatchString(filename)
}

// ReleaseFile generates a release file based on origin, label, desc codename and suite.
// It is recommended to generate this file for hosting a repo.
func ReleaseFile(origin string, label string, desc string, codename string, suite string) (string, error) {
	r := release.NewRelease()
	r.SetOrigin(origin)
	r.SetLabel(label)
	r.SetDescription(desc)
	r.SetCodename(codename)
	r.SetSuite(suite)

	// Get Packages and Packages.bz2
	packages, err := ioutil.ReadFile("Packages")
	if err != nil {
		return "", err
	}
	packagesbz, err := ioutil.ReadFile("Packages.bz2")
	if err != nil {
		return "", err
	}

	r.AddPackageSignature(packages, packagesbz)
	return r.Generate(), nil
}

// Copy copies a file from source to destination.
// Note: Copy is not in the stdlib so kudos to @elazarl
func Copy(source string, destination string) error {
	src, ferr := os.Open(source)
	if ferr != nil {
		return ferr
	}

	defer src.Close()
	dst, derr := os.Create(destination)
	if derr != nil {
		return derr
	}

	if _, err := io.Copy(dst, src); err != nil {
		dst.Close()
		return err
	}
	return dst.Close()
}

// DetectPlatform returns what host system the user is running.
func DetectPlatform() (string, error) {
	hostOS := runtime.GOOS
	switch hostOS {
	case "darwin":
		return "Since you're on a Mac, you can install dpkg via brew. \nIf you have brew installed type `brew install dpkg` and try again.", nil
	case "linux":
		return "Since you're on Linux, you can install dpkg by using `sudo apt-get install dpkg`.", nil
	case "windows":
		return "It looks like dpkg is not available on Windows. \nYou can stil use afto, you cannot build your repo without dpkg.", nil
	default:
		return "", errors.New("Unable to detect your OS.")
	}
}
<commit_msg>Update afutil.go<commit_after>// Package afutil includes utility functions for afto.
package afutil

import (
	"errors"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strconv"

	"github.com/hako/afto/deb"
	"github.com/hako/afto/release"
)

var (
	debFilesNotFound = "No .deb file(s) found. Unable to continue."
	debFileNotFound  = " not found. Unable to continue."
)

// ParseDir checks to see if a directory has the required files for a cydia repo.
// might move to separate util package.
func ParseDir(indir string) (bool, error) {
	var reqfiles = []string{"Packages", "Release"}
	var valid = false
	var reqcount = 0

	files, err := ioutil.ReadDir(indir)
	if err != nil {
		return valid, errors.New("directory " + indir + " not found or valid.")
	}
	for _, file := range files {
		for _, reqfile := range reqfiles {
			if file.Name() == reqfile {
				reqcount++
			}
		}
	}

	if reqcount < len(reqfiles) {
		count := len(reqfiles) - reqcount
		return valid, errors.New(strconv.Itoa(count) + " required files missing. (Need Packages and Release)")
	}
	valid = true
	return valid, nil
}

// CheckDPKG checks the host system has the dpkg command installed.
func CheckDPKG() error {
	_, err := exec.LookPath("dpkg")
	if err != nil {
		return errors.New("Unable to find required command 'dpkg'")
	}
	return nil
}

// CheckBzip2 checks the host system has the bzip2 command installed. (Sometimes this happens.)
func CheckBzip2() error {
	_, err := exec.LookPath("bzip2")
	if err != nil {
		return errors.New("Unable to find required command 'bzip2'")
	}
	return nil
}

// GetRepo checks if the string dir matches a valid repo in the current directory.
// This can be from a name or a path.
func GetRepo(dir string) (string, error) {
	// Check if the input directory has the valid files for a cydia repo.
	_, direrr := ParseDir(dir)
	if direrr != nil {
		return "", errors.New(direrr.Error())
	}

	// Get the absolute path from dir.
	finalPath, abserr := filepath.Abs(dir)
	if abserr != nil {
		return "", errors.New(abserr.Error())
	}

	return finalPath, nil
}

// ParseDeb parses a deb file and returns a *deb.Control struct.
func ParseDeb(debName string) (*deb.Control, error) {
	// Run dpkg --field *.deb
	fields, parseerr := exec.Command("dpkg", "-f", debName).Output()
	if parseerr != nil {
		return nil, parseerr
	}
	c := deb.NewControl()
	controlFile, errs := c.ParseString(string(fields))
	if errs != nil {
		return nil, errs
	}

	return controlFile, nil
}

// BzipPackages compresses the 'Packages' file Packages.bz2.
// Note: The stlib package "compress/bzip2" does not support compression.
func BzipPackages() error {
	// Run bzip2 -kf Packages.
	_, bzcmderr := exec.Command("bzip2", "-kf", "Packages").Output()
	if bzcmderr != nil {
		return bzcmderr
	}
	return nil
}

// CheckDeb checks if the user has deb files ready to go to the repo.
func CheckDeb() ([]string, error) {
	cwdir, err := os.Getwd()
	if err != nil {
		return nil, err
	}

	files, err := ioutil.ReadDir(cwdir)
	if err != nil {
		return nil, err
	}

	var deb []string
	for _, file := range files {
		if IsDeb(file.Name()) == true {
			deb = append(deb, file.Name())
		}
	}
	// Return error if ultimately no deb files are found.
	if len(deb) == 0 {
		return nil, errors.New(debFilesNotFound)
	}
	return deb, nil
}

// CheckDebWithPath is like CheckDeb but a path is required.
func CheckDebWithPath(path string) ([]string, error) {
	files, err := ioutil.ReadDir(path)
	if err != nil {
		return nil, err
	}

	var deb []string
	for _, file := range files {
		if IsDeb(file.Name()) == true {
			deb = append(deb, file.Name())
		}
	}
	// Return error if ultimately no deb files are found.
	if len(deb) == 0 {
		return nil, errors.New(debFilesNotFound)
	}
	return deb, nil
}

// CheckDebWithFile is like CheckDeb but a filepath is required.
func CheckDebWithFile(fp string) (string, error) {
	path, fperr := filepath.Abs(fp)
	if fperr != nil {
		return "", errors.New("\"" + fp + "\"" + debFileNotFound)
	}

	// Return error if the deb does not exist.
	if IsDeb(path) != true {
		return "", errors.New("\"" + fp + "\"" + debFileNotFound)
	}
	return path, nil
}

// SignRepo signs the repo's Packages and Packages.bz2 using devs' GPG key.
func SignRepo(fp string) error {
	repo, fperr := GetRepo(fp)
	if fperr != nil {
		return fperr
	}
	releaseFile := repo + "/Release"
	outputFile := repo + "/Release.gpg"
	_, err := ioutil.ReadFile(releaseFile)
	if err != nil {
		return err
	}
	_, gpgerr := exec.Command("gpg", "-abs", "-o", outputFile, releaseFile).Output()
	if gpgerr != nil {
		return gpgerr
	}
	return nil
}

// IsDeb returns whether the string is a deb file with regex.
func IsDeb(filename string) bool {
	re := regexp.MustCompile(`(\.deb)`)
	return re.MatchString(filename)
}

// ReleaseFile generates a release file based on origin, label, desc codename and suite.
// It is recommended to generate this file for hosting a repo.
func ReleaseFile(origin string, label string, desc string, codename string, suite string) (string, error) {
	r := release.NewRelease()
	r.SetOrigin(origin)
	r.SetLabel(label)
	r.SetDescription(desc)
	r.SetCodename(codename)
	r.SetSuite(suite)

	// Get Packages and Packages.bz2
	packages, err := ioutil.ReadFile("Packages")
	if err != nil {
		return "", err
	}
	packagesbz, err := ioutil.ReadFile("Packages.bz2")
	if err != nil {
		return "", err
	}

	r.AddPackageSignature(packages, packagesbz)
	return r.Generate(), nil
}

// Copy copies a file from source to destination.
// Note: Copy is not in the stdlib so kudos to @elazarl
func Copy(source string, destination string) error {
	src, ferr := os.Open(source)
	if ferr != nil {
		return ferr
	}

	defer src.Close()
	dst, derr := os.Create(destination)
	if derr != nil {
		return derr
	}

	if _, err := io.Copy(dst, src); err != nil {
		dst.Close()
		return err
	}
	return dst.Close()
}

// DetectPlatform returns what host system the user is running.
func DetectPlatform() (string, error) {
	hostOS := runtime.GOOS
	switch hostOS {
	case "darwin":
		return "Since you're on a Mac, you can install dpkg via brew. \nIf you have brew installed type `brew install dpkg` and try again.", nil
	case "linux":
		return "Since you're on Linux, you can install dpkg by using `sudo apt-get install dpkg`.", nil
	case "windows":
		return "It looks like dpkg is not available on Windows. \nYou can stil use afto, you cannot build your repo without dpkg.", nil
	default:
		return "", errors.New("Unable to detect your OS.")
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2018 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 annotations

import (
	"fmt"
	"net/http"
	"strconv"
	"strings"

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

	"github.com/parnurzeal/gorequest"

	"k8s.io/ingress-nginx/test/e2e/framework"
)

func noRedirectPolicyFunc(gorequest.Request, []gorequest.Request) error {
	return http.ErrUseLastResponse
}

var _ = framework.IngressNginxDescribe("Annotations - Redirect", func() {
	f := framework.NewDefaultFramework("redirect")

	BeforeEach(func() {
	})

	AfterEach(func() {
	})

	It("should respond with a standard redirect code", func() {
		By("setting permanent-redirect annotation")

		host := "redirect"
		redirectPath := "/something"
		redirectURL := "http://redirect.example.com"

		annotations := map[string]string{"nginx.ingress.kubernetes.io/permanent-redirect": redirectURL}

		ing := framework.NewSingleIngress(host, redirectPath, host, f.Namespace, "http-svc", 80, &annotations)
		f.EnsureIngress(ing)

		f.WaitForNginxServer(host,
			func(server string) bool {
				return strings.Contains(server, fmt.Sprintf("if ($uri ~* %s) {", redirectPath)) &&
					strings.Contains(server, fmt.Sprintf("return 301 %s;", redirectURL))
			})

		By("sending request to redirected URL path")

		resp, body, errs := gorequest.New().
			Get(f.GetURL(framework.HTTP)+redirectPath).
			Set("Host", host).
			RedirectPolicy(noRedirectPolicyFunc).
			End()

		Expect(errs).To(BeNil())
		Expect(resp.StatusCode).Should(BeNumerically("==", http.StatusMovedPermanently))
		Expect(resp.Header.Get("Location")).Should(Equal(redirectURL))
		Expect(body).Should(ContainSubstring("nginx/"))
	})

	It("should respond with a custom redirect code", func() {
		By("setting permanent-redirect-code annotation")

		host := "redirect"
		redirectPath := "/something"
		redirectURL := "http://redirect.example.com"
		redirectCode := http.StatusFound

		annotations := map[string]string{
			"nginx.ingress.kubernetes.io/permanent-redirect":      redirectURL,
			"nginx.ingress.kubernetes.io/permanent-redirect-code": strconv.Itoa(redirectCode),
		}

		ing := framework.NewSingleIngress(host, redirectPath, host, f.Namespace, "http-svc", 80, &annotations)
		f.EnsureIngress(ing)

		f.WaitForNginxServer(host,
			func(server string) bool {
				return strings.Contains(server, fmt.Sprintf("if ($uri ~* %s) {", redirectPath)) &&
					strings.Contains(server, fmt.Sprintf("return %d %s;", redirectCode, redirectURL))
			})

		By("sending request to redirected URL path")

		resp, body, errs := gorequest.New().
			Get(f.GetURL(framework.HTTP)+redirectPath).
			Set("Host", host).
			RedirectPolicy(noRedirectPolicyFunc).
			End()

		Expect(errs).To(BeNil())
		Expect(resp.StatusCode).Should(BeNumerically("==", redirectCode))
		Expect(resp.Header.Get("Location")).Should(Equal(redirectURL))
		Expect(body).Should(ContainSubstring("nginx/"))
	})
})
<commit_msg>Update e2e tests for openresty<commit_after>/*
Copyright 2018 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 annotations

import (
	"fmt"
	"net/http"
	"strconv"
	"strings"

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

	"github.com/parnurzeal/gorequest"

	"k8s.io/ingress-nginx/test/e2e/framework"
)

func noRedirectPolicyFunc(gorequest.Request, []gorequest.Request) error {
	return http.ErrUseLastResponse
}

var _ = framework.IngressNginxDescribe("Annotations - Redirect", func() {
	f := framework.NewDefaultFramework("redirect")

	BeforeEach(func() {
	})

	AfterEach(func() {
	})

	It("should respond with a standard redirect code", func() {
		By("setting permanent-redirect annotation")

		host := "redirect"
		redirectPath := "/something"
		redirectURL := "http://redirect.example.com"

		annotations := map[string]string{"nginx.ingress.kubernetes.io/permanent-redirect": redirectURL}

		ing := framework.NewSingleIngress(host, redirectPath, host, f.Namespace, "http-svc", 80, &annotations)
		f.EnsureIngress(ing)

		f.WaitForNginxServer(host,
			func(server string) bool {
				return strings.Contains(server, fmt.Sprintf("if ($uri ~* %s) {", redirectPath)) &&
					strings.Contains(server, fmt.Sprintf("return 301 %s;", redirectURL))
			})

		By("sending request to redirected URL path")

		resp, body, errs := gorequest.New().
			Get(f.GetURL(framework.HTTP)+redirectPath).
			Set("Host", host).
			RedirectPolicy(noRedirectPolicyFunc).
			End()

		Expect(errs).To(BeNil())
		Expect(resp.StatusCode).Should(BeNumerically("==", http.StatusMovedPermanently))
		Expect(resp.Header.Get("Location")).Should(Equal(redirectURL))
		Expect(body).Should(ContainSubstring("openresty/"))
	})

	It("should respond with a custom redirect code", func() {
		By("setting permanent-redirect-code annotation")

		host := "redirect"
		redirectPath := "/something"
		redirectURL := "http://redirect.example.com"
		redirectCode := http.StatusFound

		annotations := map[string]string{
			"nginx.ingress.kubernetes.io/permanent-redirect":      redirectURL,
			"nginx.ingress.kubernetes.io/permanent-redirect-code": strconv.Itoa(redirectCode),
		}

		ing := framework.NewSingleIngress(host, redirectPath, host, f.Namespace, "http-svc", 80, &annotations)
		f.EnsureIngress(ing)

		f.WaitForNginxServer(host,
			func(server string) bool {
				return strings.Contains(server, fmt.Sprintf("if ($uri ~* %s) {", redirectPath)) &&
					strings.Contains(server, fmt.Sprintf("return %d %s;", redirectCode, redirectURL))
			})

		By("sending request to redirected URL path")

		resp, body, errs := gorequest.New().
			Get(f.GetURL(framework.HTTP)+redirectPath).
			Set("Host", host).
			RedirectPolicy(noRedirectPolicyFunc).
			End()

		Expect(errs).To(BeNil())
		Expect(resp.StatusCode).Should(BeNumerically("==", redirectCode))
		Expect(resp.Header.Get("Location")).Should(Equal(redirectURL))
		Expect(body).Should(ContainSubstring("openresty/"))
	})
})
<|endoftext|>


<commit_before>/*
Copyright 2019 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 pod

import (
	"context"
	"fmt"
	"time"

	"github.com/onsi/ginkgo"

	v1 "k8s.io/api/core/v1"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	clientset "k8s.io/client-go/kubernetes"
	e2elog "k8s.io/kubernetes/test/e2e/framework/log"
)

const (
	// PodDeleteTimeout is how long to wait for a pod to be deleted.
	PodDeleteTimeout = 5 * time.Minute
)

// DeletePodOrFail deletes the pod of the specified namespace and name.
func DeletePodOrFail(c clientset.Interface, ns, name string) {
	ginkgo.By(fmt.Sprintf("Deleting pod %s in namespace %s", name, ns))
	err := c.CoreV1().Pods(ns).Delete(context.TODO(), name, metav1.DeleteOptions{})
	expectNoError(err, "failed to delete pod %s in namespace %s", name, ns)
}

// DeletePodWithWait deletes the passed-in pod and waits for the pod to be terminated. Resilient to the pod
// not existing.
func DeletePodWithWait(c clientset.Interface, pod *v1.Pod) error {
	if pod == nil {
		return nil
	}
	return DeletePodWithWaitByName(c, pod.GetName(), pod.GetNamespace())
}

// DeletePodWithWaitByName deletes the named and namespaced pod and waits for the pod to be terminated. Resilient to the pod
// not existing.
func DeletePodWithWaitByName(c clientset.Interface, podName, podNamespace string) error {
	e2elog.Logf("Deleting pod %q in namespace %q", podName, podNamespace)
	err := c.CoreV1().Pods(podNamespace).Delete(context.TODO(), podName, metav1.DeleteOptions{})
	if err != nil {
		if apierrors.IsNotFound(err) {
			return nil // assume pod was already deleted
		}
		return fmt.Errorf("pod Delete API error: %v", err)
	}
	e2elog.Logf("Wait up to %v for pod %q to be fully deleted", PodDeleteTimeout, podName)
	err = WaitForPodNotFoundInNamespace(c, podName, podNamespace, PodDeleteTimeout)
	if err != nil {
		return fmt.Errorf("pod %q was not deleted: %v", podName, err)
	}
	return nil
}
<commit_msg>UPSTREAM: 91221: Tolerate pod not found errors in e2e<commit_after>/*
Copyright 2019 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 pod

import (
	"context"
	"fmt"
	"time"

	"github.com/onsi/ginkgo"

	v1 "k8s.io/api/core/v1"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	clientset "k8s.io/client-go/kubernetes"
	e2elog "k8s.io/kubernetes/test/e2e/framework/log"
)

const (
	// PodDeleteTimeout is how long to wait for a pod to be deleted.
	PodDeleteTimeout = 5 * time.Minute
)

// DeletePodOrFail deletes the pod of the specified namespace and name. Resilient to the pod
// not existing.
func DeletePodOrFail(c clientset.Interface, ns, name string) {
	ginkgo.By(fmt.Sprintf("Deleting pod %s in namespace %s", name, ns))
	err := c.CoreV1().Pods(ns).Delete(context.TODO(), name, metav1.DeleteOptions{})
	if err != nil && apierrors.IsNotFound(err) {
		return
	}

	expectNoError(err, "failed to delete pod %s in namespace %s", name, ns)
}

// DeletePodWithWait deletes the passed-in pod and waits for the pod to be terminated. Resilient to the pod
// not existing.
func DeletePodWithWait(c clientset.Interface, pod *v1.Pod) error {
	if pod == nil {
		return nil
	}
	return DeletePodWithWaitByName(c, pod.GetName(), pod.GetNamespace())
}

// DeletePodWithWaitByName deletes the named and namespaced pod and waits for the pod to be terminated. Resilient to the pod
// not existing.
func DeletePodWithWaitByName(c clientset.Interface, podName, podNamespace string) error {
	e2elog.Logf("Deleting pod %q in namespace %q", podName, podNamespace)
	err := c.CoreV1().Pods(podNamespace).Delete(context.TODO(), podName, metav1.DeleteOptions{})
	if err != nil {
		if apierrors.IsNotFound(err) {
			return nil // assume pod was already deleted
		}
		return fmt.Errorf("pod Delete API error: %v", err)
	}
	e2elog.Logf("Wait up to %v for pod %q to be fully deleted", PodDeleteTimeout, podName)
	err = WaitForPodNotFoundInNamespace(c, podName, podNamespace, PodDeleteTimeout)
	if err != nil {
		return fmt.Errorf("pod %q was not deleted: %v", podName, err)
	}
	return nil
}
<|endoftext|>


<commit_before>package scheduler

import (
	"encoding/json"
	"io"
	"net/http"
	"sync"
	"time"

	"github.com/concourse/atc/builds"
	"github.com/concourse/atc/db"
	tbuilds "github.com/concourse/turbine/api/builds"
	"github.com/concourse/turbine/event"
	"github.com/concourse/turbine/routes"
	"github.com/pivotal-golang/lager"
	"github.com/tedsuo/rata"
	"github.com/vito/go-sse/sse"
)

type tracker struct {
	logger lager.Logger

	db TrackerDB

	trackingBuilds map[int]bool
	lock           *sync.Mutex
}

type TrackerDB interface {
	AppendBuildEvent(buildID int, event db.BuildEvent) error

	SaveBuildStartTime(buildID int, startTime time.Time) error
	SaveBuildEndTime(buildID int, startTime time.Time) error

	SaveBuildInput(buildID int, vr builds.VersionedResource) error
	SaveBuildOutput(buildID int, vr builds.VersionedResource) error

	SaveBuildStatus(buildID int, status builds.Status) error
}

func NewTracker(logger lager.Logger, db TrackerDB) BuildTracker {
	return &tracker{
		logger: logger,
		db:     db,

		trackingBuilds: make(map[int]bool),
		lock:           new(sync.Mutex),
	}
}

func (tracker *tracker) TrackBuild(build builds.Build) error {
	tLog := tracker.logger.Session("track-build", lager.Data{
		"buld": build.ID,
	})

	alreadyTracking := tracker.markTracking(build.ID)
	if alreadyTracking {
		tLog.Info("already-tracking")
		return nil
	}

	tLog.Info("tracking")

	defer func() {
		tLog.Info("done-tracking")
		tracker.unmarkTracking(build.ID)
	}()

	generator := rata.NewRequestGenerator(build.Endpoint, routes.Routes)

	events, err := generator.CreateRequest(
		routes.GetBuildEvents,
		rata.Params{"guid": build.Guid},
		nil,
	)
	if err != nil {
		tLog.Error("failed-to-create-events-request", err)
		return err
	}

	resp, err := http.DefaultClient.Do(events)
	if err != nil {
		tLog.Error("failed-to-get-events", err)
		return err
	}

	if resp.StatusCode == http.StatusNotFound {
		tLog.Info("saving-orphaned-build-as-errored")

		err := tracker.db.SaveBuildStatus(build.ID, builds.StatusErrored)
		if err != nil {
			tLog.Error("failed-to-save-build-as-errored", err)
			return err
		}

		return nil
	}

	reader := sse.NewReader(resp.Body)

	outputs := map[string]builds.VersionedResource{}

	var currentVersion string

	for {
		se, err := reader.Next()
		if err != nil {
			if err == io.EOF {
				tLog.Info("event-stream-completed")
				return nil
			}

			return err
		}

		err = tracker.db.AppendBuildEvent(build.ID, db.BuildEvent{
			Type:    se.Name,
			Payload: string(se.Data),
		})

		if se.Name == "version" {
			var version event.Version
			err := json.Unmarshal(se.Data, &version)
			if err != nil {
				tLog.Error("failed-to-unmarshal-version", err)
				return err
			}

			tLog.Debug("event-stream-version", lager.Data{
				"version": string(version),
			})

			currentVersion = string(version)
			continue
		}

		if se.Name == "end" {
			tLog.Debug("event-stream-ended")

			del, err := generator.CreateRequest(
				routes.DeleteBuild,
				rata.Params{"guid": build.Guid},
				nil,
			)
			if err != nil {
				tLog.Error("failed-to-create-delete-request", err)
				return err
			}

			resp, err := http.DefaultClient.Do(del)
			if err != nil {
				tLog.Error("failed-to-delete-build", err)
				return err
			}

			resp.Body.Close()
			continue
		}

		switch currentVersion {
		case "1.0":
			fallthrough
		case "1.1":
			switch se.Name {
			case "status":
				tLog.Debug("processing-build-status", lager.Data{
					"event": string(se.Data),
				})

				var status event.Status
				err := json.Unmarshal(se.Data, &status)
				if err != nil {
					tLog.Error("failed-to-unmarshal-status", err)
					return err
				}

				if status.Status == tbuilds.StatusStarted {
					err = tracker.db.SaveBuildStartTime(build.ID, time.Unix(status.Time, 0))
					if err != nil {
						tLog.Error("failed-to-save-build-start-time", err)
						return err
					}
				} else {
					err = tracker.db.SaveBuildEndTime(build.ID, time.Unix(status.Time, 0))
					if err != nil {
						tLog.Error("failed-to-save-build-end-time", err)
						return err
					}
				}

				err = tracker.db.SaveBuildStatus(build.ID, builds.Status(status.Status))
				if err != nil {
					tLog.Error("failed-to-save-build-status", err)
					return err
				}

				if status.Status == tbuilds.StatusSucceeded {
					for _, output := range outputs {
						err := tracker.db.SaveBuildOutput(build.ID, output)
						if err != nil {
							tLog.Error("failed-to-save-build-output", err)
							return err
						}
					}
				}

			case "input":
				if build.JobName == "" {
					tLog.Debug("ignoring-build-input-for-one-off")
					break
				}

				tLog.Debug("processing-build-input", lager.Data{
					"event": string(se.Data),
				})

				var input event.Input
				err := json.Unmarshal(se.Data, &input)
				if err != nil {
					tLog.Error("failed-to-unarshal-input", err)
					return err
				}

				err = tracker.db.SaveBuildInput(build.ID, vrFromInput(input.Input))
				if err != nil {
					tLog.Error("failed-to-save-build-input", err)
					return err
				}

				// record implicit output
				outputs[input.Input.Name] = vrFromInput(input.Input)

			case "output":
				if build.JobName == "" {
					tLog.Debug("ignoring-build-output-for-one-off")
					break
				}

				var output event.Output
				err := json.Unmarshal(se.Data, &output)
				if err != nil {
					tLog.Error("failed-to-unarshal-output", err)
					return err
				}

				outputs[output.Output.Name] = vrFromOutput(output.Output)
			}
		}
	}

	return nil
}

func (tracker *tracker) markTracking(buildID int) bool {
	tracker.lock.Lock()
	alreadyTracking, found := tracker.trackingBuilds[buildID]
	if !found {
		tracker.trackingBuilds[buildID] = true
	}
	tracker.lock.Unlock()

	return alreadyTracking
}

func (tracker *tracker) unmarkTracking(buildID int) {
	tracker.lock.Lock()
	delete(tracker.trackingBuilds, buildID)
	tracker.lock.Unlock()
}

func vrFromInput(input tbuilds.Input) builds.VersionedResource {
	metadata := make([]builds.MetadataField, len(input.Metadata))
	for i, md := range input.Metadata {
		metadata[i] = builds.MetadataField{
			Name:  md.Name,
			Value: md.Value,
		}
	}

	return builds.VersionedResource{
		Name:     input.Name,
		Type:     input.Type,
		Source:   builds.Source(input.Source),
		Version:  builds.Version(input.Version),
		Metadata: metadata,
	}
}

// same as input, but type is different.
//
// :(
func vrFromOutput(output tbuilds.Output) builds.VersionedResource {
	metadata := make([]builds.MetadataField, len(output.Metadata))
	for i, md := range output.Metadata {
		metadata[i] = builds.MetadataField{
			Name:  md.Name,
			Value: md.Value,
		}
	}

	return builds.VersionedResource{
		Name:     output.Name,
		Type:     output.Type,
		Source:   builds.Source(output.Source),
		Version:  builds.Version(output.Version),
		Metadata: metadata,
	}
}
<commit_msg>debug -> info for now<commit_after>package scheduler

import (
	"encoding/json"
	"io"
	"net/http"
	"sync"
	"time"

	"github.com/concourse/atc/builds"
	"github.com/concourse/atc/db"
	tbuilds "github.com/concourse/turbine/api/builds"
	"github.com/concourse/turbine/event"
	"github.com/concourse/turbine/routes"
	"github.com/pivotal-golang/lager"
	"github.com/tedsuo/rata"
	"github.com/vito/go-sse/sse"
)

type tracker struct {
	logger lager.Logger

	db TrackerDB

	trackingBuilds map[int]bool
	lock           *sync.Mutex
}

type TrackerDB interface {
	AppendBuildEvent(buildID int, event db.BuildEvent) error

	SaveBuildStartTime(buildID int, startTime time.Time) error
	SaveBuildEndTime(buildID int, startTime time.Time) error

	SaveBuildInput(buildID int, vr builds.VersionedResource) error
	SaveBuildOutput(buildID int, vr builds.VersionedResource) error

	SaveBuildStatus(buildID int, status builds.Status) error
}

func NewTracker(logger lager.Logger, db TrackerDB) BuildTracker {
	return &tracker{
		logger: logger,
		db:     db,

		trackingBuilds: make(map[int]bool),
		lock:           new(sync.Mutex),
	}
}

func (tracker *tracker) TrackBuild(build builds.Build) error {
	tLog := tracker.logger.Session("track-build", lager.Data{
		"buld": build.ID,
	})

	alreadyTracking := tracker.markTracking(build.ID)
	if alreadyTracking {
		tLog.Info("already-tracking")
		return nil
	}

	tLog.Info("tracking")

	defer func() {
		tLog.Info("done-tracking")
		tracker.unmarkTracking(build.ID)
	}()

	generator := rata.NewRequestGenerator(build.Endpoint, routes.Routes)

	events, err := generator.CreateRequest(
		routes.GetBuildEvents,
		rata.Params{"guid": build.Guid},
		nil,
	)
	if err != nil {
		tLog.Error("failed-to-create-events-request", err)
		return err
	}

	resp, err := http.DefaultClient.Do(events)
	if err != nil {
		tLog.Error("failed-to-get-events", err)
		return err
	}

	if resp.StatusCode == http.StatusNotFound {
		tLog.Info("saving-orphaned-build-as-errored")

		err := tracker.db.SaveBuildStatus(build.ID, builds.StatusErrored)
		if err != nil {
			tLog.Error("failed-to-save-build-as-errored", err)
			return err
		}

		return nil
	}

	reader := sse.NewReader(resp.Body)

	outputs := map[string]builds.VersionedResource{}

	var currentVersion string

	for {
		se, err := reader.Next()
		if err != nil {
			if err == io.EOF {
				tLog.Info("event-stream-completed")
				return nil
			}

			return err
		}

		err = tracker.db.AppendBuildEvent(build.ID, db.BuildEvent{
			Type:    se.Name,
			Payload: string(se.Data),
		})

		if se.Name == "version" {
			var version event.Version
			err := json.Unmarshal(se.Data, &version)
			if err != nil {
				tLog.Error("failed-to-unmarshal-version", err)
				return err
			}

			tLog.Info("event-stream-version", lager.Data{
				"version": string(version),
			})

			currentVersion = string(version)
			continue
		}

		if se.Name == "end" {
			tLog.Info("event-stream-ended")

			del, err := generator.CreateRequest(
				routes.DeleteBuild,
				rata.Params{"guid": build.Guid},
				nil,
			)
			if err != nil {
				tLog.Error("failed-to-create-delete-request", err)
				return err
			}

			resp, err := http.DefaultClient.Do(del)
			if err != nil {
				tLog.Error("failed-to-delete-build", err)
				return err
			}

			resp.Body.Close()
			continue
		}

		switch currentVersion {
		case "1.0":
			fallthrough
		case "1.1":
			switch se.Name {
			case "status":
				tLog.Info("processing-build-status", lager.Data{
					"event": string(se.Data),
				})

				var status event.Status
				err := json.Unmarshal(se.Data, &status)
				if err != nil {
					tLog.Error("failed-to-unmarshal-status", err)
					return err
				}

				if status.Status == tbuilds.StatusStarted {
					err = tracker.db.SaveBuildStartTime(build.ID, time.Unix(status.Time, 0))
					if err != nil {
						tLog.Error("failed-to-save-build-start-time", err)
						return err
					}
				} else {
					err = tracker.db.SaveBuildEndTime(build.ID, time.Unix(status.Time, 0))
					if err != nil {
						tLog.Error("failed-to-save-build-end-time", err)
						return err
					}
				}

				err = tracker.db.SaveBuildStatus(build.ID, builds.Status(status.Status))
				if err != nil {
					tLog.Error("failed-to-save-build-status", err)
					return err
				}

				if status.Status == tbuilds.StatusSucceeded {
					for _, output := range outputs {
						err := tracker.db.SaveBuildOutput(build.ID, output)
						if err != nil {
							tLog.Error("failed-to-save-build-output", err)
							return err
						}
					}
				}

			case "input":
				if build.JobName == "" {
					tLog.Info("ignoring-build-input-for-one-off")
					break
				}

				tLog.Info("processing-build-input", lager.Data{
					"event": string(se.Data),
				})

				var input event.Input
				err := json.Unmarshal(se.Data, &input)
				if err != nil {
					tLog.Error("failed-to-unarshal-input", err)
					return err
				}

				err = tracker.db.SaveBuildInput(build.ID, vrFromInput(input.Input))
				if err != nil {
					tLog.Error("failed-to-save-build-input", err)
					return err
				}

				// record implicit output
				outputs[input.Input.Name] = vrFromInput(input.Input)

			case "output":
				if build.JobName == "" {
					tLog.Info("ignoring-build-output-for-one-off")
					break
				}

				var output event.Output
				err := json.Unmarshal(se.Data, &output)
				if err != nil {
					tLog.Error("failed-to-unarshal-output", err)
					return err
				}

				outputs[output.Output.Name] = vrFromOutput(output.Output)
			}
		}
	}

	return nil
}

func (tracker *tracker) markTracking(buildID int) bool {
	tracker.lock.Lock()
	alreadyTracking, found := tracker.trackingBuilds[buildID]
	if !found {
		tracker.trackingBuilds[buildID] = true
	}
	tracker.lock.Unlock()

	return alreadyTracking
}

func (tracker *tracker) unmarkTracking(buildID int) {
	tracker.lock.Lock()
	delete(tracker.trackingBuilds, buildID)
	tracker.lock.Unlock()
}

func vrFromInput(input tbuilds.Input) builds.VersionedResource {
	metadata := make([]builds.MetadataField, len(input.Metadata))
	for i, md := range input.Metadata {
		metadata[i] = builds.MetadataField{
			Name:  md.Name,
			Value: md.Value,
		}
	}

	return builds.VersionedResource{
		Name:     input.Name,
		Type:     input.Type,
		Source:   builds.Source(input.Source),
		Version:  builds.Version(input.Version),
		Metadata: metadata,
	}
}

// same as input, but type is different.
//
// :(
func vrFromOutput(output tbuilds.Output) builds.VersionedResource {
	metadata := make([]builds.MetadataField, len(output.Metadata))
	for i, md := range output.Metadata {
		metadata[i] = builds.MetadataField{
			Name:  md.Name,
			Value: md.Value,
		}
	}

	return builds.VersionedResource{
		Name:     output.Name,
		Type:     output.Type,
		Source:   builds.Source(output.Source),
		Version:  builds.Version(output.Version),
		Metadata: metadata,
	}
}
<|endoftext|>


<commit_before>package main

import "golang.org/x/net/context"
import "os"
import "testing"
import "time"
import pb "github.com/brotherlogic/discogssyncer/server"
import pbd "github.com/brotherlogic/godiscogs"

type testDiscogsRetriever struct{}

func (testDiscogsRetriever) GetCollection() []pbd.Release {
	var releases = make([]pbd.Release, 0)
	releases = append(releases, pbd.Release{FolderId: 23, Id: 25})
	releases = append(releases, pbd.Release{FolderId: 23, Id: 32})
	return releases
}

func (testDiscogsRetriever) GetRelease(id int) (pbd.Release, error) {
	return pbd.Release{}, nil
}

func (testDiscogsRetriever) GetFolders() []pbd.Folder {
	var folders = make([]pbd.Folder, 0)
	folders = append(folders, pbd.Folder{Id: 23, Name: "Testing"})
	folders = append(folders, pbd.Folder{Id: 25, Name: "TestingTwo"})
	return folders
}

func (testDiscogsRetriever) MoveToFolder(fodlerID int, releaseID int, instanceID int, newFolderID int) {
	// Do nothing
}

func (testDiscogsRetriever) AddToFolder(fodlerID int, releaseID int) {
	// Do nothing
}

func TestMoveToFolder(t *testing.T) {
	syncer := GetTestSyncer(".testMoveToFolder")
	release := &pbd.Release{FolderId: 23, Id: 25, InstanceId: 37}
	releaseMove := &pb.ReleaseMove{Release: release, NewFolderId: 20}
	_, err := syncer.MoveToFolder(context.Background(), releaseMove)
	if err != nil {
		t.Errorf("Move to uncat has returned error")
	}
}

func TestAddToFolder(t *testing.T) {
	syncer := GetTestSyncer(".testAddToFolder")
	release := &pbd.Release{Id: 25}
	releaseMove := &pb.ReleaseMove{Release: release, NewFolderId: 20}
	_, err := syncer.AddToFolder(context.Background(), releaseMove)
	if err != nil {
		t.Errorf("Move to uncat has returned error")
	}
}

func TestSaveCollection(t *testing.T) {
	syncer := Syncer{saveLocation: ".testcollectionsave/"}
	syncer.SaveCollection(&testDiscogsRetriever{})
}

func TestGetCollection(t *testing.T) {
	syncer := Syncer{saveLocation: ".testcollectionsave/"}
	syncer.SaveCollection(&testDiscogsRetriever{})

	releases, err := syncer.GetCollection(context.Background(), &pb.Empty{})
	if err != nil {
		t.Errorf("Error returned on Get Collection")
	}

	if len(releases.Releases) == 0 {
		t.Errorf("No releases have been returned")
	}

	folders := syncer.getFolders()
	if len(folders.Folders) != 2 {
		t.Errorf("Not enough folders: %v", folders)
	}

	if folders.Folders[0].Name == folders.Folders[1].Name {
		t.Errorf("FOlders have same name: %v", folders)
	}
}

func TestRetrieveEmptyCollection(t *testing.T) {
	syncer := Syncer{saveLocation: ".testemptyfolder/"}
	folderList := &pb.FolderList{}
	folderList.Folders = append(folderList.Folders, &pbd.Folder{Name: "TestOne", Id: 1234})
	_, err := syncer.GetReleasesInFolder(context.Background(), folderList)
	if err == nil {
		t.Errorf("Pull from empty folder returns no error!")
	}
}

func TestSaveLocation(t *testing.T) {
	syncer := Syncer{saveLocation: ".testfolder/"}
	release := &pbd.Release{Id: 1234}
	syncer.saveRelease(release, 12)

	//Check that the file is in the right location
	if _, err := os.Stat(".testfolder/12/1234.release"); os.IsNotExist(err) {
		t.Errorf("File does not exists")
	}
}

func TestSaveMetadata(t *testing.T) {
	now := time.Now()
	syncer := Syncer{saveLocation: ".testmetadatasave/"}
	release := &pbd.Release{Id: 1234}
	syncer.saveRelease(release, 12)

	_, metadata := syncer.GetRelease(1234, 12)
	if metadata.DateAdded > now.Unix() {
		t.Errorf("Metadata is prior to adding the release: %v (%v)", metadata.DateAdded, metadata.DateAdded-now.Unix())
	}
}

func TestUpdateMetadata(t *testing.T) {
	syncer := GetTestSyncer(".testupdatemetadata")
	release := &pbd.Release{FolderId: 23, Id: 25, InstanceId: 37}
	syncer.saveRelease(release, 12)

	_, metadata := syncer.GetRelease(25, 12)

	newMetadata := pb.ReleaseMetadata{DateAdded: 1234}
	retMetadata, err := syncer.UpdateMetadata(context.Background(), pb.MetadataUpdate{Release: release, Update: newMetadata})
	if err != nil {
		t.Errorf("Failed metadata update: %v", err)
	}

	if retMetadata.DateAdded != 1234 {
		t.Errorf("Date Added has not been updated: %v", retMetadata.DateAdded)
	}

	_, metadataStored := syncer.GetRelease(25, 12)
	if metadataStored.DateAdded != 1234 {
		t.Errorf("Date Added has not been stored: %v", metadataStored.DateAdded)
	}
}

func TestSaveAndRefreshMetadata(t *testing.T) {
	now := time.Now()
	syncer := Syncer{saveLocation: ".testmetadatasave/"}
	release := &pbd.Release{Id: 1234}
	syncer.saveRelease(release, 12)

	_, metadata := syncer.GetRelease(1234, 12)
	if metadata.DateAdded > now.Unix() {
		t.Errorf("Metadata is prior to adding the release: %v (%v)", metadata.DateAdded, metadata.DateAdded-now.Unix())
	}

	time.Sleep(time.Second)
	syncer.saveRelease(release, 12)
	_, metadata2 := syncer.GetRelease(1234, 12)
	if metadata2.DateRefreshed == metadata.DateRefreshed {
		t.Errorf("Metadata has not been refreshed: %v and %v", metadata.DateRefreshed, metadata2.DateRefreshed)
	}
}

func GetTestSyncer(foldername string) Syncer {
	syncer := Syncer{
		saveLocation: foldername,
		retr:         testDiscogsRetriever{},
	}
	return syncer
}

func TestGetFolders(t *testing.T) {
	syncer := GetTestSyncer(".testgetfolders/")
	folders := &pb.FolderList{}
	folders.Folders = append(folders.Folders, &pbd.Folder{Name: "TestOne", Id: 1234})
	folders.Folders = append(folders.Folders, &pbd.Folder{Name: "TestTwo", Id: 1235})
	syncer.SaveFolders(folders)

	release := &pbd.Release{Id: 1234}
	syncer.saveRelease(release, 1234)

	folderList := &pb.FolderList{}
	folderList.Folders = append(folderList.Folders, &pbd.Folder{Name: "TestOne"})
	releases, err := syncer.GetReleasesInFolder(context.Background(), folderList)

	folderList2 := &pb.FolderList{}
	folderList2.Folders = append(folderList2.Folders, &pbd.Folder{Name: "TestTwo"})
	releases2, err2 := syncer.GetReleasesInFolder(context.Background(), folderList2)

	if err != nil {
		t.Errorf("Error retrieveing releases: %v", err)
	}

	if len(releases.Releases) == 0 {
		t.Errorf("GetReleasesInFolder came back empty")
	}

	if err2 == nil {
		t.Errorf("Error retrieving releases: %v", err2)
	}

	if len(releases2.Releases) != 0 {
		t.Errorf("Releases returned for folder 2: %v", releases2)
	}
}

func TestSaveFolderMetaata(t *testing.T) {
	syncer := GetTestSyncer(".testSaveFolderMetadata/")
	folderList := &pb.FolderList{}
	folderList.Folders = append(folderList.Folders, &pbd.Folder{Name: "TestOne", Id: 1234})
	folderList.Folders = append(folderList.Folders, &pbd.Folder{Name: "TestTwo", Id: 1232})

	syncer.SaveFolders(folderList)

	if _, err := os.Stat(".testSaveFolderMetadata/metadata/folders"); os.IsNotExist(err) {
		t.Errorf("Folder metedata has not been save")
	}

}
<commit_msg>Fixed test to fail<commit_after>package main

import "golang.org/x/net/context"
import "os"
import "testing"
import "time"
import pb "github.com/brotherlogic/discogssyncer/server"
import pbd "github.com/brotherlogic/godiscogs"

type testDiscogsRetriever struct{}

func (testDiscogsRetriever) GetCollection() []pbd.Release {
	var releases = make([]pbd.Release, 0)
	releases = append(releases, pbd.Release{FolderId: 23, Id: 25})
	releases = append(releases, pbd.Release{FolderId: 23, Id: 32})
	return releases
}

func (testDiscogsRetriever) GetRelease(id int) (pbd.Release, error) {
	return pbd.Release{}, nil
}

func (testDiscogsRetriever) GetFolders() []pbd.Folder {
	var folders = make([]pbd.Folder, 0)
	folders = append(folders, pbd.Folder{Id: 23, Name: "Testing"})
	folders = append(folders, pbd.Folder{Id: 25, Name: "TestingTwo"})
	return folders
}

func (testDiscogsRetriever) MoveToFolder(fodlerID int, releaseID int, instanceID int, newFolderID int) {
	// Do nothing
}

func (testDiscogsRetriever) AddToFolder(fodlerID int, releaseID int) {
	// Do nothing
}

func TestMoveToFolder(t *testing.T) {
	syncer := GetTestSyncer(".testMoveToFolder")
	release := &pbd.Release{FolderId: 23, Id: 25, InstanceId: 37}
	releaseMove := &pb.ReleaseMove{Release: release, NewFolderId: 20}
	_, err := syncer.MoveToFolder(context.Background(), releaseMove)
	if err != nil {
		t.Errorf("Move to uncat has returned error")
	}
}

func TestAddToFolder(t *testing.T) {
	syncer := GetTestSyncer(".testAddToFolder")
	release := &pbd.Release{Id: 25}
	releaseMove := &pb.ReleaseMove{Release: release, NewFolderId: 20}
	_, err := syncer.AddToFolder(context.Background(), releaseMove)
	if err != nil {
		t.Errorf("Move to uncat has returned error")
	}
}

func TestSaveCollection(t *testing.T) {
	syncer := Syncer{saveLocation: ".testcollectionsave/"}
	syncer.SaveCollection(&testDiscogsRetriever{})
}

func TestGetCollection(t *testing.T) {
	syncer := Syncer{saveLocation: ".testcollectionsave/"}
	syncer.SaveCollection(&testDiscogsRetriever{})

	releases, err := syncer.GetCollection(context.Background(), &pb.Empty{})
	if err != nil {
		t.Errorf("Error returned on Get Collection")
	}

	if len(releases.Releases) == 0 {
		t.Errorf("No releases have been returned")
	}

	folders := syncer.getFolders()
	if len(folders.Folders) != 2 {
		t.Errorf("Not enough folders: %v", folders)
	}

	if folders.Folders[0].Name == folders.Folders[1].Name {
		t.Errorf("FOlders have same name: %v", folders)
	}
}

func TestRetrieveEmptyCollection(t *testing.T) {
	syncer := Syncer{saveLocation: ".testemptyfolder/"}
	folderList := &pb.FolderList{}
	folderList.Folders = append(folderList.Folders, &pbd.Folder{Name: "TestOne", Id: 1234})
	_, err := syncer.GetReleasesInFolder(context.Background(), folderList)
	if err == nil {
		t.Errorf("Pull from empty folder returns no error!")
	}
}

func TestSaveLocation(t *testing.T) {
	syncer := Syncer{saveLocation: ".testfolder/"}
	release := &pbd.Release{Id: 1234}
	syncer.saveRelease(release, 12)

	//Check that the file is in the right location
	if _, err := os.Stat(".testfolder/12/1234.release"); os.IsNotExist(err) {
		t.Errorf("File does not exists")
	}
}

func TestSaveMetadata(t *testing.T) {
	now := time.Now()
	syncer := Syncer{saveLocation: ".testmetadatasave/"}
	release := &pbd.Release{Id: 1234}
	syncer.saveRelease(release, 12)

	_, metadata := syncer.GetRelease(1234, 12)
	if metadata.DateAdded > now.Unix() {
		t.Errorf("Metadata is prior to adding the release: %v (%v)", metadata.DateAdded, metadata.DateAdded-now.Unix())
	}
}

func TestUpdateMetadata(t *testing.T) {
	syncer := GetTestSyncer(".testupdatemetadata")
	release := &pbd.Release{FolderId: 23, Id: 25, InstanceId: 37}
	syncer.saveRelease(release, 12)

	_, metadata := syncer.GetRelease(25, 12)
	if metadata.DateAdded == 1234 {
		t.Errorf("Test bleed through on metadata: %v", metadata)
	}

	newMetadata := &pb.ReleaseMetadata{DateAdded: 1234}
	retMetadata, err := syncer.UpdateMetadata(context.Background(), &pb.MetadataUpdate{Release: release, Update: newMetadata})
	if err != nil {
		t.Errorf("Failed metadata update: %v", err)
	}

	if retMetadata.DateAdded != 1234 {
		t.Errorf("Date Added has not been updated: %v", retMetadata.DateAdded)
	}

	_, metadataStored := syncer.GetRelease(25, 12)
	if metadataStored.DateAdded != 1234 {
		t.Errorf("Date Added has not been stored: %v", metadataStored.DateAdded)
	}
}

func TestSaveAndRefreshMetadata(t *testing.T) {
	now := time.Now()
	syncer := Syncer{saveLocation: ".testmetadatasave/"}
	release := &pbd.Release{Id: 1234}
	syncer.saveRelease(release, 12)

	_, metadata := syncer.GetRelease(1234, 12)
	if metadata.DateAdded > now.Unix() {
		t.Errorf("Metadata is prior to adding the release: %v (%v)", metadata.DateAdded, metadata.DateAdded-now.Unix())
	}

	time.Sleep(time.Second)
	syncer.saveRelease(release, 12)
	_, metadata2 := syncer.GetRelease(1234, 12)
	if metadata2.DateRefreshed == metadata.DateRefreshed {
		t.Errorf("Metadata has not been refreshed: %v and %v", metadata.DateRefreshed, metadata2.DateRefreshed)
	}
}

func GetTestSyncer(foldername string) Syncer {
	syncer := Syncer{
		saveLocation: foldername,
		retr:         testDiscogsRetriever{},
	}
	return syncer
}

func TestGetFolders(t *testing.T) {
	syncer := GetTestSyncer(".testgetfolders/")
	folders := &pb.FolderList{}
	folders.Folders = append(folders.Folders, &pbd.Folder{Name: "TestOne", Id: 1234})
	folders.Folders = append(folders.Folders, &pbd.Folder{Name: "TestTwo", Id: 1235})
	syncer.SaveFolders(folders)

	release := &pbd.Release{Id: 1234}
	syncer.saveRelease(release, 1234)

	folderList := &pb.FolderList{}
	folderList.Folders = append(folderList.Folders, &pbd.Folder{Name: "TestOne"})
	releases, err := syncer.GetReleasesInFolder(context.Background(), folderList)

	folderList2 := &pb.FolderList{}
	folderList2.Folders = append(folderList2.Folders, &pbd.Folder{Name: "TestTwo"})
	releases2, err2 := syncer.GetReleasesInFolder(context.Background(), folderList2)

	if err != nil {
		t.Errorf("Error retrieveing releases: %v", err)
	}

	if len(releases.Releases) == 0 {
		t.Errorf("GetReleasesInFolder came back empty")
	}

	if err2 == nil {
		t.Errorf("Error retrieving releases: %v", err2)
	}

	if len(releases2.Releases) != 0 {
		t.Errorf("Releases returned for folder 2: %v", releases2)
	}
}

func TestSaveFolderMetaata(t *testing.T) {
	syncer := GetTestSyncer(".testSaveFolderMetadata/")
	folderList := &pb.FolderList{}
	folderList.Folders = append(folderList.Folders, &pbd.Folder{Name: "TestOne", Id: 1234})
	folderList.Folders = append(folderList.Folders, &pbd.Folder{Name: "TestTwo", Id: 1232})

	syncer.SaveFolders(folderList)

	if _, err := os.Stat(".testSaveFolderMetadata/metadata/folders"); os.IsNotExist(err) {
		t.Errorf("Folder metedata has not been save")
	}

}
<|endoftext|>


<commit_before>package main

import (
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strconv"
	"testing"
	"time"
)

func TestRecursive(t *testing.T) {
	// Recursive is depth first
	input := [][]int{{1, 0, 6}, {0, 4, 5}, {2, 3}}
	ch := make(chan File)
	go func() {
		recursive(File{}, ch, fakeIndex(input))
		close(ch)
	}()

	expN := 1
LOOP:
	for {
		select {
		case f, ok := <-ch:
			if !ok {
				break LOOP
			}
			n, _ := strconv.Atoi(f.Path)
			if n != expN {
				t.Errorf("%d should have been %d", n, expN)
			}
			expN++
		case <-time.After(100 * time.Millisecond):
			t.Error("timeout expected:", expN)
			break LOOP
		}
	}
	expected := flattenInts(input)
	if expN < len(expected) {
		t.Error("Missing:", expected[expN:])
	}
}

func fakeIndex(nums [][]int) IndexFn {
	i := 0
	return func(f File, ch chan File) {
		for _, n := range nums[i] {
			nf := f
			nf.Path = strconv.Itoa(n)
			if n == 0 {
				i++
			} else {
				nf = nf.SetLeaf()
			}
			ch <- nf
		}
	}
}

func flattenInts(ints [][]int) []int {
	res := []int{}
	for _, g := range ints {
		for _, n := range g {
			if n == 0 {
				continue
			}
			res = append(res, n)
		}
	}
	return res
}

func TestLocalNew(t *testing.T) {
	testLocal(t, func(f File, r io.ReadCloser) File {
		return f
	}, true)
}

func TestLocalOverwriteOlder(t *testing.T) {
	testLocal(t, func(f File, r io.ReadCloser) File {
		err := local(f, r)
		if err != nil {
			t.Error(err)
		}
		f.Mtime = f.Mtime.Add(time.Second)
		return f
	}, true)
}

func TestLocalNotOverwriteNewer(t *testing.T) {
	testLocal(t, func(f File, r io.ReadCloser) File {
		err := local(f, r)
		if err != nil {
			t.Error(err)
		}
		f.Mtime = f.Mtime.Add(-time.Second)
		return f
	}, false)
}

func TestLocalCreateDirs(t *testing.T) {
	testLocal(t, func(f File, r io.ReadCloser) File {
		f.Path += "a/dir/oh/uh/hi/ho"
		return f
	}, true)
}

// Trying to overwrite a directory fails
func TestLocalOverwriteDir(t *testing.T) {
	tmp, rm := TempDir()
	defer rm()
	f, r := someTestFile(tmp)
	err := os.Mkdir(f.Path, 777)
	if err != nil {
		t.Fatal(err)
	}
	err = os.Chtimes(f.Path, time.Now(), time.Now().Add(-time.Hour))
	if err != nil {
		t.Fatal(err)
	}
	if local(f, r) == nil {
		t.Error("should have failed")
	}
}

func testLocal(t *testing.T, init func(File, io.ReadCloser) File, overwrite bool) {
	tmp, rm := TempDir()
	of, r := someTestFile(tmp)
	f := init(of, r)
	err := local(f, r)
	if err != nil {
		t.Error(err)
	}
	if overwrite {
		of = f
	}
	checkFile(t, of)
	rm()
}

func someTestFile(tmp string) (File, io.ReadCloser) {
	f := File{Mtime: time.Now(), Path: tmp + "/a"}
	return f, newFakeCloser("test")
}

func checkFile(t *testing.T, f File) {
	st, err := os.Stat(f.Path)

	f.Mtime = removeSubSecond(f.Mtime)

	if err != nil && os.IsNotExist(err) {
		t.Error("File does not exist:", f.Path)
	} else {
		if !(st.ModTime().Equal(f.Mtime)) {
			t.Errorf("Not overwritten")
		}
	}
}

// OSX does not store time resolutions below seconds
func removeSubSecond(in time.Time) time.Time {
	return time.Date(
		in.Year(),
		in.Month(),
		in.Day(),
		in.Hour(),
		in.Minute(),
		in.Second(),
		0, in.Location())
}

func testTmp(t *testing.T) (name string, stop func()) {
	name, err := ioutil.TempDir("", "websync")
	if err != nil {
		t.Fatal(err)
	}
	name, err = filepath.EvalSymlinks(name)
	if err != nil {
		t.Fatal(err)
	}
	return name, func() {
		if err = os.RemoveAll(name); err != nil {
			t.Fatal(err)
		}
	}
}
<commit_msg>travis<commit_after>package main

import (
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strconv"
	"testing"
	"time"
)

func TestRecursive(t *testing.T) {
	// Recursive is depth first
	input := [][]int{{1, 0, 6}, {0, 4, 5}, {2, 3}}
	ch := make(chan File)
	go func() {
		recursive(File{}, ch, fakeIndex(input))
		close(ch)
	}()

	expN := 1
LOOP:
	for {
		select {
		case f, ok := <-ch:
			if !ok {
				break LOOP
			}
			n, _ := strconv.Atoi(f.Path)
			if n != expN {
				t.Errorf("%d should have been %d", n, expN)
			}
			expN++
		case <-time.After(100 * time.Millisecond):
			t.Error("timeout expected:", expN)
			break LOOP
		}
	}
	expected := flattenInts(input)
	if expN < len(expected) {
		t.Error("Missing:", expected[expN:])
	}
}

func fakeIndex(nums [][]int) IndexFn {
	i := 0
	return func(f File, ch chan File) {
		for _, n := range nums[i] {
			nf := f
			nf.Path = strconv.Itoa(n)
			if n == 0 {
				i++
			} else {
				nf = nf.SetLeaf()
			}
			ch <- nf
		}
	}
}

func flattenInts(ints [][]int) []int {
	res := []int{}
	for _, g := range ints {
		for _, n := range g {
			if n == 0 {
				continue
			}
			res = append(res, n)
		}
	}
	return res
}

func TestLocalNew(t *testing.T) {
	testLocal(t, func(f File, r io.ReadCloser) File {
		return f
	}, true)
}

func TestLocalOverwriteOlder(t *testing.T) {
	testLocal(t, func(f File, r io.ReadCloser) File {
		err := local(f, r)
		if err != nil {
			t.Error(err)
		}
		f.Mtime = f.Mtime.Add(time.Second)
		return f
	}, true)
}

func TestLocalNotOverwriteNewer(t *testing.T) {
	testLocal(t, func(f File, r io.ReadCloser) File {
		err := local(f, r)
		if err != nil {
			t.Error(err)
		}
		f.Mtime = f.Mtime.Add(-time.Second)
		return f
	}, false)
}

func TestLocalCreateDirs(t *testing.T) {
	testLocal(t, func(f File, r io.ReadCloser) File {
		f.Path += "a/dir/oh/uh/hi/ho"
		return f
	}, true)
}

// Trying to overwrite a directory fails
func TestLocalOverwriteDir(t *testing.T) {
	tmp, rm := TempDir()
	defer rm()
	f, r := someTestFile(tmp)
	err := os.Mkdir(f.Path, 777)
	if err != nil {
		t.Fatal(err)
	}
	err = os.Chtimes(f.Path, time.Now(), time.Now().Add(-time.Hour))
	if err != nil {
		t.Fatal(err)
	}
	if local(f, r) == nil {
		t.Error("should have failed")
	}
}

func testLocal(t *testing.T, init func(File, io.ReadCloser) File, overwrite bool) {
	tmp, rm := TempDir()
	of, r := someTestFile(tmp)
	f := init(of, r)
	err := local(f, r)
	if err != nil {
		t.Error(err)
	}
	if overwrite {
		of = f
	}
	checkFile(t, of)
	filepath.Walk(tmp, func(path string, info os.FileInfo, err error) error {
		t.Log(path, info.ModTime(), err)
		return nil
	})
	rm()
}

func someTestFile(tmp string) (File, io.ReadCloser) {
	f := File{Mtime: time.Now(), Path: tmp + "/a"}
	return f, newFakeCloser("test")
}

func checkFile(t *testing.T, f File) {
	st, err := os.Stat(f.Path)

	f.Mtime = removeSubSecond(f.Mtime)

	if err != nil && os.IsNotExist(err) {
		t.Error("File does not exist:", f.Path)
	} else {
		if !(st.ModTime().Equal(f.Mtime)) {
			t.Errorf("Not overwritten")
		}
	}
}

// OSX does not store time resolutions below seconds
func removeSubSecond(in time.Time) time.Time {
	return time.Date(
		in.Year(),
		in.Month(),
		in.Day(),
		in.Hour(),
		in.Minute(),
		in.Second(),
		0, in.Location())
}

func testTmp(t *testing.T) (name string, stop func()) {
	name, err := ioutil.TempDir("", "websync")
	if err != nil {
		t.Fatal(err)
	}
	name, err = filepath.EvalSymlinks(name)
	if err != nil {
		t.Fatal(err)
	}
	return name, func() {
		if err = os.RemoveAll(name); err != nil {
			t.Fatal(err)
		}
	}
}
<|endoftext|>


<commit_before>// +build linux

// Package osutils provide access to the Get Child and Set Child prctl
// flags.
// See http://man7.org/linux/man-pages/man2/prctl.2.html
package sys

import (
	"unsafe"

	"golang.org/x/sys/unix"
)

// PR_SET_CHILD_SUBREAPER allows setting the child subreaper.
// If arg2 is nonzero, set the "child subreaper" attribute of the
// calling process; if arg2 is zero, unset the attribute.  When a
// process is marked as a child subreaper, all of the children
// that it creates, and their descendants, will be marked as
// having a subreaper.  In effect, a subreaper fulfills the role
// of init(1) for its descendant processes.  Upon termination of
// a process that is orphaned (i.e., its immediate parent has
// already terminated) and marked as having a subreaper, the
// nearest still living ancestor subreaper will receive a SIGCHLD
// signal and be able to wait(2) on the process to discover its
// termination status.
const prSetChildSubreaper = 36

// PR_GET_CHILD_SUBREAPER allows retrieving the current child
// subreaper.
// Returns the "child subreaper" setting of the caller, in the
// location pointed to by (int *) arg2.
const prGetChildSubreaper = 37

// GetSubreaper returns the subreaper setting for the calling process
func GetSubreaper() (int, error) {
	var i uintptr
	if _, _, err := unix.RawSyscall(unix.SYS_PRCTL, prGetChildSubreaper, uintptr(unsafe.Pointer(&i)), 0); err != 0 {
		return -1, err
	}
	return int(i), nil
}

// SetSubreaper sets the value i as the subreaper setting for the calling process
func SetSubreaper(i int) error {
	if _, _, err := unix.RawSyscall(unix.SYS_PRCTL, prSetChildSubreaper, uintptr(i), 0); err != 0 {
		return err
	}
	return nil
}
<commit_msg>Use Prctl() and associated constants from x/sys/unix<commit_after>// +build linux

// Package sys provides access to the Get Child and Set Child prctl flags.
// See http://man7.org/linux/man-pages/man2/prctl.2.html
package sys

import (
	"unsafe"

	"golang.org/x/sys/unix"
)

// GetSubreaper returns the subreaper setting for the calling process
func GetSubreaper() (int, error) {
	var i uintptr
	// PR_GET_CHILD_SUBREAPER allows retrieving the current child
	// subreaper.
	// Returns the "child subreaper" setting of the caller, in the
	// location pointed to by (int *) arg2.
	if err := unix.Prctl(unix.PR_GET_CHILD_SUBREAPER, uintptr(unsafe.Pointer(&i)), 0, 0, 0); err != nil {
		return -1, err
	}
	return int(i), nil
}

// SetSubreaper sets the value i as the subreaper setting for the calling process
func SetSubreaper(i int) error {
	// PR_SET_CHILD_SUBREAPER allows setting the child subreaper.
	// If arg2 is nonzero, set the "child subreaper" attribute of the
	// calling process; if arg2 is zero, unset the attribute.  When a
	// process is marked as a child subreaper, all of the children
	// that it creates, and their descendants, will be marked as
	// having a subreaper.  In effect, a subreaper fulfills the role
	// of init(1) for its descendant processes.  Upon termination of
	// a process that is orphaned (i.e., its immediate parent has
	// already terminated) and marked as having a subreaper, the
	// nearest still living ancestor subreaper will receive a SIGCHLD
	// signal and be able to wait(2) on the process to discover its
	// termination status.
	return unix.Prctl(unix.PR_SET_CHILD_SUBREAPER, uintptr(i), 0, 0, 0)
}
<|endoftext|>