<commit_before>// Copyright (C) 2015 Nippon Telegraph and Telephone Corporation.
//
// 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 main

// typedef struct {
//     char *value;
//     int len;
// } buf;
//
// typedef struct path_t {
//     buf   nlri;
//     buf** path_attributes;
//     int   path_attributes_len;
//     int   path_attributes_cap;
// } path;
// extern path* new_path();
// extern void free_path(path*);
// extern int append_path_attribute(path*, int, char*);
// extern buf* get_path_attribute(path*, int);
import "C"

import (
	"encoding/json"
	"strings"

	api "github.com/osrg/gobgp/api"
	"github.com/osrg/gobgp/gobgp/cmd"
	"github.com/osrg/gobgp/packet/bgp"
)

//export get_route_family
func get_route_family(input *C.char) C.int {
	rf, err := bgp.GetRouteFamily(C.GoString(input))
	if err != nil {
		return C.int(-1)
	}
	return C.int(rf)
}

//export serialize_path
func serialize_path(rf C.int, input *C.char) *C.path {
	args := strings.Split(C.GoString(input), " ")
	pp, err := cmd.ParsePath(bgp.RouteFamily(rf), args)
	if err != nil {
		return nil
	}
	path := C.new_path()
	p := api.ToPathApi(pp, nil)
	if len(p.Nlri) > 0 {
		path.nlri.len = C.int(len(p.Nlri))
		path.nlri.value = C.CString(string(p.Nlri))
	}
	for _, attr := range p.Pattrs {
		C.append_path_attribute(path, C.int(len(attr)), C.CString(string(attr)))
	}
	return path
}

//export decode_path
func decode_path(p *C.path) *C.char {
	var buf []byte
	var nlri bgp.AddrPrefixInterface
	if p.nlri.len > 0 {
		buf = []byte(C.GoStringN(p.nlri.value, p.nlri.len))
		nlri = &bgp.IPAddrPrefix{}
		err := nlri.DecodeFromBytes(buf)
		if err != nil {
			return nil
		}
	}
	pattrs := make([]bgp.PathAttributeInterface, 0, int(p.path_attributes_len))
	for i := 0; i < int(p.path_attributes_len); i++ {
		b := C.get_path_attribute(p, C.int(i))
		buf = []byte(C.GoStringN(b.value, b.len))
		pattr, err := bgp.GetPathAttribute(buf)
		if err != nil {
			return nil
		}

		err = pattr.DecodeFromBytes(buf)
		if err != nil {
			return nil
		}

		switch pattr.GetType() {
		case bgp.BGP_ATTR_TYPE_MP_REACH_NLRI:
			mpreach := pattr.(*bgp.PathAttributeMpReachNLRI)
			if len(mpreach.Value) != 1 {
				return nil
			}
			nlri = mpreach.Value[0]
		}

		pattrs = append(pattrs, pattr)
	}
	j, _ := json.Marshal(struct {
		Nlri      bgp.AddrPrefixInterface      `json:"nlri"`
		PathAttrs []bgp.PathAttributeInterface `json:"attrs"`
	}{
		Nlri:      nlri,
		PathAttrs: pattrs,
	})
	return C.CString(string(j))
}

//export decode_capabilities
func decode_capabilities(p *C.buf) *C.char {
	buf := []byte(C.GoStringN(p.value, p.len))
	c, err := bgp.DecodeCapability(buf)
	if err != nil {
		return nil
	}
	j, _ := json.Marshal(c)
	return C.CString(string(j))

}

func main() {
	// We need the main function to make possible
	// CGO compiler to compile the package as C shared library
}
<commit_msg>gobgp/lib: Remove usage of utils of "gobgpapi"<commit_after>// Copyright (C) 2015 Nippon Telegraph and Telephone Corporation.
//
// 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 main

// typedef struct {
//     char *value;
//     int len;
// } buf;
//
// typedef struct path_t {
//     buf   nlri;
//     buf** path_attributes;
//     int   path_attributes_len;
//     int   path_attributes_cap;
// } path;
// extern path* new_path();
// extern void free_path(path*);
// extern int append_path_attribute(path*, int, char*);
// extern buf* get_path_attribute(path*, int);
import "C"

import (
	"encoding/json"
	"strings"

	"github.com/osrg/gobgp/gobgp/cmd"
	"github.com/osrg/gobgp/packet/bgp"
)

//export get_route_family
func get_route_family(input *C.char) C.int {
	rf, err := bgp.GetRouteFamily(C.GoString(input))
	if err != nil {
		return C.int(-1)
	}
	return C.int(rf)
}

//export serialize_path
func serialize_path(rf C.int, input *C.char) *C.path {
	args := strings.Split(C.GoString(input), " ")
	p, err := cmd.ParsePath(bgp.RouteFamily(rf), args)
	if err != nil {
		return nil
	}
	path := C.new_path()
	if nlri := p.GetNlri(); nlri != nil {
		buf, _ := nlri.Serialize()
		path.nlri.len = C.int(len(buf))
		path.nlri.value = C.CString(string(buf))
	}
	for _, attr := range p.GetPathAttrs() {
		buf, _ := attr.Serialize()
		C.append_path_attribute(path, C.int(len(buf)), C.CString(string(buf)))
	}
	return path
}

//export decode_path
func decode_path(p *C.path) *C.char {
	var buf []byte
	var nlri bgp.AddrPrefixInterface
	if p.nlri.len > 0 {
		buf = []byte(C.GoStringN(p.nlri.value, p.nlri.len))
		nlri = &bgp.IPAddrPrefix{}
		err := nlri.DecodeFromBytes(buf)
		if err != nil {
			return nil
		}
	}
	pattrs := make([]bgp.PathAttributeInterface, 0, int(p.path_attributes_len))
	for i := 0; i < int(p.path_attributes_len); i++ {
		b := C.get_path_attribute(p, C.int(i))
		buf = []byte(C.GoStringN(b.value, b.len))
		pattr, err := bgp.GetPathAttribute(buf)
		if err != nil {
			return nil
		}

		err = pattr.DecodeFromBytes(buf)
		if err != nil {
			return nil
		}

		switch pattr.GetType() {
		case bgp.BGP_ATTR_TYPE_MP_REACH_NLRI:
			mpreach := pattr.(*bgp.PathAttributeMpReachNLRI)
			if len(mpreach.Value) != 1 {
				return nil
			}
			nlri = mpreach.Value[0]
		}

		pattrs = append(pattrs, pattr)
	}
	j, _ := json.Marshal(struct {
		Nlri      bgp.AddrPrefixInterface      `json:"nlri"`
		PathAttrs []bgp.PathAttributeInterface `json:"attrs"`
	}{
		Nlri:      nlri,
		PathAttrs: pattrs,
	})
	return C.CString(string(j))
}

//export decode_capabilities
func decode_capabilities(p *C.buf) *C.char {
	buf := []byte(C.GoStringN(p.value, p.len))
	c, err := bgp.DecodeCapability(buf)
	if err != nil {
		return nil
	}
	j, _ := json.Marshal(c)
	return C.CString(string(j))

}

func main() {
	// We need the main function to make possible
	// CGO compiler to compile the package as C shared library
}
<|endoftext|>


<commit_before>package spdy

import (
	"bufio"
	"crypto/tls"
	"errors"
	"net"
	"net/http"
)

func NewClientConn(conn net.Conn, push Receiver, version uint16) (spdyConn Conn, err error) {
	if conn == nil {
		return nil, errors.New("Error: Connection initialised with nil net.conn.")
	}

	switch version {
	case 3:
		out := new(connV3)
		out.remoteAddr = conn.RemoteAddr().String()
		out.server = nil
		out.conn = conn
		out.buf = bufio.NewReader(conn)
		if tlsConn, ok := conn.(*tls.Conn); ok {
			out.tlsState = new(tls.ConnectionState)
			*out.tlsState = tlsConn.ConnectionState()
		}
		out.streams = make(map[StreamID]Stream)
		out.output = [8]chan Frame{}
		out.output[0] = make(chan Frame)
		out.output[1] = make(chan Frame)
		out.output[2] = make(chan Frame)
		out.output[3] = make(chan Frame)
		out.output[4] = make(chan Frame)
		out.output[5] = make(chan Frame)
		out.output[6] = make(chan Frame)
		out.output[7] = make(chan Frame)
		out.pings = make(map[uint32]chan<- Ping)
		out.nextPingID = 2
		out.compressor = NewCompressor(3)
		out.decompressor = NewDecompressor(3)
		out.receivedSettings = make(Settings)
		out.lastPushStreamID = 0
		out.lastRequestStreamID = 0
		out.oddity = 1
		out.initialWindowSize = DEFAULT_INITIAL_CLIENT_WINDOW_SIZE
		out.requestStreamLimit = newStreamLimit(NO_STREAM_LIMIT)
		out.pushStreamLimit = newStreamLimit(DEFAULT_STREAM_LIMIT)
		out.pushReceiver = push
		out.pushRequests = make(map[StreamID]*http.Request)
		out.stop = make(chan struct{})

		return out, nil

	default:
		return nil, errors.New("Error: Unrecognised SPDY version.")
	}
}
<commit_msg>Added automatic SPDY support for http.DefaultClient.<commit_after>package spdy

import (
	"bufio"
	"crypto/tls"
	"errors"
	"net"
	"net/http"
)

func init() {
	http.DefaultClient = &http.Client{ Transport: new(Transport) }
}

func NewClientConn(conn net.Conn, push Receiver, version uint16) (spdyConn Conn, err error) {
	if conn == nil {
		return nil, errors.New("Error: Connection initialised with nil net.conn.")
	}

	switch version {
	case 3:
		out := new(connV3)
		out.remoteAddr = conn.RemoteAddr().String()
		out.server = nil
		out.conn = conn
		out.buf = bufio.NewReader(conn)
		if tlsConn, ok := conn.(*tls.Conn); ok {
			out.tlsState = new(tls.ConnectionState)
			*out.tlsState = tlsConn.ConnectionState()
		}
		out.streams = make(map[StreamID]Stream)
		out.output = [8]chan Frame{}
		out.output[0] = make(chan Frame)
		out.output[1] = make(chan Frame)
		out.output[2] = make(chan Frame)
		out.output[3] = make(chan Frame)
		out.output[4] = make(chan Frame)
		out.output[5] = make(chan Frame)
		out.output[6] = make(chan Frame)
		out.output[7] = make(chan Frame)
		out.pings = make(map[uint32]chan<- Ping)
		out.nextPingID = 2
		out.compressor = NewCompressor(3)
		out.decompressor = NewDecompressor(3)
		out.receivedSettings = make(Settings)
		out.lastPushStreamID = 0
		out.lastRequestStreamID = 0
		out.oddity = 1
		out.initialWindowSize = DEFAULT_INITIAL_CLIENT_WINDOW_SIZE
		out.requestStreamLimit = newStreamLimit(NO_STREAM_LIMIT)
		out.pushStreamLimit = newStreamLimit(DEFAULT_STREAM_LIMIT)
		out.pushReceiver = push
		out.pushRequests = make(map[StreamID]*http.Request)
		out.stop = make(chan struct{})

		return out, nil

	default:
		return nil, errors.New("Error: Unrecognised SPDY version.")
	}
}
<|endoftext|>


<commit_before>//
// DISCLAIMER
//
// Copyright 2017 ArangoDB GmbH, Cologne, Germany
//
// 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.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
// Author Ewout Prangsma
//

package driver

import (
	"context"
	"time"

	"github.com/arangodb/go-driver/util"
)

// NewClient creates a new Client based on the given config setting.
func NewClient(config ClientConfig) (Client, error) {
	if config.Connection == nil {
		return nil, WithStack(InvalidArgumentError{Message: "Connection is not set"})
	}
	conn := config.Connection
	if config.Authentication != nil {
		var err error
		conn, err = conn.SetAuthentication(config.Authentication)
		if err != nil {
			return nil, WithStack(err)
		}
	}
	c := &client{
		conn: conn,
	}
	if config.SynchronizeEndpointsInterval > 0 {
		go c.autoSynchronizeEndpoints(config.SynchronizeEndpointsInterval)
	}
	return c, nil
}

// client implements the Client interface.
type client struct {
	conn Connection
}

// Connection returns the connection used by this client
func (c *client) Connection() Connection {
	return c.conn
}

// SynchronizeEndpoints fetches all endpoints from an ArangoDB cluster and updates the
// connection to use those endpoints.
// When this client is connected to a single server, nothing happens.
// When this client is connected to a cluster of servers, the connection will be updated to reflect
// the layout of the cluster.
func (c *client) SynchronizeEndpoints(ctx context.Context) error {
	role, err := c.ServerRole(ctx)
	if err != nil {
		return WithStack(err)
	}
	if role == ServerRoleSingle {
		// Standalone server, do nothing
		return nil
	}

	// Cluster mode, fetch endpoints
	cep, err := c.clusterEndpoints(ctx)
	if err != nil {
		return WithStack(err)
	}
	var endpoints []string
	for _, ep := range cep.Endpoints {
		endpoints = append(endpoints, util.FixupEndpointURLScheme(ep.Endpoint))
	}

	// Update connection
	if err := c.conn.UpdateEndpoints(endpoints); err != nil {
		return WithStack(err)
	}

	return nil
}

// autoSynchronizeEndpoints performs automatic endpoint synchronization.
func (c *client) autoSynchronizeEndpoints(interval time.Duration) {
	for {
		// SynchronizeEndpoints endpoints
		c.SynchronizeEndpoints(nil)

		// Wait a bit
		time.Sleep(interval)
	}
}

type clusterEndpointsResponse struct {
	Endpoints []clusterEndpoint `json:"endpoints,omitempty"`
}

type clusterEndpoint struct {
	Endpoint string `json:"endpoint,omitempty"`
}

