<commit_before>package irc

import (
	"strconv"
	"strings"
	"time"
)

func (irc *Connection) AddCallback(eventcode string, callback func(*Event)) {
	eventcode = strings.ToUpper(eventcode)

	if _, ok := irc.events[eventcode]; ok {
		irc.events[eventcode] = append(irc.events[eventcode], callback)

	} else {
		irc.events[eventcode] = make([]func(*Event), 1)
		irc.events[eventcode][0] = callback
	}
}

func (irc *Connection) ReplaceCallback(eventcode string, i int, callback func(*Event)) {
	eventcode = strings.ToUpper(eventcode)

	if event, ok := irc.events[eventcode]; ok {
		if i < len(event) {
			event[i] = callback
			return
		}
		irc.Log.Printf("Event found, but no callback found at index %d. Use AddCallback\n", i)
		return
	}
	irc.Log.Printf("Event not found. Use AddCallBack\n")
}

func (irc *Connection) RunCallbacks(event *Event) {
	if event.Code == "PRIVMSG" && len(event.Message) > 0 && event.Message[0] == '\x01' {
		event.Code = "CTCP" //Unknown CTCP

		if i := strings.LastIndex(event.Message, "\x01"); i > -1 {
			event.Message = event.Message[1:i]
		}

		if event.Message == "VERSION" {
			event.Code = "CTCP_VERSION"

		} else if event.Message == "TIME" {
			event.Code = "CTCP_TIME"

		} else if event.Message[0:4] == "PING" {
			event.Code = "CTCP_PING"

		} else if event.Message == "USERINFO" {
			event.Code = "CTCP_USERINFO"

		} else if event.Message == "CLIENTINFO" {
			event.Code = "CTCP_CLIENTINFO"

		} else if event.Message[0:6] == "ACTION" {
			event.Code = "CTCP_ACTION"
			event.Message = event.Message[7:]

		}
	}

	if callbacks, ok := irc.events[event.Code]; ok {
		if irc.VerboseCallbackHandler {
			irc.Log.Printf("%v (%v) >> %#v\n", event.Code, len(callbacks), event)
		}

		for _, callback := range callbacks {
			go callback(event)
		}

	} else if irc.VerboseCallbackHandler {
		irc.Log.Printf("%v (0) >> %#v\n", event.Code, event)
	}
}

func (irc *Connection) setupCallbacks() {
	irc.events = make(map[string][]func(*Event))

	//Handle ping events
	irc.AddCallback("PING", func(e *Event) { irc.SendRaw("PONG :" + e.Message) })

	//Version handler
	irc.AddCallback("CTCP_VERSION", func(e *Event) {
		irc.SendRawf("NOTICE %s :\x01VERSION %s\x01", e.Nick, irc.Version)
	})

	irc.AddCallback("CTCP_USERINFO", func(e *Event) {
		irc.SendRawf("NOTICE %s :\x01USERINFO %s\x01", e.Nick, irc.user)
	})

	irc.AddCallback("CTCP_CLIENTINFO", func(e *Event) {
		irc.SendRawf("NOTICE %s :\x01CLIENTINFO PING VERSION TIME USERINFO CLIENTINFO\x01", e.Nick)
	})

	irc.AddCallback("CTCP_TIME", func(e *Event) {
		ltime := time.Now()
		irc.SendRawf("NOTICE %s :\x01TIME %s\x01", e.Nick, ltime.String())
	})

	irc.AddCallback("CTCP_PING", func(e *Event) { irc.SendRawf("NOTICE %s :\x01%s\x01", e.Nick, e.Message) })

	irc.AddCallback("437", func(e *Event) {
		irc.nickcurrent = irc.nickcurrent + "_"
		irc.SendRawf("NICK %s", irc.nickcurrent)
	})

	irc.AddCallback("433", func(e *Event) {
		if len(irc.nickcurrent) > 8 {
			irc.nickcurrent = "_" + irc.nickcurrent

		} else {
			irc.nickcurrent = irc.nickcurrent + "_"
		}
		irc.SendRawf("NICK %s", irc.nickcurrent)
	})

	irc.AddCallback("PONG", func(e *Event) {
		ns, _ := strconv.ParseInt(e.Message, 10, 64)
		delta := time.Duration(time.Now().UnixNano() - ns)
		if irc.Debug {
			irc.Log.Printf("Lag: %vs\n", delta)
		}
	})

	irc.AddCallback("NICK", func(e *Event) {
		if e.Nick == irc.nick {
			irc.nickcurrent = e.Message
		}
	})

	irc.AddCallback("001", func(e *Event) {
		irc.nickcurrent = e.Arguments[0]
	})
}
<commit_msg>Added ability to get the index of a callback in the callback registry. Ability to process events against a 'wildcard' handler<commit_after>package irc

import (
	"strconv"
	"strings"
	"time"
)

func (irc *Connection) AddCallback(eventcode string, callback func(*Event)) (idx int) {
	eventcode = strings.ToUpper(eventcode)

	if _, ok := irc.events[eventcode]; ok {
		irc.events[eventcode] = append(irc.events[eventcode], callback)
		idx = len(irc.events[eventcode]) - 1
	} else {
		irc.events[eventcode] = make([]func(*Event), 1)
		irc.events[eventcode][0] = callback
		idx = 0
	}
	return
}

func (irc *Connection) RemoveCallback(eventcode string, i int) {
	eventcode = strings.ToUpper(eventcode)

	if event, ok := irc.events[eventcode]; ok {
		if i < len(event) {
			irc.events[eventcode] = append(event[:i], event[i+1:]...)
			return
		}
		irc.Log.Printf("Event found, but no callback found at index %d.\n", i)
		return
	}
	irc.Log.Printf("Event not found\n")
}

func (irc *Connection) ReplaceCallback(eventcode string, i int, callback func(*Event)) {
	eventcode = strings.ToUpper(eventcode)

	if event, ok := irc.events[eventcode]; ok {
		if i < len(event) {
			event[i] = callback
			return
		}
		irc.Log.Printf("Event found, but no callback found at index %d. Use AddCallback\n", i)
		return
	}
	irc.Log.Printf("Event not found. Use AddCallBack\n")
}

func (irc *Connection) RunCallbacks(event *Event) {
	if event.Code == "PRIVMSG" && len(event.Message) > 0 && event.Message[0] == '\x01' {
		event.Code = "CTCP" //Unknown CTCP

		if i := strings.LastIndex(event.Message, "\x01"); i > -1 {
			event.Message = event.Message[1:i]
		}

		if event.Message == "VERSION" {
			event.Code = "CTCP_VERSION"

		} else if event.Message == "TIME" {
			event.Code = "CTCP_TIME"

		} else if event.Message[0:4] == "PING" {
			event.Code = "CTCP_PING"

		} else if event.Message == "USERINFO" {
			event.Code = "CTCP_USERINFO"

		} else if event.Message == "CLIENTINFO" {
			event.Code = "CTCP_CLIENTINFO"

		} else if event.Message[0:6] == "ACTION" {
			event.Code = "CTCP_ACTION"
			event.Message = event.Message[7:]

		}
	}

	if callbacks, ok := irc.events[event.Code]; ok {
		if irc.VerboseCallbackHandler {
			irc.Log.Printf("%v (%v) >> %#v\n", event.Code, len(callbacks), event)
		}

		for _, callback := range callbacks {
			go callback(event)
		}
	} else if irc.VerboseCallbackHandler {
		irc.Log.Printf("%v (0) >> %#v\n", event.Code, event)
	}

	if callbacks, ok := irc.events["*"]; ok {
		if irc.VerboseCallbackHandler {
			irc.Log.Printf("Wildcard %v (%v) >> %#v\n", event.Code, len(callbacks), event)
		}

		for _, callback := range callbacks {
			go callback(event)
		}
	}
}

