<commit_before>// Copyright 2017-2019 Authors of Cilium
//
// 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 agent

import (
	"context"
	"io/ioutil"
	"net"
	"os"
	"path"
	"syscall"
	"time"

	"github.com/cilium/cilium/api/v1/models"
	"github.com/cilium/cilium/pkg/bpf"
	"github.com/cilium/cilium/pkg/defaults"
	"github.com/cilium/cilium/pkg/lock"
	"github.com/cilium/cilium/pkg/logging/logfields"
	"github.com/cilium/cilium/pkg/monitor/agent/listener"
	"github.com/cilium/cilium/pkg/monitor/payload"
	"github.com/cilium/cilium/pkg/option"
	"github.com/sirupsen/logrus"
)

const (
	pollTimeout = 5000
)

// isCtxDone is a utility function that returns true when the context's Done()
// channel is closed. It is intended to simplify goroutines that need to check
// this multiple times in their loop.
func isCtxDone(ctx context.Context) bool {
	select {
	case <-ctx.Done():
		return true
	default:
		return false
	}
}

func getPerfConfig(nPages int) *bpf.PerfEventConfig {
	// configure BPF perf buffer reader
	c := bpf.DefaultPerfEventConfig()
	c.NumPages = nPages
	return c
}

// Monitor structure for centralizing the responsibilities of the main events
// reader.
// There is some racey-ness around perfReaderCancel since it replaces on every
// perf reader start. In the event that a MonitorListener from a previous
// generation calls its cleanup after the start of the new perf reader, we
// might call the new, and incorrect, cancel function. We guard for this by
// checking the number of listeners during the cleanup call. The perf reader
// must have at least one MonitorListener (since it started) so no cancel is called.
// If it doesn't, the cancel is the correct behavior (the older generation
// cancel must have been called for us to get this far anyway).
type Monitor struct {
	lock.Mutex

	ctx              context.Context
	perfReaderCancel context.CancelFunc
	listeners        map[listener.MonitorListener]struct{}
	nPages           int
	monitorEvents    *bpf.PerCpuEvents
}

// NewMonitor creates a Monitor, and starts client connection handling and agent event
// handling.
// Note that the perf buffer reader is started only when listeners are
// connected.
func NewMonitor(ctx context.Context, nPages int, server1_2 net.Listener) (m *Monitor, err error) {
	m = &Monitor{
		ctx:              ctx,
		listeners:        make(map[listener.MonitorListener]struct{}),
		nPages:           nPages,
		perfReaderCancel: func() {}, // no-op to avoid doing null checks everywhere
	}

	// assert that we can actually connect the monitor
	c := getPerfConfig(nPages)
	mapPath := c.MapName
	if !path.IsAbs(mapPath) {
		mapPath = bpf.MapPath(mapPath)
	}
	if _, err := os.Stat(mapPath); os.IsNotExist(err) {
		return nil, err
	}

	// start new MonitorListener handler
	go m.connectionHandler1_2(ctx, server1_2)

	return m, nil
}

// registerNewListener adds the new MonitorListener to the global list. It also spawns
// a singleton goroutine to read and distribute the events. It passes a
// cancelable context to this goroutine and the cancelFunc is assigned to
// perfReaderCancel. Note that cancelling parentCtx (e.g. on program shutdown)
// will also cancel the derived context.
func (m *Monitor) registerNewListener(parentCtx context.Context, conn net.Conn, version listener.Version) {
	m.Lock()
	defer m.Unlock()

	// If this is the first listener, start the perf reader
	if len(m.listeners) == 0 {
		m.perfReaderCancel() // don't leak any old readers, just in case.
		perfEventReaderCtx, cancel := context.WithCancel(parentCtx)
		m.perfReaderCancel = cancel
		go m.perfEventReader(perfEventReaderCtx, m.nPages)
	}

	switch version {
	case listener.Version1_2:
		newListener := newListenerv1_2(conn, option.Config.MonitorQueueSize, m.removeListener)
		m.listeners[newListener] = struct{}{}

	default:
		conn.Close()
		log.WithField("version", version).Error("Closing new connection from unsupported monitor client version")
	}

	log.WithFields(logrus.Fields{
		"count.listener": len(m.listeners),
		"version":        version,
	}).Debug("New listener connected")
}

// removeListener deletes the MonitorListener from the list, closes its queue, and
// stops perfReader if this is the last MonitorListener
func (m *Monitor) removeListener(ml listener.MonitorListener) {
	m.Lock()
	defer m.Unlock()

	delete(m.listeners, ml)
	log.WithFields(logrus.Fields{
		"count.listener": len(m.listeners),
		"version":        ml.Version(),
	}).Debug("Removed listener")

	// If this was the final listener, shutdown the perf reader and unmap our
	// ring buffer readers. This tells the kernel to not emit this data.
	// Note: it is critical to hold the lock and check the number of listeners.
	// This guards against an older generation listener calling the
	// current generation perfReaderCancel
	if len(m.listeners) == 0 {
		m.perfReaderCancel()
	}
}

// perfEventReader is a goroutine that reads events from the perf buffer. It
// will exit when stopCtx is done. Note, however, that it will block in the
// Poll call but assumes enough events are generated that these blocks are
// short.
func (m *Monitor) perfEventReader(stopCtx context.Context, nPages int) {
	scopedLog := log.WithField(logfields.StartTime, time.Now())
	scopedLog.Info("Beginning to read perf buffer")
	defer scopedLog.Info("Stopped reading perf buffer")

	c := getPerfConfig(nPages)
	monitorEvents, err := bpf.NewPerCpuEvents(c)
	if err != nil {
		scopedLog.WithError(err).Fatal("Cannot initialise BPF perf ring buffer sockets")
	}
	defer monitorEvents.CloseAll()

	// update the class's monitorEvents This is only accessed by .DumpStats()
	// also grab the callbacks we need to avoid locking again. These methods never change.
	m.Lock()
	m.monitorEvents = monitorEvents
	receiveEvent := m.receiveEvent
	lostEvent := m.lostEvent
	errorEvent := m.errorEvent
	m.Unlock()

	for !isCtxDone(stopCtx) {
		todo, err := monitorEvents.Poll(pollTimeout)
		switch {
		case isCtxDone(stopCtx):
			return

		case err == syscall.EBADF:
			return

		case err != nil:
			scopedLog.WithError(err).Error("Error in Poll")
			continue
		}

		if todo > 0 {
			if err := monitorEvents.ReadAll(receiveEvent, lostEvent, errorEvent); err != nil {
				scopedLog.WithError(err).Warn("Error received while reading from perf buffer")
			}
		}
	}
}

// Status returns the current status of the monitor
func (m *Monitor) Status() *models.MonitorStatus {
	m.Lock()
	defer m.Unlock()

	if m.monitorEvents == nil {
		return nil
	}

	lost, _, unknown := m.monitorEvents.Stats()
	status := models.MonitorStatus{
		Cpus:     int64(m.monitorEvents.Cpus),
		Lost:     int64(lost),
		Npages:   int64(m.monitorEvents.Npages),
		Pagesize: int64(m.monitorEvents.Pagesize),
		Unknown:  int64(unknown),
	}

	return &status
}

// connectionHandler1_2 handles all the incoming connections and sets up the
// listener objects. It will block on Accept, but expects the caller to close
// server, inducing a return.
func (m *Monitor) connectionHandler1_2(parentCtx context.Context, server net.Listener) {
	for !isCtxDone(parentCtx) {
		conn, err := server.Accept()
		switch {
		case isCtxDone(parentCtx) && conn != nil:
			conn.Close()
			fallthrough

		case isCtxDone(parentCtx) && conn == nil:
			return

		case err != nil:
			log.WithError(err).Warn("Error accepting connection")
			continue
		}

		m.registerNewListener(parentCtx, conn, listener.Version1_2)
	}
}

// send enqueues the payload to all listeners.
func (m *Monitor) send(pl *payload.Payload) {
	m.Lock()
	defer m.Unlock()
	for ml := range m.listeners {
		ml.Enqueue(pl)
	}
}

func (m *Monitor) receiveEvent(es *bpf.PerfEventSample, c int) {
	pl := payload.Payload{Data: es.DataCopy(), CPU: c, Lost: 0, Type: payload.EventSample}
	m.send(&pl)
}

func (m *Monitor) lostEvent(el *bpf.PerfEventLost, c int) {
	pl := payload.Payload{Data: []byte{}, CPU: c, Lost: el.Lost, Type: payload.RecordLost}
	m.send(&pl)
}

func (m *Monitor) errorEvent(el *bpf.PerfEvent) {
	log.Errorf("BUG: Timeout while reading perf ring buffer: %s", el.Debug())
	dumpFile := path.Join(defaults.RuntimePath, defaults.StateDir, "ring-buffer-crash.dump")
	if err := ioutil.WriteFile(dumpFile, []byte(el.DebugDump()), 0644); err != nil {
		log.WithError(err).Errorf("Unable to dump ring buffer state to %s", dumpFile)
	}
}
<commit_msg>monitor: Rebase against pure Go perf reader<commit_after>// Copyright 2017-2019 Authors of Cilium
//
// 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 agent

import (
	"context"
	"net"
	"os"
	"time"

	"github.com/cilium/cilium/api/v1/models"
	oldBPF "github.com/cilium/cilium/pkg/bpf"
	"github.com/cilium/cilium/pkg/lock"
	"github.com/cilium/cilium/pkg/logging/logfields"
	"github.com/cilium/cilium/pkg/monitor/agent/listener"
	"github.com/cilium/cilium/pkg/monitor/payload"
	"github.com/cilium/cilium/pkg/option"

	"github.com/cilium/ebpf"
	"github.com/cilium/ebpf/perf"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
	"golang.org/x/sys/unix"
)

const (
	pollTimeout = 5000
)

var (
	eventsMapName = "cilium_events"
)

// isCtxDone is a utility function that returns true when the context's Done()
// channel is closed. It is intended to simplify goroutines that need to check
// this multiple times in their loop.
func isCtxDone(ctx context.Context) bool {
	select {
	case <-ctx.Done():
		return true
	default:
		return false
	}
}

// Monitor structure for centralizing the responsibilities of the main events
// reader.
// There is some racey-ness around perfReaderCancel since it replaces on every
// perf reader start. In the event that a MonitorListener from a previous
// generation calls its cleanup after the start of the new perf reader, we
// might call the new, and incorrect, cancel function. We guard for this by
// checking the number of listeners during the cleanup call. The perf reader
// must have at least one MonitorListener (since it started) so no cancel is called.
// If it doesn't, the cancel is the correct behavior (the older generation
// cancel must have been called for us to get this far anyway).
type Monitor struct {
	lock.Mutex
	models.MonitorStatus

	ctx              context.Context
	perfReaderCancel context.CancelFunc
	listeners        map[listener.MonitorListener]struct{}

	events        *ebpf.Map
	monitorEvents *perf.Reader
}

// NewMonitor creates a Monitor, and starts client connection handling and agent event
// handling.
// Note that the perf buffer reader is started only when listeners are
// connected.
func NewMonitor(ctx context.Context, nPages int, server1_2 net.Listener) (m *Monitor, err error) {
	// assert that we can actually connect the monitor
	path := oldBPF.MapPath(eventsMapName)
	eventsMap, err := ebpf.LoadPinnedMap(path)
	if err != nil {
		return nil, err
	}

	m = &Monitor{
		ctx:              ctx,
		listeners:        make(map[listener.MonitorListener]struct{}),
		perfReaderCancel: func() {}, // no-op to avoid doing null checks everywhere
		events:           eventsMap,
		MonitorStatus: models.MonitorStatus{
			Cpus:     int64(eventsMap.ABI().MaxEntries),
			Npages:   int64(nPages),
			Pagesize: int64(os.Getpagesize()),
		},
	}

	// start new MonitorListener handler
	go m.connectionHandler1_2(ctx, server1_2)

	return m, nil
}

// registerNewListener adds the new MonitorListener to the global list. It also spawns
// a singleton goroutine to read and distribute the events. It passes a
// cancelable context to this goroutine and the cancelFunc is assigned to
// perfReaderCancel. Note that cancelling parentCtx (e.g. on program shutdown)
// will also cancel the derived context.
func (m *Monitor) registerNewListener(parentCtx context.Context, conn net.Conn, version listener.Version) {
	m.Lock()
	defer m.Unlock()

	// If this is the first listener, start the perf reader
	if len(m.listeners) == 0 {
		m.perfReaderCancel() // don't leak any old readers, just in case.
		perfEventReaderCtx, cancel := context.WithCancel(parentCtx)
		m.perfReaderCancel = cancel
		go m.handleEvents(perfEventReaderCtx)
	}

	switch version {
	case listener.Version1_2:
		newListener := newListenerv1_2(conn, option.Config.MonitorQueueSize, m.removeListener)
		m.listeners[newListener] = struct{}{}

	default:
		conn.Close()
		log.WithField("version", version).Error("Closing new connection from unsupported monitor client version")
	}

	log.WithFields(logrus.Fields{
		"count.listener": len(m.listeners),
		"version":        version,
	}).Debug("New listener connected")
}