// clusterEndpoints returns the endpoints of a cluster.
func (c *client) clusterEndpoints(ctx context.Context) (clusterEndpointsResponse, error) {
	req, err := c.conn.NewRequest("GET", "_api/cluster/endpoints")
	if err != nil {
		return clusterEndpointsResponse{}, WithStack(err)
	}
	applyContextSettings(ctx, req)
	resp, err := c.conn.Do(ctx, req)
	if err != nil {
		return clusterEndpointsResponse{}, WithStack(err)
	}
	if err := resp.CheckStatus(200); err != nil {
		return clusterEndpointsResponse{}, WithStack(err)
	}
	var data clusterEndpointsResponse
	if err := resp.ParseBody("", &data); err != nil {
		return clusterEndpointsResponse{}, WithStack(err)
	}
	return data, nil
}
<commit_msg>Added a separate function to access the endpoint via a database instead of _system. (#157)<commit_after>//
// DISCLAIMER
//
// Copyright 2017 ArangoDB GmbH, Cologne, Germany
//
// 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.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
// Author Ewout Prangsma
//

package driver

import (
	"context"
	"path"
	"time"

	"github.com/arangodb/go-driver/util"
)

// NewClient creates a new Client based on the given config setting.
func NewClient(config ClientConfig) (Client, error) {
	if config.Connection == nil {
		return nil, WithStack(InvalidArgumentError{Message: "Connection is not set"})
	}
	conn := config.Connection
	if config.Authentication != nil {
		var err error
		conn, err = conn.SetAuthentication(config.Authentication)
		if err != nil {
			return nil, WithStack(err)
		}
	}
	c := &client{
		conn: conn,
	}
	if config.SynchronizeEndpointsInterval > 0 {
		go c.autoSynchronizeEndpoints(config.SynchronizeEndpointsInterval)
	}
	return c, nil
}

// client implements the Client interface.
type client struct {
	conn Connection
}

// Connection returns the connection used by this client
func (c *client) Connection() Connection {
	return c.conn
}

// SynchronizeEndpoints fetches all endpoints from an ArangoDB cluster and updates the
// connection to use those endpoints.
// When this client is connected to a single server, nothing happens.
// When this client is connected to a cluster of servers, the connection will be updated to reflect
// the layout of the cluster.
func (c *client) SynchronizeEndpoints(ctx context.Context) error {
	return c.SynchronizeEndpoints2(ctx, "")
}

// SynchronizeEndpoints2 fetches all endpoints from an ArangoDB cluster and updates the
// connection to use those endpoints.
// When this client is connected to a single server, nothing happens.
// When this client is connected to a cluster of servers, the connection will be updated to reflect
// the layout of the cluster.
// Compared to SynchronizeEndpoints, this function expects a database name as additional parameter.
// This database name is used to call `_db/<dbname>/_api/cluster/endpoints`. SynchronizeEndpoints uses
// the default database, i.e. `_system`. In the case the user does not have access to `_system`,
// SynchronizeEndpoints does not work with earlier versions of arangodb.
func (c *client) SynchronizeEndpoints2(ctx context.Context, dbname string) error {
	role, err := c.ServerRole(ctx)
	if err != nil {
		return WithStack(err)
	}
	if role == ServerRoleSingle {
		// Standalone server, do nothing
		return nil
	}

	// Cluster mode, fetch endpoints
	cep, err := c.clusterEndpoints(ctx, dbname)
	if err != nil {
		return WithStack(err)
	}
	var endpoints []string
	for _, ep := range cep.Endpoints {
		endpoints = append(endpoints, util.FixupEndpointURLScheme(ep.Endpoint))
	}

	// Update connection
	if err := c.conn.UpdateEndpoints(endpoints); err != nil {
		return WithStack(err)
	}

	return nil
}

// autoSynchronizeEndpoints performs automatic endpoint synchronization.
func (c *client) autoSynchronizeEndpoints(interval time.Duration) {
	for {
		// SynchronizeEndpoints endpoints
		c.SynchronizeEndpoints(nil)

		// Wait a bit
		time.Sleep(interval)
	}
}

type clusterEndpointsResponse struct {
	Endpoints []clusterEndpoint `json:"endpoints,omitempty"`
}

type clusterEndpoint struct {
	Endpoint string `json:"endpoint,omitempty"`
}

// clusterEndpoints returns the endpoints of a cluster.
func (c *client) clusterEndpoints(ctx context.Context, dbname string) (clusterEndpointsResponse, error) {
	var url string
	if dbname == "" {
		url = "_api/cluster/endpoints"
	} else {
		url = path.Join("_db", pathEscape(dbname), "_api/cluster/endpoints")
	}
	req, err := c.conn.NewRequest("GET", url)
	if err != nil {
		return clusterEndpointsResponse{}, WithStack(err)
	}
	applyContextSettings(ctx, req)
	resp, err := c.conn.Do(ctx, req)
	if err != nil {
		return clusterEndpointsResponse{}, WithStack(err)
	}
	if err := resp.CheckStatus(200); err != nil {
		return clusterEndpointsResponse{}, WithStack(err)
	}
	var data clusterEndpointsResponse
	if err := resp.ParseBody("", &data); err != nil {
		return clusterEndpointsResponse{}, WithStack(err)
	}
	return data, nil
}
<|endoftext|>


<commit_before>// client_test.go - Katzenpost client library tests.
// Copyright (C) 2019  David Stainton.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

// Package client provides a Katzenpost client library.
package client

import (
	"sync"
	"testing"
	"time"

	"github.com/katzenpost/kimchi"
	"github.com/stretchr/testify/require"
)

const basePort = 30000

// TestClientConnect tests that a client can connect and send a message to the loop service
func TestClientConnect(t *testing.T) {
	require := require.New(t)
	voting := false
	nVoting := 0
	nProvider := 2
	nMix := 6
	k := kimchi.NewKimchi(basePort+400, "", nil, voting, nVoting, nProvider, nMix)
	t.Logf("Running TestClientConnect.")
	k.Run()

	go func() {
		defer k.Shutdown()

		// create a client configuration
		cfg, username, linkKey, err := k.GetClientConfig()
		require.NoError(err)
		require.NotNil(cfg)

		<-time.After(90 * time.Second) // must wait for provider to fetch pki document
		t.Logf("Time is up!")

		// instantiate a client instance
		c, err := New(cfg)
		require.NotNil(cfg)
		require.NoError(err)

		// add client log output
		go k.LogTailer(username, cfg.Logging.File)

		// instantiate a session
		s, err := c.NewSession(linkKey)
		require.NoError(err)

		// look up a well known service
		desc, err := s.GetService("loop")
		require.NoError(err)

		// send a message
		t.Logf("desc.Provider: %s", desc.Provider)
		_, err = s.BlockingSendUnreliableMessage(desc.Name, desc.Provider, []byte("hello!"))
		require.NoError(err)
		t.Logf("Sent unreliable message to loop service")

		c.Shutdown()
		t.Logf("Shutdown requested")
		c.Wait()
	}()

	k.Wait()
	t.Logf("Terminated.")
}

// TestAutoRegisterRandomClient tests client registration
func TestAutoRegisterRandomClient(t *testing.T) {
	require := require.New(t)
	voting := false
	nVoting := 0
	nProvider := 2
	nMix := 6
	k := kimchi.NewKimchi(basePort+500, "", nil, voting, nVoting, nProvider, nMix)
	t.Logf("Running TestAutoRegisterRandomClient.")
	k.Run()

	go func() {
		defer k.Shutdown()
		<-time.After(90 * time.Second) // must wait for provider to fetch pki document
		cfg, err := k.GetClientNetconfig()
		require.NoError(err)

		_, linkKey := AutoRegisterRandomClient(cfg)
		require.NotNil(linkKey)

		// Verify that the client can connect
		c, err := New(cfg)
		require.NoError(err)

		// instantiate a session
		s, err := c.NewSession(linkKey)
		require.NoError(err)

		// look up a well known service
		desc, err := s.GetService("loop")
		require.NoError(err)
		t.Logf("Found %v kaetzchen on %v", desc.Name, desc.Provider)

		c.Shutdown()
		t.Logf("Shutdown requested")
		c.Wait()
	}()
	k.Wait()
}

// TestDecoyClient tests client with Decoy traffic enabled
func TestDecoyClient(t *testing.T) {
	require := require.New(t)
	voting := false
	nVoting := 0
	nProvider := 2
	nMix := 6
	k := kimchi.NewKimchi(basePort+500, "", nil, voting, nVoting, nProvider, nMix)
	t.Logf("Running TestAutoRegisterRandomClient.")
	k.Run()

	go func() {
		defer k.Shutdown()
		<-time.After(90 * time.Second) // must wait for provider to fetch pki document
		cfg, err := k.GetClientNetconfig()
		require.NoError(err)
		cfg.Debug.DisableDecoyTraffic = false

		_, linkKey := AutoRegisterRandomClient(cfg)
		require.NotNil(linkKey)

		// Verify that the client can connect
		c, err := New(cfg)
		require.NoError(err)

		// instantiate a session
		s, err := c.NewSession(linkKey)
		require.NoError(err)

		// look up a well known service
		desc, err := s.GetService("loop")
		require.NoError(err)
		t.Logf("Found %v kaetzchen on %v", desc.Name, desc.Provider)

		wg := &sync.WaitGroup{}
		for i := 0; i < 3; i++ {
			wg.Add(1)
			go func() {
				t.Logf("SendUnreliableMessage()")
				_, err := s.BlockingSendUnreliableMessage(desc.Name, desc.Provider, []byte("hello!"))
				require.NoError(err)
				wg.Done()
			}()
		}
		wg.Wait()

		c.Shutdown()
		t.Logf("Shutdown requested")
		c.Wait()
	}()
	k.Wait()
}
<commit_msg>Comment out broken kimchi client decoy test<commit_after>// client_test.go - Katzenpost client library tests.
// Copyright (C) 2019  David Stainton.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

// Package client provides a Katzenpost client library.
package client

import (
	"sync"
	"testing"
	"time"

	"github.com/katzenpost/kimchi"
	"github.com/stretchr/testify/require"
)

const basePort = 30000

// TestClientConnect tests that a client can connect and send a message to the loop service
func TestClientConnect(t *testing.T) {
	require := require.New(t)
	voting := false
	nVoting := 0
	nProvider := 2
	nMix := 6
	k := kimchi.NewKimchi(basePort+400, "", nil, voting, nVoting, nProvider, nMix)
	t.Logf("Running TestClientConnect.")
	k.Run()

	go func() {
		defer k.Shutdown()

		// create a client configuration
		cfg, username, linkKey, err := k.GetClientConfig()
		require.NoError(err)
		require.NotNil(cfg)

		<-time.After(90 * time.Second) // must wait for provider to fetch pki document
		t.Logf("Time is up!")

		// instantiate a client instance
		c, err := New(cfg)
		require.NotNil(cfg)
		require.NoError(err)

		// add client log output
		go k.LogTailer(username, cfg.Logging.File)

		// instantiate a session
		s, err := c.NewSession(linkKey)
		require.NoError(err)

		// look up a well known service
		desc, err := s.GetService("loop")
		require.NoError(err)

		// send a message
		t.Logf("desc.Provider: %s", desc.Provider)
		_, err = s.BlockingSendUnreliableMessage(desc.Name, desc.Provider, []byte("hello!"))
		require.NoError(err)
		t.Logf("Sent unreliable message to loop service")

		c.Shutdown()
		t.Logf("Shutdown requested")
		c.Wait()
	}()

	k.Wait()
	t.Logf("Terminated.")
}

// TestAutoRegisterRandomClient tests client registration
func TestAutoRegisterRandomClient(t *testing.T) {
	require := require.New(t)
	voting := false
	nVoting := 0
	nProvider := 2
	nMix := 6
	k := kimchi.NewKimchi(basePort+500, "", nil, voting, nVoting, nProvider, nMix)
	t.Logf("Running TestAutoRegisterRandomClient.")
	k.Run()

	go func() {
		defer k.Shutdown()
		<-time.After(90 * time.Second) // must wait for provider to fetch pki document
		cfg, err := k.GetClientNetconfig()
		require.NoError(err)

		_, linkKey := AutoRegisterRandomClient(cfg)
		require.NotNil(linkKey)

		// Verify that the client can connect
		c, err := New(cfg)
		require.NoError(err)

		// instantiate a session
		s, err := c.NewSession(linkKey)
		require.NoError(err)

		// look up a well known service
		desc, err := s.GetService("loop")
		require.NoError(err)
		t.Logf("Found %v kaetzchen on %v", desc.Name, desc.Provider)

		c.Shutdown()
		t.Logf("Shutdown requested")
		c.Wait()
	}()
	k.Wait()
}

/* XXX FIX ME

This test is currently broken and I have confirmed that in fact
the client works properly with decoy traffic using the optional docker test
entitled TestClientBlockingSendReceiveWithDecoyTraffic.

// TestDecoyClient tests client with Decoy traffic enabled
func TestDecoyClient(t *testing.T) {
	require := require.New(t)
	voting := false
	nVoting := 0
	nProvider := 2
	nMix := 6
	k := kimchi.NewKimchi(basePort+500, "", nil, voting, nVoting, nProvider, nMix)
	t.Logf("Running TestAutoRegisterRandomClient.")
	k.Run()

	go func() {
		defer k.Shutdown()
		<-time.After(90 * time.Second) // must wait for provider to fetch pki document
		cfg, err := k.GetClientNetconfig()
		require.NoError(err)
		cfg.Debug.DisableDecoyTraffic = false

		_, linkKey := AutoRegisterRandomClient(cfg)
		require.NotNil(linkKey)

		// Verify that the client can connect
		c, err := New(cfg)
		require.NoError(err)

		// instantiate a session
		s, err := c.NewSession(linkKey)
		require.NoError(err)

		// look up a well known service
		desc, err := s.GetService("loop")
		require.NoError(err)
		t.Logf("Found %v kaetzchen on %v", desc.Name, desc.Provider)

		wg := &sync.WaitGroup{}
		for i := 0; i < 3; i++ {
			wg.Add(1)
			go func() {
				t.Logf("SendUnreliableMessage()")
				_, err := s.BlockingSendUnreliableMessage(desc.Name, desc.Provider, []byte("hello!"))
				require.NoError(err)
				wg.Done()
			}()
		}
		wg.Wait()

		c.Shutdown()
		t.Logf("Shutdown requested")
		c.Wait()
	}()
	k.Wait()
}
*/
<|endoftext|>


<commit_before>// +build js

package gob

import (
	"bytes"
	"reflect"
	"testing"
)

// TODO: TestEndToEnd override can be removed once the bug with Marr field is fixed.
func TestEndToEnd(t *testing.T) {
	type T2 struct {
		T string
	}
	type T3 struct {
		X float64
		Z *int
	}
	type T1 struct {
		A, B, C  int
		M        map[string]*float64
		M2       map[int]T3
		Mstring  map[string]string
		Mintptr  map[int]*int
		Mcomp    map[complex128]complex128
		Marr     map[[2]string][2]*float64
		EmptyMap map[string]int // to check that we receive a non-nil map.
		N        *[3]float64
		Strs     *[2]string
		Int64s   *[]int64
		RI       complex64
		S        string
		Y        []byte
		T        *T2
	}
	pi := 3.14159
	e := 2.71828
	two := 2.0
	meaning := 42
	fingers := 5
	s1 := "string1"
	s2 := "string2"
	var comp1 complex128 = complex(1.0, 1.0)
	var comp2 complex128 = complex(1.0, 1.0)
	var arr1 [2]string
	arr1[0] = s1
	arr1[1] = s2
	var arr2 [2]string
	arr2[0] = s2
	arr2[1] = s1
	var floatArr1 [2]*float64
	floatArr1[0] = &pi
	floatArr1[1] = &e
	var floatArr2 [2]*float64
	floatArr2[0] = &e
	floatArr2[1] = &two
	t1 := &T1{
		A:       17,
		B:       18,
		C:       -5,
		M:       map[string]*float64{"pi": &pi, "e": &e},
		M2:      map[int]T3{4: T3{X: pi, Z: &meaning}, 10: T3{X: e, Z: &fingers}},
		Mstring: map[string]string{"pi": "3.14", "e": "2.71"},
		Mintptr: map[int]*int{meaning: &fingers, fingers: &meaning},
		Mcomp:   map[complex128]complex128{comp1: comp2, comp2: comp1},
		// TODO: Fix this problem:
		// 	TypeError: dst.$set is not a function
		// 	    at typedmemmove (/github.com/gopherjs/gopherjs/reflect.go:487:3)
		//Marr:     map[[2]string][2]*float64{arr1: floatArr1, arr2: floatArr2},
		EmptyMap: make(map[string]int),
		N:        &[3]float64{1.5, 2.5, 3.5},
		Strs:     &[2]string{s1, s2},
		Int64s:   &[]int64{77, 89, 123412342134},
		RI:       17 - 23i,
		S:        "Now is the time",
		Y:        []byte("hello, sailor"),
		T:        &T2{"this is T2"},
	}
	b := new(bytes.Buffer)
	err := NewEncoder(b).Encode(t1)
	if err != nil {
		t.Error("encode:", err)
	}
	var _t1 T1
	err = NewDecoder(b).Decode(&_t1)
	if err != nil {
		t.Fatal("decode:", err)
	}
	if !reflect.DeepEqual(t1, &_t1) {
		t.Errorf("encode expected %v got %v", *t1, _t1)
	}
	// Be absolutely sure the received map is non-nil.
	if t1.EmptyMap == nil {
		t.Errorf("nil map sent")
	}
	if _t1.EmptyMap == nil {
		t.Errorf("nil map received")
	}
}
<commit_msg>compiler/natives/src/encoding/gob: Skip TestTypeRace.<commit_after>// +build js

package gob

import (
	"bytes"
	"reflect"
	"testing"
)

// TODO: TestEndToEnd override can be removed once the bug with Marr field is fixed.
func TestEndToEnd(t *testing.T) {
	type T2 struct {
		T string
	}
	type T3 struct {
		X float64
		Z *int
	}
	type T1 struct {
		A, B, C  int
		M        map[string]*float64
		M2       map[int]T3
		Mstring  map[string]string
		Mintptr  map[int]*int
		Mcomp    map[complex128]complex128
		Marr     map[[2]string][2]*float64
		EmptyMap map[string]int // to check that we receive a non-nil map.
		N        *[3]float64
		Strs     *[2]string
		Int64s   *[]int64
		RI       complex64
		S        string
		Y        []byte
		T        *T2
	}
	pi := 3.14159
	e := 2.71828
	two := 2.0
	meaning := 42
	fingers := 5
	s1 := "string1"
	s2 := "string2"
	var comp1 complex128 = complex(1.0, 1.0)
	var comp2 complex128 = complex(1.0, 1.0)
	var arr1 [2]string
	arr1[0] = s1
	arr1[1] = s2
	var arr2 [2]string
	arr2[0] = s2
	arr2[1] = s1
	var floatArr1 [2]*float64
	floatArr1[0] = &pi
	floatArr1[1] = &e
	var floatArr2 [2]*float64
	floatArr2[0] = &e
	floatArr2[1] = &two
	t1 := &T1{
		A:       17,
		B:       18,
		C:       -5,
		M:       map[string]*float64{"pi": &pi, "e": &e},
		M2:      map[int]T3{4: T3{X: pi, Z: &meaning}, 10: T3{X: e, Z: &fingers}},
		Mstring: map[string]string{"pi": "3.14", "e": "2.71"},
		Mintptr: map[int]*int{meaning: &fingers, fingers: &meaning},
		Mcomp:   map[complex128]complex128{comp1: comp2, comp2: comp1},
		// TODO: Fix this problem:
		// 	TypeError: dst.$set is not a function
		// 	    at typedmemmove (/github.com/gopherjs/gopherjs/reflect.go:487:3)
		//Marr:     map[[2]string][2]*float64{arr1: floatArr1, arr2: floatArr2},
		EmptyMap: make(map[string]int),
		N:        &[3]float64{1.5, 2.5, 3.5},
		Strs:     &[2]string{s1, s2},
		Int64s:   &[]int64{77, 89, 123412342134},
		RI:       17 - 23i,
		S:        "Now is the time",
		Y:        []byte("hello, sailor"),
		T:        &T2{"this is T2"},
	}
	b := new(bytes.Buffer)
	err := NewEncoder(b).Encode(t1)
	if err != nil {
		t.Error("encode:", err)
	}
	var _t1 T1
	err = NewDecoder(b).Decode(&_t1)
	if err != nil {
		t.Fatal("decode:", err)
	}
	if !reflect.DeepEqual(t1, &_t1) {
		t.Errorf("encode expected %v got %v", *t1, _t1)
	}
	// Be absolutely sure the received map is non-nil.
	if t1.EmptyMap == nil {
		t.Errorf("nil map sent")
	}
	if _t1.EmptyMap == nil {
		t.Errorf("nil map received")
	}
}

func TestTypeRace(t *testing.T) {
	// encoding/gob currently uses nosync. This test uses sync.WaitGroup and
	// cannot succeed when nosync is used.
	t.Skip("using nosync")
}
<|endoftext|>


<commit_before>package cmd

import (
	"context"
	"fmt"
	"path/filepath"
	"strings"

	"github.com/jessevdk/go-flags"
	"github.com/mitchellh/cli"
	"github.com/mitchellh/go-homedir"
	"github.com/pkg/errors"

	"github.com/nerdalize/nerd/pkg/transfer"
	"github.com/nerdalize/nerd/svc"
)

//JobRun command
type JobRun struct {
	KubeOpts
	TransferOpts
	Name    string   `long:"name" short:"n" description:"assign a name to the job"`
	Env     []string `long:"env" short:"e" description:"environment variables to use"`
	Memory  string   `long:"memory" short:"m" description:"memory to use for this job. Units accepted: Ki, Mi, Gi, K, M, G" default:"3Gi"`
	VPCU    string   `long:"vcpu" description:"number of vcpus to use for this job" default:"2"`
	Inputs  []string `long:"input" description:"specify one or more inputs that will be downloaded for the job"`
	Outputs []string `long:"output" description:"specify one or more output folders that will be uploaded as datasets after the job is finished"`

	*command
}

//JobRunFactory creates the command
func JobRunFactory(ui cli.Ui) cli.CommandFactory {
	cmd := &JobRun{}
	cmd.command = createCommand(ui, cmd.Execute, cmd.Description, cmd.Usage, cmd, flags.PassAfterNonOption)
	return func() (cli.Command, error) {
		return cmd, nil
	}
}

func ParseInputSpecification(input string) (parts []string, err error) {
	parts = strings.Split(input, ":")

	//Two accepted cases:
	//- Two unix paths with a colon separating them, e.g. ~/data:/input
	//- Windows path with a disk specification, e.g. C:/data:/input
	if len(parts) != 2 && len(parts) != 3 {
		return nil, fmt.Errorf("invalid input specified, expected '<DIR|DATASET_ID>:<JOB_DIR>' format, got: %s", input)
	}

	//Handle Windows paths where DIR may contain colons
	//e.g. C:/foo/bar:/input will be parsed into []string{"C", "/foo/bar", "/input"}
	//and should be turned into []string{"C:/foo/bar", "/input"}
	//We assume that POSIX paths will never have colons
	parts = []string{strings.Join(parts[:len(parts)-1], ":"), parts[len(parts)-1]}

	//Expand tilde for homedir
	parts[0], err = homedir.Expand(parts[0])
	if err != nil {
		return nil, errors.Wrap(err, "failed to expand home directory in dataset local path")
	}

	//Normalize all slashes to native platform slashes (e.g. / to \ on Windows)
	parts[0] = filepath.FromSlash(parts[0])

	// Ensure that all parts are non-empty
	if len(strings.TrimSpace(parts[0])) == 0 {
		return nil, errors.New("input source is empty")
	} else if len(strings.TrimSpace(parts[1])) == 0 {
		return nil, errors.New("input mount path is empty")
	}

	return parts, nil
}

//Execute runs the command
func (cmd *JobRun) Execute(args []string) (err error) {
	if len(args) < 1 {
		return errShowUsage(MessageNotEnoughArguments)
	}

	kopts := cmd.KubeOpts
	deps, err := NewDeps(cmd.Logger(), kopts)
	if err != nil {
		return renderConfigError(err, "failed to configure")
	}

	//setup a context with a timeout
	ctx := context.Background()
	ctx, cancel := context.WithTimeout(ctx, cmd.Timeout)
	defer cancel()

	//setup job arguments
	jargs := []string{}
	if len(args) > 1 {
		jargs = args[1:]
	}

	jenv := map[string]string{}
	for _, l := range cmd.Env {
		split := strings.SplitN(l, "=", 2)
		if len(split) < 2 {
			return fmt.Errorf("invalid environment variable format, expected 'FOO=bar' format, got: %v", l)
		}
		jenv[split[0]] = split[1]
	}

	//setup the transfer manager
	kube := svc.NewKube(deps)
	mgr, sto, sta, err := cmd.TransferOpts.TransferManager(kube)
	if err != nil {
		return errors.Wrap(err, "failed to setup transfer manager")
	}

	//keep handles to update the job froms and to
	inputs := []transfer.Handle{}
	outputs := []transfer.Handle{}

	//start with input volumes
	vols := map[string]*svc.JobVolume{}
	for _, input := range cmd.Inputs {
		parts, err := ParseInputSpecification(input)
		if err != nil {
			return errors.Wrap(err, "failed to parse parse input specification")
		}

		//if the input spec has a path-like string, try to upload it for the user
		var h transfer.Handle
		if strings.Contains(parts[0], string(filepath.Separator)) {
			//the user has provided a path as its input, clean it and make it absolute
			parts[0], err = filepath.Abs(parts[0])
			if err != nil {
				return errors.Wrap(err, "failed to turn local dataset path into absolute path")
			}

			h, err = mgr.Create(ctx, "", *sto, *sta)
			if err != nil {
				return errors.Wrap(err, "failed to create dataset")
			}

			//@TODO extend ctx deadline

			err = h.Push(ctx, parts[0], transfer.NewDiscardReporter())
			if err != nil {
				return errors.Wrap(err, "failed to update dataset")
			}

			cmd.out.Infof("Uploaded input dataset: '%s'", h.Name())
		} else { //open an existing dataset
			h, err = mgr.Open(ctx, parts[0])
			if err != nil {
				return errors.Wrap(err, "failed to open dataset")
			}

		}

		//add handler for job mapping
		inputs = append(inputs, h)
		defer h.Close()

		vols[parts[1]] = &svc.JobVolume{
			MountPath:    parts[1],
			InputDataset: h.Name(),
		}

		err = deps.val.Struct(vols[parts[1]])
		if err != nil {
			return errors.Wrap(err, "incorrect input")
		}
	}

	for _, output := range cmd.Outputs {
		parts := strings.Split(output, ":")
		if len(parts) < 1 || len(parts) > 2 {
			return fmt.Errorf("invalid output specified, expected '<JOB_DIR>:[DATASET_NAME]' format, got: %s", output)
		}

		vol, ok := vols[parts[0]]
		if !ok {
			vol = &svc.JobVolume{MountPath: parts[0]}
			vols[parts[0]] = vol
		}

		err = deps.val.Struct(vol)
		if err != nil {
			return errors.Wrap(err, "incorrect output")
		}

		//if the second part is provided we want to upload the output to a specific  dataset
		var h transfer.Handle
		if len(parts) == 2 { //open an existing dataset
			h, err = mgr.Open(ctx, parts[1])
			if err != nil {
				return errors.Wrap(err, "failed to open dataset")
			}

		} else { //create an empty dataset for the output
			h, err = mgr.Create(ctx, "", *sto, *sta)
			if err != nil {
				return errors.Wrap(err, "failed to create dataset")
			}

			cmd.out.Infof("Setup empty output dataset: '%s'", h.Name())
		}

		//register for job mapping and cleanup
		outputs = append(outputs, h)
		defer h.Close()

		vol.OutputDataset = h.Name()
	}

	//continue with actuall creating the job
	in := &svc.RunJobInput{
		Image:  args[0],
		Name:   cmd.Name,
		Env:    jenv,
		Args:   jargs,
		Memory: cmd.Memory,
		VCPU:   cmd.VPCU,
	}

	for _, vol := range vols {
		in.Volumes = append(in.Volumes, *vol)
	}

	out, err := kube.RunJob(ctx, in)
	if err != nil {
		return renderServiceError(err, "failed to run job")
	}

	//add job to each dataset's InputFor
	for _, h := range inputs {
		_, err := kube.UpdateDataset(ctx, &svc.UpdateDatasetInput{Name: h.Name(), InputFor: out.Name})
		if err != nil {
			return err
		}
	}

	//add job to each dataset's OutputOf
	for _, h := range outputs {
		_, err := kube.UpdateDataset(ctx, &svc.UpdateDatasetInput{Name: h.Name(), OutputFrom: out.Name})
		if err != nil {
			return err
		}
	}

	cmd.out.Infof("Submitted job: '%s'", out.Name)
	cmd.out.Infof("To see whats happening, use: 'nerd job list'")
	return nil
}

// Description returns long-form help text
func (cmd *JobRun) Description() string { return cmd.Synopsis() }

// Synopsis returns a one-line
func (cmd *JobRun) Synopsis() string { return "Runs a job on your compute cluster" }

// Usage shows usage
func (cmd *JobRun) Usage() string { return "nerd job run [OPTIONS] IMAGE [COMMAND] [ARG...]" }
<commit_msg>set limits for vcpu and memory requests<commit_after>package cmd

import (
	"context"
	"fmt"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/jessevdk/go-flags"
	"github.com/mitchellh/cli"
	"github.com/mitchellh/go-homedir"
	"github.com/pkg/errors"

	"github.com/nerdalize/nerd/pkg/transfer"
	"github.com/nerdalize/nerd/svc"
)

//JobRun command
type JobRun struct {
	KubeOpts
	TransferOpts
	Name    string   `long:"name" short:"n" description:"assign a name to the job"`
	Env     []string `long:"env" short:"e" description:"environment variables to use"`
	Memory  string   `long:"memory" short:"m" description:"memory to use for this job, expressed in gigabytes" default:"3"`
	VCPU    string   `long:"vcpu" description:"number of vcpus to use for this job" default:"2"`
	Inputs  []string `long:"input" description:"specify one or more inputs that will be downloaded for the job"`
	Outputs []string `long:"output" description:"specify one or more output folders that will be uploaded as datasets after the job is finished"`

	*command
}

//JobRunFactory creates the command
func JobRunFactory(ui cli.Ui) cli.CommandFactory {
	cmd := &JobRun{}
	cmd.command = createCommand(ui, cmd.Execute, cmd.Description, cmd.Usage, cmd, flags.PassAfterNonOption)
	return func() (cli.Command, error) {
		return cmd, nil
	}
}

func ParseInputSpecification(input string) (parts []string, err error) {
	parts = strings.Split(input, ":")

	//Two accepted cases:
	//- Two unix paths with a colon separating them, e.g. ~/data:/input
	//- Windows path with a disk specification, e.g. C:/data:/input
	if len(parts) != 2 && len(parts) != 3 {
		return nil, fmt.Errorf("invalid input specified, expected '<DIR|DATASET_ID>:<JOB_DIR>' format, got: %s", input)
	}

	//Handle Windows paths where DIR may contain colons
	//e.g. C:/foo/bar:/input will be parsed into []string{"C", "/foo/bar", "/input"}
	//and should be turned into []string{"C:/foo/bar", "/input"}
	//We assume that POSIX paths will never have colons
	parts = []string{strings.Join(parts[:len(parts)-1], ":"), parts[len(parts)-1]}

	//Expand tilde for homedir
	parts[0], err = homedir.Expand(parts[0])
	if err != nil {
		return nil, errors.Wrap(err, "failed to expand home directory in dataset local path")
	}

	//Normalize all slashes to native platform slashes (e.g. / to \ on Windows)
	parts[0] = filepath.FromSlash(parts[0])

	// Ensure that all parts are non-empty
	if len(strings.TrimSpace(parts[0])) == 0 {
		return nil, errors.New("input source is empty")
	} else if len(strings.TrimSpace(parts[1])) == 0 {
		return nil, errors.New("input mount path is empty")
	}

	return parts, nil
}

//Execute runs the command
func (cmd *JobRun) Execute(args []string) (err error) {
	if len(args) < 1 {
		return errShowUsage(MessageNotEnoughArguments)
	}

	kopts := cmd.KubeOpts
	deps, err := NewDeps(cmd.Logger(), kopts)
	if err != nil {
		return renderConfigError(err, "failed to configure")
	}

	//setup a context with a timeout
	ctx := context.Background()
	ctx, cancel := context.WithTimeout(ctx, cmd.Timeout)
	defer cancel()

	err = checkResources(cmd.Memory, cmd.VCPU)
	if err != nil {
		return err
	}

	//setup job arguments
	jargs := []string{}
	if len(args) > 1 {
		jargs = args[1:]
	}

	jenv := map[string]string{}
	for _, l := range cmd.Env {
		split := strings.SplitN(l, "=", 2)
		if len(split) < 2 {
			return fmt.Errorf("invalid environment variable format, expected 'FOO=bar' format, got: %v", l)
		}
		jenv[split[0]] = split[1]
	}

	//setup the transfer manager
	kube := svc.NewKube(deps)
	mgr, sto, sta, err := cmd.TransferOpts.TransferManager(kube)
	if err != nil {
		return errors.Wrap(err, "failed to setup transfer manager")
	}

	//keep handles to update the job froms and to
	inputs := []transfer.Handle{}
	outputs := []transfer.Handle{}

	//start with input volumes
	vols := map[string]*svc.JobVolume{}
	for _, input := range cmd.Inputs {
		parts, err := ParseInputSpecification(input)
		if err != nil {
			return errors.Wrap(err, "failed to parse parse input specification")
		}

		//if the input spec has a path-like string, try to upload it for the user
		var h transfer.Handle
		if strings.Contains(parts[0], string(filepath.Separator)) {
			//the user has provided a path as its input, clean it and make it absolute
			parts[0], err = filepath.Abs(parts[0])
			if err != nil {
				return errors.Wrap(err, "failed to turn local dataset path into absolute path")
			}

			h, err = mgr.Create(ctx, "", *sto, *sta)
			if err != nil {
				return errors.Wrap(err, "failed to create dataset")
			}

			//@TODO extend ctx deadline

			err = h.Push(ctx, parts[0], transfer.NewDiscardReporter())
			if err != nil {
				return errors.Wrap(err, "failed to update dataset")
			}

			cmd.out.Infof("Uploaded input dataset: '%s'", h.Name())
		} else { //open an existing dataset
			h, err = mgr.Open(ctx, parts[0])
			if err != nil {
				return errors.Wrap(err, "failed to open dataset")
			}

		}

		//add handler for job mapping
		inputs = append(inputs, h)
		defer h.Close()

		vols[parts[1]] = &svc.JobVolume{
			MountPath:    parts[1],
			InputDataset: h.Name(),
		}

		err = deps.val.Struct(vols[parts[1]])
		if err != nil {
			return errors.Wrap(err, "incorrect input")
		}
	}

	for _, output := range cmd.Outputs {
		parts := strings.Split(output, ":")
		if len(parts) < 1 || len(parts) > 2 {
			return fmt.Errorf("invalid output specified, expected '<JOB_DIR>:[DATASET_NAME]' format, got: %s", output)
		}

		vol, ok := vols[parts[0]]
		if !ok {
			vol = &svc.JobVolume{MountPath: parts[0]}
			vols[parts[0]] = vol
		}

		err = deps.val.Struct(vol)
		if err != nil {
			return errors.Wrap(err, "incorrect output")
		}

		//if the second part is provided we want to upload the output to a specific  dataset
		var h transfer.Handle
		if len(parts) == 2 { //open an existing dataset
			h, err = mgr.Open(ctx, parts[1])
			if err != nil {
				return errors.Wrap(err, "failed to open dataset")
			}

		} else { //create an empty dataset for the output
			h, err = mgr.Create(ctx, "", *sto, *sta)
			if err != nil {
				return errors.Wrap(err, "failed to create dataset")
			}

			cmd.out.Infof("Setup empty output dataset: '%s'", h.Name())
		}

		//register for job mapping and cleanup
		outputs = append(outputs, h)
		defer h.Close()

		vol.OutputDataset = h.Name()
	}

	//continue with actuall creating the job
	in := &svc.RunJobInput{
		Image:  args[0],
		Name:   cmd.Name,
		Env:    jenv,
		Args:   jargs,
		Memory: fmt.Sprintf("%sGi", cmd.Memory),
		VCPU:   cmd.VCPU,
	}

	for _, vol := range vols {
		in.Volumes = append(in.Volumes, *vol)
	}

	out, err := kube.RunJob(ctx, in)
	if err != nil {
		return renderServiceError(err, "failed to run job")
	}

	//add job to each dataset's InputFor
	for _, h := range inputs {
		_, err := kube.UpdateDataset(ctx, &svc.UpdateDatasetInput{Name: h.Name(), InputFor: out.Name})
		if err != nil {
			return err
		}
	}

	//add job to each dataset's OutputOf
	for _, h := range outputs {
		_, err := kube.UpdateDataset(ctx, &svc.UpdateDatasetInput{Name: h.Name(), OutputFrom: out.Name})
		if err != nil {
			return err
		}
	}

	cmd.out.Infof("Submitted job: '%s'", out.Name)
	cmd.out.Infof("To see whats happening, use: 'nerd job list'")
	return nil
}

func checkResources(memory, vcpu string) error {
	if memory != "" {
		m, err := strconv.ParseFloat(memory, 64)
		if err != nil {
			return fmt.Errorf("invalid memory option format, %v", err)
		}
		if m > 60 {
			return fmt.Errorf("invalid value for memory parameter. Memory request must be lower than 60Gbs")
		}
	}
	if vcpu != "" {
		v, err := strconv.ParseFloat(vcpu, 64)
		if err != nil {
			return fmt.Errorf("invalid vcpu option format, %v", err)
		}
		if v > 40 {
			return fmt.Errorf("invalid value for vcpu parameter. VCPU request must be lower than 40")
		}
	}
	return nil
}

// Description returns long-form help text
func (cmd *JobRun) Description() string { return cmd.Synopsis() }

// Synopsis returns a one-line
func (cmd *JobRun) Synopsis() string { return "Runs a job on your compute cluster" }

// Usage shows usage
func (cmd *JobRun) Usage() string { return "nerd job run [OPTIONS] IMAGE [COMMAND] [ARG...]" }
<|endoftext|>


<commit_before>package cmd

import (
	"context"
	"github.com/asim/go-micro/v3/auth"
	"github.com/asim/go-micro/v3/broker"
	"github.com/asim/go-micro/v3/cache"
	"github.com/asim/go-micro/v3/client"
	"github.com/asim/go-micro/v3/config"
	"github.com/asim/go-micro/v3/debug/profile"
	"github.com/asim/go-micro/v3/debug/trace"
	"github.com/asim/go-micro/v3/registry"
	"github.com/asim/go-micro/v3/runtime"
	"github.com/asim/go-micro/v3/selector"
	"github.com/asim/go-micro/v3/server"
	"github.com/asim/go-micro/v3/store"
	"github.com/asim/go-micro/v3/transport"
)

type Options struct {
	// For the Command Line itself
	Name        string
	Description string
	Version     string

	// We need pointers to things so we can swap them out if needed.
	Broker    *broker.Broker
	Registry  *registry.Registry
	Selector  *selector.Selector
	Transport *transport.Transport
	Cache     *cache.Cache
	Config    *config.Config
	Client    *client.Client
	Server    *server.Server
	Runtime   *runtime.Runtime
	Store     *store.Store
	Tracer    *trace.Tracer
	Auth      *auth.Auth
	Profile   *profile.Profile

	Brokers    map[string]func(...broker.Option) broker.Broker
	Caches     map[string]func(...cache.Option) cache.Cache
	Configs    map[string]func(...config.Option) (config.Config, error)
	Clients    map[string]func(...client.Option) client.Client
	Registries map[string]func(...registry.Option) registry.Registry
	Selectors  map[string]func(...selector.Option) selector.Selector
	Servers    map[string]func(...server.Option) server.Server
	Transports map[string]func(...transport.Option) transport.Transport
	Runtimes   map[string]func(...runtime.Option) runtime.Runtime
	Stores     map[string]func(...store.Option) store.Store
	Tracers    map[string]func(...trace.Option) trace.Tracer
	Auths      map[string]func(...auth.Option) auth.Auth
	Profiles   map[string]func(...profile.Option) profile.Profile

	// Other options for implementations of the interface
	// can be stored in a context
	Context context.Context
}

// Command line Name
func Name(n string) Option {
	return func(o *Options) {
		o.Name = n
	}
}

// Command line Description
func Description(d string) Option {
	return func(o *Options) {
		o.Description = d
	}
}

// Command line Version
func Version(v string) Option {
	return func(o *Options) {
		o.Version = v
	}
}

func Broker(b *broker.Broker) Option {
	return func(o *Options) {
		o.Broker = b
	}
}

func Cache(c *cache.Cache) Option {
	return func(o *Options) {
		o.Cache = c
	}
}

func Config(c *config.Config) Option {
	return func(o *Options) {
		o.Config = c
	}
}

func Selector(s *selector.Selector) Option {
	return func(o *Options) {
		o.Selector = s
	}
}

func Registry(r *registry.Registry) Option {
	return func(o *Options) {
		o.Registry = r
	}
}

func Runtime(r *runtime.Runtime) Option {
	return func(o *Options) {
		o.Runtime = r
	}
}

func Transport(t *transport.Transport) Option {
	return func(o *Options) {
		o.Transport = t
	}
}

func Client(c *client.Client) Option {
	return func(o *Options) {
		o.Client = c
	}
}

func Server(s *server.Server) Option {
	return func(o *Options) {
		o.Server = s
	}
}

func Store(s *store.Store) Option {
	return func(o *Options) {
		o.Store = s
	}
}

func Tracer(t *trace.Tracer) Option {
	return func(o *Options) {
		o.Tracer = t
	}
}

func Auth(a *auth.Auth) Option {
	return func(o *Options) {
		o.Auth = a
	}
}

func Profile(p *profile.Profile) Option {
	return func(o *Options) {
		o.Profile = p
	}
}

// New broker func
func NewBroker(name string, b func(...broker.Option) broker.Broker) Option {
	return func(o *Options) {
		o.Brokers[name] = b
	}
}

// New cache func
func NewCache(name string, c func(...cache.Option) cache.Cache) Option {
	return func(o *Options) {
		o.Caches[name] = c
	}
}

// New client func
func NewClient(name string, b func(...client.Option) client.Client) Option {
	return func(o *Options) {
		o.Clients[name] = b
	}
}

// New registry func
func NewRegistry(name string, r func(...registry.Option) registry.Registry) Option {
	return func(o *Options) {
		o.Registries[name] = r
	}
}

// New selector func
func NewSelector(name string, s func(...selector.Option) selector.Selector) Option {
	return func(o *Options) {
		o.Selectors[name] = s
	}
}

// New server func
func NewServer(name string, s func(...server.Option) server.Server) Option {
	return func(o *Options) {
		o.Servers[name] = s
	}
}

// New transport func
func NewTransport(name string, t func(...transport.Option) transport.Transport) Option {
	return func(o *Options) {
		o.Transports[name] = t
	}
}

// New runtime func
func NewRuntime(name string, r func(...runtime.Option) runtime.Runtime) Option {
	return func(o *Options) {
		o.Runtimes[name] = r
	}
}

// New tracer func
func NewTracer(name string, t func(...trace.Option) trace.Tracer) Option {
	return func(o *Options) {
		o.Tracers[name] = t
	}
}

// New auth func
func NewAuth(name string, t func(...auth.Option) auth.Auth) Option {
	return func(o *Options) {
		o.Auths[name] = t
	}
}

// New config func
func NewConfig(name string, t func(...config.Option) (config.Config, error)) Option  {
	return func(o *Options) {
		o.Configs[name] = t
	}
}

// New profile func
func NewProfile(name string, t func(...profile.Option) profile.Profile) Option {
	return func(o *Options) {
		o.Profiles[name] = t
	}
}<commit_msg>Update options.go<commit_after>package cmd

import (
	"context"

	"github.com/asim/go-micro/v3/auth"
	"github.com/asim/go-micro/v3/broker"
	"github.com/asim/go-micro/v3/cache"
	"github.com/asim/go-micro/v3/client"
	"github.com/asim/go-micro/v3/config"
	"github.com/asim/go-micro/v3/debug/profile"
	"github.com/asim/go-micro/v3/debug/trace"
	"github.com/asim/go-micro/v3/registry"
	"github.com/asim/go-micro/v3/runtime"
	"github.com/asim/go-micro/v3/selector"
	"github.com/asim/go-micro/v3/server"
	"github.com/asim/go-micro/v3/store"
	"github.com/asim/go-micro/v3/transport"
)

type Options struct {
	// For the Command Line itself
	Name        string
	Description string
	Version     string

	// We need pointers to things so we can swap them out if needed.
	Broker    *broker.Broker
	Registry  *registry.Registry
	Selector  *selector.Selector
	Transport *transport.Transport
	Cache     *cache.Cache
	Config    *config.Config
	Client    *client.Client
	Server    *server.Server
	Runtime   *runtime.Runtime
	Store     *store.Store
	Tracer    *trace.Tracer
	Auth      *auth.Auth
	Profile   *profile.Profile

	Brokers    map[string]func(...broker.Option) broker.Broker
	Caches     map[string]func(...cache.Option) cache.Cache
	Configs    map[string]func(...config.Option) (config.Config, error)
	Clients    map[string]func(...client.Option) client.Client
	Registries map[string]func(...registry.Option) registry.Registry
	Selectors  map[string]func(...selector.Option) selector.Selector
	Servers    map[string]func(...server.Option) server.Server
	Transports map[string]func(...transport.Option) transport.Transport
	Runtimes   map[string]func(...runtime.Option) runtime.Runtime
	Stores     map[string]func(...store.Option) store.Store
	Tracers    map[string]func(...trace.Option) trace.Tracer
	Auths      map[string]func(...auth.Option) auth.Auth
	Profiles   map[string]func(...profile.Option) profile.Profile

	// Other options for implementations of the interface
	// can be stored in a context
	Context context.Context
}

// Command line Name
func Name(n string) Option {
	return func(o *Options) {
		o.Name = n
	}
}

// Command line Description
func Description(d string) Option {
	return func(o *Options) {
		o.Description = d
	}
}

// Command line Version
func Version(v string) Option {
	return func(o *Options) {
		o.Version = v
	}
}

func Broker(b *broker.Broker) Option {
	return func(o *Options) {
		o.Broker = b
	}
}

func Cache(c *cache.Cache) Option {
	return func(o *Options) {
		o.Cache = c
	}
}

func Config(c *config.Config) Option {
	return func(o *Options) {
		o.Config = c
	}
}

func Selector(s *selector.Selector) Option {
	return func(o *Options) {
		o.Selector = s
	}
}

func Registry(r *registry.Registry) Option {
	return func(o *Options) {
		o.Registry = r
	}
}

func Runtime(r *runtime.Runtime) Option {
	return func(o *Options) {
		o.Runtime = r
	}
}

func Transport(t *transport.Transport) Option {
	return func(o *Options) {
		o.Transport = t
	}
}

func Client(c *client.Client) Option {
	return func(o *Options) {
		o.Client = c
	}
}

func Server(s *server.Server) Option {
	return func(o *Options) {
		o.Server = s
	}
}

func Store(s *store.Store) Option {
	return func(o *Options) {
		o.Store = s
	}
}

func Tracer(t *trace.Tracer) Option {
	return func(o *Options) {
		o.Tracer = t
	}
}

func Auth(a *auth.Auth) Option {
	return func(o *Options) {
		o.Auth = a
	}
}

func Profile(p *profile.Profile) Option {
	return func(o *Options) {
		o.Profile = p
	}
}

// New broker func
func NewBroker(name string, b func(...broker.Option) broker.Broker) Option {
	return func(o *Options) {
		o.Brokers[name] = b
	}
}

// New cache func
func NewCache(name string, c func(...cache.Option) cache.Cache) Option {
	return func(o *Options) {
		o.Caches[name] = c
	}
}

// New client func
func NewClient(name string, b func(...client.Option) client.Client) Option {
	return func(o *Options) {
		o.Clients[name] = b
	}
}

// New registry func
func NewRegistry(name string, r func(...registry.Option) registry.Registry) Option {
	return func(o *Options) {
		o.Registries[name] = r
	}
}

// New selector func
func NewSelector(name string, s func(...selector.Option) selector.Selector) Option {
	return func(o *Options) {
		o.Selectors[name] = s
	}
}

// New server func
func NewServer(name string, s func(...server.Option) server.Server) Option {
	return func(o *Options) {
		o.Servers[name] = s
	}
}

// New transport func
func NewTransport(name string, t func(...transport.Option) transport.Transport) Option {
	return func(o *Options) {
		o.Transports[name] = t
	}
}

// New runtime func
func NewRuntime(name string, r func(...runtime.Option) runtime.Runtime) Option {
	return func(o *Options) {
		o.Runtimes[name] = r
	}
}

// New tracer func
func NewTracer(name string, t func(...trace.Option) trace.Tracer) Option {
	return func(o *Options) {
		o.Tracers[name] = t
	}
}

// New auth func
func NewAuth(name string, t func(...auth.Option) auth.Auth) Option {
	return func(o *Options) {
		o.Auths[name] = t
	}
}

// New config func
func NewConfig(name string, t func(...config.Option) (config.Config, error)) Option  {
	return func(o *Options) {
		o.Configs[name] = t
	}
}

// New profile func
func NewProfile(name string, t func(...profile.Option) profile.Profile) Option {
	return func(o *Options) {
		o.Profiles[name] = t
	}
}
<|endoftext|>


<commit_before>package cmd

import (
	"strconv"
	"strings"
	"time"

	"github.com/mobingi/mobingi-cli/client/timeout"
	"github.com/mobingi/mobingi-cli/pkg/cli"
	"github.com/mobingi/mobingi-cli/pkg/cli/confmap"
	"github.com/mobingilabs/mobingi-sdk-go/client"
	"github.com/mobingilabs/mobingi-sdk-go/mobingi/session"
	"github.com/mobingilabs/mobingi-sdk-go/pkg/nativestore"
	"github.com/pkg/errors"
	"github.com/spf13/viper"
)

func getApiVersionInt() int {
	v := 3
	vparam := viper.GetString(confmap.ConfigKey("apiver"))
	in, err := strconv.Atoi(strings.TrimLeft(vparam, "v"))
	if err != nil {
		return -1
	}

	v = in
	return v
}

func clisession() (*session.Session, error) {
	v := getApiVersionInt()
	if v < 0 {
		return nil, errors.New("cannot get api version")
	}

	// check if we have credentials in nativestore
	user, secret, err := nativestore.Get(cli.CliUrl)
	if err == nil {
		if user != "" && secret != "" {
			return session.New(&session.Config{
				ClientId:        user,
				ClientSecret:    secret,
				ApiVersion:      v,
				BaseApiUrl:      viper.GetString(confmap.ConfigKey("url")),
				BaseRegistryUrl: viper.GetString(confmap.ConfigKey("rurl")),
				HttpClientConfig: &client.Config{
					Timeout: time.Second * time.Duration(timeout.Timeout),
					Verbose: cli.Verbose,
				},
			})
		}
	}

	return session.New(&session.Config{
		ApiVersion:      v,
		AccessToken:     viper.GetString(confmap.ConfigKey("token")),
		BaseApiUrl:      viper.GetString(confmap.ConfigKey("url")),
		BaseRegistryUrl: viper.GetString(confmap.ConfigKey("rurl")),
		HttpClientConfig: &client.Config{
			Timeout: time.Second * time.Duration(timeout.Timeout),
			Verbose: cli.Verbose,
		},
	})
}
<commit_msg>Add verbose in session.<commit_after>package cmd

import (
	"strconv"
	"strings"
	"time"

	"github.com/mobingi/mobingi-cli/client/timeout"
	"github.com/mobingi/mobingi-cli/pkg/cli"
	"github.com/mobingi/mobingi-cli/pkg/cli/confmap"
	"github.com/mobingilabs/mobingi-sdk-go/client"
	"github.com/mobingilabs/mobingi-sdk-go/mobingi/session"
	d "github.com/mobingilabs/mobingi-sdk-go/pkg/debug"
	"github.com/mobingilabs/mobingi-sdk-go/pkg/nativestore"
	"github.com/pkg/errors"
	"github.com/spf13/viper"
)

func getApiVersionInt() int {
	v := 3
	vparam := viper.GetString(confmap.ConfigKey("apiver"))
	in, err := strconv.Atoi(strings.TrimLeft(vparam, "v"))
	if err != nil {
		return -1
	}

	v = in
	return v
}

func clisession() (*session.Session, error) {
	v := getApiVersionInt()
	if v < 0 {
		return nil, errors.New("cannot get api version")
	}

	// check if we have credentials in nativestore
	user, secret, err := nativestore.Get(cli.CliUrl)
	if err == nil {
		if user != "" && secret != "" {
			if cli.Verbose {
				d.Info("use credentials from native store")
			}

			return session.New(&session.Config{
				ClientId:        user,
				ClientSecret:    secret,
				ApiVersion:      v,
				BaseApiUrl:      viper.GetString(confmap.ConfigKey("url")),
				BaseRegistryUrl: viper.GetString(confmap.ConfigKey("rurl")),
				HttpClientConfig: &client.Config{
					Timeout: time.Second * time.Duration(timeout.Timeout),
					Verbose: cli.Verbose,
				},
			})
		}
	}

	if cli.Verbose {
		d.Info("cannot access native store, use config file token")
	}

	return session.New(&session.Config{
		ApiVersion:      v,
		AccessToken:     viper.GetString(confmap.ConfigKey("token")),
		BaseApiUrl:      viper.GetString(confmap.ConfigKey("url")),
		BaseRegistryUrl: viper.GetString(confmap.ConfigKey("rurl")),
		HttpClientConfig: &client.Config{
			Timeout: time.Second * time.Duration(timeout.Timeout),
			Verbose: cli.Verbose,
		},
	})
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"runtime"
)

var version = "0.5.1-dev"

type CmdVersion struct{}

func init() {
	_, err := parser.AddCommand("version",
		"display version",
		"The version command displays detailed information about the version",
		&CmdVersion{})
	if err != nil {
		panic(err)
	}
}

func (cmd CmdVersion) Execute(args []string) error {
	fmt.Printf("grobi %s\ncompiled with %v on %v\n",
		version, runtime.Version(), runtime.GOOS)

	return nil
}
<commit_msg>Release 0.5.2<commit_after>package main

import (
	"fmt"
	"runtime"
)

var version = "0.5.2"

type CmdVersion struct{}

func init() {
	_, err := parser.AddCommand("version",
		"display version",
		"The version command displays detailed information about the version",
		&CmdVersion{})
	if err != nil {
		panic(err)
	}
}

func (cmd CmdVersion) Execute(args []string) error {
	fmt.Printf("grobi %s\ncompiled with %v on %v\n",
		version, runtime.Version(), runtime.GOOS)

	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Kubernetes Authors.

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

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

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

package client

import (
	"bytes"
	"context"
	"errors"
	"testing"
	"time"

	"google.golang.org/grpc"
	"k8s.io/klog/v2"
	"sigs.k8s.io/apiserver-network-proxy/konnectivity-client/proto/client"
)

func TestDial(t *testing.T) {
	ctx := context.Background()
	s, ps := pipe()
	ts := testServer(ps, 100)

	defer ps.Close()
	defer s.Close()

	tunnel := &grpcTunnel{
		stream:      s,
		pendingDial: make(map[int64]pendingDial),
		conns:       make(map[int64]*conn),
	}

	go tunnel.serve(&fakeConn{})
	go ts.serve()

	_, err := tunnel.DialContext(ctx, "tcp", "127.0.0.1:80")
	if err != nil {
		t.Fatalf("expect nil; got %v", err)
	}

	if ts.packets[0].Type != client.PacketType_DIAL_REQ {
		t.Fatalf("expect packet.type %v; got %v", client.PacketType_DIAL_REQ, ts.packets[0].Type)
	}

	if ts.packets[0].GetDialRequest().Address != "127.0.0.1:80" {
		t.Errorf("expect packet.address %v; got %v", "127.0.0.1:80", ts.packets[0].GetDialRequest().Address)
	}
}

// TestDialRace exercises the scenario where serve() observes and handles DIAL_RSP
// before DialContext() does any work after sending the DIAL_REQ.
func TestDialRace(t *testing.T) {
	ctx := context.Background()
	s, ps := pipe()
	ts := testServer(ps, 100)

	defer ps.Close()
	defer s.Close()

	tunnel := &grpcTunnel{
		// artificially delay after calling Send, ensure handoff of result from serve to DialContext still works
		stream:      fakeSlowSend{s},
		pendingDial: make(map[int64]pendingDial),
		conns:       make(map[int64]*conn),
	}

	go tunnel.serve(&fakeConn{})
	go ts.serve()

	_, err := tunnel.DialContext(ctx, "tcp", "127.0.0.1:80")
	if err != nil {
		t.Fatalf("expect nil; got %v", err)
	}

	if ts.packets[0].Type != client.PacketType_DIAL_REQ {
		t.Fatalf("expect packet.type %v; got %v", client.PacketType_DIAL_REQ, ts.packets[0].Type)
	}

	if ts.packets[0].GetDialRequest().Address != "127.0.0.1:80" {
		t.Errorf("expect packet.address %v; got %v", "127.0.0.1:80", ts.packets[0].GetDialRequest().Address)
	}
}

// fakeSlowSend wraps ProxyService_ProxyClient and adds an artificial 1 second delay after calling Send
type fakeSlowSend struct {
	client.ProxyService_ProxyClient
}

func (s fakeSlowSend) Send(p *client.Packet) error {
	// send the request so it can start being processed immediately
	err := s.ProxyService_ProxyClient.Send(p)
	// delay returning to simulate slowness on the client side,
	// to exercise serve() observing/handling the DIAL_RSP before
	// the client does any post-Send() work
	time.Sleep(time.Second)
	return err
}

func TestData(t *testing.T) {
	ctx := context.Background()
	s, ps := pipe()
	ts := testServer(ps, 100)

	defer ps.Close()
	defer s.Close()

	tunnel := &grpcTunnel{
		stream:      s,
		pendingDial: make(map[int64]pendingDial),
		conns:       make(map[int64]*conn),
	}

	go tunnel.serve(&fakeConn{})
	go ts.serve()

	conn, err := tunnel.DialContext(ctx, "tcp", "127.0.0.1:80")
	if err != nil {
		t.Fatalf("expect nil; got %v", err)
	}

	datas := [][]byte{
		[]byte("hello"),
		[]byte(", "),
		[]byte("world."),
	}

	// send data using conn.Write
	for _, data := range datas {
		n, err := conn.Write(data)
		if err != nil {
			t.Error(err)
		}
		if n != len(data) {
			t.Errorf("expect n=%d len(%q); got %d", len(data), string(data), n)
		}
	}

	// test server should echo data back
	var buf [64]byte
	for _, data := range datas {
		n, err := conn.Read(buf[:])
		if err != nil {
			t.Error(err)
		}

		if string(buf[:n]) != "echo: "+string(data) {
			t.Errorf("expect 'echo: %s'; got %s", string(data), string(buf[:n]))
		}
	}

	// verify test server received data
	if ts.data.String() != "hello, world." {
		t.Errorf("expect server received %v; got %v", "hello, world.", ts.data.String())
	}
}

func TestClose(t *testing.T) {
	ctx := context.Background()
	s, ps := pipe()
	ts := testServer(ps, 100)

	defer ps.Close()
	defer s.Close()

	tunnel := &grpcTunnel{
		stream:      s,
		pendingDial: make(map[int64]pendingDial),
		conns:       make(map[int64]*conn),
	}

	go tunnel.serve(&fakeConn{})
	go ts.serve()

	conn, err := tunnel.DialContext(ctx, "tcp", "127.0.0.1:80")
	if err != nil {
		t.Fatalf("expect nil; got %v", err)
	}

	if err := conn.Close(); err != nil {
		t.Error(err)
	}

	if ts.packets[1].Type != client.PacketType_CLOSE_REQ {
		t.Fatalf("expect packet.type %v; got %v", client.PacketType_CLOSE_REQ, ts.packets[1].Type)
	}
	if ts.packets[1].GetCloseRequest().ConnectID != 100 {
		t.Errorf("expect connectID=100; got %d", ts.packets[1].GetCloseRequest().ConnectID)
	}
}

// TODO: Move to common testing library

// fakeStream implements ProxyService_ProxyClient
type fakeStream struct {
	grpc.ClientStream
	r <-chan *client.Packet
	w chan<- *client.Packet
}

type fakeConn struct {
}

func (f *fakeConn) Close() error {
	return nil
}

var _ clientConn = &fakeConn{}

var _ client.ProxyService_ProxyClient = &fakeStream{}

func pipe() (*fakeStream, *fakeStream) {
	r, w := make(chan *client.Packet, 2), make(chan *client.Packet, 2)
	s1, s2 := &fakeStream{}, &fakeStream{}
	s1.r, s1.w = r, w
	s2.r, s2.w = w, r
	return s1, s2
}

func (s *fakeStream) Send(packet *client.Packet) error {
	klog.V(4).InfoS("[DEBUG] send", "packet", packet)
	if packet == nil {
		return nil
	}
	s.w <- packet
	return nil
}

func (s *fakeStream) Recv() (*client.Packet, error) {
	select {
	case pkt := <-s.r:
		klog.V(4).InfoS("[DEBUG] recv", "packet", pkt)
		return pkt, nil
	case <-time.After(5 * time.Second):
		return nil, errors.New("timeout recv")
	}
}

func (s *fakeStream) Close() {
	close(s.w)
}

type proxyServer struct {
	t        testing.T
	s        client.ProxyService_ProxyClient
	handlers map[client.PacketType]handler
	connid   int64
	data     bytes.Buffer
	packets  []*client.Packet
}

func testServer(s client.ProxyService_ProxyClient, connid int64) *proxyServer {
	server := &proxyServer{
		s:        s,
		connid:   connid,
		handlers: make(map[client.PacketType]handler),
		packets:  []*client.Packet{},
	}

	server.handlers[client.PacketType_CLOSE_REQ] = server.handleClose
	server.handlers[client.PacketType_DIAL_REQ] = server.handleDial
	server.handlers[client.PacketType_DATA] = server.handleData

	return server
}

func (s *proxyServer) serve() {
	for {
		pkt, err := s.s.Recv()
		if err != nil {
			s.t.Error(err)
			return
		}

		if pkt == nil {
			return
		}

		if handler, ok := s.handlers[pkt.Type]; ok {
			if err := s.s.Send(handler(pkt)); err != nil {
				s.t.Error(err)
			}
		}
	}

}

func (s *proxyServer) handle(t client.PacketType, h handler) *proxyServer {
	s.handlers[t] = h
	return s
}

type handler func(pkt *client.Packet) *client.Packet

func (s *proxyServer) handleDial(pkt *client.Packet) *client.Packet {
	s.packets = append(s.packets, pkt)
	return &client.Packet{
		Type: client.PacketType_DIAL_RSP,
		Payload: &client.Packet_DialResponse{
			DialResponse: &client.DialResponse{
				Random:    pkt.GetDialRequest().Random,
				ConnectID: s.connid,
			},
		},
	}
}

func (s *proxyServer) handleClose(pkt *client.Packet) *client.Packet {
	s.packets = append(s.packets, pkt)
	return &client.Packet{
		Type: client.PacketType_CLOSE_RSP,
		Payload: &client.Packet_CloseResponse{
			CloseResponse: &client.CloseResponse{
				ConnectID: pkt.GetCloseRequest().ConnectID,
			},
		},
	}
}

func (s *proxyServer) handleData(pkt *client.Packet) *client.Packet {
	s.packets = append(s.packets, pkt)
	s.data.Write(pkt.GetData().Data)

	return &client.Packet{
		Type: client.PacketType_DATA,
		Payload: &client.Packet_Data{
			Data: &client.Data{
				ConnectID: pkt.GetData().ConnectID,
				Data:      append([]byte("echo: "), pkt.GetData().Data...),
			},
		},
	}
}
<commit_msg>konnectivity-client: add unit test for goroutine leak in CreateSingleUseGrpcTunnel<commit_after>/*
Copyright 2019 The Kubernetes Authors.

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

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

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

package client

import (
	"bytes"
	"context"
	"errors"
	"testing"
	"time"

	"go.uber.org/goleak"
	"google.golang.org/grpc"
	"k8s.io/klog/v2"
	"sigs.k8s.io/apiserver-network-proxy/konnectivity-client/proto/client"
)

func TestDial(t *testing.T) {
	ctx := context.Background()
	s, ps := pipe()
	ts := testServer(ps, 100)

	defer ps.Close()
	defer s.Close()

	tunnel := &grpcTunnel{
		stream:      s,
		pendingDial: make(map[int64]pendingDial),
		conns:       make(map[int64]*conn),
	}

	go tunnel.serve(&fakeConn{})
	go ts.serve()

	_, err := tunnel.DialContext(ctx, "tcp", "127.0.0.1:80")
	if err != nil {
		t.Fatalf("expect nil; got %v", err)
	}

	if ts.packets[0].Type != client.PacketType_DIAL_REQ {
		t.Fatalf("expect packet.type %v; got %v", client.PacketType_DIAL_REQ, ts.packets[0].Type)
	}

	if ts.packets[0].GetDialRequest().Address != "127.0.0.1:80" {
		t.Errorf("expect packet.address %v; got %v", "127.0.0.1:80", ts.packets[0].GetDialRequest().Address)
	}
}

// TestDialRace exercises the scenario where serve() observes and handles DIAL_RSP
// before DialContext() does any work after sending the DIAL_REQ.
func TestDialRace(t *testing.T) {
	ctx := context.Background()
	s, ps := pipe()
	ts := testServer(ps, 100)

	defer ps.Close()
	defer s.Close()

	tunnel := &grpcTunnel{
		// artificially delay after calling Send, ensure handoff of result from serve to DialContext still works
		stream:      fakeSlowSend{s},
		pendingDial: make(map[int64]pendingDial),
		conns:       make(map[int64]*conn),
	}

	go tunnel.serve(&fakeConn{})
	go ts.serve()

	_, err := tunnel.DialContext(ctx, "tcp", "127.0.0.1:80")
	if err != nil {
		t.Fatalf("expect nil; got %v", err)
	}

	if ts.packets[0].Type != client.PacketType_DIAL_REQ {
		t.Fatalf("expect packet.type %v; got %v", client.PacketType_DIAL_REQ, ts.packets[0].Type)
	}

	if ts.packets[0].GetDialRequest().Address != "127.0.0.1:80" {
		t.Errorf("expect packet.address %v; got %v", "127.0.0.1:80", ts.packets[0].GetDialRequest().Address)
	}
}

// fakeSlowSend wraps ProxyService_ProxyClient and adds an artificial 1 second delay after calling Send
type fakeSlowSend struct {
	client.ProxyService_ProxyClient
}

func (s fakeSlowSend) Send(p *client.Packet) error {
	// send the request so it can start being processed immediately
	err := s.ProxyService_ProxyClient.Send(p)
	// delay returning to simulate slowness on the client side,
	// to exercise serve() observing/handling the DIAL_RSP before
	// the client does any post-Send() work
	time.Sleep(time.Second)
	return err
}

func TestData(t *testing.T) {
	ctx := context.Background()
	s, ps := pipe()
	ts := testServer(ps, 100)

	defer ps.Close()
	defer s.Close()

	tunnel := &grpcTunnel{
		stream:      s,
		pendingDial: make(map[int64]pendingDial),
		conns:       make(map[int64]*conn),
	}

	go tunnel.serve(&fakeConn{})
	go ts.serve()

	conn, err := tunnel.DialContext(ctx, "tcp", "127.0.0.1:80")
	if err != nil {
		t.Fatalf("expect nil; got %v", err)
	}

	datas := [][]byte{
		[]byte("hello"),
		[]byte(", "),
		[]byte("world."),
	}

	// send data using conn.Write
	for _, data := range datas {
		n, err := conn.Write(data)
		if err != nil {
			t.Error(err)
		}
		if n != len(data) {
			t.Errorf("expect n=%d len(%q); got %d", len(data), string(data), n)
		}
	}

	// test server should echo data back
	var buf [64]byte
	for _, data := range datas {
		n, err := conn.Read(buf[:])
		if err != nil {
			t.Error(err)
		}

		if string(buf[:n]) != "echo: "+string(data) {
			t.Errorf("expect 'echo: %s'; got %s", string(data), string(buf[:n]))
		}
	}

	// verify test server received data
	if ts.data.String() != "hello, world." {
		t.Errorf("expect server received %v; got %v", "hello, world.", ts.data.String())
	}
}

func TestClose(t *testing.T) {
	ctx := context.Background()
	s, ps := pipe()
	ts := testServer(ps, 100)

	defer ps.Close()
	defer s.Close()

	tunnel := &grpcTunnel{
		stream:      s,
		pendingDial: make(map[int64]pendingDial),
		conns:       make(map[int64]*conn),
	}

	go tunnel.serve(&fakeConn{})
	go ts.serve()

	conn, err := tunnel.DialContext(ctx, "tcp", "127.0.0.1:80")
	if err != nil {
		t.Fatalf("expect nil; got %v", err)
	}

	if err := conn.Close(); err != nil {
		t.Error(err)
	}

	if ts.packets[1].Type != client.PacketType_CLOSE_REQ {
		t.Fatalf("expect packet.type %v; got %v", client.PacketType_CLOSE_REQ, ts.packets[1].Type)
	}
	if ts.packets[1].GetCloseRequest().ConnectID != 100 {
		t.Errorf("expect connectID=100; got %d", ts.packets[1].GetCloseRequest().ConnectID)
	}
}

func TestCreateSingleUseGrpcTunnel_NoLeakOnFailure(t *testing.T) {
	defer goleak.VerifyNone(t, goleak.IgnoreCurrent())

	tunnel, err := CreateSingleUseGrpcTunnel(context.Background(), "127.0.0.1:12345", grpc.WithInsecure())
	if tunnel != nil {
		t.Fatal("expected nil tunnel when calling CreateSingleUseGrpcTunnel")
	}
	if err == nil {
		t.Fatal("expected error when calling CreateSingleUseGrpcTunnel")
	}
}

// TODO: Move to common testing library

// fakeStream implements ProxyService_ProxyClient
type fakeStream struct {
	grpc.ClientStream
	r <-chan *client.Packet
	w chan<- *client.Packet
}

type fakeConn struct {
}

func (f *fakeConn) Close() error {
	return nil
}

var _ clientConn = &fakeConn{}

var _ client.ProxyService_ProxyClient = &fakeStream{}

func pipe() (*fakeStream, *fakeStream) {
	r, w := make(chan *client.Packet, 2), make(chan *client.Packet, 2)
	s1, s2 := &fakeStream{}, &fakeStream{}
	s1.r, s1.w = r, w
	s2.r, s2.w = w, r
	return s1, s2
}

func (s *fakeStream) Send(packet *client.Packet) error {
	klog.V(4).InfoS("[DEBUG] send", "packet", packet)
	if packet == nil {
		return nil
	}
	s.w <- packet
	return nil
}

func (s *fakeStream) Recv() (*client.Packet, error) {
	select {
	case pkt := <-s.r:
		klog.V(4).InfoS("[DEBUG] recv", "packet", pkt)
		return pkt, nil
	case <-time.After(5 * time.Second):
		return nil, errors.New("timeout recv")
	}
}

func (s *fakeStream) Close() {
	close(s.w)
}

type proxyServer struct {
	t        testing.T
	s        client.ProxyService_ProxyClient
	handlers map[client.PacketType]handler
	connid   int64
	data     bytes.Buffer
	packets  []*client.Packet
}

func testServer(s client.ProxyService_ProxyClient, connid int64) *proxyServer {
	server := &proxyServer{
		s:        s,
		connid:   connid,
		handlers: make(map[client.PacketType]handler),
		packets:  []*client.Packet{},
	}

	server.handlers[client.PacketType_CLOSE_REQ] = server.handleClose
	server.handlers[client.PacketType_DIAL_REQ] = server.handleDial
	server.handlers[client.PacketType_DATA] = server.handleData

	return server
}

func (s *proxyServer) serve() {
	for {
		pkt, err := s.s.Recv()
		if err != nil {
			s.t.Error(err)
			return
		}

		if pkt == nil {
			return
		}

		if handler, ok := s.handlers[pkt.Type]; ok {
			if err := s.s.Send(handler(pkt)); err != nil {
				s.t.Error(err)
			}
		}
	}

}

func (s *proxyServer) handle(t client.PacketType, h handler) *proxyServer {
	s.handlers[t] = h
	return s
}

type handler func(pkt *client.Packet) *client.Packet

func (s *proxyServer) handleDial(pkt *client.Packet) *client.Packet {
	s.packets = append(s.packets, pkt)
	return &client.Packet{
		Type: client.PacketType_DIAL_RSP,
		Payload: &client.Packet_DialResponse{
			DialResponse: &client.DialResponse{
				Random:    pkt.GetDialRequest().Random,
				ConnectID: s.connid,
			},
		},
	}
}

func (s *proxyServer) handleClose(pkt *client.Packet) *client.Packet {
	s.packets = append(s.packets, pkt)
	return &client.Packet{
		Type: client.PacketType_CLOSE_RSP,
		Payload: &client.Packet_CloseResponse{
			CloseResponse: &client.CloseResponse{
				ConnectID: pkt.GetCloseRequest().ConnectID,
			},
		},
	}
}

func (s *proxyServer) handleData(pkt *client.Packet) *client.Packet {
	s.packets = append(s.packets, pkt)
	s.data.Write(pkt.GetData().Data)

	return &client.Packet{
		Type: client.PacketType_DATA,
		Payload: &client.Packet_Data{
			Data: &client.Data{
				ConnectID: pkt.GetData().ConnectID,
				Data:      append([]byte("echo: "), pkt.GetData().Data...),
			},
		},
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"

	"github.com/mikepb/go-serial"
)

func main() {
	info, err := serial.ListPorts()

	if err != nil {
		log.Fatalln(err)
	}

	for _, p := range info {
		fmt.Println(p.Name())
	}
}
<commit_msg>serial write test<commit_after>package main

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"strconv"
	"strings"

	"github.com/huin/goserial"
)

type packet struct {
	header     string
	coord      string
	dataR      string
	dataG      string
	terminator string
}

func createTestPacket() *packet {
	var p packet
	p.header = "pcmat\r"
	p.coord = "000\r5ff\r"
	s := ""
	for i := 0; i < 192; i++ {
		s += "p"
	}
	s += "\r"
	p.dataR = s
	p.dataG = s
	p.terminator = "end\r"

	return &p
}

func getUsbttyList() []string {
	contents, _ := ioutil.ReadDir("/dev")
	var ret []string

	for _, f := range contents {
		if strings.Contains(f.Name(), "tty.usb") ||
			strings.Contains(f.Name(), "ttyUSB") {
			//return "/dev/" + f.Name()
			ret = append(ret, "/dev/"+f.Name())
		}
	}

	return ret
}

func writeLCDMatrix(p *packet, s io.ReadWriteCloser) {
	s.Write([]byte(p.header))
	s.Write([]byte(p.coord))
	s.Write([]byte(p.dataR))
	s.Write([]byte(p.dataG))
	s.Write([]byte(p.terminator))
}

func ttySelecter(ttys []string) (string, error) {
	for i, s := range ttys {
		fmt.Println(strconv.Itoa(i) + ": " + s)
	}
	fmt.Println()
	fmt.Print("Select tty prot: ")

	n := 0
	fmt.Scan(&n)

	if n > len(ttys)-1 {
		return "", errors.New("tty port select error. " + strconv.Itoa(n) + " is not exist.")
	}

	return ttys[n], nil
}

func viewTtySelecterUI() (string, error) {
	ttys := getUsbttyList()
	tty, err := ttySelecter(ttys)

	fmt.Println(tty)
	return tty, err
}

func main() {
	ttyPort, err := viewTtySelecterUI()
	if err != nil {
		log.Fatalln(err)
	}

	serialConfigure := &goserial.Config{Name: ttyPort, Baud: 9600}
	serialPort, _ := goserial.OpenPort(serialConfigure)

	packet := createTestPacket()
	for {
		writeLCDMatrix(packet, serialPort)
	}

}
<|endoftext|>


<commit_before>/*
Package golibwireshark use libwireshark library to decode pcap file and analyse dissection data.
*/
package golibwireshark

/*
#cgo pkg-config: glib-2.0
#cgo LDFLAGS: -lwiretap -lwsutil -lwireshark
#cgo CFLAGS: -I.
#cgo CFLAGS: -I/usr/include/glib-2.0
#cgo CFLAGS: -I/usr/lib/x86_64-linux-gnu/glib-2.0/include
#cgo CFLAGS: -I/usr/include/wireshark
#cgo CFLAGS: -I/usr/include/wireshark/wiretap
#cgo CFLAGS: -I./include

#include "./include/lib.h"

*/
import "C"
import (
	"fmt"
	"unsafe"
)

//Packet data index after dissection
type Packet struct {
	Edt   *C.struct_epan_dissect //packet data index after dissected
	Field *C.struct__proto_node  //packet field index
}

//Init initializing the dissection. If opening inputfile or savefile fail,
//return err. After dissection finish, should use Clean() to end the dissection.
func Init(inputfile, savefile string) error {
	var err C.int

	if savefile == "" {
		err = C.init(C.CString(inputfile), nil)
	} else {
		err = C.init(C.CString(inputfile), C.CString(savefile))
	}

	if err != 0 {
		return fmt.Errorf("can't open file")
	}
	return nil
}

//Clean to end the dissection.
func Clean() {

	C.clean()
}

func ReOpenInputFile(filename string) error {
	var err C.int

	err = C.init_cfile(C.CString(filename))
	if err != 0 {
		return fmt.Errorf("can't open file")
	}
	return nil
}

func ReOpenOutputFile(filename string) error {
	var err C.int

	err = C.init_pdh(C.CString(filename))
	if err != 0 {
		return fmt.Errorf("can't create output file")
	}
	return nil

}

func CloseInputFile() {
	C.clean_cfile()
}

func CloseOutputFile() {
	C.clean_pdh()
}

//Iskey find a key in packet dissection data. If key exists, ok=ture,
//value is key value, otherwise ok=false.
func (p Packet) Iskey(key string) (value string, ok bool) {
	buf := C.get_field_value(p.Edt, C.CString(key))
	defer C.free(unsafe.Pointer(buf))

	value = C.GoString(buf)
	if value == "" {
		return "", false
	} else {
		return value, true
	}
}

//GetPacket get one packet data index which has been dissected. If no more
//packet to be dissected, Edt return nil.
//After analysing packet data, should use FreePacket() to free packet
//data.
func (p *Packet) GetPacket() {
	var edt *C.struct_epan_dissect
	edt = C.next_packet()
	if edt == nil {
		p.Edt = nil
	}
	p.Edt = edt
}

//FreePacket to release packet memory
func (p *Packet) FreePacket() {
	C.free_packet(p.Edt)
}

//GetField get field index by key. If key exists, return true, Field item equal index,
//otherwise return false and Field item equal nil.
func (p *Packet) GetField(key string) bool {
	p.Field = C.get_field(p.Edt, C.CString(key))
	if p.Field != nil {
		return true
	}
	return false
}

//String do human readable printout. If Field equal nil, print out the packet.
//If Field doesn't equal nil, print out the Field.
func (p Packet) String() string {
	var node *C.struct__proto_node
	var buf string

	if p.Field != nil {
		node = p.Field
		cbuf := C.print_node(node)
		defer C.free(unsafe.Pointer(cbuf))
		buf = C.GoString(cbuf)
	} else {
		node = (p.Edt).tree
		cbuf := C.print_packet(node)
		defer C.free(unsafe.Pointer(cbuf))
		buf = C.GoString(cbuf)
	}

	return buf
}

//WriteToFile write a packet to file. If savefile aren't be initialized,
//return error.
func (p *Packet) WriteToFile() error {
	if i := C.write_to_file(); i == 0 {
		return nil
	} else if i == 1 {
		return fmt.Errorf("output file isn't opened")
	}
	return nil
}
<commit_msg>comments update<commit_after>/*
Package golibwireshark use libwireshark library to decode pcap file and analyse dissection data.
*/
package golibwireshark

/*
#cgo pkg-config: glib-2.0
#cgo LDFLAGS: -lwiretap -lwsutil -lwireshark
#cgo CFLAGS: -I.
#cgo CFLAGS: -I/usr/include/glib-2.0
#cgo CFLAGS: -I/usr/lib/x86_64-linux-gnu/glib-2.0/include
#cgo CFLAGS: -I/usr/include/wireshark
#cgo CFLAGS: -I/usr/include/wireshark/wiretap
#cgo CFLAGS: -I./include

#include "./include/lib.h"

*/
import "C"
import (
	"fmt"
	"unsafe"
)

//Packet data index after dissection
type Packet struct {
	Edt   *C.struct_epan_dissect //packet data index after dissected
	Field *C.struct__proto_node  //packet field index
}

//Init initializing the dissection. If opening inputfile or savefile fail,
//return err. After dissection finish, should use Clean() to end the dissection.
func Init(inputfile, outputfile string) error {
	var err C.int

	if outputfile == "" {
		err = C.init(C.CString(inputfile), nil)
	} else {
		err = C.init(C.CString(inputfile), C.CString(outputfile))
	}

	if err != 0 {
		return fmt.Errorf("can't open file")
	}
	return nil
}

//Clean to end the dissection.
func Clean() {

	C.clean()
}

//ReOpenInputFile open a new input file after CloseInputFile.
//If open file failed, return error.
func ReOpenInputFile(filename string) error {
	var err C.int

	err = C.init_cfile(C.CString(filename))
	if err != 0 {
		return fmt.Errorf("can't open file")
	}
	return nil
}

//ReOpenOutputFile open a new output file after CloseOutputFile.
//if open file failed, return error.
func ReOpenOutputFile(filename string) error {
	var err C.int

	err = C.init_pdh(C.CString(filename))
	if err != 0 {
		return fmt.Errorf("can't create output file")
	}
	return nil

}

//CloseInputFile close input file. Using ReOpenInputFile to open a new input file.
func CloseInputFile() {
	C.clean_cfile()
}

//CloseOutputFile close output file. Using ReOpenOutputFile to open a new output file.
func CloseOutputFile() {
	C.clean_pdh()
}

//Iskey find a key in packet dissection data. If key exists, ok=ture,
//value is key value, otherwise ok=false.
func (p Packet) Iskey(key string) (value string, ok bool) {
	buf := C.get_field_value(p.Edt, C.CString(key))
	defer C.free(unsafe.Pointer(buf))

	value = C.GoString(buf)
	if value == "" {
		return "", false
	}

	return value, true
}

//GetPacket get one packet data index which has been dissected. If no more
//packet to be dissected, Edt return nil.
//After analysing packet data, should use FreePacket() to free packet
//data.
func (p *Packet) GetPacket() {
	var edt *C.struct_epan_dissect
	edt = C.next_packet()
	if edt == nil {
		p.Edt = nil
	}
	p.Edt = edt
}

//FreePacket to release packet memory
func (p *Packet) FreePacket() {
	C.free_packet(p.Edt)
}

//GetField get field index by key. If key exists, return true, Field item equal index,
//otherwise return false and Field item equal nil.
func (p *Packet) GetField(key string) bool {
	p.Field = C.get_field(p.Edt, C.CString(key))
	if p.Field != nil {
		return true
	}
	return false
}

//String do human readable printout. If Field equal nil, print out the packet.
//If Field doesn't equal nil, print out the Field.
func (p Packet) String() string {
	var node *C.struct__proto_node
	var buf string

	if p.Field != nil {
		node = p.Field
		cbuf := C.print_node(node)
		defer C.free(unsafe.Pointer(cbuf))
		buf = C.GoString(cbuf)
	} else {
		node = (p.Edt).tree
		cbuf := C.print_packet(node)
		defer C.free(unsafe.Pointer(cbuf))
		buf = C.GoString(cbuf)
	}

	return buf
}

//WriteToFile write a packet to file. If Output file are not initialized,
//return error.
func (p *Packet) WriteToFile() error {
	if i := C.write_to_file(); i == 0 {
		return nil
	} else if i == 1 {
		return fmt.Errorf("output file isn't opened")
	}
	return nil
}
<|endoftext|>


<commit_before>package goodhosts

import (
	"fmt"
	"reflect"
	"testing"
)

func TestHostsLineIsComment(t *testing.T) {
	comment := "   # This is a comment   "
	line := NewHostsLine(comment)
	result := line.IsComment()
	if !result {
		t.Error(fmt.Sprintf("'%s' should be a comment"), comment)
	}
}

func TestNewHostsLineWithEmptyLine(t *testing.T) {
	line := NewHostsLine("")
	if line.Raw != "" {
		t.Error("Failed to load empty line.")
	}
}

func TestHostsHasEntryFindsEntry(t *testing.T) {
	hosts := new(Hosts)
	hosts.Lines = []HostsLine{
		NewHostsLine("127.0.0.1 yadda"), NewHostsLine("10.0.0.7 nada")}
	if !hosts.HasEntry("10.0.0.7", "nada") {
		t.Error("Failed to find entry.")
	}
}

func TestHostsHasEntryDoesntFindMissingEntry(t *testing.T) {
	hosts := new(Hosts)
	hosts.Lines = []HostsLine{
		NewHostsLine("127.0.0.1 yadda"), NewHostsLine("10.0.0.7 nada")}

	if hosts.HasEntry("10.0.0.7", "brada") {
		t.Error("Found missing entry.")
	}
}

func TestHostsAddEntryWhenIpHasOtherHosts(t *testing.T) {
	hosts := new(Hosts)
	hosts.Lines = []HostsLine{
		NewHostsLine("127.0.0.1 yadda"), NewHostsLine("10.0.0.7 nada")}

	hosts.AddEntry("10.0.0.7", "brada")

	expectedLines := []HostsLine{
		NewHostsLine("127.0.0.1 yadda"), NewHostsLine("10.0.0.7 nada brada")}

	if !reflect.DeepEqual(hosts.Lines, expectedLines) {
		t.Error("Add entry failed to append entry.")
	}
}

func TestHostsAddEntryWhenIpDoesntExist(t *testing.T) {
	hosts := new(Hosts)
	hosts.Lines = []HostsLine{
		NewHostsLine("127.0.0.1 yadda")}

	hosts.AddEntry("10.0.0.7", "brada")

	expectedLines := []HostsLine{
		NewHostsLine("127.0.0.1 yadda"), NewHostsLine("10.0.0.7 brada")}

	if !reflect.DeepEqual(hosts.Lines, expectedLines) {
		t.Error("Add entry failed to append entry.")
	}
}

func TestHostsAddMultipleEntries(t *testing.T) {
	hosts := new(Hosts)
	hosts.Lines = []HostsLine{
		NewHostsLine("127.0.0.1 yadda")}

	hosts.AddEntry("127.0.0.1", "brada", "prada", "nada")
	if hosts.Lines[0].Raw != "127.0.0.1 yadda brada prada nada" {
		t.Error("Failed to add multiple entries.")
	}
}

func TestHostsRemoveEntryWhenLastHostIpCombo(t *testing.T) {
	hosts := new(Hosts)
	hosts.Lines = []HostsLine{
		NewHostsLine("127.0.0.1 yadda"), NewHostsLine("10.0.0.7 nada")}

	hosts.RemoveEntry("10.0.0.7", "nada")

	expectedLines := []HostsLine{NewHostsLine("127.0.0.1 yadda")}

	if !reflect.DeepEqual(hosts.Lines, expectedLines) {
		t.Error("Remove entry failed to remove entry.")
	}
}

func TestHostsRemoveEntryWhenIpHasOtherHosts(t *testing.T) {
	hosts := new(Hosts)

	hosts.Lines = []HostsLine{
		NewHostsLine("127.0.0.1 yadda"), NewHostsLine("10.0.0.7 nada brada")}

	hosts.RemoveEntry("10.0.0.7", "nada")

	expectedLines := []HostsLine{
		NewHostsLine("127.0.0.1 yadda"), NewHostsLine("10.0.0.7 brada")}

	if !reflect.DeepEqual(hosts.Lines, expectedLines) {
		t.Error("Remove entry failed to remove entry.")
	}
}

func TestHostsRemoveMultipleEntries(t *testing.T) {
	hosts := new(Hosts)
	hosts.Lines = []HostsLine{
		NewHostsLine("127.0.0.1 yadda nadda prada")}

	hosts.RemoveEntry("127.0.0.1", "yadda", "prada")
	if hosts.Lines[0].Raw != "127.0.0.1 nadda" {
		t.Error("Failed to remove multiple entries.")
	}
}
<commit_msg>HasEntry doesn't need to be split over multiple tests.<commit_after>package goodhosts

import (
	"fmt"
	"reflect"
	"testing"
)

func TestHostsLineIsComment(t *testing.T) {
	comment := "   # This is a comment   "
	line := NewHostsLine(comment)
	result := line.IsComment()
	if !result {
		t.Error(fmt.Sprintf("'%s' should be a comment"), comment)
	}
}

func TestNewHostsLineWithEmptyLine(t *testing.T) {
	line := NewHostsLine("")
	if line.Raw != "" {
		t.Error("Failed to load empty line.")
	}
}

func TestHostsHasEntry(t *testing.T) {
	hosts := new(Hosts)
	hosts.Lines = []HostsLine{
		NewHostsLine("127.0.0.1 yadda"), NewHostsLine("10.0.0.7 nada")}

	// We should find this entry.
	if !hosts.HasEntry("10.0.0.7", "nada") {
		t.Error("Couldn't find entry in hosts file.")
	}

	// We shouldn't find this entry
	if hosts.HasEntry("10.0.0.7", "shuda") {
		t.Error("Found entry that isn't in hosts file.")
	}
}

func TestHostsHasEntryDoesntFindMissingEntry(t *testing.T) {
	hosts := new(Hosts)
	hosts.Lines = []HostsLine{
		NewHostsLine("127.0.0.1 yadda"), NewHostsLine("10.0.0.7 nada")}

	if hosts.HasEntry("10.0.0.7", "brada") {
		t.Error("Found missing entry.")
	}
}

func TestHostsAddEntryWhenIpHasOtherHosts(t *testing.T) {
	hosts := new(Hosts)
	hosts.Lines = []HostsLine{
		NewHostsLine("127.0.0.1 yadda"), NewHostsLine("10.0.0.7 nada")}

	hosts.AddEntry("10.0.0.7", "brada")

	expectedLines := []HostsLine{
		NewHostsLine("127.0.0.1 yadda"), NewHostsLine("10.0.0.7 nada brada")}

	if !reflect.DeepEqual(hosts.Lines, expectedLines) {
		t.Error("Add entry failed to append entry.")
	}
}

func TestHostsAddEntryWhenIpDoesntExist(t *testing.T) {
	hosts := new(Hosts)
	hosts.Lines = []HostsLine{
		NewHostsLine("127.0.0.1 yadda")}

	hosts.AddEntry("10.0.0.7", "brada")

	expectedLines := []HostsLine{
		NewHostsLine("127.0.0.1 yadda"), NewHostsLine("10.0.0.7 brada")}

	if !reflect.DeepEqual(hosts.Lines, expectedLines) {
		t.Error("Add entry failed to append entry.")
	}
}

func TestHostsAddMultipleEntries(t *testing.T) {
	hosts := new(Hosts)
	hosts.Lines = []HostsLine{
		NewHostsLine("127.0.0.1 yadda")}

	hosts.AddEntry("127.0.0.1", "brada", "prada", "nada")
	if hosts.Lines[0].Raw != "127.0.0.1 yadda brada prada nada" {
		t.Error("Failed to add multiple entries.")
	}
}

func TestHostsRemoveEntryWhenLastHostIpCombo(t *testing.T) {
	hosts := new(Hosts)
	hosts.Lines = []HostsLine{
		NewHostsLine("127.0.0.1 yadda"), NewHostsLine("10.0.0.7 nada")}

	hosts.RemoveEntry("10.0.0.7", "nada")

	expectedLines := []HostsLine{NewHostsLine("127.0.0.1 yadda")}

	if !reflect.DeepEqual(hosts.Lines, expectedLines) {
		t.Error("Remove entry failed to remove entry.")
	}
}

func TestHostsRemoveEntryWhenIpHasOtherHosts(t *testing.T) {
	hosts := new(Hosts)

	hosts.Lines = []HostsLine{
		NewHostsLine("127.0.0.1 yadda"), NewHostsLine("10.0.0.7 nada brada")}

	hosts.RemoveEntry("10.0.0.7", "nada")

	expectedLines := []HostsLine{
		NewHostsLine("127.0.0.1 yadda"), NewHostsLine("10.0.0.7 brada")}

	if !reflect.DeepEqual(hosts.Lines, expectedLines) {
		t.Error("Remove entry failed to remove entry.")
	}
}

func TestHostsRemoveMultipleEntries(t *testing.T) {
	hosts := new(Hosts)
	hosts.Lines = []HostsLine{
		NewHostsLine("127.0.0.1 yadda nadda prada")}

	hosts.RemoveEntry("127.0.0.1", "yadda", "prada")
	if hosts.Lines[0].Raw != "127.0.0.1 nadda" {
		t.Error("Failed to remove multiple entries.")
	}
}
<|endoftext|>


<commit_before>package bootstrap

import "github.com/dtylman/gowd"
/*

        «

1

2

3

4

5

        »

 */

type Pagination struct {
	*gowd.Element
	Items *List
}

func NewPagination() *Pagination {
	p := new(Pagination)
	p.Element = gowd.NewElement("nav")
	p.Items = NewList(ListUnordered, "pagination")
	p.AddElement(p.Items.Element)
	return p

}
<commit_msg>"add item" to pagination<commit_after>package bootstrap

import "github.com/dtylman/gowd"
/*

        «

1

2

3

4

5

        »

 */

type Pagination struct {
	*gowd.Element
	Items *List
}

func NewPagination() *Pagination {
	p := new(Pagination)
	p.Element = gowd.NewElement("nav")
	p.Items = NewList(ListUnordered, "pagination")
	p.AddElement(p.Items.Element)
	return p

}

func (p* Pagination) AddItem(caption string, active bool,handler gowd.EventHandler) *gowd.Element{
	link :=NewLinkButton(caption)
	if handler!=nil{
		link.OnEvent(gowd.OnClick,handler)
	}
	item:=p.Items.AddItem(link)
	if active{
		item.SetClass("active")
	}
	return link
}<|endoftext|>