func (irc *Connection) setupCallbacks() {
	irc.events = make(map[string][]func(*Event))

	//Handle ping events
	irc.AddCallback("PING", func(e *Event) { irc.SendRaw("PONG :" + e.Message) })

	//Version handler
	irc.AddCallback("CTCP_VERSION", func(e *Event) {
		irc.SendRawf("NOTICE %s :\x01VERSION %s\x01", e.Nick, irc.Version)
	})

	irc.AddCallback("CTCP_USERINFO", func(e *Event) {
		irc.SendRawf("NOTICE %s :\x01USERINFO %s\x01", e.Nick, irc.user)
	})

	irc.AddCallback("CTCP_CLIENTINFO", func(e *Event) {
		irc.SendRawf("NOTICE %s :\x01CLIENTINFO PING VERSION TIME USERINFO CLIENTINFO\x01", e.Nick)
	})

	irc.AddCallback("CTCP_TIME", func(e *Event) {
		ltime := time.Now()
		irc.SendRawf("NOTICE %s :\x01TIME %s\x01", e.Nick, ltime.String())
	})

	irc.AddCallback("CTCP_PING", func(e *Event) { irc.SendRawf("NOTICE %s :\x01%s\x01", e.Nick, e.Message) })

	irc.AddCallback("437", func(e *Event) {
		irc.nickcurrent = irc.nickcurrent + "_"
		irc.SendRawf("NICK %s", irc.nickcurrent)
	})

	irc.AddCallback("433", func(e *Event) {
		if len(irc.nickcurrent) > 8 {
			irc.nickcurrent = "_" + irc.nickcurrent

		} else {
			irc.nickcurrent = irc.nickcurrent + "_"
		}
		irc.SendRawf("NICK %s", irc.nickcurrent)
	})

	irc.AddCallback("PONG", func(e *Event) {
		ns, _ := strconv.ParseInt(e.Message, 10, 64)
		delta := time.Duration(time.Now().UnixNano() - ns)
		if irc.Debug {
			irc.Log.Printf("Lag: %vs\n", delta)
		}
	})

	irc.AddCallback("NICK", func(e *Event) {
		if e.Nick == irc.nick {
			irc.nickcurrent = e.Message
		}
	})

	irc.AddCallback("001", func(e *Event) {
		irc.nickcurrent = e.Arguments[0]
	})
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Vitess Authors.

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

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

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

package sqltypes

import (
	"testing"

	"github.com/golang/protobuf/proto"
	querypb "vitess.io/vitess/go/vt/proto/query"
	vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
	"vitess.io/vitess/go/vt/vterrors"
)

func TestResult(t *testing.T) {
	fields := []*querypb.Field{{
		Name: "col1",
		Type: VarChar,
	}, {
		Name: "col2",
		Type: Int64,
	}, {
		Name: "col3",
		Type: Float64,
	}}
	sqlResult := &Result{
		Fields:       fields,
		InsertID:     1,
		RowsAffected: 2,
		Rows: [][]Value{{
			TestValue(VarChar, "aa"),
			TestValue(Int64, "1"),
			TestValue(Float64, "2"),
		}, {
			MakeTrusted(VarChar, []byte("bb")),
			NULL,
			NULL,
		}},
	}
	p3Result := &querypb.QueryResult{
		Fields:       fields,
		InsertId:     1,
		RowsAffected: 2,
		Rows: []*querypb.Row{{
			Lengths: []int64{2, 1, 1},
			Values:  []byte("aa12"),
		}, {
			Lengths: []int64{2, -1, -1},
			Values:  []byte("bb"),
		}},
	}
	p3converted := ResultToProto3(sqlResult)
	if !proto.Equal(p3converted, p3Result) {
		t.Errorf("P3:\n%v, want\n%v", p3converted, p3Result)
	}

	reverse := Proto3ToResult(p3Result)
	if !reverse.Equal(sqlResult) {
		t.Errorf("reverse:\n%#v, want\n%#v", reverse, sqlResult)
	}

	// Test custom fields.
	fields[1].Type = VarBinary
	sqlResult.Rows[0][1] = TestValue(VarBinary, "1")
	reverse = CustomProto3ToResult(fields, p3Result)
	if !reverse.Equal(sqlResult) {
		t.Errorf("reverse:\n%#v, want\n%#v", reverse, sqlResult)
	}
}

func TestResults(t *testing.T) {
	fields1 := []*querypb.Field{{
		Name: "col1",
		Type: VarChar,
	}, {
		Name: "col2",
		Type: Int64,
	}, {
		Name: "col3",
		Type: Float64,
	}}
	fields2 := []*querypb.Field{{
		Name: "col11",
		Type: VarChar,
	}, {
		Name: "col12",
		Type: Int64,
	}, {
		Name: "col13",
		Type: Float64,
	}}
	sqlResults := []Result{{
		Fields:       fields1,
		InsertID:     1,
		RowsAffected: 2,
		Rows: [][]Value{{
			TestValue(VarChar, "aa"),
			TestValue(Int64, "1"),
			TestValue(Float64, "2"),
		}},
	}, {
		Fields:       fields2,
		InsertID:     3,
		RowsAffected: 4,
		Rows: [][]Value{{
			TestValue(VarChar, "bb"),
			TestValue(Int64, "3"),
			TestValue(Float64, "4"),
		}},
	}}
	p3Results := []*querypb.QueryResult{{
		Fields:       fields1,
		InsertId:     1,
		RowsAffected: 2,
		Rows: []*querypb.Row{{
			Lengths: []int64{2, 1, 1},
			Values:  []byte("aa12"),
		}},
	}, {
		Fields:       fields2,
		InsertId:     3,
		RowsAffected: 4,
		Rows: []*querypb.Row{{
			Lengths: []int64{2, 1, 1},
			Values:  []byte("bb34"),
		}},
	}}
	p3converted := ResultsToProto3(sqlResults)
	if !Proto3ResultsEqual(p3converted, p3Results) {
		t.Errorf("P3:\n%v, want\n%v", p3converted, p3Results)
	}

	reverse := Proto3ToResults(p3Results)
	if !ResultsEqual(reverse, sqlResults) {
		t.Errorf("reverse:\n%#v, want\n%#v", reverse, sqlResults)
	}
}

func TestQueryReponses(t *testing.T) {
	fields1 := []*querypb.Field{{
		Name: "col1",
		Type: VarChar,
	}, {
		Name: "col2",
		Type: Int64,
	}, {
		Name: "col3",
		Type: Float64,
	}}
	fields2 := []*querypb.Field{{
		Name: "col11",
		Type: VarChar,
	}, {
		Name: "col12",
		Type: Int64,
	}, {
		Name: "col13",
		Type: Float64,
	}}

	queryResponses := []QueryResponse{
		{
			QueryResult: &Result{
				Fields:       fields1,
				InsertID:     1,
				RowsAffected: 2,
				Rows: [][]Value{{
					TestValue(VarChar, "aa"),
					TestValue(Int64, "1"),
					TestValue(Float64, "2"),
				}},
			},
			QueryError: nil,
		}, {
			QueryResult: &Result{
				Fields:       fields2,
				InsertID:     3,
				RowsAffected: 4,
				Rows: [][]Value{{
					TestValue(VarChar, "bb"),
					TestValue(Int64, "3"),
					TestValue(Float64, "4"),
				}},
			},
			QueryError: nil,
		}, {
			QueryResult: nil,
			QueryError:  vterrors.New(vtrpcpb.Code_DEADLINE_EXCEEDED, "deadline exceeded"),
		},
	}

	p3ResultWithError := []*querypb.ResultWithError{
		{
			Error: nil,
			Result: &querypb.QueryResult{
				Fields:       fields1,
				InsertId:     1,
				RowsAffected: 2,
				Rows: []*querypb.Row{{
					Lengths: []int64{2, 1, 1},
					Values:  []byte("aa12"),
				}},
			},
		}, {
			Error: nil,
			Result: &querypb.QueryResult{
				Fields:       fields2,
				InsertId:     3,
				RowsAffected: 4,
				Rows: []*querypb.Row{{
					Lengths: []int64{2, 1, 1},
					Values:  []byte("bb34"),
				}},
			},
		}, {
			Error: &vtrpcpb.RPCError{
				LegacyCode: vtrpcpb.LegacyErrorCode_DEADLINE_EXCEEDED_LEGACY,
				Message:    "deadline exceeded",
				Code:       vtrpcpb.Code_DEADLINE_EXCEEDED,
			},
			Result: nil,
		},
	}
	p3converted := QueryResponsesToProto3(queryResponses)
	if !Proto3QueryResponsesEqual(p3converted, p3ResultWithError) {
		t.Errorf("P3:\n%v, want\n%v", p3converted, p3ResultWithError)
	}

	reverse := Proto3ToQueryReponses(p3ResultWithError)
	if !QueryResponsesEqual(reverse, queryResponses) {
		t.Errorf("reverse:\n%#v, want\n%#v", reverse, queryResponses)
	}
}
<commit_msg>Add unit test for func Proto3ValuesEqual.<commit_after>/*
Copyright 2019 The Vitess Authors.

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

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

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

package sqltypes

import (
	"testing"

	"github.com/golang/protobuf/proto"
	"github.com/stretchr/testify/require"
	querypb "vitess.io/vitess/go/vt/proto/query"
	vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
	"vitess.io/vitess/go/vt/vterrors"
)

func TestResult(t *testing.T) {
	fields := []*querypb.Field{{
		Name: "col1",
		Type: VarChar,
	}, {
		Name: "col2",
		Type: Int64,
	}, {
		Name: "col3",
		Type: Float64,
	}}
	sqlResult := &Result{
		Fields:       fields,
		InsertID:     1,
		RowsAffected: 2,
		Rows: [][]Value{{
			TestValue(VarChar, "aa"),
			TestValue(Int64, "1"),
			TestValue(Float64, "2"),
		}, {
			MakeTrusted(VarChar, []byte("bb")),
			NULL,
			NULL,
		}},
	}
	p3Result := &querypb.QueryResult{
		Fields:       fields,
		InsertId:     1,
		RowsAffected: 2,
		Rows: []*querypb.Row{{
			Lengths: []int64{2, 1, 1},
			Values:  []byte("aa12"),
		}, {
			Lengths: []int64{2, -1, -1},
			Values:  []byte("bb"),
		}},
	}
	p3converted := ResultToProto3(sqlResult)
	if !proto.Equal(p3converted, p3Result) {
		t.Errorf("P3:\n%v, want\n%v", p3converted, p3Result)
	}

	reverse := Proto3ToResult(p3Result)
	if !reverse.Equal(sqlResult) {
		t.Errorf("reverse:\n%#v, want\n%#v", reverse, sqlResult)
	}

	// Test custom fields.
	fields[1].Type = VarBinary
	sqlResult.Rows[0][1] = TestValue(VarBinary, "1")
	reverse = CustomProto3ToResult(fields, p3Result)
	if !reverse.Equal(sqlResult) {
		t.Errorf("reverse:\n%#v, want\n%#v", reverse, sqlResult)
	}
}

func TestResults(t *testing.T) {
	fields1 := []*querypb.Field{{
		Name: "col1",
		Type: VarChar,
	}, {
		Name: "col2",
		Type: Int64,
	}, {
		Name: "col3",
		Type: Float64,
	}}
	fields2 := []*querypb.Field{{
		Name: "col11",
		Type: VarChar,
	}, {
		Name: "col12",
		Type: Int64,
	}, {
		Name: "col13",
		Type: Float64,
	}}
	sqlResults := []Result{{
		Fields:       fields1,
		InsertID:     1,
		RowsAffected: 2,
		Rows: [][]Value{{
			TestValue(VarChar, "aa"),
			TestValue(Int64, "1"),
			TestValue(Float64, "2"),
		}},
	}, {
		Fields:       fields2,
		InsertID:     3,
		RowsAffected: 4,
		Rows: [][]Value{{
			TestValue(VarChar, "bb"),
			TestValue(Int64, "3"),
			TestValue(Float64, "4"),
		}},
	}}
	p3Results := []*querypb.QueryResult{{
		Fields:       fields1,
		InsertId:     1,
		RowsAffected: 2,
		Rows: []*querypb.Row{{
			Lengths: []int64{2, 1, 1},
			Values:  []byte("aa12"),
		}},
	}, {
		Fields:       fields2,
		InsertId:     3,
		RowsAffected: 4,
		Rows: []*querypb.Row{{
			Lengths: []int64{2, 1, 1},
			Values:  []byte("bb34"),
		}},
	}}
	p3converted := ResultsToProto3(sqlResults)
	if !Proto3ResultsEqual(p3converted, p3Results) {
		t.Errorf("P3:\n%v, want\n%v", p3converted, p3Results)
	}

	reverse := Proto3ToResults(p3Results)
	if !ResultsEqual(reverse, sqlResults) {
		t.Errorf("reverse:\n%#v, want\n%#v", reverse, sqlResults)
	}
}

func TestQueryReponses(t *testing.T) {
	fields1 := []*querypb.Field{{
		Name: "col1",
		Type: VarChar,
	}, {
		Name: "col2",
		Type: Int64,
	}, {
		Name: "col3",
		Type: Float64,
	}}
	fields2 := []*querypb.Field{{
		Name: "col11",
		Type: VarChar,
	}, {
		Name: "col12",
		Type: Int64,
	}, {
		Name: "col13",
		Type: Float64,
	}}

	queryResponses := []QueryResponse{
		{
			QueryResult: &Result{
				Fields:       fields1,
				InsertID:     1,
				RowsAffected: 2,
				Rows: [][]Value{{
					TestValue(VarChar, "aa"),
					TestValue(Int64, "1"),
					TestValue(Float64, "2"),
				}},
			},
			QueryError: nil,
		}, {
			QueryResult: &Result{
				Fields:       fields2,
				InsertID:     3,
				RowsAffected: 4,
				Rows: [][]Value{{
					TestValue(VarChar, "bb"),
					TestValue(Int64, "3"),
					TestValue(Float64, "4"),
				}},
			},
			QueryError: nil,
		}, {
			QueryResult: nil,
			QueryError:  vterrors.New(vtrpcpb.Code_DEADLINE_EXCEEDED, "deadline exceeded"),
		},
	}

	p3ResultWithError := []*querypb.ResultWithError{
		{
			Error: nil,
			Result: &querypb.QueryResult{
				Fields:       fields1,
				InsertId:     1,
				RowsAffected: 2,
				Rows: []*querypb.Row{{
					Lengths: []int64{2, 1, 1},
					Values:  []byte("aa12"),
				}},
			},
		}, {
			Error: nil,
			Result: &querypb.QueryResult{
				Fields:       fields2,
				InsertId:     3,
				RowsAffected: 4,
				Rows: []*querypb.Row{{
					Lengths: []int64{2, 1, 1},
					Values:  []byte("bb34"),
				}},
			},
		}, {
			Error: &vtrpcpb.RPCError{
				LegacyCode: vtrpcpb.LegacyErrorCode_DEADLINE_EXCEEDED_LEGACY,
				Message:    "deadline exceeded",
				Code:       vtrpcpb.Code_DEADLINE_EXCEEDED,
			},
			Result: nil,
		},
	}
	p3converted := QueryResponsesToProto3(queryResponses)
	if !Proto3QueryResponsesEqual(p3converted, p3ResultWithError) {
		t.Errorf("P3:\n%v, want\n%v", p3converted, p3ResultWithError)
	}

	reverse := Proto3ToQueryReponses(p3ResultWithError)
	if !QueryResponsesEqual(reverse, queryResponses) {
		t.Errorf("reverse:\n%#v, want\n%#v", reverse, queryResponses)
	}
}

func TestProto3ValuesEqual(t *testing.T) {
	for _, tc := range []struct {
		v1, v2   []*querypb.Value
		expected bool
	}{
		{
			v1: []*querypb.Value{
				{
					Type:  0,
					Value: []byte{0, 1},
				},
			},
			v2: []*querypb.Value{
				{
					Type:  0,
					Value: []byte{0, 1},
				},
				{
					Type:  1,
					Value: []byte{0, 1, 2},
				},
			},
			expected: false,
		},
		{
			v1: []*querypb.Value{
				{
					Type:  0,
					Value: []byte{0, 1},
				},
				{
					Type:  1,
					Value: []byte{0, 1, 2},
				},
			},
			v2: []*querypb.Value{
				{
					Type:  0,
					Value: []byte{0, 1},
				},
				{
					Type:  1,
					Value: []byte{0, 1, 2},
				},
			},
			expected: true,
		},
		{
			v1: []*querypb.Value{
				{
					Type:  0,
					Value: []byte{0, 1},
				},
				{
					Type:  1,
					Value: []byte{0, 1},
				},
			},
			v2: []*querypb.Value{
				{
					Type:  0,
					Value: []byte{0, 1},
				},
				{
					Type:  1,
					Value: []byte{0, 1, 2},
				},
			},
			expected: false,
		},
	} {
		require.Equal(t, tc.expected, Proto3ValuesEqual(tc.v1, tc.v2))
	}
}
<|endoftext|>


<commit_before>package gocd

import (
	"github.com/h2non/gock"
	"testing"
)

type MockClient struct {
}

//func TestConfigurationService(t *testing.T) {
//	defer gock.Off() // Flush pending mocks after test execution
//	cs := ConfigurationService{}
//}
<commit_msg>Removed unused imports<commit_after>package gocd

type MockClient struct {
}

//func TestConfigurationService(t *testing.T) {
//	defer gock.Off() // Flush pending mocks after test execution
//	cs := ConfigurationService{}
//}
<|endoftext|>


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

// +build ignore

// Command makestatic reads a set of files and writes a Go source file to "static.go"
// that declares a map of string constants containing contents of the input files.
// It is intended to be invoked via "go generate" (directive in "gen.go").
package main

import (
	"bytes"
	"fmt"
	"go/format"
	"io/ioutil"
	"os"
	"time"
	"unicode/utf8"
)

var files = []string{
	"analysis/call3.png",
	"analysis/call-eg.png",
	"analysis/callers1.png",
	"analysis/callers2.png",
	"analysis/chan1.png",
	"analysis/chan2a.png",
	"analysis/chan2b.png",
	"analysis/error1.png",
	"analysis/help.html",
	"analysis/ident-def.png",
	"analysis/ident-field.png",
	"analysis/ident-func.png",
	"analysis/ipcg-func.png",
	"analysis/ipcg-pkg.png",
	"analysis/typeinfo-pkg.png",
	"analysis/typeinfo-src.png",
	"callgraph.html",
	"codewalk.html",
	"codewalkdir.html",
	"dirlist.html",
	"error.html",
	"example.html",
	"godoc.html",
	"godocs.js",
	"images/minus.gif",
	"images/plus.gif",
	"images/treeview-black-line.gif",
	"images/treeview-black.gif",
	"images/treeview-default-line.gif",
	"images/treeview-default.gif",
	"images/treeview-gray-line.gif",
	"images/treeview-gray.gif",
	"implements.html",
	"jquery.js",
	"jquery.treeview.css",
	"jquery.treeview.edit.js",
	"jquery.treeview.js",
	"methodset.html",
	"opensearch.xml",
	"package.html",
	"packageroot.html",
	"package.txt",
	"play.js",
	"playground.js",
	"search.html",
	"search.txt",
	"searchcode.html",
	"searchdoc.html",
	"searchtxt.html",
	"style.css",
}

func main() {
	if err := makestatic(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

func makestatic() error {
	f, err := os.Create("static.go")
	if err != nil {
		return err
	}
	defer f.Close()
	buf := new(bytes.Buffer)
	fmt.Fprintf(buf, "%v\n\n%v\n\npackage static\n\n", license, warning)
	fmt.Fprintf(buf, "var Files = map[string]string{\n")
	for _, fn := range files {
		b, err := ioutil.ReadFile(fn)
		if err != nil {
			return err
		}
		fmt.Fprintf(buf, "\t%q: ", fn)
		if utf8.Valid(b) {
			fmt.Fprintf(buf, "`%s`", sanitize(b))
		} else {
			fmt.Fprintf(buf, "%q", b)
		}
		fmt.Fprintln(buf, ",\n")
	}
	fmt.Fprintln(buf, "}")
	fmtbuf, err := format.Source(buf.Bytes())
	if err != nil {
		return err
	}
	return ioutil.WriteFile("static.go", fmtbuf, 0666)
}

// sanitize prepares a valid UTF-8 string as a raw string constant.
func sanitize(b []byte) []byte {
	// Replace ` with `+"`"+`
	b = bytes.Replace(b, []byte("`"), []byte("`+\"`\"+`"), -1)

	// Replace BOM with `+"\xEF\xBB\xBF"+`
	// (A BOM is valid UTF-8 but not permitted in Go source files.
	// I wouldn't bother handling this, but for some insane reason
	// jquery.js has a BOM somewhere in the middle.)
	return bytes.Replace(b, []byte("\xEF\xBB\xBF"), []byte("`+\"\\xEF\\xBB\\xBF\"+`"), -1)
}

const warning = `// Code generated by "makestatic"; DO NOT EDIT.`

var license = fmt.Sprintf(`// Copyright %d The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.`, time.Now().UTC().Year())
<commit_msg>godoc/static: cleanup unused lines in makestatic.go<commit_after>// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build ignore

// Command makestatic reads a set of files and writes a Go source file to "static.go"
// that declares a map of string constants containing contents of the input files.
// It is intended to be invoked via "go generate" (directive in "gen.go").
package main

import (
	"bytes"
	"fmt"
	"go/format"
	"io/ioutil"
	"os"
	"time"
	"unicode/utf8"
)

var files = []string{
	"analysis/call3.png",
	"analysis/call-eg.png",
	"analysis/callers1.png",
	"analysis/callers2.png",
	"analysis/chan1.png",
	"analysis/chan2a.png",
	"analysis/chan2b.png",
	"analysis/error1.png",
	"analysis/help.html",
	"analysis/ident-def.png",
	"analysis/ident-field.png",
	"analysis/ident-func.png",
	"analysis/ipcg-func.png",
	"analysis/ipcg-pkg.png",
	"analysis/typeinfo-pkg.png",
	"analysis/typeinfo-src.png",
	"callgraph.html",
	"codewalk.html",
	"codewalkdir.html",
	"dirlist.html",
	"error.html",
	"example.html",
	"godoc.html",
	"godocs.js",
	"images/minus.gif",
	"images/plus.gif",
	"images/treeview-black-line.gif",
	"images/treeview-black.gif",
	"images/treeview-default-line.gif",
	"images/treeview-default.gif",
	"images/treeview-gray-line.gif",
	"images/treeview-gray.gif",
	"implements.html",
	"jquery.js",
	"jquery.treeview.css",
	"jquery.treeview.edit.js",
	"jquery.treeview.js",
	"methodset.html",
	"opensearch.xml",
	"package.html",
	"packageroot.html",
	"package.txt",
	"play.js",
	"playground.js",
	"search.html",
	"search.txt",
	"searchcode.html",
	"searchdoc.html",
	"searchtxt.html",
	"style.css",
}

func main() {
	if err := makestatic(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

func makestatic() error {
	buf := new(bytes.Buffer)
	fmt.Fprintf(buf, "%v\n\n%v\n\npackage static\n\n", license, warning)
	fmt.Fprintf(buf, "var Files = map[string]string{\n")
	for _, fn := range files {
		b, err := ioutil.ReadFile(fn)
		if err != nil {
			return err
		}
		fmt.Fprintf(buf, "\t%q: ", fn)
		if utf8.Valid(b) {
			fmt.Fprintf(buf, "`%s`", sanitize(b))
		} else {
			fmt.Fprintf(buf, "%q", b)
		}
		fmt.Fprintln(buf, ",\n")
	}
	fmt.Fprintln(buf, "}")
	fmtbuf, err := format.Source(buf.Bytes())
	if err != nil {
		return err
	}
	return ioutil.WriteFile("static.go", fmtbuf, 0666)
}

// sanitize prepares a valid UTF-8 string as a raw string constant.
func sanitize(b []byte) []byte {
	// Replace ` with `+"`"+`
	b = bytes.Replace(b, []byte("`"), []byte("`+\"`\"+`"), -1)

	// Replace BOM with `+"\xEF\xBB\xBF"+`
	// (A BOM is valid UTF-8 but not permitted in Go source files.
	// I wouldn't bother handling this, but for some insane reason
	// jquery.js has a BOM somewhere in the middle.)
	return bytes.Replace(b, []byte("\xEF\xBB\xBF"), []byte("`+\"\\xEF\\xBB\\xBF\"+`"), -1)
}

const warning = `// Code generated by "makestatic"; DO NOT EDIT.`

var license = fmt.Sprintf(`// Copyright %d The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.`, time.Now().UTC().Year())
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"html/template"
	"os"
)

type Installations struct {
	InstallationItems []installationItem `json:"installations"`
}

type installationItem struct {
	Label       string `json:"label"`
	Services    []ServiceItem `json:"services"`
	Lambdas     []string `json:"lambdas"`
}

type CredentialsItem struct {
	Profile   string `json:"profile"`
	AwsKey    string `json:"awsKey"`
	AwsSecret string `json:"awsSecret"`
}

type ServiceItem struct {
	Label   string `json:"label"`
	Cluster string `json:"cluster"`
	Service string `json:"service"`
}

type Output struct {
	Installations []OutputTemplate
}

type OutputTemplate struct {
	Label    string
	Services []OutputItem
	Lambdas []LambdaOutputItem
}

type OutputItem struct {
	Label        string
	TaskDefName  string
	Image        string
	Version      string
	DesiredCount int64
	RunningCount int64
}

type LambdaOutputItem struct {
	Label string
	Version string
	Description string
}

func GenerateReport(jsonData []byte, templateFile string) {
	var config Installations

	err := json.Unmarshal(jsonData, &config)

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

	output := Output{}

	for i := 0; i < len(config.InstallationItems); i++ {
		installation := config.InstallationItems[i];

		outputTemplate := OutputTemplate{
			Label : installation.Label,
		}

		for j := 0; j < len(installation.Services); j++ {

			service := installation.Services[j]
			clusterArn := GetClusterArn(service.Cluster);
			serviceArn := GetServiceArn(clusterArn, service.Service);

			serviceDescription := _describeService(clusterArn, serviceArn)

			for k := 0; k < len(serviceDescription.Services); k++ {

				realService := serviceDescription.Services[k];

				taskDefinition := _describeTaskDefinition(*realService.TaskDefinition);
				version, image := ExtractVersion(*taskDefinition.TaskDefinition.ContainerDefinitions[0].Image)

				for l := 0; l < len(realService.Deployments); l++ {
					deployment := realService.Deployments[l];
					outputItem := OutputItem{
						Version: version,
						Image:ExtractImageName(image),
						TaskDefName:ExtractName(deployment.TaskDefinition),
						Label:service.Label,
						RunningCount:*deployment.RunningCount,
						DesiredCount:*deployment.DesiredCount,
					}
					outputTemplate.Services = append(outputTemplate.Services, outputItem)
				}
			}

		}

		for k := 0; k < len(installation.Lambdas); k++ {
			lambdaFunction := installation.Lambdas[k]

			aliasInfo := _getLambdaFunctionAliasInfo(lambdaFunction, "PRIMARY")

			functionInfo := _getLambdaFunctionInfo(lambdaFunction, *aliasInfo.FunctionVersion);

			outputItem := LambdaOutputItem{
				Description: *aliasInfo.Description,
				Version: *functionInfo.Version,
				Label: *functionInfo.Description,
			}

			outputTemplate.Lambdas = append(outputTemplate.Lambdas, outputItem)
		}

		output.Installations = append(output.Installations, outputTemplate)
	}

	reportTemplate, err := template.New("report").Parse(templateFile)

	if err != nil {
		errState(err.Error())
	}

	err = reportTemplate.Execute(os.Stdout, output)

	if err != nil {
		errState(err.Error())
	}
}

<commit_msg>Fix for label in lambda output in reporting<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"html/template"
	"os"
)

type Installations struct {
	InstallationItems []installationItem `json:"installations"`
}

type installationItem struct {
	Label       string `json:"label"`
	Services    []ServiceItem `json:"services"`
	Lambdas     []string `json:"lambdas"`
}

type CredentialsItem struct {
	Profile   string `json:"profile"`
	AwsKey    string `json:"awsKey"`
	AwsSecret string `json:"awsSecret"`
}

type ServiceItem struct {
	Label   string `json:"label"`
	Cluster string `json:"cluster"`
	Service string `json:"service"`
}

type Output struct {
	Installations []OutputTemplate
}

type OutputTemplate struct {
	Label    string
	Services []OutputItem
	Lambdas []LambdaOutputItem
}

type OutputItem struct {
	Label        string
	TaskDefName  string
	Image        string
	Version      string
	DesiredCount int64
	RunningCount int64
}

type LambdaOutputItem struct {
	Label string
	Version string
	Description string
}

func GenerateReport(jsonData []byte, templateFile string) {
	var config Installations

	err := json.Unmarshal(jsonData, &config)

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

	output := Output{}

	for i := 0; i < len(config.InstallationItems); i++ {
		installation := config.InstallationItems[i];

		outputTemplate := OutputTemplate{
			Label : installation.Label,
		}

		for j := 0; j < len(installation.Services); j++ {

			service := installation.Services[j]
			clusterArn := GetClusterArn(service.Cluster);
			serviceArn := GetServiceArn(clusterArn, service.Service);

			serviceDescription := _describeService(clusterArn, serviceArn)

			for k := 0; k < len(serviceDescription.Services); k++ {

				realService := serviceDescription.Services[k];

				taskDefinition := _describeTaskDefinition(*realService.TaskDefinition);
				version, image := ExtractVersion(*taskDefinition.TaskDefinition.ContainerDefinitions[0].Image)

				for l := 0; l < len(realService.Deployments); l++ {
					deployment := realService.Deployments[l];
					outputItem := OutputItem{
						Version: version,
						Image:ExtractImageName(image),
						TaskDefName:ExtractName(deployment.TaskDefinition),
						Label:service.Label,
						RunningCount:*deployment.RunningCount,
						DesiredCount:*deployment.DesiredCount,
					}
					outputTemplate.Services = append(outputTemplate.Services, outputItem)
				}
			}

		}

		for k := 0; k < len(installation.Lambdas); k++ {
			lambdaFunction := installation.Lambdas[k]

			aliasInfo := _getLambdaFunctionAliasInfo(lambdaFunction, "PRIMARY")

			functionInfo := _getLambdaFunctionInfo(lambdaFunction, *aliasInfo.FunctionVersion);

			outputItem := LambdaOutputItem{
				Description: *aliasInfo.Description,
				Version: *functionInfo.Version,
				Label: lambdaFunction,
			}

			outputTemplate.Lambdas = append(outputTemplate.Lambdas, outputItem)
		}

		output.Installations = append(output.Installations, outputTemplate)
	}

	reportTemplate, err := template.New("report").Parse(templateFile)

	if err != nil {
		errState(err.Error())
	}

	err = reportTemplate.Execute(os.Stdout, output)

	if err != nil {
		errState(err.Error())
	}
}

<|endoftext|>


<commit_before>package tvdbapi

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"time"
)

type searchData struct {
	Series []Series `json:"data"`
}

type SearchQuery struct {
	Name           string
	ImdbId         string
	Zap2itId       string
	AcceptLanguage string
}

type AiredTime struct {
	time.Time
}

const ctLayout = "2006-01-02"

func (ct *AiredTime) UnmarshalJSON(b []byte) (err error) {
	if b[0] == '"' && b[len(b)-1] == '"' {
		b = b[1 : len(b)-1]
	}
	ct.Time, err = time.Parse(ctLayout, string(b))
	return
}

type Series struct {
	Id              int       `json:"id"`
	SeriesName      string    `json:"seriesName"`
	Aliases         []string  `json:"aliases"`
	Banner          string    `json:"banner"`
	SeriesId        string    `json:"seriesId"`
	Status          string    `json:"status"`
	FirstAired      AiredTime `json:"firstAired"`
	Network         string    `json:"network"`
	NetworkId       string    `json:"networkId"`
	Runtime         string    `json:"runtime"`
	Genre           []string  `json:"genre"`
	Overview        string    `json:"overview"`
	LastUpdated     int       `json:"lastUpdated"`
	AirsDayOfWeek   string    `json:"airsDayOfWeek"`
	AirsTime        string    `json:"airsTime"`
	Rating          string    `json:"rating"`
	ImdbId          string    `json:"imdbId"`
	Zap2itId        string    `json:"zap2itId"`
	Added           string    `json:"added"`
	SiteRating      float32   `json:"siteRating"`
	SiteRatingCount int       `json:"siteRatingCount"`
}

type seriesInfoData struct {
	Series Series `json:"data"`
}

func (client Client) Search(query SearchQuery) []Series {
	result := searchData{}
	values := url.Values{}

	if query.Name != "" {
		values.Add("name", query.Name)
	}

	if query.ImdbId != "" {
		values.Add("imdbId", query.ImdbId)
	}

	if query.Zap2itId != "" {
		values.Add("zap2itId", query.Zap2itId)
	}

	url := fmt.Sprintf("https://api.thetvdb.com/search/series?%s", values.Encode())

	req, _ := http.NewRequest("GET", url, nil)

	req.Header.Add("authorization", "Bearer "+client.ApiToken)
	if query.AcceptLanguage != "" {
		req.Header.Add("Accept-Language", query.AcceptLanguage)
	}

	res, _ := http.DefaultClient.Do(req)
	defer res.Body.Close()

	body, _ := ioutil.ReadAll(res.Body)

	err := json.Unmarshal(body, &result)

	if err != nil {
		log.Fatal(err)
		return result.Series
	}

	log.Println("search completed successfully")
	log.Println(fmt.Sprintf("Total found: %v", len(result.Series)))

	return result.Series
}

func (client Client) GetSeriesInfo(series Series) Series {
	return client.GetSeriesInfoById(series.Id)
}

func (client Client) GetSeriesInfoById(seriesId int) Series {
	result := seriesInfoData{}

	url := fmt.Sprintf("https://api.thetvdb.com/series/%v", seriesId)

	req, _ := http.NewRequest("GET", url, nil)

	req.Header.Add("authorization", "Bearer "+client.ApiToken)

	res, _ := http.DefaultClient.Do(req)
	defer res.Body.Close()

	body, _ := ioutil.ReadAll(res.Body)

	err := json.Unmarshal(body, &result)

	if err != nil {
		log.Fatal(err)
		return result.Series
	}

	log.Println("get series info completed successfully")
	log.Println(fmt.Sprintf("Series: %s; ImdbId: %s; LastUpdated: %s; Zip2itid: %s; First Aired: %v",
		result.Series.SeriesName,
		result.Series.ImdbId,
		result.Series.LastUpdated,
		result.Series.Zap2itId,
		result.Series.FirstAired))

	return result.Series
}
<commit_msg>Fix empty AiredDate<commit_after>package tvdbapi

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"time"
)

type searchData struct {
	Series []Series `json:"data"`
}

type SearchQuery struct {
	Name           string
	ImdbId         string
	Zap2itId       string
	AcceptLanguage string
}

type AiredTime struct {
	time.Time
}

const ctLayout = "2006-01-02"

func (ct *AiredTime) UnmarshalJSON(b []byte) (err error) {
	if b[0] == '"' && b[len(b)-1] == '"' {
		b = b[1 : len(b)-1]
	}
	if len(b) == 0 {
		// sometimes AiredDate is empty. Lets it will be 1900-01-01
		ct.Time, err = time.Parse(ctLayout, "1900-01-01")
	} else {
		ct.Time, err = time.Parse(ctLayout, string(b))
	}
	return
}

type Series struct {
	Id              int       `json:"id"`
	SeriesName      string    `json:"seriesName"`
	Aliases         []string  `json:"aliases"`
	Banner          string    `json:"banner"`
	SeriesId        string    `json:"seriesId"`
	Status          string    `json:"status"`
	FirstAired      AiredTime `json:"firstAired"`
	Network         string    `json:"network"`
	NetworkId       string    `json:"networkId"`
	Runtime         string    `json:"runtime"`
	Genre           []string  `json:"genre"`
	Overview        string    `json:"overview"`
	LastUpdated     int       `json:"lastUpdated"`
	AirsDayOfWeek   string    `json:"airsDayOfWeek"`
	AirsTime        string    `json:"airsTime"`
	Rating          string    `json:"rating"`
	ImdbId          string    `json:"imdbId"`
	Zap2itId        string    `json:"zap2itId"`
	Added           string    `json:"added"`
	SiteRating      float32   `json:"siteRating"`
	SiteRatingCount int       `json:"siteRatingCount"`
}

type seriesInfoData struct {
	Series Series `json:"data"`
}

func (client Client) Search(query SearchQuery) []Series {
	result := searchData{}
	values := url.Values{}

	if query.Name != "" {
		values.Add("name", query.Name)
	}

	if query.ImdbId != "" {
		values.Add("imdbId", query.ImdbId)
	}

	if query.Zap2itId != "" {
		values.Add("zap2itId", query.Zap2itId)
	}

	url := fmt.Sprintf("https://api.thetvdb.com/search/series?%s", values.Encode())

	req, _ := http.NewRequest("GET", url, nil)

	req.Header.Add("authorization", "Bearer "+client.ApiToken)
	if query.AcceptLanguage != "" {
		req.Header.Add("Accept-Language", query.AcceptLanguage)
	}

	res, _ := http.DefaultClient.Do(req)
	defer res.Body.Close()

	body, _ := ioutil.ReadAll(res.Body)

	err := json.Unmarshal(body, &result)

	if err != nil {
		log.Fatal(err)
		return result.Series
	}

	log.Println("search completed successfully")
	log.Println(fmt.Sprintf("Total found: %v", len(result.Series)))

	return result.Series
}

func (client Client) GetSeriesInfo(series Series) Series {
	return client.GetSeriesInfoById(series.Id)
}

func (client Client) GetSeriesInfoById(seriesId int) Series {
	result := seriesInfoData{}

	url := fmt.Sprintf("https://api.thetvdb.com/series/%v", seriesId)

	req, _ := http.NewRequest("GET", url, nil)

	req.Header.Add("authorization", "Bearer "+client.ApiToken)

	res, _ := http.DefaultClient.Do(req)
	defer res.Body.Close()

	body, _ := ioutil.ReadAll(res.Body)

	err := json.Unmarshal(body, &result)

	if err != nil {
		log.Fatal(err)
		return result.Series
	}

	log.Println("get series info completed successfully")
	log.Println(fmt.Sprintf("Series: %s; ImdbId: %s; LastUpdated: %s; Zip2itid: %s; First Aired: %v",
		result.Series.SeriesName,
		result.Series.ImdbId,
		result.Series.LastUpdated,
		result.Series.Zap2itId,
		result.Series.FirstAired))

	return result.Series
}
<|endoftext|>


<commit_before>package googledrive

import (
	"io/ioutil"
	"time"

	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"
	"google.golang.org/api/drive/v2"
)

var (
	config *oauth2.Config
)

// AuthURL() returns a URL to the Google OAuth2 login page
func AuthURL() string {
	return config.AuthCodeURL("google", oauth2.AccessTypeOffline)
}

// Config() reads the information from the client_secret.json file and
// parses it into the global config object, so the other functions can
// access it.
func Config(filepath string) error {
	secret, err := ioutil.ReadFile(filepath)
	if err != nil {
		return err
	}

	config, err = google.ConfigFromJSON(secret, drive.DriveScope)
	if err != nil {
		return err
	}

	return nil
}

// Validate() validates an access code against the oauth2.config object. It
// then returns the real token togehter with an expiry date.
func Validate(code string) (string, time.Time, error) {
	token, err := config.Exchange(oauth2.NoContext, code)
	return token.AccessToken, token.Expiry, err
}
<commit_msg>minor syntax change for golint<commit_after>package googledrive

import (
	"io/ioutil"
	"time"

	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"
	"google.golang.org/api/drive/v2"
)

var (
	config *oauth2.Config
)

// AuthURL returns a URL to the Google OAuth2 login page
func AuthURL() string {
	return config.AuthCodeURL("google", oauth2.AccessTypeOffline)
}

// Config reads the information from the client_secret.json file and
// parses it into the global config object, so the other functions can
// access it.
func Config(filepath string) error {
	secret, err := ioutil.ReadFile(filepath)
	if err != nil {
		return err
	}

	config, err = google.ConfigFromJSON(secret, drive.DriveScope)
	if err != nil {
		return err
	}

	return nil
}

// Validate validates an access code against the oauth2.config object. It
// then returns the real token togehter with an expiry date.
func Validate(code string) (string, time.Time, error) {
	token, err := config.Exchange(oauth2.NoContext, code)
	return token.AccessToken, token.Expiry, err
}
<|endoftext|>


<commit_before>package gqt_test

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"strings"

	"code.cloudfoundry.org/garden"
	"code.cloudfoundry.org/guardian/gqt/runner"
	"code.cloudfoundry.org/guardian/rundmc/runrunc"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
)

var _ = Describe("Runtime Plugin", func() {
	var (
		client *runner.RunningGarden
	)

	JustBeforeEach(func() {
		client = runner.Start(config)
	})

	AfterEach(func() {
		Expect(client.DestroyAndStop()).To(Succeed())
	})

	Context("when a runtime plugin is provided", func() {
		BeforeEach(func() {
			config.RuntimePluginBin = binaries.RuntimePlugin
			config.NetworkPluginBin = binaries.NetworkPlugin
			config.ImagePluginBin = binaries.NoopPlugin
			config.RuntimePluginExtraArgs = []string{
				`"--image-store"`, `some-image-store`,
			}
		})

		Describe("creating a container", func() {
			var (
				handle       string
				argsFilepath string
			)

			JustBeforeEach(func() {
				handle = fmt.Sprintf("runtime-plugin-test-handle-%s", config.Tag)
			})

			// The "on Linux / on Windows" Contexts here are only temporary.
			// Right now winc does not support "winc run -d" so we have to branch
			// the logic.
			// The winc team are aware and have a story to add support:
			// https://www.pivotaltracker.com/n/projects/1156164/stories/153062983
			Context("on Linux", func() {
				JustBeforeEach(func() {
					onlyOnLinux()
					argsFilepath = filepath.Join(client.TmpDir, "run-args")
				})

				It("executes the plugin, passing the correct args for create", func() {
					_, err := client.Create(garden.ContainerSpec{Handle: handle})
					Expect(err).ToNot(HaveOccurred())

					Expect(readPluginArgs(argsFilepath)).To(ConsistOf(
						binaries.RuntimePlugin,
						"--debug",
						"--log", HaveSuffix(filepath.Join("containers", handle, "create.log")),
						"--log-format", "json",
						"--image-store", "some-image-store",
						"run",
						"--detach",
						"--no-new-keyring",
						"--bundle", HaveSuffix(filepath.Join("containers", handle)),
						"--pid-file", HaveSuffix(filepath.Join("containers", handle, "pidfile")),
						handle,
					))
				})
			})

			Context("on Windows", func() {
				JustBeforeEach(func() {
					onlyOnWindows()
					argsFilepath = filepath.Join(client.TmpDir, "create-args")
				})

				It("executes the plugin, passing the correct args for create", func() {
					_, err := client.Create(garden.ContainerSpec{Handle: handle})
					Expect(err).ToNot(HaveOccurred())

					Expect(readPluginArgs(argsFilepath)).To(ConsistOf(
						binaries.RuntimePlugin,
						"--debug",
						"--log", HaveSuffix(filepath.Join("containers", handle, "create.log")),
						"--log-format", "json",
						"--image-store", "some-image-store",
						"create",
						"--no-new-keyring",
						"--bundle", HaveSuffix(filepath.Join("containers", handle)),
						"--pid-file", HaveSuffix(filepath.Join("containers", handle, "pidfile")),
						handle,
					))
				})
			})

			Context("when the network plugin returns configuration", func() {
				BeforeEach(func() {
					pluginReturn := `{
					"properties":{
						"foo":"bar",
						"kawasaki.mtu":"1499",
						"garden.network.container-ip":"10.255.10.10",
						"garden.network.host-ip":"255.255.255.255"
					},
					"dns_servers": [
						"1.2.3.4",
						"1.2.3.5"
					]
			  }`
					config.NetworkPluginExtraArgs = []string{
						os.DevNull,
						os.DevNull,
						pluginReturn,
					}
				})

				It("succeeds", func() {
					_, err := client.Create(garden.ContainerSpec{Handle: handle})
					Expect(err).ToNot(HaveOccurred())
				})
			})

			Context("when runtime plugin state returns a pid of zero for a created container", func() {
				var networkPluginArgsFile string

				BeforeEach(func() {
					networkPluginArgsFile = filepath.Join(config.TmpDir, fmt.Sprintf("network-a-%d", GinkgoParallelNode()))
					config.NetworkPluginExtraArgs = []string{networkPluginArgsFile, os.DevNull, "unused"}
				})

				AfterEach(func() {
					Expect(os.Remove(networkPluginArgsFile)).To(Succeed())
				})

				JustBeforeEach(func() {
					Expect(ioutil.WriteFile(
						filepath.Join(client.TmpDir, "runtime-state-output"),
						[]byte(`{"pid": 0, "status": "created"}`),
						0600,
					)).To(Succeed())
				})

				It("returns an error without calling the network plugin", func() {
					_, err := client.Create(garden.ContainerSpec{Handle: handle})
					Expect(err).To(HaveOccurred())
					Expect(readFile(networkPluginArgsFile)).NotTo(ContainSubstring("up"))
				})
			})

			Describe("starting a process", func() {
				var (
					runtimePluginExitCode int
					stdoutContents        string
					stderrContents        string

					process      garden.Process
					stdoutWriter *gbytes.Buffer
					stderrWriter *gbytes.Buffer
					runErr       error
				)

				BeforeEach(func() {
					runtimePluginExitCode = 0

					stdoutWriter = gbytes.NewBuffer()
					stderrWriter = gbytes.NewBuffer()
				})

				JustBeforeEach(func() {
					argsFilepath = filepath.Join(client.TmpDir, "exec-args")

					container, err := client.Create(garden.ContainerSpec{Handle: handle})
					Expect(err).ToNot(HaveOccurred())

					process, runErr = container.Run(garden.ProcessSpec{
						Path: "some-idiosyncratic-binary",
						Args: []string{fmt.Sprintf("%d", runtimePluginExitCode), stdoutContents, stderrContents},
					}, garden.ProcessIO{
						Stdout: io.MultiWriter(GinkgoWriter, stdoutWriter),
						Stderr: io.MultiWriter(GinkgoWriter, stderrWriter),
					})
				})

				It("returns no error", func() {
					Expect(runErr).NotTo(HaveOccurred())
				})

				It("executes the plugin, passing the correct args for exec", func() {
					logfileMatcher := MatchRegexp(".*")
					if runtime.GOOS == "windows" {
						logfileMatcher = HaveSuffix("exec.log")
					}

					pluginArgs := []interface{}{
						binaries.RuntimePlugin,
						"--debug",
						"--log", logfileMatcher,
						"--log-format", "json",
						"exec",
						"-p", MatchRegexp(".*"),
						"--pid-file", MatchRegexp(".*"),
						handle,
					}
					if runtime.GOOS != "windows" {
						pluginArgs = append(pluginArgs, "-d")
					}
					Expect(readPluginArgs(argsFilepath)).To(ConsistOf(pluginArgs))

					_, err := process.Wait() // ensure plugin has finished running before asserting on output(s)
					Expect(err).NotTo(HaveOccurred())
				})

				It("passes the spec serialised into a file", func() {
					processSpecFilePath := filepath.Join(client.TmpDir, "exec-process-spec")
					Eventually(processSpecFilePath).Should(BeAnExistingFile())

					var processSpec runrunc.PreparedSpec
					processSpecContent, err := ioutil.ReadFile(processSpecFilePath)
					Expect(err).ToNot(HaveOccurred())
					Expect(json.Unmarshal(processSpecContent, &processSpec)).To(Succeed())

					Expect(processSpec.Process.Args[0]).To(Equal("some-idiosyncratic-binary"))
				})

				Describe("runtime plugin stdio", func() {
					BeforeEach(func() {
						stdoutContents = "some stdout content"
						stderrContents = "some stderr content"
					})

					It("returns the runtime plugin's stdout", func() {
						Eventually(stdoutWriter).Should(gbytes.Say(stdoutContents))
					})

					It("returns the runtime plugin's stderr", func() {
						Eventually(stderrWriter).Should(gbytes.Say(stderrContents))
					})
				})

				Context("when the runtime plugin exits with 32", func() {
					BeforeEach(func() {
						runtimePluginExitCode = 32
					})

					It("returns an error because the runtime plugin exits non-zero on Linux", func() {
						onlyOnLinux()
						Expect(runErr).To(MatchError(ContainSubstring("exit status 32")))
					})

					It("returns no error on Windows", func() {
						onlyOnWindows()
						Expect(runErr).NotTo(HaveOccurred())
					})
				})

				Describe("the returned process", func() {
					Describe("Wait", func() {
						It("returns the exit status of the runtime plugin", func() {
							Expect(process.Wait()).To(Equal(0))
						})

						Context("when the runtime plugin exits with 42", func() {
							BeforeEach(func() {
								runtimePluginExitCode = 42
							})

							It("returns the exit status of the runtime plugin on Windows", func() {
								onlyOnWindows()
								Expect(process.Wait()).To(Equal(42))
							})
						})
					})
				})
			})

			Describe("destroying a container", func() {
				var (
					argsFilepath string
				)

				JustBeforeEach(func() {
					handle = fmt.Sprintf("runtime-plugin-test-handle-%s", config.Tag)
					argsFilepath = filepath.Join(client.TmpDir, "delete-args")

					_, err := client.Create(garden.ContainerSpec{Handle: handle})
					Expect(err).ToNot(HaveOccurred())
				})

				It("executes the plugin, passing the correct args for delete", func() {
					Expect(client.Destroy(handle)).To(Succeed())

					Expect(readPluginArgs(argsFilepath)).To(ConsistOf(
						binaries.RuntimePlugin,
						"--debug",
						"--log", MatchRegexp(".*"),
						"--log-format", "json",
						"delete",
						handle,
					))
				})
			})
		})
	})
})

func readPluginArgs(argsFilePath string) []string {
	Eventually(argsFilePath).Should(BeAnExistingFile())
	pluginArgsBytes, err := ioutil.ReadFile(argsFilePath)
	Expect(err).ToNot(HaveOccurred())
	return strings.Split(string(pluginArgsBytes), " ")
}

func onlyOnLinux() {
	onlyOn("linux")
}

func onlyOnWindows() {
	onlyOn("windows")
}

func onlyOn(goos string) {
	if runtime.GOOS != goos {
		Skip(goos + " only")
	}
}
<commit_msg>Add debug to flaky runtime test<commit_after>package gqt_test

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"strings"

	"code.cloudfoundry.org/garden"
	"code.cloudfoundry.org/guardian/gqt/runner"
	"code.cloudfoundry.org/guardian/rundmc/runrunc"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
)

var _ = Describe("Runtime Plugin", func() {
	var (
		client *runner.RunningGarden
	)

	JustBeforeEach(func() {
		client = runner.Start(config)
	})

	AfterEach(func() {
		Expect(client.DestroyAndStop()).To(Succeed())
	})

	Context("when a runtime plugin is provided", func() {
		BeforeEach(func() {
			config.RuntimePluginBin = binaries.RuntimePlugin
			config.NetworkPluginBin = binaries.NetworkPlugin
			config.ImagePluginBin = binaries.NoopPlugin
			config.RuntimePluginExtraArgs = []string{
				`"--image-store"`, `some-image-store`,
			}
		})

		Describe("creating a container", func() {
			var (
				handle       string
				argsFilepath string
			)

			JustBeforeEach(func() {
				handle = fmt.Sprintf("runtime-plugin-test-handle-%s", config.Tag)
			})

			// The "on Linux / on Windows" Contexts here are only temporary.
			// Right now winc does not support "winc run -d" so we have to branch
			// the logic.
			// The winc team are aware and have a story to add support:
			// https://www.pivotaltracker.com/n/projects/1156164/stories/153062983
			Context("on Linux", func() {
				JustBeforeEach(func() {
					onlyOnLinux()
					argsFilepath = filepath.Join(client.TmpDir, "run-args")
				})

				It("executes the plugin, passing the correct args for create", func() {
					_, err := client.Create(garden.ContainerSpec{Handle: handle})
					Expect(err).ToNot(HaveOccurred())

					Expect(readPluginArgs(argsFilepath)).To(ConsistOf(
						binaries.RuntimePlugin,
						"--debug",
						"--log", HaveSuffix(filepath.Join("containers", handle, "create.log")),
						"--log-format", "json",
						"--image-store", "some-image-store",
						"run",
						"--detach",
						"--no-new-keyring",
						"--bundle", HaveSuffix(filepath.Join("containers", handle)),
						"--pid-file", HaveSuffix(filepath.Join("containers", handle, "pidfile")),
						handle,
					))
				})
			})

			Context("on Windows", func() {
				JustBeforeEach(func() {
					onlyOnWindows()
					argsFilepath = filepath.Join(client.TmpDir, "create-args")
				})

				It("executes the plugin, passing the correct args for create", func() {
					_, err := client.Create(garden.ContainerSpec{Handle: handle})
					Expect(err).ToNot(HaveOccurred())

					Expect(readPluginArgs(argsFilepath)).To(ConsistOf(
						binaries.RuntimePlugin,
						"--debug",
						"--log", HaveSuffix(filepath.Join("containers", handle, "create.log")),
						"--log-format", "json",
						"--image-store", "some-image-store",
						"create",
						"--no-new-keyring",
						"--bundle", HaveSuffix(filepath.Join("containers", handle)),
						"--pid-file", HaveSuffix(filepath.Join("containers", handle, "pidfile")),
						handle,
					))
				})
			})

			Context("when the network plugin returns configuration", func() {
				BeforeEach(func() {
					pluginReturn := `{
					"properties":{
						"foo":"bar",
						"kawasaki.mtu":"1499",
						"garden.network.container-ip":"10.255.10.10",
						"garden.network.host-ip":"255.255.255.255"
					},
					"dns_servers": [
						"1.2.3.4",
						"1.2.3.5"
					]
			  }`
					config.NetworkPluginExtraArgs = []string{
						os.DevNull,
						os.DevNull,
						pluginReturn,
					}
				})

				It("succeeds", func() {
					_, err := client.Create(garden.ContainerSpec{Handle: handle})
					Expect(err).ToNot(HaveOccurred())
				})
			})

			Context("when runtime plugin state returns a pid of zero for a created container", func() {
				var networkPluginArgsFile string

				BeforeEach(func() {
					networkPluginArgsFile = filepath.Join(config.TmpDir, fmt.Sprintf("network-a-%d", GinkgoParallelNode()))
					config.NetworkPluginExtraArgs = []string{networkPluginArgsFile, os.DevNull, "unused"}
				})

				AfterEach(func() {
					Expect(os.Remove(networkPluginArgsFile)).To(Succeed())
				})

				JustBeforeEach(func() {
					Expect(ioutil.WriteFile(
						filepath.Join(client.TmpDir, "runtime-state-output"),
						[]byte(`{"pid": 0, "status": "created"}`),
						0600,
					)).To(Succeed())
				})

				It("returns an error without calling the network plugin", func() {
					_, err := client.Create(garden.ContainerSpec{Handle: handle})
					Expect(err).To(HaveOccurred())
					Expect(readFile(networkPluginArgsFile)).NotTo(ContainSubstring("up"))
				})
			})

			Describe("starting a process", func() {
				var (
					runtimePluginExitCode int
					stdoutContents        string
					stderrContents        string

					process      garden.Process
					stdoutWriter *gbytes.Buffer
					stderrWriter *gbytes.Buffer
					runErr       error
				)

				BeforeEach(func() {
					runtimePluginExitCode = 0

					stdoutWriter = gbytes.NewBuffer()
					stderrWriter = gbytes.NewBuffer()
				})

				JustBeforeEach(func() {
					argsFilepath = filepath.Join(client.TmpDir, "exec-args")

					container, err := client.Create(garden.ContainerSpec{Handle: handle})
					Expect(err).ToNot(HaveOccurred())

					process, runErr = container.Run(garden.ProcessSpec{
						Path: "some-idiosyncratic-binary",
						Args: []string{fmt.Sprintf("%d", runtimePluginExitCode), stdoutContents, stderrContents},
					}, garden.ProcessIO{
						Stdout: io.MultiWriter(GinkgoWriter, stdoutWriter),
						Stderr: io.MultiWriter(GinkgoWriter, stderrWriter),
					})
				})

				It("returns no error", func() {
					Expect(runErr).NotTo(HaveOccurred())
				})

				It("executes the plugin, passing the correct args for exec", func() {
					logfileMatcher := MatchRegexp(".*")
					if runtime.GOOS == "windows" {
						logfileMatcher = HaveSuffix("exec.log")
					}

					pluginArgs := []interface{}{
						binaries.RuntimePlugin,
						"--debug",
						"--log", logfileMatcher,
						"--log-format", "json",
						"exec",
						"-p", MatchRegexp(".*"),
						"--pid-file", MatchRegexp(".*"),
						handle,
					}
					if runtime.GOOS != "windows" {
						pluginArgs = append(pluginArgs, "-d")
					}
					Expect(readPluginArgs(argsFilepath)).To(ConsistOf(pluginArgs))

					_, err := process.Wait() // ensure plugin has finished running before asserting on output(s)
					Expect(err).NotTo(HaveOccurred())
				})

				It("passes the spec serialised into a file", func() {
					processSpecFilePath := filepath.Join(client.TmpDir, "exec-process-spec")
					Eventually(processSpecFilePath).Should(BeAnExistingFile())

					var processSpec runrunc.PreparedSpec
					processSpecContent, err := ioutil.ReadFile(processSpecFilePath)
					Expect(err).ToNot(HaveOccurred())
					Expect(json.Unmarshal(processSpecContent, &processSpec)).To(Succeed(), fmt.Sprintf("Process Spec: %s\n", string(processSpecContent)))

					Expect(processSpec.Process.Args[0]).To(Equal("some-idiosyncratic-binary"))
				})

				Describe("runtime plugin stdio", func() {
					BeforeEach(func() {
						stdoutContents = "some stdout content"
						stderrContents = "some stderr content"
					})

					It("returns the runtime plugin's stdout", func() {
						Eventually(stdoutWriter).Should(gbytes.Say(stdoutContents))
					})

					It("returns the runtime plugin's stderr", func() {
						Eventually(stderrWriter).Should(gbytes.Say(stderrContents))
					})
				})

				Context("when the runtime plugin exits with 32", func() {
					BeforeEach(func() {
						runtimePluginExitCode = 32
					})

					It("returns an error because the runtime plugin exits non-zero on Linux", func() {
						onlyOnLinux()
						Expect(runErr).To(MatchError(ContainSubstring("exit status 32")))
					})

					It("returns no error on Windows", func() {
						onlyOnWindows()
						Expect(runErr).NotTo(HaveOccurred())
					})
				})

				Describe("the returned process", func() {
					Describe("Wait", func() {
						It("returns the exit status of the runtime plugin", func() {
							Expect(process.Wait()).To(Equal(0))
						})

						Context("when the runtime plugin exits with 42", func() {
							BeforeEach(func() {
								runtimePluginExitCode = 42
							})

							It("returns the exit status of the runtime plugin on Windows", func() {
								onlyOnWindows()
								Expect(process.Wait()).To(Equal(42))
							})
						})
					})
				})
			})

			Describe("destroying a container", func() {
				var (
					argsFilepath string
				)

				JustBeforeEach(func() {
					handle = fmt.Sprintf("runtime-plugin-test-handle-%s", config.Tag)
					argsFilepath = filepath.Join(client.TmpDir, "delete-args")

					_, err := client.Create(garden.ContainerSpec{Handle: handle})
					Expect(err).ToNot(HaveOccurred())
				})

				It("executes the plugin, passing the correct args for delete", func() {
					Expect(client.Destroy(handle)).To(Succeed())

					Expect(readPluginArgs(argsFilepath)).To(ConsistOf(
						binaries.RuntimePlugin,
						"--debug",
						"--log", MatchRegexp(".*"),
						"--log-format", "json",
						"delete",
						handle,
					))
				})
			})
		})
	})
})

func readPluginArgs(argsFilePath string) []string {
	Eventually(argsFilePath).Should(BeAnExistingFile())
	pluginArgsBytes, err := ioutil.ReadFile(argsFilePath)
	Expect(err).ToNot(HaveOccurred())
	return strings.Split(string(pluginArgsBytes), " ")
}

func onlyOnLinux() {
	onlyOn("linux")
}

func onlyOnWindows() {
	onlyOn("windows")
}

func onlyOn(goos string) {
	if runtime.GOOS != goos {
		Skip(goos + " only")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"reflect"
	"testing"
)

type testUnmarshalCase struct {
	ok   bool
	in   []byte
	want interface{}
}

func testUnmarshalCases() map[string]testUnmarshalCase {
	c := map[string]testUnmarshalCase{
		"ok": {
			ok:   true,
			in:   []byte(`{"i":123, "f":123.456, "b":true,"s":"abc"}`),
			want: T{I: int64(123), F: float64(123.456), B: true, S: []byte{'a', 'b', 'c'}},
		},
	}
	return c
}

func TestUnmarshal(t *testing.T) {
	for name, tc := range testUnmarshalCases() {
		t.Run(name, func(t *testing.T) {
			testUnmarshal(t, tc)
		})
	}
}

func testUnmarshal(t *testing.T, tc testUnmarshalCase) {
	var got T
	err := json.Unmarshal(tc.in, &got)
	if !tc.ok {
		if !reflect.DeepEqual(got, tc.want) || err == nil {
			t.Errorf("got %+v, %v; want %+v, <error>", got, err, tc.want)
		}
		return
	}
	if !reflect.DeepEqual(got, tc.want) || err != nil {
		t.Errorf("got %+v, %+v; want %+v, <nil>", got, err, tc.want)
	}
}
<commit_msg>ff: fix tests<commit_after>package main

import (
	"encoding/json"
	"reflect"
	"testing"
)

type testUnmarshalCase struct {
	ok   bool
	in   []byte
	want interface{}
}

func testUnmarshalCases() map[string]testUnmarshalCase {
	c := map[string]testUnmarshalCase{
		"ok": {
			ok:   true,
			in:   []byte(`{"i":123, "f":123.456, "b":true,"s":"abc"}`),
			want: One{I: int64(123), F: float64(123.456), B: true, S: "abc"},
		},
	}
	return c
}

func TestUnmarshal(t *testing.T) {
	for name, tc := range testUnmarshalCases() {
		t.Run(name, func(t *testing.T) {
			testUnmarshal(t, tc)
		})
	}
}

func testUnmarshal(t *testing.T, tc testUnmarshalCase) {
	var got One
	err := json.Unmarshal(tc.in, &got)
	if !tc.ok {
		if !reflect.DeepEqual(got, tc.want) || err == nil {
			t.Errorf("got %+v, %v; want %+v, <error>", got, err, tc.want)
		}
		return
	}
	if !reflect.DeepEqual(got, tc.want) || err != nil {
		t.Errorf("got %+v, %+v; want %+v, <nil>", got, err, tc.want)
	}
}
<|endoftext|>


<commit_before>package fdcount

import (
	"net"
	"testing"
	"time"

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

func TestTCP(t *testing.T) {
	// Lower maxAssertAttempts to keep this test from running too long
	maxAssertAttempts = 2

	l0, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		t.Fatal(err)
	}
	defer l0.Close()

	start, fdc, err := Matching("TCP")
	if err != nil {
		t.Fatal(err)
	}
	assert.Equal(t, 1, start, "Starting count should have been 1")

	err = fdc.AssertDelta(0)
	if err != nil {
		t.Fatal(err)
	}
	assert.NoError(t, err, "Initial TCP count should be 0")

	l, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		t.Fatal(err)
	}
	defer l.Close()
	_, middle, err := Matching("TCP")
	if err != nil {
		t.Fatal(err)
	}

	err = fdc.AssertDelta(0)
	if assert.Error(t, err, "Asserting wrong count should fail") {
		assert.Contains(t, err.Error(), "Expected 0, have 1")
		assert.True(t, len(err.Error()) > 100)
	}
	err = fdc.AssertDelta(1)
	assert.NoError(t, err, "Ending TCP count should be 1")

	err = fdc.AssertDelta(0)
	if assert.Error(t, err, "Asserting wrong count should fail") {
		assert.Contains(t, err.Error(), "Expected 0, have 1")
		assert.Contains(t, err.Error(), "New")
		assert.True(t, len(err.Error()) > 100)
	}

	l.Close()
	err = middle.AssertDelta(0)
	if assert.Error(t, err, "Asserting wrong count should fail") {
		assert.Contains(t, err.Error(), "Expected 0, have -1")
		assert.Contains(t, err.Error(), "Removed")
		assert.True(t, len(err.Error()) > 100)
	}
}

func TestWaitUntilNoneMatchOK(t *testing.T) {
	conn, err := net.Dial("tcp", "www.google.com:80")
	if err != nil {
		t.Fatalf("Unable to dial google: %v", err)
	}
	defer conn.Close()

	wait := 250 * time.Millisecond
	start := time.Now()
	go func() {
		time.Sleep(wait)
		conn.Close()
	}()

	err = WaitUntilNoneMatch("TCP", wait*2)
	elapsed := time.Now().Sub(start)
	assert.NoError(t, err, "Waiting should have succeeded")
	assert.True(t, elapsed >= wait, "Should have waited a while")
}

func TestWaitUntilNoneMatchTimeout(t *testing.T) {
	conn, err := net.Dial("tcp", "www.google.com:80")
	if err != nil {
		t.Fatalf("Unable to dial google: %v", err)
	}
	defer conn.Close()

	wait := 250 * time.Millisecond
	start := time.Now()
	go func() {
		time.Sleep(wait)
		conn.Close()
	}()

	err = WaitUntilNoneMatch("TCP", wait/2)
	elapsed := time.Now().Sub(start)
	assert.Error(t, err, "Waiting should have failed")
	assert.True(t, elapsed < wait, "Should have waited less than time to close conn")
}
<commit_msg>double wait time in TestWaitUntilNoneMatchTimeout<commit_after>package fdcount

import (
	"net"
	"testing"
	"time"

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

func TestTCP(t *testing.T) {
	// Lower maxAssertAttempts to keep this test from running too long
	maxAssertAttempts = 2

	l0, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		t.Fatal(err)
	}
	defer l0.Close()

	start, fdc, err := Matching("TCP")
	if err != nil {
		t.Fatal(err)
	}
	assert.Equal(t, 1, start, "Starting count should have been 1")

	err = fdc.AssertDelta(0)
	if err != nil {
		t.Fatal(err)
	}
	assert.NoError(t, err, "Initial TCP count should be 0")

	l, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		t.Fatal(err)
	}
	defer l.Close()
	_, middle, err := Matching("TCP")
	if err != nil {
		t.Fatal(err)
	}

	err = fdc.AssertDelta(0)
	if assert.Error(t, err, "Asserting wrong count should fail") {
		assert.Contains(t, err.Error(), "Expected 0, have 1")
		assert.True(t, len(err.Error()) > 100)
	}
	err = fdc.AssertDelta(1)
	assert.NoError(t, err, "Ending TCP count should be 1")

	err = fdc.AssertDelta(0)
	if assert.Error(t, err, "Asserting wrong count should fail") {
		assert.Contains(t, err.Error(), "Expected 0, have 1")
		assert.Contains(t, err.Error(), "New")
		assert.True(t, len(err.Error()) > 100)
	}

	l.Close()
	err = middle.AssertDelta(0)
	if assert.Error(t, err, "Asserting wrong count should fail") {
		assert.Contains(t, err.Error(), "Expected 0, have -1")
		assert.Contains(t, err.Error(), "Removed")
		assert.True(t, len(err.Error()) > 100)
	}
}

func TestWaitUntilNoneMatchOK(t *testing.T) {
	conn, err := net.Dial("tcp", "www.google.com:80")
	if err != nil {
		t.Fatalf("Unable to dial google: %v", err)
	}
	defer conn.Close()

	wait := 250 * time.Millisecond
	start := time.Now()
	go func() {
		time.Sleep(wait)
		conn.Close()
	}()

	err = WaitUntilNoneMatch("TCP", wait*2)
	elapsed := time.Now().Sub(start)
	assert.NoError(t, err, "Waiting should have succeeded")
	assert.True(t, elapsed >= wait, "Should have waited a while")
}

func TestWaitUntilNoneMatchTimeout(t *testing.T) {
	conn, err := net.Dial("tcp", "www.google.com:80")
	if err != nil {
		t.Fatalf("Unable to dial google: %v", err)
	}
	defer conn.Close()

	wait := 500 * time.Millisecond
	start := time.Now()
	go func() {
		time.Sleep(wait)
		conn.Close()
	}()

	err = WaitUntilNoneMatch("TCP", wait/2)
	elapsed := time.Now().Sub(start)
	assert.Error(t, err, "Waiting should have failed")
	assert.True(t, elapsed < wait, "Should have waited less than time to close conn")
}
<|endoftext|>


<commit_before>package receiver

import (
	"github.com/tgermain/grandRepositorySky/communicator"
	"github.com/tgermain/grandRepositorySky/communicator/sender"
	"github.com/tgermain/grandRepositorySky/node"
	"github.com/tgermain/grandRepositorySky/shared"
	"net"
	"runtime"
	// "time"
)

//Objects parts ---------------------------------------------------------

type ReceiverLink struct {
	node   *node.DHTnode
	sender *sender.SenderLink
}

//Private methods -------------------------------------------------------
func (r *ReceiverLink) handleRequest(payload []byte) {
	//unmarshall message
	msg := communicator.UnmarshallMessage(payload)
	//switch depending of message type
	shared.Logger.Debug("Handle Request receive something : %#v", msg)
	switch {
	case msg.TypeOfMsg == communicator.LOOKUP:
		{
			r.receiveLookup(&msg)
		}
	case msg.TypeOfMsg == communicator.LOOKUPRESPONSE:
		{
			r.receiveLookupResponse(&msg)
		}
	case msg.TypeOfMsg == communicator.JOINRING:
		{
			r.receiveJoinRing(&msg)
		}
	case msg.TypeOfMsg == communicator.UPDATESUCCESSOR:
		{
			r.receiveUpdateSuccessor(&msg)
		}
	case msg.TypeOfMsg == communicator.UPDATEPREDECESSOR:
		{
			r.receiveUpdatePredecessor(&msg)
		}
	case msg.TypeOfMsg == communicator.PRINTRING:
		{
			r.receivePrintRing(&msg)
		}
	case msg.TypeOfMsg == communicator.UPDATEFINGERTABLE:
		{
			r.receiveUpdateFingerTable(&msg)
		}
	case msg.TypeOfMsg == communicator.AREYOUALIVE:
		{
			r.receiveHeartBeat(&msg)
		}
	case msg.TypeOfMsg == communicator.IAMALIVE:
		{
			r.receiveHeartBeatResponse(&msg)
		}
	case msg.TypeOfMsg == communicator.GETSUCCESORE:
		{
			r.receiveGetSuccesor(&msg)
		}
	case msg.TypeOfMsg == communicator.GETSUCCESORERESPONSE:
		{
			r.receiveGetSuccesorResponse(&msg)
		}
	case msg.TypeOfMsg == communicator.GETDATA:
		{
			r.receiveGetData(&msg)
		}
	case msg.TypeOfMsg == communicator.GETDATARESPONSE:
		{
			r.receiveGetDataResponse(&msg)
		}
	case msg.TypeOfMsg == communicator.DELETEDATA:
		{
			r.receiveDeleteData(&msg)
		}
	default:
		{
			//rejected mesage
			shared.Logger.Error("Message rejected")
		}
	}
	// multiple launch a go routine
}

//========RECEIVE
func (r *ReceiverLink) receiveUpdatePredecessor(msg *communicator.Message) {
	if checkRequiredParams(msg.Parameters, "newNodeID", "newNodeIp", "newNodePort") {
		newNodeID, _ := msg.Parameters["newNodeID"]
		newNodeIp, _ := msg.Parameters["newNodeIp"]
		newNodePort, _ := msg.Parameters["newNodePort"]
		shared.Logger.Info("Receive an update Predecessor to %s", newNodeID)

		r.node.UpdatePredecessor(&shared.DistantNode{
			newNodeID,
			newNodeIp,
			newNodePort,
		})

	}
}

func (r *ReceiverLink) receiveUpdateSuccessor(msg *communicator.Message) {
	if checkRequiredParams(msg.Parameters, "newNodeID", "newNodeIp", "newNodePort") {
		newNodeID, _ := msg.Parameters["newNodeID"]
		newNodeIp, _ := msg.Parameters["newNodeIp"]
		newNodePort, _ := msg.Parameters["newNodePort"]
		shared.Logger.Info("Receive an update Successor %s", newNodeID)

		r.node.UpdateSuccessor(&shared.DistantNode{
			newNodeID,
			newNodeIp,
			newNodePort,
		})

	}
}

func (r *ReceiverLink) receivePrintRing(msg *communicator.Message) {
	//write your info and if the successor is the origine of the communicator.Message, send it back to him
	if checkRequiredParams(msg.Parameters, "currentString") {
		currentString, _ := msg.Parameters["currentString"]

		shared.Logger.Info("Receiving a print ring request from %s", msg.Origin.Id)
		if shared.LocalId == msg.Origin.Id {
			shared.Logger.Info("And %s is me !", msg.Origin.Id)
			//I launch this request know print the result
			shared.Logger.Info("The ring is like :\n%s", currentString)
		} else {
			//pass the request around
			r.node.PrintNodeName(&currentString)
			msg.Parameters["currentString"] = currentString
			go r.sender.RelayPrintRing(r.node.GetSuccesor(), msg)
		}
	}
}

func (r *ReceiverLink) receiveJoinRing(msg *communicator.Message) {
	shared.Logger.Info("Receiving join ring message from %s", msg.Origin)
	go r.node.AddToRing(&msg.Origin)
}

func (r *ReceiverLink) receiveLookup(msg *communicator.Message) {
	//check if the parameter are correct
	if checkRequiredParams(msg.Parameters, "idAnswer", "idSearched") {
		idSearched, _ := msg.Parameters["idSearched"]
		idAnswer, _ := msg.Parameters["idAnswer"]
		shared.Logger.Info("Receive a lookup for : %s", idSearched)

		//Am I responsible for the key requested  ?
		if r.node.IsResponsible(idSearched) {
			shared.Logger.Info("I'm responsible !")
			go r.sender.SendLookupResponse(&msg.Origin, idAnswer, idSearched)
		} else {
			//no -> sending the request to the closest node
			shared.Logger.Info("relay the lookup")
			go r.sender.RelayLookup(r.node.FindClosestNode(idSearched), msg)
		}

	}

}

func (r *ReceiverLink) receiveLookupResponse(msg *communicator.Message) {
	//heck if everything required is here
	if checkRequiredParams(msg.Parameters, "idAnswer", "idSearched") {
		idSearched, _ := msg.Parameters["idSearched"]
		idAnswer, _ := msg.Parameters["idAnswer"]

		shared.Logger.Info("Receive a lookup response for : %s", idSearched)

		chanResp, ok2 := communicator.PendingLookups[idAnswer]
		if ok2 {
			chanResp <- msg.Origin
		}
	}
}

func (r *ReceiverLink) receiveUpdateFingerTable(msg *communicator.Message) {
	shared.Logger.Info("Receiving update finger table from %s", msg.Origin.Id)
	r.node.UpdateFingerTable()
}

func (r *ReceiverLink) receiveHeartBeat(msg *communicator.Message) {
	if checkRequiredParams(msg.Parameters, "idAnswer") {
		shared.Logger.Info("Receiving a heartBeat from %s", msg.Origin.Id)
		idAnswer, _ := msg.Parameters["idAnswer"]

		go r.sender.SendHeartBeatResponse(&msg.Origin, idAnswer)
	}
}

func (r *ReceiverLink) receiveHeartBeatResponse(msg *communicator.Message) {
	if checkRequiredParams(msg.Parameters, "idAnswer") {
		idAnswer, _ := msg.Parameters["idAnswer"]
		shared.Logger.Info("Receiving a heartBeat response from %s for %s", msg.Origin.Id, idAnswer)

		chanResp, ok2 := communicator.PendingHearBeat[idAnswer]
		if ok2 {
			chanResp <- msg.Origin
		}
	}
}

func (r *ReceiverLink) receiveGetSuccesor(msg *communicator.Message) {
	if checkRequiredParams(msg.Parameters, "idAnswer") {
		shared.Logger.Info("Receiving a get successor from %s", msg.Origin.Id)
		idAnswer, _ := msg.Parameters["idAnswer"]

		go r.sender.SendGetSuccResponse(&msg.Origin, idAnswer, r.node.GetSuccesor())
	}
}

func (r *ReceiverLink) receiveGetSuccesorResponse(msg *communicator.Message) {
	if checkRequiredParams(msg.Parameters, "idAnswer", "succSuccID",
		"succSuccIp",
		"succSuccPort") {
		idAnswer, _ := msg.Parameters["idAnswer"]
		succSuccID, _ := msg.Parameters["succSuccID"]
		succSuccIp, _ := msg.Parameters["succSuccIp"]
		succSuccPort, _ := msg.Parameters["succSuccPort"]

		shared.Logger.Info("Receiving a GetSuccesor response from %s for %s", msg.Origin.Id, idAnswer)

		succSucc := shared.DistantNode{
			succSuccID,
			succSuccIp,
			succSuccPort,
		}

		chanResp, ok2 := communicator.PendingGetSucc[idAnswer]
		if ok2 {
			chanResp <- succSucc
		}
	}
}

func (r *ReceiverLink) receiveGetData(msg *communicator.Message) {
	if checkRequiredParams(msg.Parameters, "keySearched", "idAnswer") {
		shared.Logger.Info("Receiving a get data from %s", msg.Origin.Id)
		keySearched, _ := msg.Parameters["keySearched"]
		idAnswer, _ := msg.Parameters["idAnswer"]
		_, forced := msg.Parameters["forced"]

		var result string
		if forced {
			result = r.node.GetLocalData(keySearched)
		} else {
			result = r.node.GetData(keySearched)
		}
		r.sender.SendGetDataResponse(&msg.Origin, idAnswer, result)
	}
}

func (r *ReceiverLink) receiveGetDataResponse(msg *communicator.Message) {
	if checkRequiredParams(msg.Parameters, "idAnswer", "value") {
		idAnswer, _ := msg.Parameters["idAnswer"]
		value, _ := msg.Parameters["value"]

		shared.Logger.Info("Receiving a get data response from %s for %s", msg.Origin.Id, idAnswer)

		chanResp, ok2 := communicator.PendingGetData[idAnswer]
		if ok2 {
			chanResp <- value
		}
	}
}

func (r *ReceiverLink) receiveSetData(msg *communicator.Message) {
	if checkRequiredParams(msg.Parameters, "key", "value") {
		key, _ := msg.Parameters["key"]
		value, _ := msg.Parameters["value"]
		tag, forced := msg.Parameters["forced"]
		shared.Logger.Info("Receiving a set data from %s with data %s", msg.Origin.Id, value)

		if forced {
			r.node.SetLocalData(key, value, tag)
		} else {
			r.node.SetData(key, value)
		}
	}
}

func (r *ReceiverLink) receiveDeleteData(msg *communicator.Message) {
	if checkRequiredParams(msg.Parameters, "key") {
		key, _ := msg.Parameters["key"]
		shared.Logger.Info("Receiving a delete data from %s for key %s", msg.Origin.Id, key)

		r.node.DeleteLocalData(key)
	}
}

func checkRequiredParams(params map[string]string, p ...string) bool {
	for _, v := range p {
		_, ok := params[v]
		if !ok {
			shared.Logger.Error("missing parameter %s", v)
			return false
		}
	}
	return true
}

//Exported methods ------------------------------------------------------

func (r *ReceiverLink) StartAndListen() {

	//launch a go routine and start to listen on local address
	//handle incoming communicator.Message

	addr, err := net.ResolveUDPAddr("udp", (shared.LocalIp + ":" + shared.LocalPort))
	if err != nil {
		shared.Logger.Critical("error when resolving udp address:", err)
		panic(err)
	}
	conn, err := net.ListenUDP("udp", addr)
	if err != nil {
		shared.Logger.Critical("error when connecting to udp:", err)
		panic(err)
	}
	// defer conn.Close()
	go func() {
		shared.Logger.Info("Receiver starting to listen on address [%s]", addr)
		for {
			//multiple goroutine ! work !
			buffer := make([]byte, 1024)
			bytesReads, err := conn.Read(buffer)
			if err != nil {
				shared.Logger.Critical("error while reading:", err)
				panic(err)
			}
			payload := buffer[0:bytesReads]
			go r.handleRequest(payload)
			// time.Sleep(time.Millisecond * 10)
			runtime.Gosched()
		}
	}()

}

func MakeReceiver(n *node.DHTnode, s *sender.SenderLink) *ReceiverLink {
	return &ReceiverLink{
		n,
		s,
	}
}
<commit_msg>forgeting to handle a type of message<commit_after>package receiver

import (
	"github.com/tgermain/grandRepositorySky/communicator"
	"github.com/tgermain/grandRepositorySky/communicator/sender"
	"github.com/tgermain/grandRepositorySky/node"
	"github.com/tgermain/grandRepositorySky/shared"
	"net"
	"runtime"
	// "time"
)

//Objects parts ---------------------------------------------------------

type ReceiverLink struct {
	node   *node.DHTnode
	sender *sender.SenderLink
}

//Private methods -------------------------------------------------------
func (r *ReceiverLink) handleRequest(payload []byte) {
	//unmarshall message
	msg := communicator.UnmarshallMessage(payload)
	//switch depending of message type
	shared.Logger.Debug("Handle Request receive something : %#v", msg)
	switch {
	case msg.TypeOfMsg == communicator.LOOKUP:
		{
			r.receiveLookup(&msg)
		}
	case msg.TypeOfMsg == communicator.LOOKUPRESPONSE:
		{
			r.receiveLookupResponse(&msg)
		}
	case msg.TypeOfMsg == communicator.JOINRING:
		{
			r.receiveJoinRing(&msg)
		}
	case msg.TypeOfMsg == communicator.UPDATESUCCESSOR:
		{
			r.receiveUpdateSuccessor(&msg)
		}
	case msg.TypeOfMsg == communicator.UPDATEPREDECESSOR:
		{
			r.receiveUpdatePredecessor(&msg)
		}
	case msg.TypeOfMsg == communicator.PRINTRING:
		{
			r.receivePrintRing(&msg)
		}
	case msg.TypeOfMsg == communicator.UPDATEFINGERTABLE:
		{
			r.receiveUpdateFingerTable(&msg)
		}
	case msg.TypeOfMsg == communicator.AREYOUALIVE:
		{
			r.receiveHeartBeat(&msg)
		}
	case msg.TypeOfMsg == communicator.IAMALIVE:
		{
			r.receiveHeartBeatResponse(&msg)
		}
	case msg.TypeOfMsg == communicator.GETSUCCESORE:
		{
			r.receiveGetSuccesor(&msg)
		}
	case msg.TypeOfMsg == communicator.GETSUCCESORERESPONSE:
		{
			r.receiveGetSuccesorResponse(&msg)
		}
	case msg.TypeOfMsg == communicator.GETDATA:
		{
			r.receiveGetData(&msg)
		}
	case msg.TypeOfMsg == communicator.GETDATARESPONSE:
		{
			r.receiveGetDataResponse(&msg)
		}
	case msg.TypeOfMsg == communicator.DELETEDATA:
		{
			r.receiveDeleteData(&msg)
		}
	case msg.TypeOfMsg == communicator.SETDATA:
		{
			r.receiveSetData(&msg)
		}
	default:
		{
			//rejected mesage
			shared.Logger.Error("Message rejected")
			shared.Logger.Error("Handle Request receive something : %#v", msg)
		}
	}
	// multiple launch a go routine
}

//========RECEIVE
func (r *ReceiverLink) receiveUpdatePredecessor(msg *communicator.Message) {
	if checkRequiredParams(msg.Parameters, "newNodeID", "newNodeIp", "newNodePort") {
		newNodeID, _ := msg.Parameters["newNodeID"]
		newNodeIp, _ := msg.Parameters["newNodeIp"]
		newNodePort, _ := msg.Parameters["newNodePort"]
		shared.Logger.Error("Receive an update Predecessor to %s from %s : %s", newNodeID, msg.Origin.Ip, msg.Origin.Port)

		r.node.UpdatePredecessor(&shared.DistantNode{
			newNodeID,
			newNodeIp,
			newNodePort,
		})

	}
}

func (r *ReceiverLink) receiveUpdateSuccessor(msg *communicator.Message) {
	if checkRequiredParams(msg.Parameters, "newNodeID", "newNodeIp", "newNodePort") {
		newNodeID, _ := msg.Parameters["newNodeID"]
		newNodeIp, _ := msg.Parameters["newNodeIp"]
		newNodePort, _ := msg.Parameters["newNodePort"]
		shared.Logger.Error("Receive an update Successor %s from %s : %s", newNodeID, msg.Origin.Ip, msg.Origin.Port)

		r.node.UpdateSuccessor(&shared.DistantNode{
			newNodeID,
			newNodeIp,
			newNodePort,
		})

	}
}

func (r *ReceiverLink) receivePrintRing(msg *communicator.Message) {
	//write your info and if the successor is the origine of the communicator.Message, send it back to him
	if checkRequiredParams(msg.Parameters, "currentString") {
		currentString, _ := msg.Parameters["currentString"]

		shared.Logger.Info("Receiving a print ring request from %s", msg.Origin.Id)
		if shared.LocalId == msg.Origin.Id {
			shared.Logger.Info("And %s is me !", msg.Origin.Id)
			//I launch this request know print the result
			shared.Logger.Info("The ring is like :\n%s", currentString)
		} else {
			//pass the request around
			r.node.PrintNodeName(&currentString)
			msg.Parameters["currentString"] = currentString
			go r.sender.RelayPrintRing(r.node.GetSuccesor(), msg)
		}
	}
}

func (r *ReceiverLink) receiveJoinRing(msg *communicator.Message) {
	shared.Logger.Info("Receiving join ring message from %s", msg.Origin)
	go r.node.AddToRing(&msg.Origin)
}

func (r *ReceiverLink) receiveLookup(msg *communicator.Message) {
	//check if the parameter are correct
	if checkRequiredParams(msg.Parameters, "idAnswer", "idSearched") {
		idSearched, _ := msg.Parameters["idSearched"]
		idAnswer, _ := msg.Parameters["idAnswer"]
		shared.Logger.Info("Receive a lookup for : %s", idSearched)

		//Am I responsible for the key requested  ?
		if r.node.IsResponsible(idSearched) {
			shared.Logger.Info("I'm responsible !")
			go r.sender.SendLookupResponse(&msg.Origin, idAnswer, idSearched)
		} else {
			//no -> sending the request to the closest node
			shared.Logger.Info("relay the lookup")
			go r.sender.RelayLookup(r.node.FindClosestNode(idSearched), msg)
		}

	}

}

func (r *ReceiverLink) receiveLookupResponse(msg *communicator.Message) {
	//heck if everything required is here
	if checkRequiredParams(msg.Parameters, "idAnswer", "idSearched") {
		idSearched, _ := msg.Parameters["idSearched"]
		idAnswer, _ := msg.Parameters["idAnswer"]

		shared.Logger.Info("Receive a lookup response for : %s", idSearched)

		chanResp, ok2 := communicator.PendingLookups[idAnswer]
		if ok2 {
			chanResp <- msg.Origin
		}
	}
}

func (r *ReceiverLink) receiveUpdateFingerTable(msg *communicator.Message) {
	shared.Logger.Info("Receiving update finger table from %s", msg.Origin.Id)
	r.node.UpdateFingerTable()
}

func (r *ReceiverLink) receiveHeartBeat(msg *communicator.Message) {
	if checkRequiredParams(msg.Parameters, "idAnswer") {
		shared.Logger.Info("Receiving a heartBeat from %s", msg.Origin.Id)
		idAnswer, _ := msg.Parameters["idAnswer"]

		go r.sender.SendHeartBeatResponse(&msg.Origin, idAnswer)
	}
}

func (r *ReceiverLink) receiveHeartBeatResponse(msg *communicator.Message) {
	if checkRequiredParams(msg.Parameters, "idAnswer") {
		idAnswer, _ := msg.Parameters["idAnswer"]
		shared.Logger.Info("Receiving a heartBeat response from %s for %s", msg.Origin.Id, idAnswer)

		chanResp, ok2 := communicator.PendingHearBeat[idAnswer]
		if ok2 {
			chanResp <- msg.Origin
		}
	}
}

func (r *ReceiverLink) receiveGetSuccesor(msg *communicator.Message) {
	if checkRequiredParams(msg.Parameters, "idAnswer") {
		shared.Logger.Info("Receiving a get successor from %s", msg.Origin.Id)
		idAnswer, _ := msg.Parameters["idAnswer"]

		go r.sender.SendGetSuccResponse(&msg.Origin, idAnswer, r.node.GetSuccesor())
	}
}

func (r *ReceiverLink) receiveGetSuccesorResponse(msg *communicator.Message) {
	if checkRequiredParams(msg.Parameters, "idAnswer", "succSuccID",
		"succSuccIp",
		"succSuccPort") {
		idAnswer, _ := msg.Parameters["idAnswer"]
		succSuccID, _ := msg.Parameters["succSuccID"]
		succSuccIp, _ := msg.Parameters["succSuccIp"]
		succSuccPort, _ := msg.Parameters["succSuccPort"]

		shared.Logger.Info("Receiving a GetSuccesor response from %s for %s", msg.Origin.Id, idAnswer)

		succSucc := shared.DistantNode{
			succSuccID,
			succSuccIp,
			succSuccPort,
		}

		chanResp, ok2 := communicator.PendingGetSucc[idAnswer]
		if ok2 {
			chanResp <- succSucc
		}
	}
}

func (r *ReceiverLink) receiveGetData(msg *communicator.Message) {
	if checkRequiredParams(msg.Parameters, "keySearched", "idAnswer") {
		shared.Logger.Info("Receiving a get data from %s", msg.Origin.Id)
		keySearched, _ := msg.Parameters["keySearched"]
		idAnswer, _ := msg.Parameters["idAnswer"]
		_, forced := msg.Parameters["forced"]

		var result string
		if forced {
			result = r.node.GetLocalData(keySearched)
		} else {
			result = r.node.GetData(keySearched)
		}
		r.sender.SendGetDataResponse(&msg.Origin, idAnswer, result)
	}
}

func (r *ReceiverLink) receiveGetDataResponse(msg *communicator.Message) {
	if checkRequiredParams(msg.Parameters, "idAnswer", "value") {
		idAnswer, _ := msg.Parameters["idAnswer"]
		value, _ := msg.Parameters["value"]

		shared.Logger.Info("Receiving a get data response from %s for %s", msg.Origin.Id, idAnswer)

		chanResp, ok2 := communicator.PendingGetData[idAnswer]
		if ok2 {
			chanResp <- value
		}
	}
}

func (r *ReceiverLink) receiveSetData(msg *communicator.Message) {
	if checkRequiredParams(msg.Parameters, "key", "value") {
		key, _ := msg.Parameters["key"]
		value, _ := msg.Parameters["value"]
		tag, forced := msg.Parameters["forced"]
		shared.Logger.Info("Receiving a set data from %s with data %s", msg.Origin.Id, value)

		if forced {
			r.node.SetLocalData(key, value, tag)
		} else {
			r.node.SetData(key, value)
		}
	}
}

func (r *ReceiverLink) receiveDeleteData(msg *communicator.Message) {
	if checkRequiredParams(msg.Parameters, "key") {
		key, _ := msg.Parameters["key"]
		shared.Logger.Info("Receiving a delete data from %s for key %s", msg.Origin.Id, key)

		r.node.DeleteLocalData(key)
	}
}

func checkRequiredParams(params map[string]string, p ...string) bool {
	for _, v := range p {
		_, ok := params[v]
		if !ok {
			shared.Logger.Error("missing parameter %s", v)
			return false
		}
	}
	return true
}

//Exported methods ------------------------------------------------------

func (r *ReceiverLink) StartAndListen() {

	//launch a go routine and start to listen on local address
	//handle incoming communicator.Message

	addr, err := net.ResolveUDPAddr("udp", ("" + ":" + shared.LocalPort))
	if err != nil {
		shared.Logger.Critical("error when resolving udp address:", err)
		panic(err)
	}
	conn, err := net.ListenUDP("udp", addr)
	if err != nil {
		shared.Logger.Critical("error when connecting to udp:", err)
		panic(err)
	}
	// defer conn.Close()
	go func() {
		shared.Logger.Info("Receiver starting to listen on address [%s]", addr)
		for {
			//multiple goroutine ! work !
			buffer := make([]byte, 1024)
			bytesReads, err := conn.Read(buffer)
			if err != nil {
				shared.Logger.Critical("error while reading:", err)
				panic(err)
			}
			payload := buffer[0:bytesReads]
			go r.handleRequest(payload)
			// time.Sleep(time.Millisecond * 10)
			runtime.Gosched()
		}
	}()

}

func MakeReceiver(n *node.DHTnode, s *sender.SenderLink) *ReceiverLink {
	return &ReceiverLink{
		n,
		s,
	}
}
<|endoftext|>


<commit_before>package p4

import (
	"errors"
	"fmt"
	"regexp"
	"strconv"
	"strings"
)

type Describe struct {
	Change      int
	User        string
	Client      string
	Time        string
	Description string
	Status      string
	Files       []DescribeFile
}

type DescribeFile struct {
	Path    string
	Version int
	Action  string
}

type Review struct {
	Change int
	User   string
	Email  string
	Name   string
}

var newlineRegexp = regexp.MustCompile("\r\n|\r|\n")

var countersRegexp = regexp.MustCompile("(?m)^(.+) = (.+)$")
var describeRegexp = regexp.MustCompile("\\AChange (\\d+) by (.+)@(.+) on (.+)((?: *pending*)?)\n\n((?:\t.*\n)*)\nAffected files ...\n\n((?:... (?:.+) (?:[\\w/]+)\n)*)\n\\z")
var describeAffectedRegexp = regexp.MustCompile("(?m)^... (.+)#(\\d+) ([\\w/]+)$")
var printRegexp = regexp.MustCompile("(?m)\\A(.+)(@|#)(\\d+)(?: - | )(.+)$")
var reviewRegexp = regexp.MustCompile("(?m)^Change (\\d+) (.+) <(.+)> \\((.+)\\)$")

func (c *Connection) Counters() (map[string]string, error) {
	counters := map[string]string{}

	if data, err := c.execP4("counters"); err == nil {
		submatch := countersRegexp.FindAllSubmatch(data, 1000000)

		for _, counter := range submatch {
			counters[string(counter[1])] = string(counter[2])
		}

		return counters, nil
	} else {
		return nil, err
	}
}

func (c *Connection) Describe(change int) (Describe, error) {
	var describe Describe

	if data, err := c.execP4("describe", "-s", strconv.Itoa(change)); err == nil {
		submatch := describeRegexp.FindSubmatch(data)
		intChange, err := strconv.Atoi(string(submatch[1]))

		if err != nil {
			return describe, err
		}

		status := "submitted"

		if string(submatch[5]) == " *pending" {
			status = "pending"
		}

		describe = Describe{
			Change:      intChange,
			User:        string(submatch[2]),
			Client:      string(submatch[3]),
			Time:        string(submatch[4]),
			Description: string(submatch[6]),
			Status:      status,
		}

		affectedSubmatch := describeAffectedRegexp.FindAllSubmatch(submatch[7], 10000000)

		for _, m := range affectedSubmatch {
			intVersion, err := strconv.Atoi(string(m[2]))

			if err != nil {
				return describe, err
			}

			describe.Files = append(describe.Files, DescribeFile{
				Path:    string(m[1]),
				Version: intVersion,
				Action:  string(m[3]),
			})
		}

		return describe, nil
	} else {
		return describe, err
	}
}

func (c *Connection) GetCounter(counter string) (string, error) {
	if data, err := c.execP4("counter", counter); err == nil {
		return strings.TrimRight(string(data), "\n"), nil
	} else {
		return "", err
	}
}

func (c *Connection) Print(path string, clNumber int) ([]byte, error) {
	// We can not use p4's -q flag here, as that leaves us with no method of
	// distinguishing an actual error from a file happens to contain an error
	// message. The process exits with a status code of 0 in both cases.
	//
	// The first line of output differs slightly between a successful request
	// and an error:
	//
	//  * On error, the line begins with the path followed by `@` and the
	//    changelist number.
	//  * On success, the line begins with the path followed by `#` and the
	//    file revision.
	//
	// Another limitation of p4's print is automatic line-ending conversions
	// on text files. This can not be disabled. It also can not be determined
	// if the file is treated as text or binary by Perforce.
	//
	// No attempt is made to correct this anomaly. Whatever p4 gives us, we
	// give you.

	url := fmt.Sprintf("%s@%d", path, clNumber)

	if data, err := c.execP4("print", url); err == nil {
		lines := newlineRegexp.Split(string(data), 2)

		if len(lines) != 2 {
			return nil, errors.New("no newlines found in p4's output")
		}

		submatch := printRegexp.FindSubmatch([]byte(lines[0]))

		if len(submatch) == 0 {
			return nil, errors.New("first line from p4 print of invalid format")
		}

		if submatch[2][0] != '#' {
			return nil, P4Error{
				errors.New(string(submatch[4])),
				[]string{"p4", "print", url},
				data,
			}
		}

		return []byte(lines[1]), nil
	} else {
		return nil, err
	}
}

func (c *Connection) ReviewByChangelist(clNumber int) ([]Review, error) {
	return c.review("review", "-c", strconv.Itoa(clNumber))
}

func (c *Connection) ReviewByCounter(counter string) ([]Review, error) {
	return c.review("review", "-t", counter)
}

func (c *Connection) review(arguments ...string) ([]Review, error) {
	reviews := []Review{}

	if data, err := c.execP4(arguments...); err == nil {
		submatch := reviewRegexp.FindAllSubmatch(data, 10000000)

		for _, review := range submatch {
			intChange, err := strconv.Atoi(string(review[1]))

			if err != nil {
				return nil, err
			}

			reviews = append(reviews, Review{
				Change: intChange,
				User:   string(review[2]),
				Email:  string(review[3]),
				Name:   string(review[4]),
			})
		}

		return reviews, nil
	} else {
		return nil, err
	}
}

func (c *Connection) SetCounter(counter string, value string) error {
	if _, err := c.execP4("counter", counter, value); err == nil {
		return nil
	} else {
		return err
	}
}

func (c *Connection) Sync(path string, clNumber int) error {
	if _, err := c.execP4("sync", "-f", fmt.Sprintf("%s@%d", path, clNumber)); err == nil {
		return nil
	} else {
		return err
	}
}
<commit_msg>Add `user` command<commit_after>package p4

import (
	"errors"
	"fmt"
	"regexp"
	"strconv"
	"strings"
)

type Describe struct {
	Change      int
	User        string
	Client      string
	Time        string
	Description string
	Status      string
	Files       []DescribeFile
}

type DescribeFile struct {
	Path    string
	Version int
	Action  string
}

type Review struct {
	Change int
	User   string
	Email  string
	Name   string
}

type User struct {
	User     string
	Email    string
	FullName string
}

var newlineRegexp = regexp.MustCompile("\r\n|\r|\n")

var countersRegexp = regexp.MustCompile("(?m)^(.+) = (.+)$")
var describeRegexp = regexp.MustCompile("\\AChange (\\d+) by (.+)@(.+) on (.+)((?: *pending*)?)\n\n((?:\t.*\n)*)\nAffected files ...\n\n((?:... (?:.+) (?:[\\w/]+)\n)*)\n\\z")
var describeAffectedRegexp = regexp.MustCompile("(?m)^... (.+)#(\\d+) ([\\w/]+)$")
var printRegexp = regexp.MustCompile("(?m)\\A(.+)(@|#)(\\d+)(?: - | )(.+)$")
var reviewRegexp = regexp.MustCompile("(?m)^Change (\\d+) (.+) <(.+)> \\((.+)\\)$")

func (c *Connection) Counters() (map[string]string, error) {
	counters := map[string]string{}

	if data, err := c.execP4("counters"); err == nil {
		submatch := countersRegexp.FindAllSubmatch(data, 1000000)

		for _, counter := range submatch {
			counters[string(counter[1])] = string(counter[2])
		}

		return counters, nil
	} else {
		return nil, err
	}
}

func (c *Connection) Describe(change int) (Describe, error) {
	var describe Describe

	if data, err := c.execP4("describe", "-s", strconv.Itoa(change)); err == nil {
		submatch := describeRegexp.FindSubmatch(data)
		intChange, err := strconv.Atoi(string(submatch[1]))

		if err != nil {
			return describe, err
		}

		status := "submitted"

		if string(submatch[5]) == " *pending" {
			status = "pending"
		}

		describe = Describe{
			Change:      intChange,
			User:        string(submatch[2]),
			Client:      string(submatch[3]),
			Time:        string(submatch[4]),
			Description: string(submatch[6]),
			Status:      status,
		}

		affectedSubmatch := describeAffectedRegexp.FindAllSubmatch(submatch[7], 10000000)

		for _, m := range affectedSubmatch {
			intVersion, err := strconv.Atoi(string(m[2]))

			if err != nil {
				return describe, err
			}

			describe.Files = append(describe.Files, DescribeFile{
				Path:    string(m[1]),
				Version: intVersion,
				Action:  string(m[3]),
			})
		}

		return describe, nil
	} else {
		return describe, err
	}
}

var emailRegex = regexp.MustCompile(`(?m)^Email:\s+(.*)$`)
var fullNameRegex = regexp.MustCompile(`(?m)^FullName:\s+(.*)$`)

func (c *Connection) User(username string) (User, error) {
	if data, err := c.execP4("user", "-o", username); err == nil {
		user := User{
			User:     username,
			Email:    string(emailRegex.FindSubmatch(data)[1]),
			FullName: string(fullNameRegex.FindSubmatch(data)[1]),
		}
		return user, nil
	} else {
		return User{}, err
	}
}

func (c *Connection) GetCounter(counter string) (string, error) {
	if data, err := c.execP4("counter", counter); err == nil {
		return strings.TrimRight(string(data), "\n"), nil
	} else {
		return "", err
	}
}

func (c *Connection) Print(path string, clNumber int) ([]byte, error) {
	// We can not use p4's -q flag here, as that leaves us with no method of
	// distinguishing an actual error from a file happens to contain an error
	// message. The process exits with a status code of 0 in both cases.
	//
	// The first line of output differs slightly between a successful request
	// and an error:
	//
	//  * On error, the line begins with the path followed by `@` and the
	//    changelist number.
	//  * On success, the line begins with the path followed by `#` and the
	//    file revision.
	//
	// Another limitation of p4's print is automatic line-ending conversions
	// on text files. This can not be disabled. It also can not be determined
	// if the file is treated as text or binary by Perforce.
	//
	// No attempt is made to correct this anomaly. Whatever p4 gives us, we
	// give you.

	url := fmt.Sprintf("%s@%d", path, clNumber)

	if data, err := c.execP4("print", url); err == nil {
		lines := newlineRegexp.Split(string(data), 2)

		if len(lines) != 2 {
			return nil, errors.New("no newlines found in p4's output")
		}

		submatch := printRegexp.FindSubmatch([]byte(lines[0]))

		if len(submatch) == 0 {
			return nil, errors.New("first line from p4 print of invalid format")
		}

		if submatch[2][0] != '#' {
			return nil, P4Error{
				errors.New(string(submatch[4])),
				[]string{"p4", "print", url},
				data,
			}
		}

		return []byte(lines[1]), nil
	} else {
		return nil, err
	}
}

func (c *Connection) ReviewByChangelist(clNumber int) ([]Review, error) {
	return c.review("review", "-c", strconv.Itoa(clNumber))
}

func (c *Connection) ReviewByCounter(counter string) ([]Review, error) {
	return c.review("review", "-t", counter)
}

func (c *Connection) review(arguments ...string) ([]Review, error) {
	reviews := []Review{}

	if data, err := c.execP4(arguments...); err == nil {
		submatch := reviewRegexp.FindAllSubmatch(data, 10000000)

		for _, review := range submatch {
			intChange, err := strconv.Atoi(string(review[1]))

			if err != nil {
				return nil, err
			}

			reviews = append(reviews, Review{
				Change: intChange,
				User:   string(review[2]),
				Email:  string(review[3]),
				Name:   string(review[4]),
			})
		}

		return reviews, nil
	} else {
		return nil, err
	}
}

func (c *Connection) SetCounter(counter string, value string) error {
	if _, err := c.execP4("counter", counter, value); err == nil {
		return nil
	} else {
		return err
	}
}

func (c *Connection) Sync(path string, clNumber int) error {
	if _, err := c.execP4("sync", "-f", fmt.Sprintf("%s@%d", path, clNumber)); err == nil {
		return nil
	} else {
		return err
	}
}
<|endoftext|>