// removeListener deletes the MonitorListener from the list, closes its queue, and
// stops perfReader if this is the last MonitorListener
func (m *Monitor) removeListener(ml listener.MonitorListener) {
	m.Lock()
	defer m.Unlock()

	delete(m.listeners, ml)
	log.WithFields(logrus.Fields{
		"count.listener": len(m.listeners),
		"version":        ml.Version(),
	}).Debug("Removed listener")

	// If this was the final listener, shutdown the perf reader and unmap our
	// ring buffer readers. This tells the kernel to not emit this data.
	// Note: it is critical to hold the lock and check the number of listeners.
	// This guards against an older generation listener calling the
	// current generation perfReaderCancel
	if len(m.listeners) == 0 {
		m.perfReaderCancel()
	}
}

// handleEvents reads events from the perf buffer and processes them. It
// will exit when stopCtx is done. Note, however, that it will block in the
// Poll call but assumes enough events are generated that these blocks are
// short.
func (m *Monitor) handleEvents(stopCtx context.Context) {
	scopedLog := log.WithField(logfields.StartTime, time.Now())
	scopedLog.Info("Beginning to read perf buffer")
	defer scopedLog.Info("Stopped reading perf buffer")

	bufferSize := int(m.Pagesize * m.Npages)
	monitorEvents, err := perf.NewReader(m.events, bufferSize)
	if err != nil {
		scopedLog.WithError(err).Fatal("Cannot initialise BPF perf ring buffer sockets")
	}
	defer func() {
		monitorEvents.Close()
		m.Lock()
		m.monitorEvents = nil
		m.Unlock()
	}()

	m.Lock()
	m.monitorEvents = monitorEvents
	m.Unlock()

	for !isCtxDone(stopCtx) {
		record, err := monitorEvents.Read()
		switch {
		case isCtxDone(stopCtx):
			return
		case err != nil:
			if perf.IsUnknownEvent(err) {
				m.Lock()
				m.MonitorStatus.Unknown++
				m.Unlock()
			} else {
				scopedLog.WithError(err).Warn("Error received while reading from perf buffer")
				if errors.Cause(err) == unix.EBADFD {
					return
				}
			}
			continue
		}

		m.Lock()
		plType := payload.EventSample
		if record.LostSamples > 0 {
			plType = payload.RecordLost
			m.MonitorStatus.Lost += int64(record.LostSamples)
		}
		pl := payload.Payload{
			Data: record.RawSample,
			CPU:  record.CPU,
			Lost: record.LostSamples,
			Type: plType,
		}
		m.sendLocked(&pl)
		m.Unlock()
	}
}

// Status returns the current status of the monitor
func (m *Monitor) Status() *models.MonitorStatus {
	m.Lock()
	defer m.Unlock()

	if m.monitorEvents == nil {
		return nil
	}

	// Shallow-copy the structure, then return the newly allocated copy.
	status := m.MonitorStatus
	return &status
}

// connectionHandler1_2 handles all the incoming connections and sets up the
// listener objects. It will block on Accept, but expects the caller to close
// server, inducing a return.
func (m *Monitor) connectionHandler1_2(parentCtx context.Context, server net.Listener) {
	for !isCtxDone(parentCtx) {
		conn, err := server.Accept()
		switch {
		case isCtxDone(parentCtx) && conn != nil:
			conn.Close()
			fallthrough

		case isCtxDone(parentCtx) && conn == nil:
			return

		case err != nil:
			log.WithError(err).Warn("Error accepting connection")
			continue
		}

		m.registerNewListener(parentCtx, conn, listener.Version1_2)
	}
}

// send enqueues the payload to all listeners.
func (m *Monitor) send(pl *payload.Payload) {
	m.Lock()
	defer m.Unlock()
	m.sendLocked(pl)
}

// sendLocked enqueues the payload to all listeners while holding the monitor lock.
func (m *Monitor) sendLocked(pl *payload.Payload) {
	for ml := range m.listeners {
		ml.Enqueue(pl)
	}
}
<|endoftext|>


<commit_before>// Copyright 2014 Google Inc. All Rights Reserved.
//
// 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 pages

import (
	"fmt"
	"html/template"
	"net/http"

	auth "github.com/abbot/go-http-auth"
	"github.com/golang/glog"
	"github.com/google/cadvisor/info"
	"github.com/google/cadvisor/manager"
)

var pageTemplate *template.Template

type link struct {
	// Text to show in the link.
	Text string

	// Web address to link to.
	Link string
}

type pageData struct {
	DisplayName        string
	ContainerName      string
	ParentContainers   []link
	Subcontainers      []link
	Spec               info.ContainerSpec
	Stats              []*info.ContainerStats
	MachineInfo        *info.MachineInfo
	IsRoot             bool
	ResourcesAvailable bool
	CpuAvailable       bool
	MemoryAvailable    bool
	NetworkAvailable   bool
	FsAvailable        bool
}

func init() {
	pageTemplate = template.New("containersTemplate").Funcs(funcMap)
	_, err := pageTemplate.Parse(containersHtmlTemplate)
	if err != nil {
		glog.Fatalf("Failed to parse template: %s", err)
	}
}

func containerHandlerNoAuth(containerManager manager.Manager) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		err := serveContainersPage(containerManager, w, r.URL)
		if err != nil {
			fmt.Fprintf(w, "%s", err)
		}
	}
}

func containerHandler(containerManager manager.Manager) auth.AuthenticatedHandlerFunc {
	return func(w http.ResponseWriter, r *auth.AuthenticatedRequest) {
		err := serveContainersPage(containerManager, w, r.URL)
		if err != nil {
			fmt.Fprintf(w, "%s", err)
		}
	}
}

func dockerHandlerNoAuth(containerManager manager.Manager) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		err := serveDockerPage(containerManager, w, r.URL)
		if err != nil {
			fmt.Fprintf(w, "%s", err)
		}
	}
}

func dockerHandler(containerManager manager.Manager) auth.AuthenticatedHandlerFunc {
	return func(w http.ResponseWriter, r *auth.AuthenticatedRequest) {
		err := serveDockerPage(containerManager, w, r.URL)
		if err != nil {
			fmt.Fprintf(w, "%s", err)
		}
	}
}

// Register http handlers
func RegisterHandlersDigest(containerManager manager.Manager, authenticator *auth.DigestAuth) error {
	// Register the handler for the containers page.
	if authenticator != nil {
		http.HandleFunc(ContainersPage, authenticator.Wrap(containerHandler(containerManager)))
		http.HandleFunc(DockerPage, authenticator.Wrap(dockerHandler(containerManager)))
	} else {
		http.HandleFunc(ContainersPage, containerHandlerNoAuth(containerManager))
		http.HandleFunc(DockerPage, dockerHandlerNoAuth(containerManager))
	}
	return nil
}

func RegisterHandlersBasic(containerManager manager.Manager, authenticator *auth.BasicAuth) error {
	// Register the handler for the containers and docker age.
	if authenticator != nil {
		http.HandleFunc(ContainersPage, authenticator.Wrap(containerHandler(containerManager)))
		http.HandleFunc(DockerPage, authenticator.Wrap(dockerHandler(containerManager)))
	} else {
		http.HandleFunc(ContainersPage, containerHandlerNoAuth(containerManager))
		http.HandleFunc(DockerPage, dockerHandlerNoAuth(containerManager))
	}
	return nil
}

func getContainerDisplayName(cont info.ContainerReference) string {
	// Pick the shortest name of the container as the display name.
	displayName := cont.Name
	for _, alias := range cont.Aliases {
		if len(displayName) >= len(alias) {
			displayName = alias
		}
	}

	// Add the full container name to the display name.
	if displayName != cont.Name {
		displayName = fmt.Sprintf("%s (%s)", displayName, cont.Name)
	}

	return displayName
}
<commit_msg>Always use alias as display name if its available.<commit_after>// Copyright 2014 Google Inc. All Rights Reserved.
//
// 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 pages

import (
	"fmt"
	"html/template"
	"net/http"
	"strings"

	auth "github.com/abbot/go-http-auth"
	"github.com/golang/glog"
	"github.com/google/cadvisor/info"
	"github.com/google/cadvisor/manager"
)

var pageTemplate *template.Template

type link struct {
	// Text to show in the link.
	Text string

	// Web address to link to.
	Link string
}

type pageData struct {
	DisplayName        string
	ContainerName      string
	ParentContainers   []link
	Subcontainers      []link
	Spec               info.ContainerSpec
	Stats              []*info.ContainerStats
	MachineInfo        *info.MachineInfo
	IsRoot             bool
	ResourcesAvailable bool
	CpuAvailable       bool
	MemoryAvailable    bool
	NetworkAvailable   bool
	FsAvailable        bool
}

func init() {
	pageTemplate = template.New("containersTemplate").Funcs(funcMap)
	_, err := pageTemplate.Parse(containersHtmlTemplate)
	if err != nil {
		glog.Fatalf("Failed to parse template: %s", err)
	}
}

func containerHandlerNoAuth(containerManager manager.Manager) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		err := serveContainersPage(containerManager, w, r.URL)
		if err != nil {
			fmt.Fprintf(w, "%s", err)
		}
	}
}

func containerHandler(containerManager manager.Manager) auth.AuthenticatedHandlerFunc {
	return func(w http.ResponseWriter, r *auth.AuthenticatedRequest) {
		err := serveContainersPage(containerManager, w, r.URL)
		if err != nil {
			fmt.Fprintf(w, "%s", err)
		}
	}
}

func dockerHandlerNoAuth(containerManager manager.Manager) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		err := serveDockerPage(containerManager, w, r.URL)
		if err != nil {
			fmt.Fprintf(w, "%s", err)
		}
	}
}

func dockerHandler(containerManager manager.Manager) auth.AuthenticatedHandlerFunc {
	return func(w http.ResponseWriter, r *auth.AuthenticatedRequest) {
		err := serveDockerPage(containerManager, w, r.URL)
		if err != nil {
			fmt.Fprintf(w, "%s", err)
		}
	}
}

// Register http handlers
func RegisterHandlersDigest(containerManager manager.Manager, authenticator *auth.DigestAuth) error {
	// Register the handler for the containers page.
	if authenticator != nil {
		http.HandleFunc(ContainersPage, authenticator.Wrap(containerHandler(containerManager)))
		http.HandleFunc(DockerPage, authenticator.Wrap(dockerHandler(containerManager)))
	} else {
		http.HandleFunc(ContainersPage, containerHandlerNoAuth(containerManager))
		http.HandleFunc(DockerPage, dockerHandlerNoAuth(containerManager))
	}
	return nil
}

func RegisterHandlersBasic(containerManager manager.Manager, authenticator *auth.BasicAuth) error {
	// Register the handler for the containers and docker age.
	if authenticator != nil {
		http.HandleFunc(ContainersPage, authenticator.Wrap(containerHandler(containerManager)))
		http.HandleFunc(DockerPage, authenticator.Wrap(dockerHandler(containerManager)))
	} else {
		http.HandleFunc(ContainersPage, containerHandlerNoAuth(containerManager))
		http.HandleFunc(DockerPage, dockerHandlerNoAuth(containerManager))
	}
	return nil
}

func getContainerDisplayName(cont info.ContainerReference) string {
	// Pick a user-added alias as display name.
	displayName := ""
	for _, alias := range cont.Aliases {
		// ignore container id as alias.
		if strings.Contains(cont.Name, alias) {
			continue
		}
		// pick shortest display name if multiple aliases are available.
		if displayName == "" || len(displayName) >= len(alias) {
			displayName = alias
		}
	}

	if displayName == "" {
		displayName = cont.Name
	} else if len(displayName) > 50 {
		// truncate display name to fit in one line.
		displayName = displayName[:50] + "..."
	}

	// Add the full container name to the display name.
	if displayName != cont.Name {
		displayName = fmt.Sprintf("%s (%s)", displayName, cont.Name)
	}

	return displayName
}
<|endoftext|>


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

package optimize

import (
	"github.com/gonum/floats"
	"github.com/gonum/matrix/mat64"
)

// BFGS implements the Method interface to perform the Broyden–Fletcher–Goldfarb–Shanno
// optimization method with the given linesearch method. If Linesearcher is nil,
// it will be set to a reasonable default.
//
// BFGS is a quasi-Newton method that performs successive rank-one updates to
// an estimate of the inverse-Hessian of the function. It exhibits super-linear
// convergence when in proximity to a local minimum. It has memory cost that is
// O(n^2) relative to the input dimension.
type BFGS struct {
	Linesearcher Linesearcher

	ls *LinesearchMethod

	x    []float64 // location of the last major iteration
	grad []float64 // gradient at the last major iteration
	dim  int

	// Temporary memory
	y      []float64
	yVec   *mat64.Vector
	s      []float64
	sVec   *mat64.Vector
	tmp    []float64
	tmpVec *mat64.Vector

	invHess *mat64.SymDense

	first bool // Is it the first iteration (used to set the scale of the initial hessian)
}

func (b *BFGS) Init(loc *Location) (Operation, error) {
	if b.Linesearcher == nil {
		b.Linesearcher = &Bisection{}
	}
	if b.ls == nil {
		b.ls = &LinesearchMethod{}
	}
	b.ls.Linesearcher = b.Linesearcher
	b.ls.NextDirectioner = b

	return b.ls.Init(loc)
}

func (b *BFGS) Iterate(loc *Location) (Operation, error) {
	return b.ls.Iterate(loc)
}

func (b *BFGS) InitDirection(loc *Location, dir []float64) (stepSize float64) {
	dim := len(loc.X)
	b.dim = dim

	b.x = resize(b.x, dim)
	copy(b.x, loc.X)
	b.grad = resize(b.grad, dim)
	copy(b.grad, loc.Gradient)

	b.y = resize(b.y, dim)
	b.s = resize(b.s, dim)
	b.tmp = resize(b.tmp, dim)
	b.yVec = mat64.NewVector(dim, b.y)
	b.sVec = mat64.NewVector(dim, b.s)
	b.tmpVec = mat64.NewVector(dim, b.tmp)

	if b.invHess == nil || cap(b.invHess.RawSymmetric().Data) < dim*dim {
		b.invHess = mat64.NewSymDense(dim, nil)
	} else {
		b.invHess = mat64.NewSymDense(dim, b.invHess.RawSymmetric().Data[:dim*dim])
	}

	// The values of the hessian are initialized in the first call to NextDirection

	// initial direcion is just negative of gradient because the hessian is 1
	copy(dir, loc.Gradient)
	floats.Scale(-1, dir)

	b.first = true

	return 1 / floats.Norm(dir, 2)
}

func (b *BFGS) NextDirection(loc *Location, dir []float64) (stepSize float64) {
	if len(loc.X) != b.dim {
		panic("bfgs: unexpected size mismatch")
	}
	if len(loc.Gradient) != b.dim {
		panic("bfgs: unexpected size mismatch")
	}
	if len(dir) != b.dim {
		panic("bfgs: unexpected size mismatch")
	}

	// Compute the gradient difference in the last step
	// y = g_{k+1} - g_{k}
	floats.SubTo(b.y, loc.Gradient, b.grad)

	// Compute the step difference
	// s = x_{k+1} - x_{k}
	floats.SubTo(b.s, loc.X, b.x)

	sDotY := floats.Dot(b.s, b.y)
	sDotYSquared := sDotY * sDotY

	if b.first {
		// Rescale the initial hessian.
		// From: Numerical optimization, Nocedal and Wright, Page 143, Eq. 6.20 (second edition).
		yDotY := floats.Dot(b.y, b.y)
		scale := sDotY / yDotY
		for i := 0; i < len(loc.X); i++ {
			for j := 0; j < len(loc.X); j++ {
				if i == j {
					b.invHess.SetSym(i, i, scale)
				} else {
					b.invHess.SetSym(i, j, 0)
				}
			}
		}
		b.first = false
	}

	// Compute the update rule
	//     B_{k+1}^-1
	// First term is just the existing inverse hessian
	// Second term is
	//     (sk^T yk + yk^T B_k^-1 yk)(s_k sk_^T) / (sk^T yk)^2
	// Third term is
	//     B_k ^-1 y_k sk^T + s_k y_k^T B_k-1
	//
	// y_k^T B_k^-1 y_k is a scalar, and the third term is a rank-two update
	// where B_k^-1 y_k is one vector and s_k is the other. Compute the update
	// values then actually perform the rank updates.
	yBy := mat64.Inner(b.yVec, b.invHess, b.yVec)
	firstTermConst := (sDotY + yBy) / (sDotYSquared)
	b.tmpVec.MulVec(b.invHess, b.yVec)

	b.invHess.RankTwo(b.invHess, -1/sDotY, b.tmpVec, b.sVec)
	b.invHess.SymRankOne(b.invHess, firstTermConst, b.sVec)

	// update the bfgs stored data to the new iteration
	copy(b.x, loc.X)
	copy(b.grad, loc.Gradient)

	// Compute the new search direction
	d := mat64.NewVector(b.dim, dir)
	g := mat64.NewVector(b.dim, loc.Gradient)

	d.MulVec(b.invHess, g) // new direction stored in place
	floats.Scale(-1, dir)
	return 1
}

func (*BFGS) Needs() struct {
	Gradient bool
	Hessian  bool
} {
	return struct {
		Gradient bool
		Hessian  bool
	}{true, false}
}
<commit_msg>Initialize only the upper half of the Hessian<commit_after>// Copyright ©2014 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package optimize

import (
	"github.com/gonum/floats"
	"github.com/gonum/matrix/mat64"
)

// BFGS implements the Method interface to perform the Broyden–Fletcher–Goldfarb–Shanno
// optimization method with the given linesearch method. If Linesearcher is nil,
// it will be set to a reasonable default.
//
// BFGS is a quasi-Newton method that performs successive rank-one updates to
// an estimate of the inverse-Hessian of the function. It exhibits super-linear
// convergence when in proximity to a local minimum. It has memory cost that is
// O(n^2) relative to the input dimension.
type BFGS struct {
	Linesearcher Linesearcher

	ls *LinesearchMethod

	x    []float64 // location of the last major iteration
	grad []float64 // gradient at the last major iteration
	dim  int

	// Temporary memory
	y      []float64
	yVec   *mat64.Vector
	s      []float64
	sVec   *mat64.Vector
	tmp    []float64
	tmpVec *mat64.Vector

	invHess *mat64.SymDense

	first bool // Is it the first iteration (used to set the scale of the initial hessian)
}

func (b *BFGS) Init(loc *Location) (Operation, error) {
	if b.Linesearcher == nil {
		b.Linesearcher = &Bisection{}
	}
	if b.ls == nil {
		b.ls = &LinesearchMethod{}
	}
	b.ls.Linesearcher = b.Linesearcher
	b.ls.NextDirectioner = b

	return b.ls.Init(loc)
}

func (b *BFGS) Iterate(loc *Location) (Operation, error) {
	return b.ls.Iterate(loc)
}

func (b *BFGS) InitDirection(loc *Location, dir []float64) (stepSize float64) {
	dim := len(loc.X)
	b.dim = dim

	b.x = resize(b.x, dim)
	copy(b.x, loc.X)
	b.grad = resize(b.grad, dim)
	copy(b.grad, loc.Gradient)

	b.y = resize(b.y, dim)
	b.s = resize(b.s, dim)
	b.tmp = resize(b.tmp, dim)
	b.yVec = mat64.NewVector(dim, b.y)
	b.sVec = mat64.NewVector(dim, b.s)
	b.tmpVec = mat64.NewVector(dim, b.tmp)

	if b.invHess == nil || cap(b.invHess.RawSymmetric().Data) < dim*dim {
		b.invHess = mat64.NewSymDense(dim, nil)
	} else {
		b.invHess = mat64.NewSymDense(dim, b.invHess.RawSymmetric().Data[:dim*dim])
	}

	// The values of the hessian are initialized in the first call to NextDirection

	// initial direcion is just negative of gradient because the hessian is 1
	copy(dir, loc.Gradient)
	floats.Scale(-1, dir)

	b.first = true

	return 1 / floats.Norm(dir, 2)
}

func (b *BFGS) NextDirection(loc *Location, dir []float64) (stepSize float64) {
	if len(loc.X) != b.dim {
		panic("bfgs: unexpected size mismatch")
	}
	if len(loc.Gradient) != b.dim {
		panic("bfgs: unexpected size mismatch")
	}
	if len(dir) != b.dim {
		panic("bfgs: unexpected size mismatch")
	}

	// Compute the gradient difference in the last step
	// y = g_{k+1} - g_{k}
	floats.SubTo(b.y, loc.Gradient, b.grad)

	// Compute the step difference
	// s = x_{k+1} - x_{k}
	floats.SubTo(b.s, loc.X, b.x)

	sDotY := floats.Dot(b.s, b.y)
	sDotYSquared := sDotY * sDotY

	if b.first {
		// Rescale the initial hessian.
		// From: Numerical optimization, Nocedal and Wright, Page 143, Eq. 6.20 (second edition).
		yDotY := floats.Dot(b.y, b.y)
		scale := sDotY / yDotY
		for i := 0; i < len(loc.X); i++ {
			for j := i; j < len(loc.X); j++ {
				if i == j {
					b.invHess.SetSym(i, i, scale)
				} else {
					b.invHess.SetSym(i, j, 0)
				}
			}
		}
		b.first = false
	}

	// Compute the update rule
	//     B_{k+1}^-1
	// First term is just the existing inverse hessian
	// Second term is
	//     (sk^T yk + yk^T B_k^-1 yk)(s_k sk_^T) / (sk^T yk)^2
	// Third term is
	//     B_k ^-1 y_k sk^T + s_k y_k^T B_k-1
	//
	// y_k^T B_k^-1 y_k is a scalar, and the third term is a rank-two update
	// where B_k^-1 y_k is one vector and s_k is the other. Compute the update
	// values then actually perform the rank updates.
	yBy := mat64.Inner(b.yVec, b.invHess, b.yVec)
	firstTermConst := (sDotY + yBy) / (sDotYSquared)
	b.tmpVec.MulVec(b.invHess, b.yVec)

	b.invHess.RankTwo(b.invHess, -1/sDotY, b.tmpVec, b.sVec)
	b.invHess.SymRankOne(b.invHess, firstTermConst, b.sVec)

	// update the bfgs stored data to the new iteration
	copy(b.x, loc.X)
	copy(b.grad, loc.Gradient)

	// Compute the new search direction
	d := mat64.NewVector(b.dim, dir)
	g := mat64.NewVector(b.dim, loc.Gradient)

	d.MulVec(b.invHess, g) // new direction stored in place
	floats.Scale(-1, dir)
	return 1
}

func (*BFGS) Needs() struct {
	Gradient bool
	Hessian  bool
} {
	return struct {
		Gradient bool
		Hessian  bool
	}{true, false}
}
<|endoftext|>


<commit_before>// +build windows

package disk

import (
	"bytes"
	"context"
	"unsafe"

	"github.com/shirou/gopsutil/internal/common"
	"golang.org/x/sys/windows"
)

var (
	procGetDiskFreeSpaceExW     = common.Modkernel32.NewProc("GetDiskFreeSpaceExW")
	procGetLogicalDriveStringsW = common.Modkernel32.NewProc("GetLogicalDriveStringsW")
	procGetDriveType            = common.Modkernel32.NewProc("GetDriveTypeW")
	procGetVolumeInformation    = common.Modkernel32.NewProc("GetVolumeInformationW")
)

var (
	FileFileCompression = int64(16)     // 0x00000010
	FileReadOnlyVolume  = int64(524288) // 0x00080000
)

type Win32_PerfFormattedData struct {
	Name                    string
	AvgDiskBytesPerRead     uint64
	AvgDiskBytesPerWrite    uint64
	AvgDiskReadQueueLength  uint64
	AvgDiskWriteQueueLength uint64
	AvgDisksecPerRead       uint64
	AvgDisksecPerWrite      uint64
}

const WaitMSec = 500

func Usage(path string) (*UsageStat, error) {
	return UsageWithContext(context.Background(), path)
}

func UsageWithContext(ctx context.Context, path string) (*UsageStat, error) {
	ret := &UsageStat{}

	lpFreeBytesAvailable := int64(0)
	lpTotalNumberOfBytes := int64(0)
	lpTotalNumberOfFreeBytes := int64(0)
	diskret, _, err := procGetDiskFreeSpaceExW.Call(
		uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(path))),
		uintptr(unsafe.Pointer(&lpFreeBytesAvailable)),
		uintptr(unsafe.Pointer(&lpTotalNumberOfBytes)),
		uintptr(unsafe.Pointer(&lpTotalNumberOfFreeBytes)))
	if diskret == 0 {
		return nil, err
	}
	ret = &UsageStat{
		Path:        path,
		Total:       uint64(lpTotalNumberOfBytes),
		Free:        uint64(lpTotalNumberOfFreeBytes),
		Used:        uint64(lpTotalNumberOfBytes) - uint64(lpTotalNumberOfFreeBytes),
		UsedPercent: (float64(lpTotalNumberOfBytes) - float64(lpTotalNumberOfFreeBytes)) / float64(lpTotalNumberOfBytes) * 100,
		// InodesTotal: 0,
		// InodesFree: 0,
		// InodesUsed: 0,
		// InodesUsedPercent: 0,
	}
	return ret, nil
}

func Partitions(all bool) ([]PartitionStat, error) {
	return PartitionsWithContext(context.Background(), all)
}

func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, error) {
	var ret []PartitionStat
	lpBuffer := make([]byte, 254)
	diskret, _, err := procGetLogicalDriveStringsW.Call(
		uintptr(len(lpBuffer)),
		uintptr(unsafe.Pointer(&lpBuffer[0])))
	if diskret == 0 {
		return ret, err
	}
	for _, v := range lpBuffer {
		if v >= 65 && v <= 90 {
			path := string(v) + ":"
			typepath, _ := windows.UTF16PtrFromString(path)
			typeret, _, _ := procGetDriveType.Call(uintptr(unsafe.Pointer(typepath)))
			if typeret == 0 {
				return ret, windows.GetLastError()
			}
			// 2: DRIVE_REMOVABLE 3: DRIVE_FIXED 4: DRIVE_REMOTE 5: DRIVE_CDROM

			if typeret == 2 || typeret == 3 || typeret == 4 || typeret == 5 {
				lpVolumeNameBuffer := make([]byte, 256)
				lpVolumeSerialNumber := int64(0)
				lpMaximumComponentLength := int64(0)
				lpFileSystemFlags := int64(0)
				lpFileSystemNameBuffer := make([]byte, 256)
				volpath, _ := windows.UTF16PtrFromString(string(v) + ":/")
				driveret, _, err := procGetVolumeInformation.Call(
					uintptr(unsafe.Pointer(volpath)),
					uintptr(unsafe.Pointer(&lpVolumeNameBuffer[0])),
					uintptr(len(lpVolumeNameBuffer)),
					uintptr(unsafe.Pointer(&lpVolumeSerialNumber)),
					uintptr(unsafe.Pointer(&lpMaximumComponentLength)),
					uintptr(unsafe.Pointer(&lpFileSystemFlags)),
					uintptr(unsafe.Pointer(&lpFileSystemNameBuffer[0])),
					uintptr(len(lpFileSystemNameBuffer)))
				if driveret == 0 {
					if typeret == 5 || typeret == 2 {
						continue //device is not ready will happen if there is no disk in the drive
					}
					return ret, err
				}
				opts := "rw"
				if lpFileSystemFlags&FileReadOnlyVolume != 0 {
					opts = "ro"
				}
				if lpFileSystemFlags&FileFileCompression != 0 {
					opts += ".compress"
				}

				d := PartitionStat{
					Mountpoint: path,
					Device:     path,
					Fstype:     string(bytes.Replace(lpFileSystemNameBuffer, []byte("\x00"), []byte(""), -1)),
					Opts:       opts,
				}
				ret = append(ret, d)
			}
		}
	}
	return ret, nil
}

func IOCounters(names ...string) (map[string]IOCountersStat, error) {
	return IOCountersWithContext(context.Background(), names...)
}

func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) {
	ret := make(map[string]IOCountersStat, 0)
	var dst []Win32_PerfFormattedData

	err := common.WMIQueryWithContext(ctx, "SELECT * FROM Win32_PerfFormattedData_PerfDisk_LogicalDisk", &dst)
	if err != nil {
		return ret, err
	}
	for _, d := range dst {
		if len(d.Name) > 3 { // not get _Total or Harddrive
			continue
		}

		if len(names) > 0 && !common.StringsHas(names, d.Name) {
			continue
		}

		ret[d.Name] = IOCountersStat{
			Name:       d.Name,
			ReadCount:  uint64(d.AvgDiskReadQueueLength),
			WriteCount: d.AvgDiskWriteQueueLength,
			ReadBytes:  uint64(d.AvgDiskBytesPerRead),
			WriteBytes: uint64(d.AvgDiskBytesPerWrite),
			ReadTime:   d.AvgDisksecPerRead,
			WriteTime:  d.AvgDisksecPerWrite,
		}
	}
	return ret, nil
}
<commit_msg>[disk][windows]: does not define ret at begining of the function.<commit_after>// +build windows

package disk

import (
	"bytes"
	"context"
	"unsafe"

	"github.com/shirou/gopsutil/internal/common"
	"golang.org/x/sys/windows"
)

var (
	procGetDiskFreeSpaceExW     = common.Modkernel32.NewProc("GetDiskFreeSpaceExW")
	procGetLogicalDriveStringsW = common.Modkernel32.NewProc("GetLogicalDriveStringsW")
	procGetDriveType            = common.Modkernel32.NewProc("GetDriveTypeW")
	procGetVolumeInformation    = common.Modkernel32.NewProc("GetVolumeInformationW")
)

var (
	FileFileCompression = int64(16)     // 0x00000010
	FileReadOnlyVolume  = int64(524288) // 0x00080000
)

type Win32_PerfFormattedData struct {
	Name                    string
	AvgDiskBytesPerRead     uint64
	AvgDiskBytesPerWrite    uint64
	AvgDiskReadQueueLength  uint64
	AvgDiskWriteQueueLength uint64
	AvgDisksecPerRead       uint64
	AvgDisksecPerWrite      uint64
}

const WaitMSec = 500

func Usage(path string) (*UsageStat, error) {
	return UsageWithContext(context.Background(), path)
}

func UsageWithContext(ctx context.Context, path string) (*UsageStat, error) {
	lpFreeBytesAvailable := int64(0)
	lpTotalNumberOfBytes := int64(0)
	lpTotalNumberOfFreeBytes := int64(0)
	diskret, _, err := procGetDiskFreeSpaceExW.Call(
		uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(path))),
		uintptr(unsafe.Pointer(&lpFreeBytesAvailable)),
		uintptr(unsafe.Pointer(&lpTotalNumberOfBytes)),
		uintptr(unsafe.Pointer(&lpTotalNumberOfFreeBytes)))
	if diskret == 0 {
		return nil, err
	}
	ret := &UsageStat{
		Path:        path,
		Total:       uint64(lpTotalNumberOfBytes),
		Free:        uint64(lpTotalNumberOfFreeBytes),
		Used:        uint64(lpTotalNumberOfBytes) - uint64(lpTotalNumberOfFreeBytes),
		UsedPercent: (float64(lpTotalNumberOfBytes) - float64(lpTotalNumberOfFreeBytes)) / float64(lpTotalNumberOfBytes) * 100,
		// InodesTotal: 0,
		// InodesFree: 0,
		// InodesUsed: 0,
		// InodesUsedPercent: 0,
	}
	return ret, nil
}

func Partitions(all bool) ([]PartitionStat, error) {
	return PartitionsWithContext(context.Background(), all)
}

func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, error) {
	var ret []PartitionStat
	lpBuffer := make([]byte, 254)
	diskret, _, err := procGetLogicalDriveStringsW.Call(
		uintptr(len(lpBuffer)),
		uintptr(unsafe.Pointer(&lpBuffer[0])))
	if diskret == 0 {
		return ret, err
	}
	for _, v := range lpBuffer {
		if v >= 65 && v <= 90 {
			path := string(v) + ":"
			typepath, _ := windows.UTF16PtrFromString(path)
			typeret, _, _ := procGetDriveType.Call(uintptr(unsafe.Pointer(typepath)))
			if typeret == 0 {
				return ret, windows.GetLastError()
			}
			// 2: DRIVE_REMOVABLE 3: DRIVE_FIXED 4: DRIVE_REMOTE 5: DRIVE_CDROM

			if typeret == 2 || typeret == 3 || typeret == 4 || typeret == 5 {
				lpVolumeNameBuffer := make([]byte, 256)
				lpVolumeSerialNumber := int64(0)
				lpMaximumComponentLength := int64(0)
				lpFileSystemFlags := int64(0)
				lpFileSystemNameBuffer := make([]byte, 256)
				volpath, _ := windows.UTF16PtrFromString(string(v) + ":/")
				driveret, _, err := procGetVolumeInformation.Call(
					uintptr(unsafe.Pointer(volpath)),
					uintptr(unsafe.Pointer(&lpVolumeNameBuffer[0])),
					uintptr(len(lpVolumeNameBuffer)),
					uintptr(unsafe.Pointer(&lpVolumeSerialNumber)),
					uintptr(unsafe.Pointer(&lpMaximumComponentLength)),
					uintptr(unsafe.Pointer(&lpFileSystemFlags)),
					uintptr(unsafe.Pointer(&lpFileSystemNameBuffer[0])),
					uintptr(len(lpFileSystemNameBuffer)))
				if driveret == 0 {
					if typeret == 5 || typeret == 2 {
						continue //device is not ready will happen if there is no disk in the drive
					}
					return ret, err
				}
				opts := "rw"
				if lpFileSystemFlags&FileReadOnlyVolume != 0 {
					opts = "ro"
				}
				if lpFileSystemFlags&FileFileCompression != 0 {
					opts += ".compress"
				}

				d := PartitionStat{
					Mountpoint: path,
					Device:     path,
					Fstype:     string(bytes.Replace(lpFileSystemNameBuffer, []byte("\x00"), []byte(""), -1)),
					Opts:       opts,
				}
				ret = append(ret, d)
			}
		}
	}
	return ret, nil
}

func IOCounters(names ...string) (map[string]IOCountersStat, error) {
	return IOCountersWithContext(context.Background(), names...)
}

func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) {
	ret := make(map[string]IOCountersStat, 0)
	var dst []Win32_PerfFormattedData

	err := common.WMIQueryWithContext(ctx, "SELECT * FROM Win32_PerfFormattedData_PerfDisk_LogicalDisk", &dst)
	if err != nil {
		return ret, err
	}
	for _, d := range dst {
		if len(d.Name) > 3 { // not get _Total or Harddrive
			continue
		}

		if len(names) > 0 && !common.StringsHas(names, d.Name) {
			continue
		}

		ret[d.Name] = IOCountersStat{
			Name:       d.Name,
			ReadCount:  uint64(d.AvgDiskReadQueueLength),
			WriteCount: d.AvgDiskWriteQueueLength,
			ReadBytes:  uint64(d.AvgDiskBytesPerRead),
			WriteBytes: uint64(d.AvgDiskBytesPerWrite),
			ReadTime:   d.AvgDisksecPerRead,
			WriteTime:  d.AvgDisksecPerWrite,
		}
	}
	return ret, nil
}
<|endoftext|>


<commit_before>package native

import (
	"testing"

	"github.com/CyCoreSystems/ari"
	"github.com/CyCoreSystems/ari/internal/dockertest"
)

func createClientURL(t *testing.T, baseURL string) (*ari.Client, bool) {
	client, err := New(&Options{
		Application:  "",
		URL:          baseURL,
		WebsocketURL: baseURL + "/events",
		Username:     "admin",
		Password:     "admin",
	})
	if err != nil {
		t.Errorf("Error building connection: %s", err)
		return nil, false
	}

	return client, true
}

func TestApplication(t *testing.T) {

	// start asterisk in docker container
	url, deferFn, err := dockertest.StartAsterisk()
	if err != nil {
		t.Fatalf("cannot start asterisk in container for testing: %s", err)
	}
	defer deferFn()

	client, ok := createClientURL(t, url)
	if !ok {
		return
	}

	_, err = client.Application.Data("")
	if err == nil {
		t.Errorf("Expected error getting zero-length application")
	}

	_, err = client.Application.Data("test")
	if err == nil {
		t.Errorf("Expected error getting application 'test'")
	}
}
<commit_msg>v3 - native client - Add Application List test<commit_after>package native

import (
	"testing"

	"github.com/CyCoreSystems/ari"
	"github.com/CyCoreSystems/ari/internal/dockertest"
)

func createClientURL(t *testing.T, baseURL string) (*ari.Client, bool) {
	client, err := New(&Options{
		Application:  "",
		URL:          baseURL,
		WebsocketURL: baseURL + "/events",
		Username:     "admin",
		Password:     "admin",
	})
	if err != nil {
		t.Errorf("Error building connection: %s", err)
		return nil, false
	}

	return client, true
}

func TestApplicationData(t *testing.T) {

	// start asterisk in docker container
	url, deferFn, err := dockertest.StartAsterisk()
	if err != nil {
		t.Fatalf("cannot start asterisk in container for testing: %s", err)
	}
	defer deferFn()

	client, ok := createClientURL(t, url)
	if !ok {
		return
	}

	_, err = client.Application.Data("")
	if err == nil {
		t.Errorf("Expected error getting zero-length application")
	}

	_, err = client.Application.Data("test")
	if err == nil {
		t.Errorf("Expected error getting application 'test'")
	}

	//TODO: populate data, attempt a valid get
}

func TestApplicationList(t *testing.T) {

	// start asterisk in docker container
	url, deferFn, err := dockertest.StartAsterisk()
	if err != nil {
		t.Fatalf("cannot start asterisk in container for testing: %s", err)
	}
	defer deferFn()

	client, ok := createClientURL(t, url)
	if !ok {
		return
	}

	l, err := client.Application.List()
	if err != nil {
		t.Errorf("Unexpected error: %s", err)
	}

	if len(l) != 0 {
		t.Errorf("Expected list to be empty, was '%+v'", l)
	}

	//TODO: populate list of apps, attempt a valid List
}
<|endoftext|>


<commit_before>package git

/*
#include <git2.h>
#include <string.h>

extern int _go_git_blob_create_fromchunks(git_oid *id,
	git_repository *repo,
	const char *hintpath,
	void *payload);

*/
import "C"
import (
	"io"
	"runtime"
	"unsafe"
)

type Blob struct {
	gitObject
	cast_ptr *C.git_blob
}

func (v *Blob) Size() int64 {
	return int64(C.git_blob_rawsize(v.cast_ptr))
}

func (v *Blob) Contents() []byte {
	size := C.int(C.git_blob_rawsize(v.cast_ptr))
	buffer := unsafe.Pointer(C.git_blob_rawcontent(v.cast_ptr))
	return C.GoBytes(buffer, size)
}

func (repo *Repository) CreateBlobFromBuffer(data []byte) (*Oid, error) {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	var id C.git_oid
	var ptr unsafe.Pointer

	if len(data) > 0 {
		ptr = unsafe.Pointer(&data[0])
	} else {
		ptr = unsafe.Pointer(nil)
	}

	ecode := C.git_blob_create_frombuffer(&id, repo.ptr, ptr, C.size_t(len(data)))
	if ecode < 0 {
		return nil, MakeGitError(ecode)
	}
	return newOidFromC(&id), nil
}

type BlobChunkCallback func(maxLen int) ([]byte, error)

type BlobCallbackData struct {
	Callback BlobChunkCallback
	Error    error
}

//export blobChunkCb
func blobChunkCb(buffer *C.char, maxLen C.size_t, handle unsafe.Pointer) int {
	payload := pointerHandles.Get(handle)
	data, ok := payload.(*BlobCallbackData)
	if !ok {
		panic("could not retrieve blob callback data")
	}

	goBuf, err := data.Callback(int(maxLen))
	if err == io.EOF {
		return 0
	} else if err != nil {
		data.Error = err
		return -1
	}
	C.memcpy(unsafe.Pointer(buffer), unsafe.Pointer(&goBuf[0]), C.size_t(len(goBuf)))
	return len(goBuf)
}

func (repo *Repository) CreateBlobFromChunks(hintPath string, callback BlobChunkCallback) (*Oid, error) {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	var chintPath *C.char = nil
	if len(hintPath) > 0 {
		C.CString(hintPath)
		defer C.free(unsafe.Pointer(chintPath))
	}
	oid := C.git_oid{}

	payload := &BlobCallbackData{Callback: callback}
	handle := pointerHandles.Track(payload)
	defer pointerHandles.Untrack(handle)

	ecode := C._go_git_blob_create_fromchunks(&oid, repo.ptr, chintPath, handle)
	if payload.Error != nil {
		return nil, payload.Error
	}
	if ecode < 0 {
		return nil, MakeGitError(ecode)
	}
	return newOidFromC(&oid), nil
}
<commit_msg>Don't drop CreateBlobFromChunks hintPath argument<commit_after>package git

/*
#include <git2.h>
#include <string.h>

extern int _go_git_blob_create_fromchunks(git_oid *id,
	git_repository *repo,
	const char *hintpath,
	void *payload);

*/
import "C"
import (
	"io"
	"runtime"
	"unsafe"
)

type Blob struct {
	gitObject
	cast_ptr *C.git_blob
}

func (v *Blob) Size() int64 {
	return int64(C.git_blob_rawsize(v.cast_ptr))
}

func (v *Blob) Contents() []byte {
	size := C.int(C.git_blob_rawsize(v.cast_ptr))
	buffer := unsafe.Pointer(C.git_blob_rawcontent(v.cast_ptr))
	return C.GoBytes(buffer, size)
}

func (repo *Repository) CreateBlobFromBuffer(data []byte) (*Oid, error) {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	var id C.git_oid
	var ptr unsafe.Pointer

	if len(data) > 0 {
		ptr = unsafe.Pointer(&data[0])
	} else {
		ptr = unsafe.Pointer(nil)
	}

	ecode := C.git_blob_create_frombuffer(&id, repo.ptr, ptr, C.size_t(len(data)))
	if ecode < 0 {
		return nil, MakeGitError(ecode)
	}
	return newOidFromC(&id), nil
}

type BlobChunkCallback func(maxLen int) ([]byte, error)

type BlobCallbackData struct {
	Callback BlobChunkCallback
	Error    error
}

//export blobChunkCb
func blobChunkCb(buffer *C.char, maxLen C.size_t, handle unsafe.Pointer) int {
	payload := pointerHandles.Get(handle)
	data, ok := payload.(*BlobCallbackData)
	if !ok {
		panic("could not retrieve blob callback data")
	}

	goBuf, err := data.Callback(int(maxLen))
	if err == io.EOF {
		return 0
	} else if err != nil {
		data.Error = err
		return -1
	}
	C.memcpy(unsafe.Pointer(buffer), unsafe.Pointer(&goBuf[0]), C.size_t(len(goBuf)))
	return len(goBuf)
}

func (repo *Repository) CreateBlobFromChunks(hintPath string, callback BlobChunkCallback) (*Oid, error) {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	var chintPath *C.char = nil
	if len(hintPath) > 0 {
		chintPath = C.CString(hintPath)
		defer C.free(unsafe.Pointer(chintPath))
	}
	oid := C.git_oid{}

	payload := &BlobCallbackData{Callback: callback}
	handle := pointerHandles.Track(payload)
	defer pointerHandles.Untrack(handle)

	ecode := C._go_git_blob_create_fromchunks(&oid, repo.ptr, chintPath, handle)
	if payload.Error != nil {
		return nil, payload.Error
	}
	if ecode < 0 {
		return nil, MakeGitError(ecode)
	}
	return newOidFromC(&oid), nil
}
<|endoftext|>


<commit_before>package toystore

import (
	"log"
	"net/rpc"
	"time"

	"github.com/rlayte/toystore/data"
)

type PeerClient interface {
	Get(address string, key string) (value *data.Data, status bool)
	Put(address string, value *data.Data) (status bool)
	CoordinateGet(address string, key string) (value *data.Data, status bool)
	CoordinatePut(address string, value *data.Data) (status bool)
	HintPut(address string, hint string, value *data.Data) (status bool)
	Transfer(address string, data []*data.Data) (status bool)
}

func dial(address string) *rpc.Client {
	var err error
	var conn *rpc.Client
	success := make(chan *rpc.Client)

	go func() {
		conn, err = rpc.Dial("tcp", address)

		for err != nil {
			conn, err = rpc.Dial("tcp", address)
			time.Sleep(time.Second / 3)
		}

		success <- conn
	}()

	select {
	case conn := <-success:
		return conn
	case <-time.After(time.Second):
		panic(err)
		return nil
	}
}

func call(address string, method string, args interface{}, reply interface{}) bool {
	conn := dial(address)

	err := conn.Call(method, args, reply)
	conn.Close()

	if err != nil {
		return false
	}

	return true
}

type RPCPeerClient struct {
}

func (r *RPCPeerClient) Get(address string, key string) (*data.Data, bool) {
	args := &GetArgs{key}
	reply := &GetReply{}

	call(address, "RpcHandler.Get", args, reply)

	return reply.Value, reply.Ok
}

func (r *RPCPeerClient) Put(address string, value *data.Data) bool {
	args := &PutArgs{value}
	reply := &PutReply{}

	call(address, "RpcHandler.Put", args, reply)

	return reply.Ok
}

func (r *RPCPeerClient) CoordinateGet(address string, key string) (*data.Data, bool) {
	log.Printf("Forwarding GET request to %s for %s", address, key)
	args := &GetArgs{key}
	reply := &GetReply{}

	call(address, "RpcHandler.CoordinateGet", args, reply)

	return reply.Value, reply.Ok
}

func (r *RPCPeerClient) CoordinatePut(address string, value *data.Data) bool {
	log.Printf("Forwarding PUT request to coordinator %s for %s", address, value.Key)

	args := &PutArgs{value}
	reply := &PutReply{}

	call(address, "RpcHandler.CoordinatePut", args, reply)

	return reply.Ok
}

func (r *RPCPeerClient) HintPut(address string, hint string, data *data.Data) bool {
	log.Printf("Sending hint to %s for %s (%s)", address, hint, data)

	args := &HintArgs{data, hint}
	reply := &HintReply{}

	call(address, "RpcHandler.HintPut", args, reply)

	return reply.Ok
}

func (r *RPCPeerClient) Transfer(address string, data []*data.Data) bool {
	log.Printf("Transferring data to %s - %v", address, data)
	args := &TransferArgs{data}
	reply := &TransferReply{}

	call(address, "RpcHandler.Transfer", args, reply)

	return reply.Ok
}

func NewRpcClient() *RPCPeerClient {
	return &RPCPeerClient{}
}
<commit_msg>Add docs for peer_client<commit_after>package toystore

import (
	"log"
	"net/rpc"
	"time"

	"github.com/rlayte/toystore/data"
)

// PeerClient defines the possible interactions between nodes in the cluster.
// Should be implemented with a specific transport client.
type PeerClient interface {
	Get(address string, key string) (value *data.Data, status bool)
	Put(address string, value *data.Data) (status bool)
	CoordinateGet(address string, key string) (value *data.Data, status bool)
	CoordinatePut(address string, value *data.Data) (status bool)
	HintPut(address string, hint string, value *data.Data) (status bool)
	Transfer(address string, data []*data.Data) (status bool)
}

// dial attempts to connect to a specified RPC server.
// It will retry every 1/3 seconds if connection fails.
// If it can't connect within 1 second it aborts and panics.
func dial(address string) *rpc.Client {
	var err error
	var conn *rpc.Client
	success := make(chan *rpc.Client)

	go func() {
		conn, err = rpc.Dial("tcp", address)

		for err != nil {
			conn, err = rpc.Dial("tcp", address)
			time.Sleep(time.Second / 3)
		}

		success <- conn
	}()

	select {
	case conn := <-success:
		return conn
	case <-time.After(time.Second):
		panic(err)
		return nil
	}
}

// call attempts to make an RPC.
// If the connection fails it returns false, otherwise true.
func call(address string, method string, args interface{}, reply interface{}) bool {
	conn := dial(address)

	err := conn.Call(method, args, reply)
	conn.Close()

	if err != nil {
		return false
	}

	return true
}

// RpcClient implements PeerClient using Go's RPC package.
type RpcClient struct {
}

// Get makes an RPC to the address to find the specified key and returns
// the value and an existence bool.
func (r *RpcClient) Get(address string, key string) (*data.Data, bool) {
	args := &GetArgs{key}
	reply := &GetReply{}

	call(address, "RpcHandler.Get", args, reply)

	return reply.Value, reply.Ok
}

// Put makes an RPC to the address to add the Data value and returns a boolean
// representing the status of this operation.
func (r *RpcClient) Put(address string, value *data.Data) bool {
	args := &PutArgs{value}
	reply := &PutReply{}

	call(address, "RpcHandler.Put", args, reply)

	return reply.Ok
}

// CoordinateGet forwards the key to the coordinating node so it can organize
// the Get operation.
func (r *RpcClient) CoordinateGet(address string, key string) (*data.Data, bool) {
	log.Printf("Forwarding GET request to %s for %s", address, key)
	args := &GetArgs{key}
	reply := &GetReply{}

	call(address, "RpcHandler.CoordinateGet", args, reply)

	return reply.Value, reply.Ok
}

// CoordinatePut forwards the Data value to the coordinating node so it can organize
// the Put operation.
func (r *RpcClient) CoordinatePut(address string, value *data.Data) bool {
	log.Printf("Forwarding PUT request to coordinator %s for %s", address, value.Key)

	args := &PutArgs{value}
	reply := &PutReply{}

	call(address, "RpcHandler.CoordinatePut", args, reply)

	return reply.Ok
}

// HintPut makes an RPC to add hint data to the specified node.
func (r *RpcClient) HintPut(address string, hint string, data *data.Data) bool {
	log.Printf("Sending hint to %s for %s (%s)", address, hint, data)

	args := &HintArgs{data, hint}
	reply := &HintReply{}

	call(address, "RpcHandler.HintPut", args, reply)

	return reply.Ok
}

// Transfer makes an RPC call to send a set of keys to the specified address.
func (r *RpcClient) Transfer(address string, data []*data.Data) bool {
	log.Printf("Transferring data to %s - %v", address, data)
	args := &TransferArgs{data}
	reply := &TransferReply{}

	call(address, "RpcHandler.Transfer", args, reply)

	return reply.Ok
}

// NewRpcClient returns a new RpcClient instance.
func NewRpcClient() *RpcClient {
	return &RpcClient{}
}
<|endoftext|>


<commit_before>// +build !linux,!windows

/*
Copyright 2014 The Kubernetes Authors.

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

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

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

package mount

import (
	"errors"
)

// Mounter implements mount.Interface for unsupported platforms
type Mounter struct {
	mounterPath string
}

var errUnsupported = errors.New("util/mount on this platform is not supported")

// New returns a mount.Interface for the current system.
// It provides options to override the default mounter behavior.
// mounterPath allows using an alternative to `/bin/mount` for mounting.
func New(mounterPath string) Interface {
	return &Mounter{
		mounterPath: mounterPath,
	}
}

// Mount always returns an error on unsupported platforms
func (mounter *Mounter) Mount(source string, target string, fstype string, options []string) error {
	return errUnsupported
}

// MountSensitive always returns an error on unsupported platforms
func (mounter *Mounter) MountSensitive(source string, target string, fstype string, options []string, sensitiveOptions []string) error {
	return errUnsupported
}

// MountSensitiveWithoutSystemd always returns an error on unsupported platforms
func (mounter *Mounter) MountSensitiveWithoutSystemd(source string, target string, fstype string, options []string, sensitiveOptions []string) error {
	return errUnsupported
}

// Unmount always returns an error on unsupported platforms
func (mounter *Mounter) Unmount(target string) error {
	return errUnsupported
}

// List always returns an error on unsupported platforms
func (mounter *Mounter) List() ([]MountPoint, error) {
	return []MountPoint{}, errUnsupported
}

// IsLikelyNotMountPoint always returns an error on unsupported platforms
func (mounter *Mounter) IsLikelyNotMountPoint(file string) (bool, error) {
	return true, errUnsupported
}

// GetMountRefs always returns an error on unsupported platforms
func (mounter *Mounter) GetMountRefs(pathname string) ([]string, error) {
	return nil, errUnsupported
}

func (mounter *SafeFormatAndMount) formatAndMountSensitive(source string, target string, fstype string, options []string, sensitiveOptions []string) error {
	return mounter.Interface.Mount(source, target, fstype, options)
}

func (mounter *SafeFormatAndMount) diskLooksUnformatted(disk string) (bool, error) {
	return true, errUnsupported
}
<commit_msg>Add missing interface method in mount_unsupported.go<commit_after>// +build !linux,!windows

/*
Copyright 2014 The Kubernetes Authors.

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

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

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

package mount

import (
	"errors"
)

// Mounter implements mount.Interface for unsupported platforms
type Mounter struct {
	mounterPath string
}

var errUnsupported = errors.New("util/mount on this platform is not supported")

// New returns a mount.Interface for the current system.
// It provides options to override the default mounter behavior.
// mounterPath allows using an alternative to `/bin/mount` for mounting.
func New(mounterPath string) Interface {
	return &Mounter{
		mounterPath: mounterPath,
	}
}

// Mount always returns an error on unsupported platforms
func (mounter *Mounter) Mount(source string, target string, fstype string, options []string) error {
	return errUnsupported
}

// MountSensitive always returns an error on unsupported platforms
func (mounter *Mounter) MountSensitive(source string, target string, fstype string, options []string, sensitiveOptions []string) error {
	return errUnsupported
}

// MountSensitiveWithoutSystemd always returns an error on unsupported platforms
func (mounter *Mounter) MountSensitiveWithoutSystemd(source string, target string, fstype string, options []string, sensitiveOptions []string) error {
	return errUnsupported
}

// MountSensitiveWithoutSystemdWithMountFlags always returns an error on unsupported platforms
func (mounter *Mounter) MountSensitiveWithoutSystemdWithMountFlags(source string, target string, fstype string, options []string, sensitiveOptions []string, mountFlags []string) error {
	return errUnsupported
}

// Unmount always returns an error on unsupported platforms
func (mounter *Mounter) Unmount(target string) error {
	return errUnsupported
}

// List always returns an error on unsupported platforms
func (mounter *Mounter) List() ([]MountPoint, error) {
	return []MountPoint{}, errUnsupported
}

// IsLikelyNotMountPoint always returns an error on unsupported platforms
func (mounter *Mounter) IsLikelyNotMountPoint(file string) (bool, error) {
	return true, errUnsupported
}

// GetMountRefs always returns an error on unsupported platforms
func (mounter *Mounter) GetMountRefs(pathname string) ([]string, error) {
	return nil, errUnsupported
}

func (mounter *SafeFormatAndMount) formatAndMountSensitive(source string, target string, fstype string, options []string, sensitiveOptions []string) error {
	return mounter.Interface.Mount(source, target, fstype, options)
}

func (mounter *SafeFormatAndMount) diskLooksUnformatted(disk string) (bool, error) {
	return true, errUnsupported
}
<|endoftext|>


<commit_before>package gsvm

import (
	"fmt"
	"go/ast"
	"go/parser"
	"go/scanner"
	"go/token"
	"log"
	"reflect"
	"strconv"
	"strings"
)

type Machine interface {
	Run(line string) (isFragment bool)
}

type NameSpace interface {
	// Returns a reflect.Value with pointer to a variable
	FindVar(ident string) reflect.Value
	// Returns a reflect.Value with pointer to a local variable
	FindLocalVar(ident string) reflect.Value
	// Adding a reflect.Value with pointer to a new variable
	AddLocalVar(ident string, v reflect.Value)
}

type theNameSpace struct {
	UpperVars map[string]reflect.Value
	LocalVars map[string]reflect.Value
}

func newNameSpace() NameSpace {
	return &theNameSpace{
		UpperVars: make(map[string]reflect.Value),
		LocalVars: make(map[string]reflect.Value),
	}
}

func (ns *theNameSpace) FindVar(ident string) reflect.Value {
	if v := ns.FindLocalVar(ident); v != noValue {
		return v
	}
	if v, ok := ns.UpperVars[ident]; ok {
		return v
	}
	return noValue
}

func (ns *theNameSpace) FindLocalVar(ident string) reflect.Value {
	if v, ok := ns.LocalVars[ident]; ok {
		return v
	}
	return noValue
}

func (ns *theNameSpace) AddLocalVar(ident string, v reflect.Value) {
	ns.LocalVars[ident] = v
}

type machine struct {
	GlobalNameSpace NameSpace
	Packages        map[string]map[string]reflect.Value
}

var (
	noValue = reflect.ValueOf(nil)
)

func doSelect(v reflect.Value, sel string) (reflect.Value, error) {
	// TODO
	return noValue, nil
}

func (mch *machine) findSelected(ns NameSpace, x, sel string) (reflect.Value, error) {
	if xv := ns.FindVar(x); xv != noValue {
		// x is a variable's name
		return doSelect(reflect.Indirect(xv), sel)
	}

	if funcs, ok := mch.Packages[x]; ok {
		// x is a package name
		if f, ok := funcs[sel]; ok {
			return f, nil
		}
		return noValue, fmt.Errorf("Undefined: %s.%s", x, sel)
	}

	return noValue, fmt.Errorf("Undefined: %s", x)
}

func checkSingleValue(vls []reflect.Value, err error) (reflect.Value, error) {
	if err !=  nil {
		return noValue, err
	}
	if len(vls) != 1 {
		return noValue, fmt.Errorf("multiple-value(%d) in single-value context", len(vls))
	}
	return vls[0], nil
}

func fromSingleValue(vl reflect.Value, err error) ([]reflect.Value, error) {
	if err != nil {
		return nil, err
	}
	return []reflect.Value{vl}, nil
}

// Returns slice of values themselves not the pointers.
func (mch *machine) evalExpr(ns NameSpace, expr ast.Expr) ([]reflect.Value, error) {
	switch expr := expr.(type) {
	case *ast.BasicLit:
		switch expr.Kind {
		case token.INT:
			i, _ := strconv.Atoi(expr.Value)
			return []reflect.Value{reflect.ValueOf(i)}, nil

		case token.STRING:
			s, _ := strconv.Unquote(expr.Value)
			return []reflect.Value{reflect.ValueOf(s)}, nil

		default:
			log.Println("Unknown BasicLit Kind")
			ast.Print(token.NewFileSet(), expr)
			return []reflect.Value{reflect.ValueOf(expr)}, nil
		}

	case *ast.Ident:
		v := ns.FindVar(expr.Name)
		if v == noValue {
			return nil, fmt.Errorf("Unknown Ident %v", expr.Name)
		}
		return []reflect.Value{reflect.Indirect(v)}, nil

	case *ast.CallExpr:
		fn, err := checkSingleValue(mch.evalExpr(ns, expr.Fun))
		if err != nil {
			return nil, err
		}

		if fn.Kind() != reflect.Func {
			return nil, fmt.Errorf("cannot call non-function (type %s)", fn.Type())
		}

		// TODO when len(expr.Args) == 1, check multi return value situation
		args := make([]reflect.Value, len(expr.Args))
		for i, arg := range expr.Args {
			argV, err := checkSingleValue(mch.evalExpr(ns, arg))
			if err != nil {
				return nil, err
			}
			args[i] = argV
		}

		return fn.Call(args), nil

	case *ast.SelectorExpr:
		switch x := expr.X.(type) {
		case *ast.Ident:
			return fromSingleValue(mch.findSelected(ns, x.Name, expr.Sel.Name))
		default:
			log.Println("Unknown SelectorExpr X type")
			ast.Print(token.NewFileSet(), x)
			return []reflect.Value{reflect.ValueOf(expr)}, nil
		}

	default:
		log.Println("Unknown expr type")
		ast.Print(token.NewFileSet(), expr)
		return []reflect.Value{reflect.ValueOf(expr)}, nil
	}
}

func (mch *machine) typeOf(tp ast.Expr) (reflect.Type, error) {
	switch tp := tp.(type) {
	case *ast.Ident:
		switch tp.Name {
		case "int": return reflect.TypeOf(1), nil
		case "string": return reflect.TypeOf(""), nil
		default:
			return nil, fmt.Errorf("Unknown type %s", tp.Name)
		}
	default:
		return nil, fmt.Errorf("Unknown type expr: %s", tp)
	}
}

func (mch *machine) runStatement(ns NameSpace, st ast.Stmt) error {
	switch st := st.(type) {
	case *ast.AssignStmt:
		// TODO when len(st.Rhs) == 1, check multi value return
		if len(st.Lhs) != len(st.Rhs) {
			return fmt.Errorf("assignment count mismatch: %d %s %d", len(st.Lhs), st.Tok, len(st.Rhs))
		}
		if st.Tok == token.DEFINE {
			hasNew := false
			for _, l := range st.Lhs {
				lIdent := l.(*ast.Ident)
				if v := ns.FindLocalVar(lIdent.Name); v == noValue {
					hasNew = true
				}
			}
			if !hasNew {
				return fmt.Errorf("no new on left side of :=")
			}

			for i, l := range st.Lhs {
				lIdent := l.(*ast.Ident)
				r := st.Rhs[i]
				if v := ns.FindLocalVar(lIdent.Name); v != noValue {
					return redeclareVarErr(lIdent.Name)
				}

				vl, err := checkSingleValue(mch.evalExpr(ns, r))
				if err != nil {
					return err
				}
				v := reflect.New(vl.Type())
				v.Elem().Set(vl)
				ns.AddLocalVar(lIdent.Name, v)
			}
		} else {
			// FIXME should be parallel assignment
			for i, l := range st.Lhs {
				lV, err := checkSingleValue(mch.evalExpr(ns, l))
				if err != nil {
					return err
				}
				if !lV.CanSet() {
					return fmt.Errorf("Can not assign to %s", l)
				}

				rV, err := mch.evalExpr(ns, st.Rhs[i])
				if err != nil {
					return err
				}

				lV.Set(rV[0])
			}
		}

	case *ast.ExprStmt:
		_, err := mch.evalExpr(ns, st.X)
		return err

	case *ast.DeclStmt:
		switch decl := st.Decl.(type) {
		case *ast.GenDecl:
			for _, spec := range decl.Specs {
				spec := spec.(*ast.ValueSpec)
				var values []reflect.Value
				if len(spec.Values) == 1 {
					var err error
					values, err = mch.evalExpr(ns, spec.Values[0])
					if err != nil {
						return err
					}
				} else if len(spec.Values) > 0 {
					values = make([]reflect.Value, len(spec.Values))
					for i, valueExpr := range spec.Values {
						value, err := checkSingleValue(mch.evalExpr(ns, valueExpr))
						if err != nil {
							return err
						}
						values[i] = value
					}
				} else if spec.Type == nil {
					return fmt.Errorf("Need type")
				}

				if values != nil && len(spec.Names) != len(values) {
					return fmt.Errorf(" assignment count mismatch: %d = %d", len(spec.Names), len(values))
				}

				for i, name := range spec.Names {
					if v := ns.FindLocalVar(name.Name); v != noValue {
						return redeclareVarErr(name.Name)
					}
					var v reflect.Value
					if spec.Type != nil {
						tp, err := mch.typeOf(spec.Type)
						if err != nil {
							return err
						}
						v = reflect.New(tp)
					} else {
						v = reflect.New(values[i].Type())
					}

					if values != nil {
						v.Elem().Set(values[i])
					}
					ns.AddLocalVar(name.Name, v)
				}
			}

		case *ast.FuncDecl:
			ast.Print(token.NewFileSet(), decl)
			return nil
		}

	default:
		log.Println("Unknown statement type")
		ast.Print(token.NewFileSet(), st)
		return fmt.Errorf("Unknown statement type")
	}
	return nil
}

func isFragmentError(errList scanner.ErrorList, lastLine int) bool {
	return len(errList) != 1 && errList[0].Pos.Line == lastLine
}

const (
	srcPrefix = `package main; func main() {
`
	srcSuffix = `
}`
)

func (mch *machine) Run(line string) (isFragment bool) {
	src := srcPrefix + line + srcSuffix

	nLines := len(strings.Split(src, "\n"))

	fs := token.NewFileSet()
	f, err := parser.ParseFile(fs, "", src, 0)
	if err != nil {
		isFragment = isFragmentError(err.(scanner.ErrorList), nLines)
		if isFragment {
			return true
		}
		ast.Print(token.NewFileSet(), err)
		log.Printf("Syntax error: %v", err)
		return false
	}
	//	log.Println(line)
	for _, st := range f.Decls[0].(*ast.FuncDecl).Body.List {
		if err := mch.runStatement(mch.GlobalNameSpace, st); err != nil {
			log.Println(err)
			break
		}
	}
	//	log.Println(mch.GlobalNameSpace)
	return false
}

func New() Machine {
	return &machine{
		GlobalNameSpace: newNameSpace(),
		Packages: map[string]map[string]reflect.Value{
			"fmt": map[string]reflect.Value{
				"Println": reflect.ValueOf(fmt.Println),
			},
		},
	}
}
<commit_msg>Fix bugs of parallel assigment<commit_after>package gsvm

import (
	"fmt"
	"go/ast"
	"go/parser"
	"go/scanner"
	"go/token"
	"log"
	"reflect"
	"strconv"
	"strings"
)

type Machine interface {
	Run(line string) (isFragment bool)
}

type NameSpace interface {
	// Returns a reflect.Value with pointer to a variable
	FindVar(ident string) reflect.Value
	// Returns a reflect.Value with pointer to a local variable
	FindLocalVar(ident string) reflect.Value
	// Adding a reflect.Value with pointer to a new variable
	AddLocalVar(ident string, v reflect.Value)
}

type theNameSpace struct {
	UpperVars map[string]reflect.Value
	LocalVars map[string]reflect.Value
}

func newNameSpace() NameSpace {
	return &theNameSpace{
		UpperVars: make(map[string]reflect.Value),
		LocalVars: make(map[string]reflect.Value),
	}
}

func (ns *theNameSpace) FindVar(ident string) reflect.Value {
	if v := ns.FindLocalVar(ident); v != noValue {
		return v
	}
	if v, ok := ns.UpperVars[ident]; ok {
		return v
	}
	return noValue
}

func (ns *theNameSpace) FindLocalVar(ident string) reflect.Value {
	if v, ok := ns.LocalVars[ident]; ok {
		return v
	}
	return noValue
}

func (ns *theNameSpace) AddLocalVar(ident string, v reflect.Value) {
	ns.LocalVars[ident] = v
}

type machine struct {
	GlobalNameSpace NameSpace
	Packages        map[string]map[string]reflect.Value
}

var (
	noValue = reflect.ValueOf(nil)
)

func doSelect(v reflect.Value, sel string) (reflect.Value, error) {
	// TODO
	return noValue, nil
}

func (mch *machine) findSelected(ns NameSpace, x, sel string) (reflect.Value, error) {
	if xv := ns.FindVar(x); xv != noValue {
		// x is a variable's name
		return doSelect(reflect.Indirect(xv), sel)
	}

	if funcs, ok := mch.Packages[x]; ok {
		// x is a package name
		if f, ok := funcs[sel]; ok {
			return f, nil
		}
		return noValue, fmt.Errorf("Undefined: %s.%s", x, sel)
	}

	return noValue, fmt.Errorf("Undefined: %s", x)
}

func checkSingleValue(vls []reflect.Value, err error) (reflect.Value, error) {
	if err !=  nil {
		return noValue, err
	}
	if len(vls) != 1 {
		return noValue, fmt.Errorf("multiple-value(%d) in single-value context", len(vls))
	}
	return vls[0], nil
}

func fromSingleValue(vl reflect.Value, err error) ([]reflect.Value, error) {
	if err != nil {
		return nil, err
	}
	return []reflect.Value{vl}, nil
}

// Returns slice of values themselves not the pointers.
func (mch *machine) evalExpr(ns NameSpace, expr ast.Expr) ([]reflect.Value, error) {
	switch expr := expr.(type) {
	case *ast.BasicLit:
		switch expr.Kind {
		case token.INT:
			i, _ := strconv.Atoi(expr.Value)
			return []reflect.Value{reflect.ValueOf(i)}, nil

		case token.STRING:
			s, _ := strconv.Unquote(expr.Value)
			return []reflect.Value{reflect.ValueOf(s)}, nil

		default:
			log.Println("Unknown BasicLit Kind")
			ast.Print(token.NewFileSet(), expr)
			return []reflect.Value{reflect.ValueOf(expr)}, nil
		}

	case *ast.Ident:
		v := ns.FindVar(expr.Name)
		if v == noValue {
			return nil, fmt.Errorf("Unknown Ident %v", expr.Name)
		}
		return []reflect.Value{reflect.Indirect(v)}, nil

	case *ast.CallExpr:
		fn, err := checkSingleValue(mch.evalExpr(ns, expr.Fun))
		if err != nil {
			return nil, err
		}

		if fn.Kind() != reflect.Func {
			return nil, fmt.Errorf("cannot call non-function (type %s)", fn.Type())
		}

		// TODO when len(expr.Args) == 1, check multi return value situation
		args := make([]reflect.Value, len(expr.Args))
		for i, arg := range expr.Args {
			argV, err := checkSingleValue(mch.evalExpr(ns, arg))
			if err != nil {
				return nil, err
			}
			args[i] = argV
		}

		return fn.Call(args), nil

	case *ast.SelectorExpr:
		switch x := expr.X.(type) {
		case *ast.Ident:
			return fromSingleValue(mch.findSelected(ns, x.Name, expr.Sel.Name))
		default:
			log.Println("Unknown SelectorExpr X type")
			ast.Print(token.NewFileSet(), x)
			return []reflect.Value{reflect.ValueOf(expr)}, nil
		}

	default:
		log.Println("Unknown expr type")
		ast.Print(token.NewFileSet(), expr)
		return []reflect.Value{reflect.ValueOf(expr)}, nil
	}
}

func (mch *machine) typeOf(tp ast.Expr) (reflect.Type, error) {
	switch tp := tp.(type) {
	case *ast.Ident:
		switch tp.Name {
		case "int": return reflect.TypeOf(1), nil
		case "string": return reflect.TypeOf(""), nil
		default:
			return nil, fmt.Errorf("Unknown type %s", tp.Name)
		}
	default:
		return nil, fmt.Errorf("Unknown type expr: %s", tp)
	}
}

func (mch *machine) runStatement(ns NameSpace, st ast.Stmt) error {
	switch st := st.(type) {
	case *ast.AssignStmt:
		// TODO when len(st.Rhs) == 1, check multi value return
		if len(st.Lhs) != len(st.Rhs) {
			return fmt.Errorf("assignment count mismatch: %d %s %d", len(st.Lhs), st.Tok, len(st.Rhs))
		}
		if st.Tok == token.DEFINE {
			// FIXME should be parallel assignment
			hasNew := false
			for _, l := range st.Lhs {
				lIdent := l.(*ast.Ident)
				if v := ns.FindLocalVar(lIdent.Name); v == noValue {
					hasNew = true
				}
			}
			if !hasNew {
				return fmt.Errorf("no new on left side of :=")
			}

			for i, l := range st.Lhs {
				lIdent := l.(*ast.Ident)
				r := st.Rhs[i]
				if v := ns.FindLocalVar(lIdent.Name); v != noValue {
					return redeclareVarErr(lIdent.Name)
				}

				vl, err := checkSingleValue(mch.evalExpr(ns, r))
				if err != nil {
					return err
				}
				v := reflect.New(vl.Type())
				v.Elem().Set(vl)
				ns.AddLocalVar(lIdent.Name, v)
			}
		} else {
			values := make([]reflect.Value, len(st.Rhs))
			for i, r := range st.Rhs {
				rV, err := checkSingleValue(mch.evalExpr(ns, r))
				if err != nil {
					return err
				}
				if len(st.Rhs) > 1 && rV.CanAddr() {
					// Make a copy for a parallel assignment
					tmp := reflect.New(rV.Type())
					tmp.Elem().Set(rV)
					rV = tmp.Elem()
				}
				values[i] = rV
			}
			for i, l := range st.Lhs {
				lV, err := checkSingleValue(mch.evalExpr(ns, l))
				if err != nil {
					return err
				}
				if !lV.CanSet() {
					return fmt.Errorf("Can not assign to %s", l)
				}
				lV.Set(values[i])
			}
		}

	case *ast.ExprStmt:
		_, err := mch.evalExpr(ns, st.X)
		return err

	case *ast.DeclStmt:
		switch decl := st.Decl.(type) {
		case *ast.GenDecl:
			for _, spec := range decl.Specs {
				spec := spec.(*ast.ValueSpec)
				var values []reflect.Value
				if len(spec.Values) == 1 {
					var err error
					values, err = mch.evalExpr(ns, spec.Values[0])
					if err != nil {
						return err
					}
				} else if len(spec.Values) > 0 {
					values = make([]reflect.Value, len(spec.Values))
					for i, valueExpr := range spec.Values {
						value, err := checkSingleValue(mch.evalExpr(ns, valueExpr))
						if err != nil {
							return err
						}
						values[i] = value
					}
				} else if spec.Type == nil {
					return fmt.Errorf("Need type")
				}

				if values != nil && len(spec.Names) != len(values) {
					return fmt.Errorf(" assignment count mismatch: %d = %d", len(spec.Names), len(values))
				}

				for i, name := range spec.Names {
					if v := ns.FindLocalVar(name.Name); v != noValue {
						return redeclareVarErr(name.Name)
					}
					var v reflect.Value
					if spec.Type != nil {
						tp, err := mch.typeOf(spec.Type)
						if err != nil {
							return err
						}
						v = reflect.New(tp)
					} else {
						v = reflect.New(values[i].Type())
					}

					if values != nil {
						v.Elem().Set(values[i])
					}
					ns.AddLocalVar(name.Name, v)
				}
			}

		case *ast.FuncDecl:
			ast.Print(token.NewFileSet(), decl)
			return nil
		}

	default:
		log.Println("Unknown statement type")
		ast.Print(token.NewFileSet(), st)
		return fmt.Errorf("Unknown statement type")
	}
	return nil
}

func isFragmentError(errList scanner.ErrorList, lastLine int) bool {
	return len(errList) != 1 && errList[0].Pos.Line == lastLine
}

const (
	srcPrefix = `package main; func main() {
`
	srcSuffix = `
}`
)

func (mch *machine) Run(line string) (isFragment bool) {
	src := srcPrefix + line + srcSuffix

	nLines := len(strings.Split(src, "\n"))

	fs := token.NewFileSet()
	f, err := parser.ParseFile(fs, "", src, 0)
	if err != nil {
		isFragment = isFragmentError(err.(scanner.ErrorList), nLines)
		if isFragment {
			return true
		}
		ast.Print(token.NewFileSet(), err)
		log.Printf("Syntax error: %v", err)
		return false
	}
	//	log.Println(line)
	for _, st := range f.Decls[0].(*ast.FuncDecl).Body.List {
		if err := mch.runStatement(mch.GlobalNameSpace, st); err != nil {
			log.Println(err)
			break
		}
	}
	//	log.Println(mch.GlobalNameSpace)
	return false
}

func New() Machine {
	return &machine{
		GlobalNameSpace: newNameSpace(),
		Packages: map[string]map[string]reflect.Value{
			"fmt": map[string]reflect.Value{
				"Println": reflect.ValueOf(fmt.Println),
			},
		},
	}
}
<|endoftext|>


<commit_before>package cmds

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"testing"

	"github.com/pachyderm/pachyderm/src/client/pkg/require"
	"github.com/spf13/cobra"
)

const badJSON1 = `
{
"356weryt

}
`

const badJSON2 = `
{
    "a": 1,
    "b": [23,4,4,64,56,36,7456,7],
    "c": {a,f,g,h,j,j},
    "d": 3452.36456,
}
`

func testJSONSyntaxErrorsReported() {
	address := "0.0.0.0:30650"

	rootCmd := &cobra.Command{
		Use: os.Args[0],
		Long: `Access the Pachyderm API.

Envronment variables:
  ADDRESS=0.0.0.0:30650, the server to connect to.
`,
	}

	cmds, _ := Cmds(address)
	for _, cmd := range cmds {
		rootCmd.AddCommand(cmd)
	}

	// Call create job

	ioutil.WriteFile("bad1.json", []byte(badJSON1), 0644)
	defer func() {
		os.Remove("bad1.json")
	}()
	os.Args = []string{"pachctl", "create-job", "-f", "bad1.json"}

	rootCmd.Execute()
}

func TestJSONSyntaxErrorsReported(t *testing.T) {
	if os.Getenv("BE_CRASHER") == "1" {
		testJSONSyntaxErrorsReported()
		return
	}
	cmd := exec.Command(os.Args[0], "-test.run=TestJSONSyntaxErrorsReported")
	cmd.Env = append(os.Environ(), "BE_CRASHER=1")
	out, err := cmd.CombinedOutput()

	require.YesError(t, err)
	if e, ok := err.(*exec.ExitError); ok && !e.Success() {

		descriptiveOutput := `Error parsing job spec: Syntax Error on line 3:

"356weryt

         ^
invalid character '\n' in string literal
`

		require.Equal(t, descriptiveOutput, string(out))
		return
	}
	t.Fatalf("process ran with err %v, want exit status 1", err)

	fmt.Printf("err? %v\n", err)
	fmt.Printf("asdf")

}
<commit_msg>Add second test for create-job. Now will fill in cases for create/run pipeline<commit_after>package cmds

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"testing"

	"github.com/pachyderm/pachyderm/src/client/pkg/require"
	"github.com/spf13/cobra"
)

const badJSON1 = `
{
"356weryt

}
`

const badJSON2 = `
{
    "a": 1,
    "b": [23,4,4,64,56,36,7456,7],
    "c": {a,f,g,h,j,j},
    "d": 3452.36456,
}
`

func testJSONSyntaxErrorsReported(inputFile string, inputFileValue string, inputCommand []string) {
	address := "0.0.0.0:30650"

	rootCmd := &cobra.Command{
		Use: os.Args[0],
		Long: `Access the Pachyderm API.

Envronment variables:
  ADDRESS=0.0.0.0:30650, the server to connect to.
`,
	}

	cmds, _ := Cmds(address)
	for _, cmd := range cmds {
		rootCmd.AddCommand(cmd)
	}

	// Call create job

	ioutil.WriteFile(inputFile, []byte(inputFileValue), 0644)
	defer func() {
		os.Remove(inputFile)
	}()
	os.Args = inputCommand
	rootCmd.Execute()
}

func testBadJSON(t *testing.T, testName string, inputFile string, inputFileValue string, inputCommand []string, expectedOutput string) {

	if os.Getenv("BE_CRASHER") == "1" {
		testJSONSyntaxErrorsReported(inputFile, inputFileValue, inputCommand)
		return
	}
	cmd := exec.Command(os.Args[0], fmt.Sprintf("-test.run=%v", testName))
	cmd.Env = append(os.Environ(), "BE_CRASHER=1")
	out, err := cmd.CombinedOutput()

	require.YesError(t, err)
	if e, ok := err.(*exec.ExitError); ok && !e.Success() {
		require.Equal(t, expectedOutput, string(out))
		return
	}
	t.Fatalf("process ran with err %v, want exit status 1", err)

}

func TestJSONSyntaxErrorsReportedCreateJob(t *testing.T) {
	descriptiveOutput := `Error parsing job spec: Syntax Error on line 3:

"356weryt

         ^
invalid character '\n' in string literal
`
	cmd := []string{"pachctl", "create-job", "-f", "bad1.json"}
	testBadJSON(t, "TestJSONSyntaxErrorsReportedCreateJob", "bad1.json", badJSON1, cmd, descriptiveOutput)
	fmt.Printf("err?")
}

func TestJSONSyntaxErrorsReportedCreateJob2(t *testing.T) {
	descriptiveOutput := `Error parsing job spec: Syntax Error on line 5:

    "c": {a
          ^
invalid character 'a' looking for beginning of object key string
`
	cmd := []string{"pachctl", "create-job", "-f", "bad2.json"}
	testBadJSON(t, "TestJSONSyntaxErrorsReportedCreateJob2", "bad2.json", badJSON2, cmd, descriptiveOutput)
	fmt.Printf("err?")
}
<|endoftext|>


<commit_before>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2016 Load Impact
 *
 * 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 k6_test

import (
	"context"
	"net"
	"testing"
	"time"

	"github.com/loadimpact/k6/js"
	"github.com/loadimpact/k6/lib"
	"github.com/loadimpact/k6/lib/testutils"
	"github.com/loadimpact/k6/lib/types"
	"github.com/loadimpact/k6/stats"
	"github.com/spf13/afero"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	null "gopkg.in/guregu/null.v3"
)

func TestSetupDataMarshalling(t *testing.T) {
	tb := testutils.NewHTTPMultiBin(t)
	defer tb.Cleanup()

	script := []byte(tb.Replacer.Replace(`
		import http from "k6/http";
		import html from "k6/html";
		import ws from "k6/ws";
		export let options = { setupTimeout: "10s" };

		function make_jar() {
			let jar = http.cookieJar();
			jar.set("test", "something")
			return jar;
		}

		export function setup() {
			let res = http.get("http://test.loadimpact.com:HTTPBIN_PORT");
			let html_selection = html.parseHTML(res.body);
			let ws_res = ws.connect("ws://test.loadimpact.com:HTTPBIN_PORT/ws-echo", function(socket){
				socket.on("open", function() {
					socket.send("test")
				})
				socket.on("message", function (data){
					if (!data=="test") {
						throw new Error ("echo'd data doesn't match our message!");
					}
					socket.close()
				});
			});

			return {
				http_response: res,
				html_selection: html_selection,
				html_element: html_selection.find('html'),
				html_attribute: html_selection.find('html').children('body').get(0).attributes(),
				jar: make_jar(),
				ws_res: ws_res,
			};
		}

		function get_non_function_properties(object) {
			return Object.keys(object).filter(element =>
				typeof(object[element]) !== "function");
		}

		function arrays_are_equal(first, second) {
			if (first.length != second.length) {
				return false
			}
			return first.every(element => second.includes(element))
		}

		function diff_object_properties(name, first, second) {
			let first_properties = get_non_function_properties(first).sort();
			let second_properties = get_non_function_properties(second).sort();
			if (!(arrays_are_equal(first_properties, second_properties))) {
				console.error("for " + name + ":\n" +
					"first_properties : " + JSON.stringify(first_properties) + "\n" +
					"second_properties: " + JSON.stringify(second_properties) + "\n" +
					"are not the same");
				throw new Error("not matching " + name);
			}
			first_properties.
				filter(element => typeof(first[element]) === "object").
					forEach(function(element) {
						diff_object_properties(name+"."+element,
											   first[element],
											   second[element]);
			});
		}

		export default function (data) {
			let first_properties = get_non_function_properties(data).sort();
			diff_object_properties("setupdata", data, setup());
		}
	`))

	runner, err := js.New(
		&lib.SourceData{Filename: "/script.js", Data: script},
		afero.NewMemMapFs(),
		lib.RuntimeOptions{Env: map[string]string{"setupTimeout": "10s"}},
	)

	runner.SetOptions(lib.Options{
		SetupTimeout: types.NullDurationFrom(1 * time.Second),
		MaxRedirects: null.IntFrom(10),
		Throw:        null.BoolFrom(true),
		Hosts: map[string]net.IP{
			"test.loadimpact.com": net.ParseIP("127.0.0.1"),
		},
	})

	require.NoError(t, err)

	samples := make(chan stats.SampleContainer, 100)

	if !assert.NoError(t, runner.Setup(context.Background(), samples)) {
		return
	}
	vu, err := runner.NewVU(samples)
	if assert.NoError(t, err) {
		err := vu.RunOnce(context.Background())
		assert.NoError(t, err)
	}
}
<commit_msg>Implement PR requested changes<commit_after>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2018 Load Impact
 *
 * 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 k6_test

import (
	"context"
	"testing"
	"time"

	"github.com/loadimpact/k6/js"
	"github.com/loadimpact/k6/lib"
	"github.com/loadimpact/k6/lib/testutils"
	"github.com/loadimpact/k6/lib/types"
	"github.com/loadimpact/k6/stats"
	"github.com/spf13/afero"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestSetupDataMarshalling(t *testing.T) {
	tb := testutils.NewHTTPMultiBin(t)
	defer tb.Cleanup()

	script := []byte(tb.Replacer.Replace(`
		import http from "k6/http";
		import html from "k6/html";
		import ws from "k6/ws";

		function make_jar() {
			let jar = http.cookieJar();
			jar.set("test", "something")
			return jar;
		}

		export function setup() {
			let res = http.get("HTTPBIN_URL/html");
			let html_selection = html.parseHTML(res.body);
			let ws_res = ws.connect("ws://HTTPBIN_DOMAIN:HTTPBIN_PORT/ws-echo", function(socket){
				socket.on("open", function() {
					socket.send("test")
				})
				socket.on("message", function (data){
					if (!data=="test") {
						throw new Error ("echo'd data doesn't match our message!");
					}
					socket.close()
				});
			});

			return {
				http_response: res,
				html_selection: html_selection,
				html_element: html_selection.find('html'),
				html_attribute: html_selection.find('html').children('body').get(0).attributes(),
				jar: make_jar(),
				ws_res: ws_res,
			};
		}

		function get_non_function_properties(object) {
			return Object.keys(object).filter(element =>
				typeof(object[element]) !== "function");
		}

		function arrays_are_equal(first, second) {
			if (first.length != second.length) {
				return false
			}
			return first.every(function(element, idx) {
				return element === second[idx]
			});
		}

		function diff_object_properties(name, first, second) {
			let first_properties = get_non_function_properties(first).sort();
			let second_properties = get_non_function_properties(second).sort();
			if (!(arrays_are_equal(first_properties, second_properties))) {
				console.error("for " + name + ":\n" +
					"first_properties : " + JSON.stringify(first_properties) + "\n" +
					"second_properties: " + JSON.stringify(second_properties) + "\n" +
					"are not the same");
				throw new Error("not matching " + name);
			}
			first_properties.
				filter(element => typeof(first[element]) === "object").
					forEach(function(element) {
						diff_object_properties(name+"."+element,
											   first[element],
											   second[element]);
			});
		}

		export default function (data) {
			diff_object_properties("setupdata", data, setup());
		}
	`))

	runner, err := js.New(
		&lib.SourceData{Filename: "/script.js", Data: script},
		afero.NewMemMapFs(),
		lib.RuntimeOptions{},
	)

	runner.SetOptions(lib.Options{
		SetupTimeout: types.NullDurationFrom(1 * time.Second),
		Hosts:        tb.Dialer.Hosts,
	})

	require.NoError(t, err)

	samples := make(chan stats.SampleContainer, 100)

	if !assert.NoError(t, runner.Setup(context.Background(), samples)) {
		return
	}
	vu, err := runner.NewVU(samples)
	if assert.NoError(t, err) {
		err := vu.RunOnce(context.Background())
		assert.NoError(t, err)
	}
}
<|endoftext|>


<commit_before>package slack

import (
	"errors"
	"net/url"
)

// Bot contains information about a bot
type Bot struct {
	ID      string `json:"id"`
	Name    string `json:"name"`
	Deleted bool   `json:"deleted"`
	Icons   Icons  `json:"icons"`
}

type botResponseFull struct {
	Bot `json:"bot,omitempty"` // GetBotInfo
	SlackResponse
}

func botRequest(path string, values url.Values, debug bool) (*botResponseFull, error) {
	response := &botResponseFull{}
	err := post(path, values, response, debug)
	if err != nil {
		return nil, err
	}
	if !response.Ok {
		return nil, errors.New(response.Error)
	}
	return response, nil
}

// GetBotInfo will retrive the complete bot information
func (api *Client) GetBotInfo(bot string) (*Bot, error) {
	values := url.Values{
		"token": {api.config.token},
		"bot":   {bot},
	}
	response, err := botRequest("bots.info", values, api.debug)
	if err != nil {
		return nil, err
	}
	return &response.Bot, nil
}
<commit_msg>Fix typo<commit_after>package slack

import (
	"errors"
	"net/url"
)

// Bot contains information about a bot
type Bot struct {
	ID      string `json:"id"`
	Name    string `json:"name"`
	Deleted bool   `json:"deleted"`
	Icons   Icons  `json:"icons"`
}

type botResponseFull struct {
	Bot `json:"bot,omitempty"` // GetBotInfo
	SlackResponse
}

func botRequest(path string, values url.Values, debug bool) (*botResponseFull, error) {
	response := &botResponseFull{}
	err := post(path, values, response, debug)
	if err != nil {
		return nil, err
	}
	if !response.Ok {
		return nil, errors.New(response.Error)
	}
	return response, nil
}

// GetBotInfo will retrieve the complete bot information
func (api *Client) GetBotInfo(bot string) (*Bot, error) {
	values := url.Values{
		"token": {api.config.token},
		"bot":   {bot},
	}
	response, err := botRequest("bots.info", values, api.debug)
	if err != nil {
		return nil, err
	}
	return &response.Bot, nil
}
<|endoftext|>