<commit_before>// Copyright 2020 Google LLC
//
// 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
//
// 	https://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 safehttptest

import (
	"io"
	"net/http"
	"strings"

	"github.com/google/go-safeweb/safehttp"
)

// ResponseRecorder encapsulates a safehttp.ResponseWriter that records
// mutations for later inspection in tests. The safehttp.ResponseWriter
// should be passed as part of the handler function in tests.
type ResponseRecorder struct {
	safehttp.ResponseWriter
	rw *TestResponseWriter
	b  *strings.Builder
}

// NewResponseRecorder creates a ResponseRecorder.
func NewResponseRecorder() *ResponseRecorder {
	var b strings.Builder
	rw := NewTestResponseWriter(&b)
	return &ResponseRecorder{
		rw:             rw,
		b:              &b,
		ResponseWriter: safehttp.DeprecatedNewResponseWriter(rw, nil),
	}
}

// NewResponseRecorderFromDispatcher creates a ResponseRecorder.
func NewResponseRecorderFromDispatcher(d safehttp.Dispatcher) *ResponseRecorder {
	var b strings.Builder
	rw := NewTestResponseWriter(&b)
	return &ResponseRecorder{
		rw:             rw,
		b:              &b,
		ResponseWriter: safehttp.DeprecatedNewResponseWriter(rw, d),
	}
}

// Header returns the recorded response headers.
func (r *ResponseRecorder) Header() http.Header {
	return r.rw.Header()
}

// Status returns the recorded response status code.
func (r *ResponseRecorder) Status() safehttp.StatusCode {
	return r.rw.status
}

// Body returns the recorded response body.
func (r *ResponseRecorder) Body() string {
	return r.b.String()
}

// TestResponseWriter is an implementation of the http.ResponseWriter interface
// used for constructing an HTTP response for testing purposes.
type TestResponseWriter struct {
	header http.Header
	writer io.Writer
	status safehttp.StatusCode
}

// NewTestResponseWriter creates a new TestResponseWriter.
func NewTestResponseWriter(w io.Writer) *TestResponseWriter {
	return &TestResponseWriter{
		header: http.Header{},
		writer: w,
		status: safehttp.StatusOK,
	}
}

// Status returns the response status.
func (r *TestResponseWriter) Status() safehttp.StatusCode {
	return r.status
}

// Header implements http.ResponseWriter. It returns the response headers that
// could have been mutated within a handler.
func (r *TestResponseWriter) Header() http.Header {
	return r.header
}

// WriteHeader implements http.ResponseWriter.
func (r *TestResponseWriter) WriteHeader(statusCode int) {
	r.status = safehttp.StatusCode(statusCode)
}

// Write implements http.ResponseWriter.
func (r *TestResponseWriter) Write(data []byte) (int, error) {
	return r.writer.Write(data)
}
<commit_msg>Removed safehttp.TestResponseWriter from the public API.<commit_after>// Copyright 2020 Google LLC
//
// 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
//
// 	https://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 safehttptest

import (
	"io"
	"net/http"
	"strings"

	"github.com/google/go-safeweb/safehttp"
)

// ResponseRecorder encapsulates a safehttp.ResponseWriter that records
// mutations for later inspection in tests. The safehttp.ResponseWriter
// should be passed as part of the handler function in tests.
type ResponseRecorder struct {
	safehttp.ResponseWriter
	rw *testResponseWriter
	b  *strings.Builder
}

// NewResponseRecorder creates a ResponseRecorder.
func NewResponseRecorder() *ResponseRecorder {
	var b strings.Builder
	rw := NewTestResponseWriter(&b)
	return &ResponseRecorder{
		rw:             rw,
		b:              &b,
		ResponseWriter: safehttp.DeprecatedNewResponseWriter(rw, nil),
	}
}

// NewResponseRecorderFromDispatcher creates a ResponseRecorder.
func NewResponseRecorderFromDispatcher(d safehttp.Dispatcher) *ResponseRecorder {
	var b strings.Builder
	rw := NewTestResponseWriter(&b)
	return &ResponseRecorder{
		rw:             rw,
		b:              &b,
		ResponseWriter: safehttp.DeprecatedNewResponseWriter(rw, d),
	}
}

// Header returns the recorded response headers.
func (r *ResponseRecorder) Header() http.Header {
	return r.rw.Header()
}

// Status returns the recorded response status code.
func (r *ResponseRecorder) Status() safehttp.StatusCode {
	return r.rw.status
}

// Body returns the recorded response body.
func (r *ResponseRecorder) Body() string {
	return r.b.String()
}

// testResponseWriter is an implementation of the http.ResponseWriter interface
// used for constructing an HTTP response for testing purposes.
type testResponseWriter struct {
	header http.Header
	writer io.Writer
	status safehttp.StatusCode
}

// NewTestResponseWriter creates a new TestResponseWriter.
func NewTestResponseWriter(w io.Writer) *testResponseWriter {
	return &testResponseWriter{
		header: http.Header{},
		writer: w,
		status: safehttp.StatusOK,
	}
}

// Status returns the response status.
func (r *testResponseWriter) Status() safehttp.StatusCode {
	return r.status
}

// Header implements http.ResponseWriter. It returns the response headers that
// could have been mutated within a handler.
func (r *testResponseWriter) Header() http.Header {
	return r.header
}

// WriteHeader implements http.ResponseWriter.
func (r *testResponseWriter) WriteHeader(statusCode int) {
	r.status = safehttp.StatusCode(statusCode)
}

// Write implements http.ResponseWriter.
func (r *testResponseWriter) Write(data []byte) (int, error) {
	return r.writer.Write(data)
}
<|endoftext|>


<commit_before>package gopherjs_http

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"time"

	"code.google.com/p/go.net/html"
	"code.google.com/p/go.net/html/atom"
	"github.com/shurcooL/go/pipe_util"
	"gopkg.in/pipe.v2"
)

// HtmlFile returns a handler that serves the given .html file, with the "text/go" scripts compiled to JavaScript via GopherJS.
func HtmlFile(name string) http.Handler {
	return &htmlFile{name: name}
}

type htmlFile struct {
	name string
}

func (this *htmlFile) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	file, err := os.Open(this.name)
	if err != nil {
		panic(err)
	}
	defer file.Close()

	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	processHtmlFile(file).WriteTo(w)
}

// TODO: Write into writer, no need for buffer. Or, alternatively, parse html and serve minified version?
// TODO: Support non-inline <script src="..."> tags.
func processHtmlFile(r io.Reader) *bytes.Buffer {
	var buff bytes.Buffer
	tokenizer := html.NewTokenizer(r)

	depth := 0

	for {
		if tokenizer.Next() == html.ErrorToken {
			err := tokenizer.Err()
			if err == io.EOF {
				return &buff
			}

			return &bytes.Buffer{}
		}

		token := tokenizer.Token()
		switch token.Type {
		case html.DoctypeToken:
			buff.WriteString(token.String())
		case html.CommentToken:
			buff.WriteString(token.String())
		case html.StartTagToken:
			if token.DataAtom == atom.Script && getType(token.Attr) == "text/go" {
				depth++
				//goon.Dump(token.Attr)
				buff.WriteString(`<script type="text/javascript">`)
			} else {
				buff.WriteString(token.String())
			}
		case html.EndTagToken:
			if token.DataAtom == atom.Script && depth > 0 {
				depth--
			}
			buff.WriteString(token.String())
		case html.SelfClosingTagToken:
			buff.WriteString(token.String())
		case html.TextToken:
			if depth > 0 {
				buff.WriteString(goToJs(token.Data))
			} else {
				buff.WriteString(token.Data)
			}
		default:
			panic("unknown token type")
		}
	}
}

func getType(attrs []html.Attribute) string {
	for _, attr := range attrs {
		if attr.Key == "type" {
			return attr.Val
		}
	}
	return ""
}

func goToJs(goCode string) (jsCode string) {
	started := time.Now()
	defer func() { fmt.Println("goToJs taken:", time.Since(started)) }()

	// TODO: Don't shell out, and avoid having to write/read temporary files, instead
	//       use http://godoc.org/github.com/gopherjs/gopherjs/compiler directly, etc.
	p := pipe.Script(
		pipe.Line(
			pipe.Print(goCode),
			pipe.WriteFile("tmp.go", 0666),
		),
		pipe.Exec("gopherjs", "build", "tmp.go"),
		pipe.ReadFile("tmp.js"),
	)

	// Use a temporary dir.
	tempDir, err := ioutil.TempDir("", "gopherjs_")
	if err != nil {
		panic(err)
	}
	defer func() {
		err := os.RemoveAll(tempDir)
		if err != nil {
			fmt.Fprintln(os.Stderr, "warning: error removing temp dir:", err)
		}
	}()

	stdout, stderr, err := pipe_util.DividedOutputDir(p, tempDir)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Stderr.Write(stderr)
	}

	// TODO: Serve the .map too, somehow?
	stdout = bytes.Replace(stdout, []byte("//# sourceMappingURL=tmp.js.map\n"), []byte("\n"), -1)

	return string(stdout)
}
<commit_msg>Add support for non-inlined text/go script tags.<commit_after>package gopherjs_http

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"time"

	"code.google.com/p/go.net/html"
	"code.google.com/p/go.net/html/atom"
	"github.com/shurcooL/go/pipe_util"
	"gopkg.in/pipe.v2"
)

// HtmlFile returns a handler that serves the given .html file, with the "text/go" scripts compiled to JavaScript via GopherJS.
func HtmlFile(name string) http.Handler {
	return &htmlFile{name: name}
}

type htmlFile struct {
	name string
}

func (this *htmlFile) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	file, err := os.Open(this.name)
	if err != nil {
		panic(err)
	}
	defer file.Close()

	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	ProcessHtml(file).WriteTo(w)
}

// TODO: Write into writer, no need for buffer (unless want to be able to abort on error?). Or, alternatively, parse html and serve minified version?
func ProcessHtml(r io.Reader) *bytes.Buffer {
	insideTextGo := false
	tokenizer := html.NewTokenizer(r)
	var buf bytes.Buffer

	for {
		if tokenizer.Next() == html.ErrorToken {
			err := tokenizer.Err()
			if err == io.EOF {
				return &buf
			}

			return &bytes.Buffer{}
		}

		token := tokenizer.Token()
		switch token.Type {
		case html.DoctypeToken:
			buf.WriteString(token.String())
		case html.CommentToken:
			buf.WriteString(token.String())
		case html.StartTagToken:
			if token.DataAtom == atom.Script && getType(token.Attr) == "text/go" {
				insideTextGo = true

				buf.WriteString(`<script type="text/javascript">`)

				if src := getSrc(token.Attr); src != "" {
					if data, err := ioutil.ReadFile(src); err == nil {
						buf.WriteString(goToJs(string(data)))
					}
				}
			} else {
				buf.WriteString(token.String())
			}
		case html.EndTagToken:
			if token.DataAtom == atom.Script && insideTextGo {
				insideTextGo = false
			}
			buf.WriteString(token.String())
		case html.SelfClosingTagToken:
			// TODO: Support <script type="text/go" src="..." />.
			buf.WriteString(token.String())
		case html.TextToken:
			if insideTextGo {
				buf.WriteString(goToJs(token.Data))
			} else {
				buf.WriteString(token.Data)
			}
		default:
			panic("unknown token type")
		}
	}
}

func getType(attrs []html.Attribute) string {
	for _, attr := range attrs {
		if attr.Key == "type" {
			return attr.Val
		}
	}
	return ""
}

func getSrc(attrs []html.Attribute) string {
	for _, attr := range attrs {
		if attr.Key == "src" {
			return attr.Val
		}
	}
	return ""
}

func goToJs(goCode string) (jsCode string) {
	started := time.Now()
	defer func() { fmt.Println("goToJs taken:", time.Since(started)) }()

	// TODO: Don't shell out, and avoid having to write/read temporary files, instead
	//       use http://godoc.org/github.com/gopherjs/gopherjs/compiler directly, etc.
	p := pipe.Script(
		pipe.Line(
			pipe.Print(goCode),
			pipe.WriteFile("tmp.go", 0666),
		),
		pipe.Exec("gopherjs", "build", "tmp.go"),
		pipe.ReadFile("tmp.js"),
	)

	// Use a temporary dir.
	tempDir, err := ioutil.TempDir("", "gopherjs_")
	if err != nil {
		panic(err)
	}
	defer func() {
		err := os.RemoveAll(tempDir)
		if err != nil {
			fmt.Fprintln(os.Stderr, "warning: error removing temp dir:", err)
		}
	}()

	stdout, stderr, err := pipe_util.DividedOutputDir(p, tempDir)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Stderr.Write(stderr)
	}

	// TODO: Serve the .map too, somehow?
	stdout = bytes.Replace(stdout, []byte("//# sourceMappingURL=tmp.js.map\n"), []byte("\n"), -1)

	return string(stdout)
}
<|endoftext|>


<commit_before>// Copyright 2014 The Cockroach 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. See the AUTHORS file
// for names of contributors.
//
// Author: Spencer Kimball (spencer.kimball@gmail.com)

package gossip

import (
	"testing"
	"time"

	"github.com/cockroachdb/cockroach/proto"
	"github.com/cockroachdb/cockroach/rpc"
	"github.com/cockroachdb/cockroach/util"
	"github.com/cockroachdb/cockroach/util/hlc"
	"github.com/cockroachdb/cockroach/util/leaktest"
	"github.com/cockroachdb/cockroach/util/log"
	"github.com/cockroachdb/cockroach/util/stop"
)

const (
	// With the default gossip interval, some tests
	// may take longer than they need.
	gossipInterval = 20 * time.Millisecond
)

// startGossip creates local and remote gossip instances.
// The remote gossip instance launches its gossip service.
func startGossip(t *testing.T) (local, remote *Gossip, stopper *stop.Stopper) {
	lclock := hlc.NewClock(hlc.UnixNano)
	stopper = stop.NewStopper()
	lRPCContext := rpc.NewContext(nodeTestBaseContext, lclock, stopper)

	laddr := util.CreateTestAddr("tcp")
	lserver := rpc.NewServer(laddr, lRPCContext)
	if err := lserver.Start(); err != nil {
		t.Fatal(err)
	}
	local = New(lRPCContext, gossipInterval, TestBootstrap)
	if err := local.SetNodeDescriptor(&proto.NodeDescriptor{
		NodeID: 1,
		Address: proto.Addr{
			Network: laddr.Network(),
			Address: laddr.String(),
		}}); err != nil {
		t.Fatal(err)
	}
	rclock := hlc.NewClock(hlc.UnixNano)
	raddr := util.CreateTestAddr("tcp")
	rRPCContext := rpc.NewContext(nodeTestBaseContext, rclock, stopper)
	rserver := rpc.NewServer(raddr, rRPCContext)
	if err := rserver.Start(); err != nil {
		t.Fatal(err)
	}
	remote = New(rRPCContext, gossipInterval, TestBootstrap)
	if err := local.SetNodeDescriptor(&proto.NodeDescriptor{
		NodeID: 2,
		Address: proto.Addr{
			Network: raddr.Network(),
			Address: raddr.String(),
		},
	}); err != nil {
		t.Fatal(err)
	}
	local.start(lserver, stopper)
	remote.start(rserver, stopper)
	time.Sleep(time.Millisecond)
	return
}

// TestClientGossip verifies a client can gossip a delta to the server.
func TestClientGossip(t *testing.T) {
	defer leaktest.AfterTest(t)
	local, remote, stopper := startGossip(t)
	if err := local.AddInfo("local-key", "local value", time.Second); err != nil {
		t.Fatal(err)
	}
	if err := remote.AddInfo("remote-key", "remote value", time.Second); err != nil {
		t.Fatal(err)
	}
	disconnected := make(chan *client, 1)

	client := newClient(remote.is.NodeAddr)
	// Use an insecure context. We're talking to unix socket which are not in the certs.
	lclock := hlc.NewClock(hlc.UnixNano)
	rpcContext := rpc.NewContext(nodeTestBaseContext, lclock, stopper)
	client.start(local, disconnected, rpcContext, stopper)

	util.SucceedsWithin(t, 500*time.Millisecond, func() error {
		if _, err := remote.GetInfo("local-key"); err != nil {
			return err
		}
		if _, err := local.GetInfo("remote-key"); err != nil {
			return err
		}
		return nil
	})

	stopper.Stop()
	log.Info("done serving")
	if client != <-disconnected {
		t.Errorf("expected client disconnect after remote close")
	}
}

// TestClientDisconnectRedundant verifies that the gossip server
// will drop an outgoing client connection that is already an
// inbound client connection of another node.
func TestClientDisconnectRedundant(t *testing.T) {
	defer leaktest.AfterTest(t)
	local, remote, stopper := startGossip(t)
	defer stopper.Stop()
	// startClient doesn't lock the underlying gossip
	// object, so we acquire those locks here.
	local.mu.Lock()
	remote.mu.Lock()
	rAddr := remote.is.NodeAddr
	lAddr := local.is.NodeAddr
	lclock := hlc.NewClock(hlc.UnixNano)
	rpcContext := rpc.NewContext(nodeTestBaseContext, lclock, stopper)
	local.startClient(rAddr, rpcContext, stopper)
	remote.startClient(lAddr, rpcContext, stopper)
	local.mu.Unlock()
	remote.mu.Unlock()
	local.manage(stopper)
	remote.manage(stopper)
	wasConnected1, wasConnected2 := false, false
	if err := util.IsTrueWithin(func() bool {
		// Check which of the clients is connected to the other.
		ok1 := local.findClient(func(c *client) bool { return c.addr.String() == rAddr.String() }) != nil
		ok2 := remote.findClient(func(c *client) bool { return c.addr.String() == lAddr.String() }) != nil
		if ok1 {
			wasConnected1 = true
		}
		if ok2 {
			wasConnected2 = true
		}
		// Check if at some point both nodes were connected to
		// each other, but now aren't any more.
		// Unfortunately it's difficult to get a more direct
		// read on what's happening without really messing with
		// the internals.
		if wasConnected1 && wasConnected2 && (!ok1 || !ok2) {
			return true
		}
		return false
	}, 10*time.Second); err != nil {
		t.Fatal(err)
	}
}
<commit_msg>Make sure stopper gets stopped<commit_after>// Copyright 2014 The Cockroach 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. See the AUTHORS file
// for names of contributors.
//
// Author: Spencer Kimball (spencer.kimball@gmail.com)

package gossip

import (
	"testing"
	"time"

	"github.com/cockroachdb/cockroach/proto"
	"github.com/cockroachdb/cockroach/rpc"
	"github.com/cockroachdb/cockroach/util"
	"github.com/cockroachdb/cockroach/util/hlc"
	"github.com/cockroachdb/cockroach/util/leaktest"
	"github.com/cockroachdb/cockroach/util/stop"
)

const (
	// With the default gossip interval, some tests
	// may take longer than they need.
	gossipInterval = 20 * time.Millisecond
)

// startGossip creates local and remote gossip instances.
// The remote gossip instance launches its gossip service.
func startGossip(t *testing.T) (local, remote *Gossip, stopper *stop.Stopper) {
	lclock := hlc.NewClock(hlc.UnixNano)
	stopper = stop.NewStopper()
	lRPCContext := rpc.NewContext(nodeTestBaseContext, lclock, stopper)

	laddr := util.CreateTestAddr("tcp")
	lserver := rpc.NewServer(laddr, lRPCContext)
	if err := lserver.Start(); err != nil {
		t.Fatal(err)
	}
	local = New(lRPCContext, gossipInterval, TestBootstrap)
	if err := local.SetNodeDescriptor(&proto.NodeDescriptor{
		NodeID: 1,
		Address: proto.Addr{
			Network: laddr.Network(),
			Address: laddr.String(),
		}}); err != nil {
		t.Fatal(err)
	}
	rclock := hlc.NewClock(hlc.UnixNano)
	raddr := util.CreateTestAddr("tcp")
	rRPCContext := rpc.NewContext(nodeTestBaseContext, rclock, stopper)
	rserver := rpc.NewServer(raddr, rRPCContext)
	if err := rserver.Start(); err != nil {
		t.Fatal(err)
	}
	remote = New(rRPCContext, gossipInterval, TestBootstrap)
	if err := local.SetNodeDescriptor(&proto.NodeDescriptor{
		NodeID: 2,
		Address: proto.Addr{
			Network: raddr.Network(),
			Address: raddr.String(),
		},
	}); err != nil {
		t.Fatal(err)
	}
	local.start(lserver, stopper)
	remote.start(rserver, stopper)
	time.Sleep(time.Millisecond)
	return
}

// TestClientGossip verifies a client can gossip a delta to the server.
func TestClientGossip(t *testing.T) {
	defer leaktest.AfterTest(t)
	local, remote, stopper := startGossip(t)
	disconnected := make(chan *client, 1)
	client := newClient(remote.is.NodeAddr)

	defer func() {
		stopper.Stop()
		if client != <-disconnected {
			t.Errorf("expected client disconnect after remote close")
		}
	}()

	if err := local.AddInfo("local-key", "local value", time.Second); err != nil {
		t.Fatal(err)
	}
	if err := remote.AddInfo("remote-key", "remote value", time.Second); err != nil {
		t.Fatal(err)
	}

	// Use an insecure context. We're talking to unix socket which are not in the certs.
	lclock := hlc.NewClock(hlc.UnixNano)
	rpcContext := rpc.NewContext(nodeTestBaseContext, lclock, stopper)
	client.start(local, disconnected, rpcContext, stopper)

	util.SucceedsWithin(t, 500*time.Millisecond, func() error {
		if _, err := remote.GetInfo("local-key"); err != nil {
			return err
		}
		if _, err := local.GetInfo("remote-key"); err != nil {
			return err
		}
		return nil
	})
}

// TestClientDisconnectRedundant verifies that the gossip server
// will drop an outgoing client connection that is already an
// inbound client connection of another node.
func TestClientDisconnectRedundant(t *testing.T) {
	defer leaktest.AfterTest(t)
	local, remote, stopper := startGossip(t)
	defer stopper.Stop()
	// startClient doesn't lock the underlying gossip
	// object, so we acquire those locks here.
	local.mu.Lock()
	remote.mu.Lock()
	rAddr := remote.is.NodeAddr
	lAddr := local.is.NodeAddr
	lclock := hlc.NewClock(hlc.UnixNano)
	rpcContext := rpc.NewContext(nodeTestBaseContext, lclock, stopper)
	local.startClient(rAddr, rpcContext, stopper)
	remote.startClient(lAddr, rpcContext, stopper)
	local.mu.Unlock()
	remote.mu.Unlock()
	local.manage(stopper)
	remote.manage(stopper)
	wasConnected1, wasConnected2 := false, false
	if err := util.IsTrueWithin(func() bool {
		// Check which of the clients is connected to the other.
		ok1 := local.findClient(func(c *client) bool { return c.addr.String() == rAddr.String() }) != nil
		ok2 := remote.findClient(func(c *client) bool { return c.addr.String() == lAddr.String() }) != nil
		if ok1 {
			wasConnected1 = true
		}
		if ok2 {
			wasConnected2 = true
		}
		// Check if at some point both nodes were connected to
		// each other, but now aren't any more.
		// Unfortunately it's difficult to get a more direct
		// read on what's happening without really messing with
		// the internals.
		if wasConnected1 && wasConnected2 && (!ok1 || !ok2) {
			return true
		}
		return false
	}, 10*time.Second); err != nil {
		t.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package parsers

import (
	"bytes"
	"strings"

	"github.com/evepraisal/go-evepraisal/typedb"
)

const (
	HEURISTIC_ITEM     = iota
	HEURISTIC_QUANTITY = iota
	HEURISTIC_IGNORE   = iota
)

var HeuristicSpecs = [][]int{
	{HEURISTIC_IGNORE, HEURISTIC_ITEM, HEURISTIC_IGNORE, HEURISTIC_QUANTITY},
	{HEURISTIC_QUANTITY, HEURISTIC_IGNORE, HEURISTIC_ITEM},
	{HEURISTIC_ITEM, HEURISTIC_QUANTITY},
	{HEURISTIC_QUANTITY, HEURISTIC_ITEM},
	{HEURISTIC_IGNORE, HEURISTIC_ITEM},
	{HEURISTIC_ITEM},
}

type HeuristicParser struct {
	typeDB typedb.TypeDB
}

func heuristicTrimStrings(parts []string, trim string) []string {
	for i := range parts {
		parts[i] = strings.Trim(parts[i], trim)
	}
	return parts
}

func removeEmpty(parts []string) []string {
	newParts := make([]string, 0)
	for _, s := range parts {
		if s != "" {
			newParts = append(newParts, s)
		}
	}
	return newParts
}

type HeuristicResult struct {
	Items []HeuristicItem
	lines []int
}

func (r *HeuristicResult) Name() string {
	return "heuristic"
}

func (r *HeuristicResult) Lines() []int {
	return r.lines
}

type HeuristicItem struct {
	Name     string
	Quantity int64
}

func NewHeuristicParser(typeDB typedb.TypeDB) Parser {
	p := &HeuristicParser{typeDB: typeDB}
	return p.Parse
}

func (p *HeuristicParser) Parse(input Input) (ParserResult, Input) {
	var items []HeuristicItem
	var lines []int
	rest := make(Input)
	for i, line := range input {
		var lineResults []HeuristicItem
		lineResults = p.heuristicMethod1(line)
		if lineResults != nil {
			items = append(items, lineResults...)
			lines = append(lines, i)
			continue
		}

		lineResults = p.heuristicMethod2(line)
		if lineResults != nil {
			items = append(items, lineResults...)
			lines = append(lines, i)
			continue
		}

		// We give up. :(
		rest[i] = line
	}

	return &HeuristicResult{
		Items: items,
		lines: lines,
	}, rest
}

func (p *HeuristicParser) heuristicMethod1(line string) []HeuristicItem {
	parts := removeEmpty(heuristicTrimStrings(strings.Split(line, "\t"), ", _=-[]"))
	if len(parts) == 1 {
		parts = removeEmpty(heuristicTrimStrings(strings.Split(line, "  "), ", _=-[]"))
	}
	if len(parts) == 1 {
		parts = removeEmpty(heuristicTrimStrings(strings.Split(line, " "), ", _=-[]"))
	}

	if len(parts) == 1 {
		return nil
	}

	for _, spec := range HeuristicSpecs {
		if len(parts) < len(spec) {
			continue
		}

		name := ""
		quantity := int64(1)
		matched := true
		for index, specPart := range spec {
			switch specPart {
			case HEURISTIC_IGNORE:
			case HEURISTIC_ITEM:
				name = parts[index]
				if !p.typeDB.HasType(name) {
					matched = false
					break
				}
			case HEURISTIC_QUANTITY:
				quantity = ToInt(parts[index])
				if quantity == 0 {
					matched = false
					break
				}
			}
		}

		if matched {
			return []HeuristicItem{{Name: name, Quantity: quantity}}
		}
	}
	return nil
}

func (p *HeuristicParser) heuristicMethod2(line string) []HeuristicItem {
	var b bytes.Buffer
	for _, part := range strings.Split(line, " ") {
		b.WriteString(strings.Trim(part, ",\t "))
		name := b.String()
		if !p.typeDB.HasType(strings.ToLower(name)) {
			return []HeuristicItem{{Name: name, Quantity: 1}}
		}
	}
	return nil
}
<commit_msg>Cool, some formats put asterisks at the end of names!<commit_after>package parsers

import (
	"bytes"
	"strings"

	"github.com/evepraisal/go-evepraisal/typedb"
)

const (
	HEURISTIC_ITEM     = iota
	HEURISTIC_QUANTITY = iota
	HEURISTIC_IGNORE   = iota
)

var HeuristicSpecs = [][]int{
	{HEURISTIC_IGNORE, HEURISTIC_ITEM, HEURISTIC_IGNORE, HEURISTIC_QUANTITY},
	{HEURISTIC_QUANTITY, HEURISTIC_IGNORE, HEURISTIC_ITEM},
	{HEURISTIC_ITEM, HEURISTIC_QUANTITY},
	{HEURISTIC_QUANTITY, HEURISTIC_ITEM},
	{HEURISTIC_IGNORE, HEURISTIC_ITEM},
	{HEURISTIC_ITEM},
}

type HeuristicParser struct {
	typeDB typedb.TypeDB
}

func heuristicTrimStrings(parts []string, trim string) []string {
	for i := range parts {
		parts[i] = strings.Trim(parts[i], trim)
	}
	return parts
}

func removeEmpty(parts []string) []string {
	newParts := make([]string, 0)
	for _, s := range parts {
		if s != "" {
			newParts = append(newParts, s)
		}
	}
	return newParts
}

type HeuristicResult struct {
	Items []HeuristicItem
	lines []int
}

func (r *HeuristicResult) Name() string {
	return "heuristic"
}

func (r *HeuristicResult) Lines() []int {
	return r.lines
}

type HeuristicItem struct {
	Name     string
	Quantity int64
}

func NewHeuristicParser(typeDB typedb.TypeDB) Parser {
	p := &HeuristicParser{typeDB: typeDB}
	return p.Parse
}

func (p *HeuristicParser) Parse(input Input) (ParserResult, Input) {
	var items []HeuristicItem
	var lines []int
	rest := make(Input)
	for i, line := range input {
		var lineResults []HeuristicItem
		lineResults = p.heuristicMethod1(line)
		if lineResults != nil {
			items = append(items, lineResults...)
			lines = append(lines, i)
			continue
		}

		lineResults = p.heuristicMethod2(line)
		if lineResults != nil {
			items = append(items, lineResults...)
			lines = append(lines, i)
			continue
		}

		// We give up. :(
		rest[i] = line
	}

	return &HeuristicResult{
		Items: items,
		lines: lines,
	}, rest
}

func (p *HeuristicParser) heuristicMethod1(line string) []HeuristicItem {
	parts := removeEmpty(heuristicTrimStrings(strings.Split(line, "\t"), ", _=-[]*"))
	if len(parts) == 1 {
		parts = removeEmpty(heuristicTrimStrings(strings.Split(line, "  "), ", _=-[]*"))
	}
	if len(parts) == 1 {
		parts = removeEmpty(heuristicTrimStrings(strings.Split(line, " "), ", _=-[]*"))
	}

	if len(parts) == 1 {
		return nil
	}

	for _, spec := range HeuristicSpecs {
		if len(parts) < len(spec) {
			continue
		}

		name := ""
		quantity := int64(1)
		matched := true
		for index, specPart := range spec {
			switch specPart {
			case HEURISTIC_IGNORE:
			case HEURISTIC_ITEM:
				name = parts[index]
				if !p.typeDB.HasType(name) {
					matched = false
					break
				}
			case HEURISTIC_QUANTITY:
				quantity = ToInt(parts[index])
				if quantity == 0 {
					matched = false
					break
				}
			}
		}

		if matched {
			return []HeuristicItem{{Name: name, Quantity: quantity}}
		}
	}
	return nil
}

func (p *HeuristicParser) heuristicMethod2(line string) []HeuristicItem {
	var b bytes.Buffer
	for _, part := range strings.Split(line, " ") {
		b.WriteString(strings.Trim(part, ",\t "))
		name := b.String()
		if !p.typeDB.HasType(strings.ToLower(name)) {
			return []HeuristicItem{{Name: name, Quantity: 1}}
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package parsers

import (
	"bytes"
	"strings"

	"github.com/evepraisal/go-evepraisal/typedb"
)

const (
	HEURISTIC_ITEM     = iota
	HEURISTIC_QUANTITY = iota
	HEURISTIC_IGNORE   = iota
)

var HeuristicSpecs = [][]int{
	{HEURISTIC_IGNORE, HEURISTIC_ITEM, HEURISTIC_IGNORE, HEURISTIC_QUANTITY},
	{HEURISTIC_QUANTITY, HEURISTIC_IGNORE, HEURISTIC_ITEM},
	{HEURISTIC_ITEM, HEURISTIC_QUANTITY},
	{HEURISTIC_QUANTITY, HEURISTIC_ITEM},
	{HEURISTIC_IGNORE, HEURISTIC_ITEM},
	{HEURISTIC_ITEM},
}

type HeuristicParser struct {
	typeDB typedb.TypeDB
}

func heuristicTrimStrings(parts []string, trim string) []string {
	for i := range parts {
		parts[i] = strings.Trim(parts[i], trim)
	}
	return parts
}

func removeEmpty(parts []string) []string {
	newParts := make([]string, 0)
	for _, s := range parts {
		if s != "" {
			newParts = append(newParts, s)
		}
	}
	return newParts
}

type HeuristicResult struct {
	Items []HeuristicItem
	lines []int
}

func (r *HeuristicResult) Name() string {
	return "heuristic"
}

func (r *HeuristicResult) Lines() []int {
	return r.lines
}

type HeuristicItem struct {
	Name     string
	Quantity int64
}

func NewHeuristicParser(typeDB typedb.TypeDB) Parser {
	p := &HeuristicParser{typeDB: typeDB}
	return p.Parse
}

func (p *HeuristicParser) Parse(input Input) (ParserResult, Input) {
	var items []HeuristicItem
	var lines []int
	rest := make(Input)
	for i, line := range input {
		var lineResults []HeuristicItem
		lineResults = p.heuristicMethod1(line)
		if lineResults != nil {
			items = append(items, lineResults...)
			lines = append(lines, i)
			continue
		}

		lineResults = p.heuristicMethod2(line)
		if lineResults != nil {
			items = append(items, lineResults...)
			lines = append(lines, i)
			continue
		}

		// We give up. :(
		rest[i] = line
	}

	return &HeuristicResult{
		Items: items,
		lines: lines,
	}, rest
}

func (p *HeuristicParser) heuristicMethod1(line string) []HeuristicItem {
	parts := removeEmpty(heuristicTrimStrings(strings.Split(line, "\t"), ", _=-[]*"))
	if len(parts) == 1 {
		parts = removeEmpty(heuristicTrimStrings(strings.Split(line, "-"), ", _=-[]*"))
	}
	if len(parts) == 1 {
		parts = removeEmpty(heuristicTrimStrings(strings.Split(line, "  "), ", _=-[]*"))
	}
	if len(parts) == 1 {
		parts = removeEmpty(heuristicTrimStrings(strings.Split(line, " "), ", _=-[]*"))
	}
	if len(parts) == 1 {
		parts = removeEmpty(heuristicTrimStrings(strings.Split(line, " "), ", _=-[]*"))
	}

	if len(parts) == 1 {
		return nil
	}

	for _, spec := range HeuristicSpecs {
		if len(parts) < len(spec) {
			continue
		}

		name := ""
		quantity := int64(1)
		matched := true
		for index, specPart := range spec {
			switch specPart {
			case HEURISTIC_IGNORE:
			case HEURISTIC_ITEM:
				name = parts[index]
				if !p.typeDB.HasType(name) {
					matched = false
					break
				}
			case HEURISTIC_QUANTITY:
				quantity = ToInt(parts[index])
				if quantity == 0 {
					matched = false
					break
				}
			}
		}

		if matched {
			return []HeuristicItem{{Name: name, Quantity: quantity}}
		}
	}

	r, _ := NewContextListingParser(p.typeDB)(StringsToInput(parts))
	if len(r.Lines()) > 0 {
		switch r := r.(type) {
		case *Listing:
			var items []HeuristicItem
			for _, item := range r.Items {
				items = append(items, HeuristicItem{Name: item.Name, Quantity: item.Quantity})
			}
			return items
		}
	}
	return nil
}

func (p *HeuristicParser) heuristicMethod2(line string) []HeuristicItem {
	var b bytes.Buffer
	for _, part := range strings.Fields(line) {
		b.WriteString(strings.Trim(part, ",\t "))
		name := b.String()
		if p.typeDB.HasType(name) {
			return []HeuristicItem{{Name: name, Quantity: 1}}
		}
	}
	return nil
}
<commit_msg>Tweak heuristic parser<commit_after>package parsers

import (
	"bytes"
	"strings"

	"github.com/evepraisal/go-evepraisal/typedb"
)

const (
	HEURISTIC_ITEM     = iota
	HEURISTIC_QUANTITY = iota
	HEURISTIC_IGNORE   = iota
)

var HeuristicSpecs = [][]int{
	{HEURISTIC_IGNORE, HEURISTIC_ITEM, HEURISTIC_IGNORE, HEURISTIC_QUANTITY},
	{HEURISTIC_QUANTITY, HEURISTIC_IGNORE, HEURISTIC_ITEM},
	{HEURISTIC_ITEM, HEURISTIC_QUANTITY},
	{HEURISTIC_QUANTITY, HEURISTIC_ITEM},
}

type HeuristicParser struct {
	typeDB typedb.TypeDB
}

func heuristicTrimStrings(parts []string, trim string) []string {
	for i := range parts {
		parts[i] = strings.Trim(parts[i], trim)
	}
	return parts
}

func removeEmpty(parts []string) []string {
	newParts := make([]string, 0)
	for _, s := range parts {
		s = strings.TrimSpace(s)
		if s != "" {
			newParts = append(newParts, s)
		}
	}
	return newParts
}

type HeuristicResult struct {
	Items []HeuristicItem
	lines []int
}

func (r *HeuristicResult) Name() string {
	return "heuristic"
}

func (r *HeuristicResult) Lines() []int {
	return r.lines
}

type HeuristicItem struct {
	Name     string
	Quantity int64
}

func NewHeuristicParser(typeDB typedb.TypeDB) Parser {
	p := &HeuristicParser{typeDB: typeDB}
	return p.Parse
}

func (p *HeuristicParser) Parse(input Input) (ParserResult, Input) {
	var items []HeuristicItem
	var lines []int
	rest := make(Input)
	for i, line := range input {
		var lineResults []HeuristicItem
		lineResults = p.heuristicMethod1(line)
		if lineResults != nil {
			items = append(items, lineResults...)
			lines = append(lines, i)
			continue
		}

		lineResults = p.heuristicMethod2(line)
		if lineResults != nil {
			items = append(items, lineResults...)
			lines = append(lines, i)
			continue
		}

		// We give up. :(
		rest[i] = line
	}

	return &HeuristicResult{
		Items: items,
		lines: lines,
	}, rest
}

func (p *HeuristicParser) heuristicMethod1(line string) []HeuristicItem {
	// Let's try tab separators
	parts := removeEmpty(heuristicTrimStrings(strings.Split(line, "\t"), ", _=-[]*"))
	if len(parts) == 1 {
		// Let's try double space separators
		parts = removeEmpty(heuristicTrimStrings(strings.Split(line, "  "), ", _=-[]*"))
	}
	if len(parts) == 1 {
		// Let's try dash separators
		parts = removeEmpty(heuristicTrimStrings(strings.Split(line, "-"), ", _=-[]*"))
	}
	if len(parts) == 1 {
		// Let's try space separators
		parts = removeEmpty(heuristicTrimStrings(strings.Split(line, " "), ", _=-[]*"))
	}

	if len(parts) == 1 {
		return nil
	}

	for _, spec := range HeuristicSpecs {
		if len(parts) < len(spec) {
			continue
		}

		name := ""
		quantity := int64(1)
		matched := true
		for index, specPart := range spec {
			switch specPart {
			case HEURISTIC_IGNORE:
			case HEURISTIC_ITEM:
				name = parts[index]
				if !p.typeDB.HasType(name) {
					matched = false
					break
				}
			case HEURISTIC_QUANTITY:
				quantity = ToInt(parts[index])
				if quantity == 0 {
					matched = false
					break
				}
			}
		}

		if matched {
			return []HeuristicItem{{Name: name, Quantity: quantity}}
		}
	}

	r, _ := NewContextListingParser(p.typeDB)(StringsToInput(parts))
	if len(r.Lines()) > 0 {
		switch r := r.(type) {
		case *Listing:
			var items []HeuristicItem
			for _, item := range r.Items {
				items = append(items, HeuristicItem{Name: item.Name, Quantity: item.Quantity})
			}
			return items
		}
	}
	return nil
}

func (p *HeuristicParser) heuristicMethod2(line string) []HeuristicItem {
	var b bytes.Buffer
	for _, part := range strings.Fields(line) {
		b.WriteString(strings.Trim(part, ",\t "))
		name := b.String()
		if p.typeDB.HasType(name) {
			return []HeuristicItem{{Name: name, Quantity: 1}}
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	logpkg "log"
	"net"
    "net/http"
	"os"
    "io"
	"strings"
	"time"
)

const listenAddr = "localhost:7777"

var log = logpkg.New(os.Stderr, "", logpkg.Ldate|logpkg.Ltime)

type Version struct {
	AppId      string `json:"app_id"`
	Name       string `json:"name"`
	Version    string `json:"version"`
	Host       string `json:"host"`
	Instance   uint16 `json:"instance"`
	HostIP     string `json:"host_ip"`
	LastUpdate int64  `json:"last_update"`
}

func safeRunes(r rune) rune {
	if 'a' <= r && r <= 'z' {
		return r
	}
	return '_'
}

func AppNameToID(app string) (id string) {
	id = strings.ToLower(app)
	id = strings.Map(safeRunes, id)
	return
}

func parsePacket(host string, b []byte) (v Version, err error) {
	v.HostIP = host
	v.LastUpdate = time.Now().Unix()
	err = json.Unmarshal(b[:len(b)], &v)
	if err != nil {
		log.Print("parsePacket: ", err)
	}
	v.AppId = AppNameToID(v.Name)
	log.Print(v)
	return
}

func handleUpdateUDP(conn net.PacketConn) {
	for {
		b := make([]byte, 2048)
		n, addr, err := conn.ReadFrom(b)
		if err != nil {
			log.Print("Error reading UDP packet:\n  ", err)
			continue
		}
		ip := addr.(*net.UDPAddr).IP
		parsePacket(ip.String(), b[:n])
	}
}

// hello world, the web server
func HelloServer(w http.ResponseWriter, req *http.Request) {
	io.WriteString(w, "hello, world!\n")
}

func main() {
	log.Print("Starting.")

	conn, err := net.ListenPacket("udp", listenAddr)
	if err != nil {
		log.Fatalf("Error opening listen socket: %v\n  %v", listenAddr, err)
	}
	log.Print("listening on: ", conn.LocalAddr())

	go handleUpdateUDP(conn)

	http.HandleFunc("/", HelloServer)
	err = http.ListenAndServe(listenAddr, nil)
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
	log.Print("Exit.")
}
<commit_msg>gofmt<commit_after>package main

import (
	"encoding/json"
	"io"
	logpkg "log"
	"net"
	"net/http"
	"os"
	"strings"
	"time"
)

const listenAddr = "localhost:7777"

var log = logpkg.New(os.Stderr, "", logpkg.Ldate|logpkg.Ltime)

type Version struct {
	AppId      string `json:"app_id"`
	Name       string `json:"name"`
	Version    string `json:"version"`
	Host       string `json:"host"`
	Instance   uint16 `json:"instance"`
	HostIP     string `json:"host_ip"`
	LastUpdate int64  `json:"last_update"`
}

func safeRunes(r rune) rune {
	if 'a' <= r && r <= 'z' {
		return r
	}
	return '_'
}

func AppNameToID(app string) (id string) {
	id = strings.ToLower(app)
	id = strings.Map(safeRunes, id)
	return
}

func parsePacket(host string, b []byte) (v Version, err error) {
	v.HostIP = host
	v.LastUpdate = time.Now().Unix()
	err = json.Unmarshal(b[:len(b)], &v)
	if err != nil {
		log.Print("parsePacket: ", err)
	}
	v.AppId = AppNameToID(v.Name)
	log.Print(v)
	return
}

func handleUpdateUDP(conn net.PacketConn) {
	for {
		b := make([]byte, 2048)
		n, addr, err := conn.ReadFrom(b)
		if err != nil {
			log.Print("Error reading UDP packet:\n  ", err)
			continue
		}
		ip := addr.(*net.UDPAddr).IP
		parsePacket(ip.String(), b[:n])
	}
}

// hello world, the web server
func HelloServer(w http.ResponseWriter, req *http.Request) {
	io.WriteString(w, "hello, world!\n")
}

func main() {
	log.Print("Starting.")

	conn, err := net.ListenPacket("udp", listenAddr)
	if err != nil {
		log.Fatalf("Error opening listen socket: %v\n  %v", listenAddr, err)
	}
	log.Print("listening on: ", conn.LocalAddr())

	go handleUpdateUDP(conn)

	http.HandleFunc("/", HelloServer)
	err = http.ListenAndServe(listenAddr, nil)
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
	log.Print("Exit.")
}
<|endoftext|>


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

package cache

import (
	"context"
	"fmt"
	"strings"
	"sync"

	"golang.org/x/tools/internal/lsp/source"
	"golang.org/x/tools/internal/lsp/xlog"
	"golang.org/x/tools/internal/span"
)

type session struct {
	cache *cache
	// the logger to use to communicate back with the client
	log xlog.Logger

	viewMu  sync.Mutex
	views   []*view
	viewMap map[span.URI]source.View

	overlayMu sync.Mutex
	overlays  map[span.URI]*source.FileContent

	openFiles     sync.Map
	filesWatchMap *WatchMap
}

func (s *session) Shutdown(ctx context.Context) {
	s.viewMu.Lock()
	defer s.viewMu.Unlock()
	for _, view := range s.views {
		view.shutdown(ctx)
	}
	s.views = nil
	s.viewMap = nil
}

func (s *session) Cache() source.Cache {
	return s.cache
}

func (s *session) NewView(name string, folder span.URI) source.View {
	s.viewMu.Lock()
	defer s.viewMu.Unlock()
	ctx := context.Background()
	backgroundCtx, cancel := context.WithCancel(ctx)
	v := &view{
		session:        s,
		baseCtx:        ctx,
		backgroundCtx:  backgroundCtx,
		cancel:         cancel,
		name:           name,
		folder:         folder,
		filesByURI:     make(map[span.URI]viewFile),
		filesByBase:    make(map[string][]viewFile),
		contentChanges: make(map[span.URI]func()),
		mcache: &metadataCache{
			packages: make(map[string]*metadata),
		},
		pcache: &packageCache{
			packages: make(map[string]*entry),
		},
		ignoredURIs: make(map[span.URI]struct{}),
	}
	s.views = append(s.views, v)
	// we always need to drop the view map
	s.viewMap = make(map[span.URI]source.View)
	return v
}

// View returns the view by name.
func (s *session) View(name string) source.View {
	s.viewMu.Lock()
	defer s.viewMu.Unlock()
	for _, view := range s.views {
		if view.Name() == name {
			return view
		}
	}
	return nil
}

// ViewOf returns a view corresponding to the given URI.
// If the file is not already associated with a view, pick one using some heuristics.
func (s *session) ViewOf(uri span.URI) source.View {
	s.viewMu.Lock()
	defer s.viewMu.Unlock()

	// check if we already know this file
	if v, found := s.viewMap[uri]; found {
		return v
	}

	// pick the best view for this file and memoize the result
	v := s.bestView(uri)
	s.viewMap[uri] = v
	return v
}

func (s *session) Views() []source.View {
	s.viewMu.Lock()
	defer s.viewMu.Unlock()
	result := make([]source.View, len(s.views))
	for i, v := range s.views {
		result[i] = v
	}
	return result
}

// bestView finds the best view to associate a given URI with.
// viewMu must be held when calling this method.
func (s *session) bestView(uri span.URI) source.View {
	// we need to find the best view for this file
	var longest source.View
	for _, view := range s.views {
		if longest != nil && len(longest.Folder()) > len(view.Folder()) {
			continue
		}
		if strings.HasPrefix(string(uri), string(view.Folder())) {
			longest = view
		}
	}
	if longest != nil {
		return longest
	}
	//TODO: are there any more heuristics we can use?
	return s.views[0]
}

func (s *session) removeView(ctx context.Context, view *view) error {
	s.viewMu.Lock()
	defer s.viewMu.Unlock()
	// we always need to drop the view map
	s.viewMap = make(map[span.URI]source.View)
	for i, v := range s.views {
		if view == v {
			// delete this view... we don't care about order but we do want to make
			// sure we can garbage collect the view
			s.views[i] = s.views[len(s.views)-1]
			s.views[len(s.views)-1] = nil
			s.views = s.views[:len(s.views)-1]
			v.shutdown(ctx)
			return nil
		}
	}
	return fmt.Errorf("view %s for %v not found", view.Name(), view.Folder())
}

func (s *session) Logger() xlog.Logger {
	return s.log
}

func (s *session) DidOpen(uri span.URI) {
	s.openFiles.Store(uri, true)
}

func (s *session) DidSave(uri span.URI) {
}

func (s *session) DidClose(uri span.URI) {
	s.openFiles.Delete(uri)
}

func (s *session) IsOpen(uri span.URI) bool {
	_, open := s.openFiles.Load(uri)
	return open
}

func (s *session) ReadFile(uri span.URI) *source.FileContent {
	s.overlayMu.Lock()
	defer s.overlayMu.Unlock()
	// We might have the content saved in an overlay.
	if overlay, ok := s.overlays[uri]; ok {
		return overlay
	}
	// fall back to the cache level file system
	return s.Cache().ReadFile(uri)
}

func (s *session) SetOverlay(uri span.URI, data []byte) {
	s.overlayMu.Lock()
	defer func() {
		s.overlayMu.Unlock()
		s.filesWatchMap.Notify(uri)
	}()
	if data == nil {
		delete(s.overlays, uri)
		return
	}
	s.overlays[uri] = &source.FileContent{
		URI:  uri,
		Data: data,
		Hash: hashContents(data),
	}
}

func (s *session) buildOverlay() map[string][]byte {
	s.overlayMu.Lock()
	defer s.overlayMu.Unlock()
	overlays := make(map[string][]byte)
	for uri, overlay := range s.overlays {
		if overlay.Error != nil {
			continue
		}
		if filename, err := uri.Filename(); err == nil {
			overlays[filename] = overlay.Data
		}
	}
	return overlays
}
<commit_msg>internal/lsp: set env to os.Environ to start<commit_after>// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package cache

import (
	"context"
	"fmt"
	"os"
	"strings"
	"sync"

	"golang.org/x/tools/internal/lsp/source"
	"golang.org/x/tools/internal/lsp/xlog"
	"golang.org/x/tools/internal/span"
)

type session struct {
	cache *cache
	// the logger to use to communicate back with the client
	log xlog.Logger

	viewMu  sync.Mutex
	views   []*view
	viewMap map[span.URI]source.View

	overlayMu sync.Mutex
	overlays  map[span.URI]*source.FileContent

	openFiles     sync.Map
	filesWatchMap *WatchMap
}

func (s *session) Shutdown(ctx context.Context) {
	s.viewMu.Lock()
	defer s.viewMu.Unlock()
	for _, view := range s.views {
		view.shutdown(ctx)
	}
	s.views = nil
	s.viewMap = nil
}

func (s *session) Cache() source.Cache {
	return s.cache
}

func (s *session) NewView(name string, folder span.URI) source.View {
	s.viewMu.Lock()
	defer s.viewMu.Unlock()
	ctx := context.Background()
	backgroundCtx, cancel := context.WithCancel(ctx)
	v := &view{
		session:        s,
		baseCtx:        ctx,
		backgroundCtx:  backgroundCtx,
		cancel:         cancel,
		name:           name,
		env:            os.Environ(),
		folder:         folder,
		filesByURI:     make(map[span.URI]viewFile),
		filesByBase:    make(map[string][]viewFile),
		contentChanges: make(map[span.URI]func()),
		mcache: &metadataCache{
			packages: make(map[string]*metadata),
		},
		pcache: &packageCache{
			packages: make(map[string]*entry),
		},
		ignoredURIs: make(map[span.URI]struct{}),
	}
	s.views = append(s.views, v)
	// we always need to drop the view map
	s.viewMap = make(map[span.URI]source.View)
	return v
}

// View returns the view by name.
func (s *session) View(name string) source.View {
	s.viewMu.Lock()
	defer s.viewMu.Unlock()
	for _, view := range s.views {
		if view.Name() == name {
			return view
		}
	}
	return nil
}

// ViewOf returns a view corresponding to the given URI.
// If the file is not already associated with a view, pick one using some heuristics.
func (s *session) ViewOf(uri span.URI) source.View {
	s.viewMu.Lock()
	defer s.viewMu.Unlock()

	// check if we already know this file
	if v, found := s.viewMap[uri]; found {
		return v
	}

	// pick the best view for this file and memoize the result
	v := s.bestView(uri)
	s.viewMap[uri] = v
	return v
}

func (s *session) Views() []source.View {
	s.viewMu.Lock()
	defer s.viewMu.Unlock()
	result := make([]source.View, len(s.views))
	for i, v := range s.views {
		result[i] = v
	}
	return result
}

// bestView finds the best view to associate a given URI with.
// viewMu must be held when calling this method.
func (s *session) bestView(uri span.URI) source.View {
	// we need to find the best view for this file
	var longest source.View
	for _, view := range s.views {
		if longest != nil && len(longest.Folder()) > len(view.Folder()) {
			continue
		}
		if strings.HasPrefix(string(uri), string(view.Folder())) {
			longest = view
		}
	}
	if longest != nil {
		return longest
	}
	//TODO: are there any more heuristics we can use?
	return s.views[0]
}

func (s *session) removeView(ctx context.Context, view *view) error {
	s.viewMu.Lock()
	defer s.viewMu.Unlock()
	// we always need to drop the view map
	s.viewMap = make(map[span.URI]source.View)
	for i, v := range s.views {
		if view == v {
			// delete this view... we don't care about order but we do want to make
			// sure we can garbage collect the view
			s.views[i] = s.views[len(s.views)-1]
			s.views[len(s.views)-1] = nil
			s.views = s.views[:len(s.views)-1]
			v.shutdown(ctx)
			return nil
		}
	}
	return fmt.Errorf("view %s for %v not found", view.Name(), view.Folder())
}

func (s *session) Logger() xlog.Logger {
	return s.log
}

func (s *session) DidOpen(uri span.URI) {
	s.openFiles.Store(uri, true)
}

func (s *session) DidSave(uri span.URI) {
}

func (s *session) DidClose(uri span.URI) {
	s.openFiles.Delete(uri)
}

func (s *session) IsOpen(uri span.URI) bool {
	_, open := s.openFiles.Load(uri)
	return open
}

func (s *session) ReadFile(uri span.URI) *source.FileContent {
	s.overlayMu.Lock()
	defer s.overlayMu.Unlock()
	// We might have the content saved in an overlay.
	if overlay, ok := s.overlays[uri]; ok {
		return overlay
	}
	// fall back to the cache level file system
	return s.Cache().ReadFile(uri)
}

func (s *session) SetOverlay(uri span.URI, data []byte) {
	s.overlayMu.Lock()
	defer func() {
		s.overlayMu.Unlock()
		s.filesWatchMap.Notify(uri)
	}()
	if data == nil {
		delete(s.overlays, uri)
		return
	}
	s.overlays[uri] = &source.FileContent{
		URI:  uri,
		Data: data,
		Hash: hashContents(data),
	}
}

func (s *session) buildOverlay() map[string][]byte {
	s.overlayMu.Lock()
	defer s.overlayMu.Unlock()
	overlays := make(map[string][]byte)
	for uri, overlay := range s.overlays {
		if overlay.Error != nil {
			continue
		}
		if filename, err := uri.Filename(); err == nil {
			overlays[filename] = overlay.Data
		}
	}
	return overlays
}
<|endoftext|>


<commit_before>package overview

import (
	"fmt"
	"log"
	"net/http"
	"os"

	"github.com/davecgh/go-spew/spew"
	"github.com/heptio/developer-dash/internal/cluster"
	"github.com/heptio/developer-dash/internal/hcli"
)

// ClusterOverview is an API for generating a cluster overview.
type ClusterOverview struct {
	client cluster.ClientInterface

	namespace string

	watchFactory func(namespace string, clusterClient cluster.ClientInterface, cache Cache) Watch

	cache  Cache
	stopFn func()

	generator *realGenerator
}

// NewClusterOverview creates an instance of ClusterOverview.
func NewClusterOverview(client cluster.ClientInterface, namespace string) *ClusterOverview {
	var opts []MemoryCacheOpt

	if os.Getenv("DASH_VERBOSE_CACHE") != "" {
		ch := make(chan CacheNotification)

		go func() {
			for notif := range ch {
				spew.Dump(notif)
			}
		}()

		opts = append(opts, CacheNotificationOpt(ch))
	}

	cache := NewMemoryCache(opts...)
	g := newGenerator(cache, defaultPathFilters)

	return &ClusterOverview{
		namespace:    namespace,
		client:       client,
		cache:        cache,
		watchFactory: watchFactory,
		generator:    g,
	}
}

// Name returns the name for this module.
func (co *ClusterOverview) Name() string {
	return "overview"
}

// ContentPath returns the content path for overview.
func (co *ClusterOverview) ContentPath() string {
	return fmt.Sprintf("/%s", co.Name())
}

// Handler returns a handler for serving overview HTTP content.
func (co *ClusterOverview) Handler(prefix string) http.Handler {
	return newHandler(prefix, co.generator, stream)
}

// Namespaces returns a list of namespace names for a cluster.
func (co *ClusterOverview) Namespaces() ([]string, error) {
	nsClient, err := co.client.NamespaceClient()
	if err != nil {
		return nil, err
	}

	return nsClient.Names()
}

// Navigation returns navigation entries for overview.
func (co *ClusterOverview) Navigation(root string) (*hcli.Navigation, error) {
	return navigationEntries(root)
}

// SetNamespace sets the current namespace.
func (co *ClusterOverview) SetNamespace(namespace string) error {
	log.Printf("Setting namespace for overview to %q", namespace)
	if co.stopFn != nil {
		co.stopFn()
	}

	co.namespace = namespace
	go co.Start()

	return nil
}

// Start starts overview.
func (co *ClusterOverview) Start() error {
	if co.namespace == "" {
		return nil
	}

	log.Printf("Starting cluster overview")

	stopFn, err := co.watch(co.namespace)
	if err != nil {
		return err
	}

	co.stopFn = stopFn

	return nil
}

// Stop stops overview.
func (co *ClusterOverview) Stop() {
	if co.stopFn != nil {
		log.Printf("Stopping cluster overview")

		co.stopFn()
	}
}

func (co *ClusterOverview) watch(namespace string) (StopFunc, error) {
	log.Printf("Watching namespace %s", namespace)

	watch := co.watchFactory(namespace, co.client, co.cache)
	return watch.Start()
}

func watchFactory(namespace string, clusterClient cluster.ClientInterface, cache Cache) Watch {
	return NewWatch(namespace, clusterClient, cache)
}
<commit_msg>Revert "asynchronously update namespace in overview"<commit_after>package overview

import (
	"fmt"
	"log"
	"net/http"
	"os"

	"github.com/davecgh/go-spew/spew"
	"github.com/heptio/developer-dash/internal/cluster"
	"github.com/heptio/developer-dash/internal/hcli"
)

// ClusterOverview is an API for generating a cluster overview.
type ClusterOverview struct {
	client cluster.ClientInterface

	namespace string

	watchFactory func(namespace string, clusterClient cluster.ClientInterface, cache Cache) Watch

	cache  Cache
	stopFn func()

	generator *realGenerator
}

// NewClusterOverview creates an instance of ClusterOverview.
func NewClusterOverview(client cluster.ClientInterface, namespace string) *ClusterOverview {
	var opts []MemoryCacheOpt

	if os.Getenv("DASH_VERBOSE_CACHE") != "" {
		ch := make(chan CacheNotification)

		go func() {
			for notif := range ch {
				spew.Dump(notif)
			}
		}()

		opts = append(opts, CacheNotificationOpt(ch))
	}

	cache := NewMemoryCache(opts...)
	g := newGenerator(cache, defaultPathFilters)

	return &ClusterOverview{
		namespace:    namespace,
		client:       client,
		cache:        cache,
		watchFactory: watchFactory,
		generator:    g,
	}
}

// Name returns the name for this module.
func (co *ClusterOverview) Name() string {
	return "overview"
}

// ContentPath returns the content path for overview.
func (co *ClusterOverview) ContentPath() string {
	return fmt.Sprintf("/%s", co.Name())
}

// Handler returns a handler for serving overview HTTP content.
func (co *ClusterOverview) Handler(prefix string) http.Handler {
	return newHandler(prefix, co.generator, stream)
}

// Namespaces returns a list of namespace names for a cluster.
func (co *ClusterOverview) Namespaces() ([]string, error) {
	nsClient, err := co.client.NamespaceClient()
	if err != nil {
		return nil, err
	}

	return nsClient.Names()
}

// Navigation returns navigation entries for overview.
func (co *ClusterOverview) Navigation(root string) (*hcli.Navigation, error) {
	return navigationEntries(root)
}

// SetNamespace sets the current namespace.
func (co *ClusterOverview) SetNamespace(namespace string) error {
	log.Printf("Setting namespace for overview to %q", namespace)
	if co.stopFn != nil {
		co.stopFn()
	}

	co.namespace = namespace
	return co.Start()
}

// Start starts overview.
func (co *ClusterOverview) Start() error {
	if co.namespace == "" {
		return nil
	}

	log.Printf("Starting cluster overview")

	stopFn, err := co.watch(co.namespace)
	if err != nil {
		return err
	}

	co.stopFn = stopFn

	return nil
}

// Stop stops overview.
func (co *ClusterOverview) Stop() {
	if co.stopFn != nil {
		log.Printf("Stopping cluster overview")

		co.stopFn()
	}
}

func (co *ClusterOverview) watch(namespace string) (StopFunc, error) {
	log.Printf("Watching namespace %s", namespace)

	watch := co.watchFactory(namespace, co.client, co.cache)
	return watch.Start()
}

func watchFactory(namespace string, clusterClient cluster.ClientInterface, cache Cache) Watch {
	return NewWatch(namespace, clusterClient, cache)
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"path"
	"strconv"
	"syscall"

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

func processExists(pid int) bool {
	proc, _ := os.FindProcess(pid)
	err := proc.Signal(syscall.Signal(0))
	// err could also be "permission denied", but for this test it's good enough
	return err == nil
}

var _ = Describe("Ssh", func() {
	Context("When starting ssh-agent", func() {
		vars := "SSH_AGENT_PID=123; export SSH_AGENT_PID;\nFOO=bar; export FOO;\nANSWER=42\n"
		BeforeEach(func() {
			os.Setenv("SSH_AGENT_PID", "")
			os.Setenv("FOO", "")
			os.Setenv("ANSWER", "")
		})

		It("sets the environment variables ssh-agent prints to STDOUT", func() {
			setEnvironmentVariablesFromString(vars)

			Expect(os.Getenv("SSH_AGENT_PID")).To(Equal("123"))
			Expect(os.Getenv("FOO")).To(Equal("bar"))
			Expect(os.Getenv("ANSWER")).To(Equal("42"))
		})

		It("can start and kill the agent", func() {
			err := startSshAgent()
			Expect(err).To(BeNil())

			Expect(os.Getenv("SSH_AGENT_PID")).ToNot(BeEmpty())

			pid, err := strconv.Atoi(os.Getenv("SSH_AGENT_PID"))
			Expect(err).To(BeNil())

			err = killSshAgent()
			Expect(err).To(BeNil())

			Eventually(func() bool {
				return processExists(pid)
			}).Should(BeFalse())
		})
	})

	homeDir := "/tmp"
	sshDir := path.Join(homeDir, ".ssh")
	sshClientConfigFile := path.Join(homeDir, ".ssh/config")

	Context("When configuring ssh", func() {
		It("can crete the directory", func() {

			// ensure the directory doesn't exists
			_, sshDirErr := os.Stat(sshDir)
			Expect(sshDirErr).NotTo(BeNil())

			err := mkSSHDir(sshClientConfigFile)
			Expect(err).To(BeNil())

			// check that the directory now exists
			_, resultErr := os.Stat(sshDir)
			Expect(resultErr).To(BeNil())

			// cleanup
			err = os.RemoveAll(sshDir)
			Expect(err).To(BeNil())
		})
		It("can ignores when the directory already exists", func() {

			// make sure the directory already exists
			sshDirErr := os.MkdirAll(sshDir, 0700)
			Expect(sshDirErr).To(BeNil())

			err := mkSSHDir(sshClientConfigFile)
			Expect(err).To(BeNil())

			// cleanup
			err = os.RemoveAll(sshDir)
			Expect(err).To(BeNil())
		})

	})
})
<commit_msg>changes based on review<commit_after>package main

import (
	"os"
	"path"
	"strconv"
	"syscall"

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

func processExists(pid int) bool {
	proc, _ := os.FindProcess(pid)
	err := proc.Signal(syscall.Signal(0))
	// err could also be "permission denied", but for this test it's good enough
	return err == nil
}

var _ = Describe("Ssh", func() {
	Context("When starting ssh-agent", func() {
		vars := "SSH_AGENT_PID=123; export SSH_AGENT_PID;\nFOO=bar; export FOO;\nANSWER=42\n"
		BeforeEach(func() {
			os.Setenv("SSH_AGENT_PID", "")
			os.Setenv("FOO", "")
			os.Setenv("ANSWER", "")
		})

		It("sets the environment variables ssh-agent prints to STDOUT", func() {
			setEnvironmentVariablesFromString(vars)

			Expect(os.Getenv("SSH_AGENT_PID")).To(Equal("123"))
			Expect(os.Getenv("FOO")).To(Equal("bar"))
			Expect(os.Getenv("ANSWER")).To(Equal("42"))
		})

		It("can start and kill the agent", func() {
			err := startSshAgent()
			Expect(err).To(BeNil())

			Expect(os.Getenv("SSH_AGENT_PID")).ToNot(BeEmpty())

			pid, err := strconv.Atoi(os.Getenv("SSH_AGENT_PID"))
			Expect(err).To(BeNil())

			err = killSshAgent()
			Expect(err).To(BeNil())

			Eventually(func() bool {
				return processExists(pid)
			}).Should(BeFalse())
		})
	})

	Context("When configuring ssh", func() {
		homeDir := "/tmp"
		sshDir := path.Join(homeDir, ".ssh")
		sshClientConfigFile := path.Join(homeDir, ".ssh/config")

		AfterEach(func() {
			// cleanup
			err := os.RemoveAll(sshDir)
			Expect(err).To(BeNil())
		})
		It("can crete the directory", func() {

			// ensure the directory doesn't exists
			_, sshDirErr := os.Stat(sshDir)
			Expect(sshDirErr).NotTo(BeNil())

			err := mkSSHDir(sshClientConfigFile)
			Expect(err).To(BeNil())

			// check that the directory now exists
			_, resultErr := os.Stat(sshDir)
			Expect(resultErr).To(BeNil())
		})
		It("can ignores when the directory already exists", func() {

			// make sure the directory already exists
			sshDirErr := os.MkdirAll(sshDir, 0700)
			Expect(sshDirErr).To(BeNil())

			err := mkSSHDir(sshClientConfigFile)
			Expect(err).To(BeNil())
		})

	})
})
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"testing"
	"time"

	"google.golang.org/grpc/metadata"
	"google.golang.org/grpc/peer"

	"golang.org/x/net/context"

	"github.com/getcfs/megacfs/formic"
	pb "github.com/getcfs/megacfs/formic/proto"
	"github.com/gogo/protobuf/proto"
	"github.com/satori/go.uuid"
)

// Minimal FileService for testing
type TestFS struct {
	writes [][]byte
	reads  [][]byte
}

func NewTestFS() *TestFS {
	return &TestFS{
		writes: make([][]byte, 0),
		reads:  make([][]byte, 0),
	}
}

func (fs *TestFS) InitFs(ctx context.Context, fsid []byte) error {
	return nil
}

func (fs *TestFS) GetDirent(ctx context.Context, parent []byte, name string) (*pb.DirEntry, error) {
	return nil, nil
}

func (fs *TestFS) GetInode(ctx context.Context, id []byte) (*pb.InodeEntry, error) {
	return nil, nil
}

func (fs *TestFS) GetChunk(ctx context.Context, id []byte) ([]byte, error) {
	if len(fs.reads) > 0 {
		chunk := fs.reads[0]
		fs.reads = fs.reads[1:]
		return chunk, nil
	} else {
		return []byte(""), nil
	}
}

func (fs *TestFS) WriteChunk(ctx context.Context, id, data []byte) error {
	fs.writes = append(fs.writes, data)
	return nil
}

func (fs *TestFS) DeleteChunk(ctx context.Context, id []byte, tsm int64) error {
	return nil
}

func (fs *TestFS) DeleteListing(ctx context.Context, parent []byte, name string, tsm int64) error {
	return nil
}

func (fs *TestFS) clearwrites() {
	fs.writes = make([][]byte, 0)
}

func (fs *TestFS) addread(d []byte) {
	fs.reads = append(fs.reads, d)
}

func (ds *TestFS) GetAttr(ctx context.Context, id []byte) (*pb.Attr, error) {
	return &pb.Attr{}, nil
}

func (ds *TestFS) SetAttr(ctx context.Context, id []byte, attr *pb.Attr, valid uint32) (*pb.Attr, error) {
	return &pb.Attr{}, nil
}

func (ds *TestFS) Create(ctx context.Context, parent, id []byte, inode uint64, name string, attr *pb.Attr, isdir bool) (string, *pb.Attr, error) {
	return name, attr, nil
}

func (ds *TestFS) Lookup(ctx context.Context, parent []byte, name string) (string, *pb.Attr, error) {
	return "", &pb.Attr{}, nil
}

func (ds *TestFS) ReadDirAll(ctx context.Context, id []byte) (*pb.ReadDirAllResponse, error) {
	return &pb.ReadDirAllResponse{}, nil
}

func (ds *TestFS) Remove(ctx context.Context, parent []byte, name string) (int32, error) {
	return 1, nil
}

func (ds *TestFS) Update(ctx context.Context, id []byte, block, blocksize, size uint64, mtime int64) error {
	return nil
}

func (ds *TestFS) Symlink(ctx context.Context, parent, id []byte, name string, target string, attr *pb.Attr, inode uint64) (*pb.SymlinkResponse, error) {
	return &pb.SymlinkResponse{}, nil
}

func (ds *TestFS) Readlink(ctx context.Context, id []byte) (*pb.ReadlinkResponse, error) {
	return &pb.ReadlinkResponse{}, nil
}

func (ds *TestFS) Getxattr(ctx context.Context, id []byte, name string) (*pb.GetxattrResponse, error) {
	return &pb.GetxattrResponse{}, nil
}

func (ds *TestFS) Setxattr(ctx context.Context, id []byte, name string, value []byte) (*pb.SetxattrResponse, error) {
	return &pb.SetxattrResponse{}, nil
}

func (ds *TestFS) Listxattr(ctx context.Context, id []byte) (*pb.ListxattrResponse, error) {
	return &pb.ListxattrResponse{}, nil
}

func (ds *TestFS) Removexattr(ctx context.Context, id []byte, name string) (*pb.RemovexattrResponse, error) {
	return &pb.RemovexattrResponse{}, nil
}

func (ds *TestFS) Rename(ctx context.Context, oldParent, newParent []byte, oldName, newName string) (*pb.RenameResponse, error) {
	return &pb.RenameResponse{}, nil
}

type fakePeerAddr struct {
}

func (f fakePeerAddr) Network() string {
	return "localhost"
}

func (f fakePeerAddr) String() string {
	return "127.0.0.1:1234"
}

func getContext() context.Context {
	fsid := uuid.NewV4()
	c, _ := context.WithTimeout(context.Background(), 5*time.Second)
	c = metadata.NewContext(
		c,
		metadata.Pairs("fsid", fsid.String()),
	)
	p := &peer.Peer{
		Addr: fakePeerAddr{},
	}
	c = peer.NewContext(c, p)
	return c
}

func TestGetID(t *testing.T) {
	id1 := formic.GetID([]byte("1"), uint64(1), uint64(1))
	id2 := formic.GetID([]byte("1"), uint64(1), uint64(1))
	if !bytes.Equal(id1, id2) {
		t.Errorf("Generated IDs not equal")
	}
	id3 := formic.GetID([]byte("1"), uint64(1), uint64(2))
	if bytes.Equal(id1, id3) {
		t.Errorf("Generated IDs were equal")
	}
}

func TestCreate(t *testing.T) {
	api := NewApiServer(NewTestFS(), 1, nil)
	_, err := api.Create(getContext(), &pb.CreateRequest{Parent: 1, Name: "Test", Attr: &pb.Attr{Gid: 1001, Uid: 1001}})
	if err != nil {
		t.Error("Create Failed: ", err)
	}

}

func TestWrite_Basic(t *testing.T) {
	fs := NewTestFS()
	api := NewApiServer(fs, 1, nil)
	api.blocksize = 10
	chunk := pb.WriteRequest{
		Inode:   0,
		Offset:  0,
		Payload: []byte("1234567890"),
	}
	r, err := api.Write(getContext(), &chunk)
	if err != nil {
		t.Error("Write Failed: ", err)
	}
	if r.Status != 0 {
		t.Error("Write status expected: 0, received: ", r.Status)
	}
	if !bytes.Equal(chunk.Payload, fs.writes[0]) {
		fmt.Println(fs.writes)
		t.Errorf("Expected write: '%s' recieved: '%s'", chunk.Payload, fs.writes[0])
	}
	chunk.Payload = []byte("1")
	fs.clearwrites()
	r, err = api.Write(getContext(), &chunk)
	if err != nil {
		t.Error("Write Failed: ", err)
	}
	if r.Status != 0 {
		t.Error("Write status expected: 0, received: ", r.Status)
	}
	if !bytes.Equal(chunk.Payload, fs.writes[0]) {
		fmt.Println(fs.writes)
		t.Errorf("Expected write: '%s' recieved: '%s'", chunk.Payload, fs.writes[0])
	}

}

func TestWrite_Chunk(t *testing.T) {
	fs := NewTestFS()
	api := NewApiServer(fs, 1, nil)
	api.blocksize = 5
	chunk := pb.WriteRequest{
		Inode:   0,
		Offset:  0,
		Payload: []byte("1234567890"),
	}
	r, err := api.Write(getContext(), &chunk)
	if err != nil {
		t.Error("Write Failed: ", err)
	}
	if r.Status != 0 {
		t.Error("Write status expected: 0, received: ", r.Status)
	}
	if !bytes.Equal(chunk.Payload[:5], fs.writes[0]) {
		fmt.Println(fs.writes)
		t.Errorf("Expected write: '%s' recieved: '%s'", chunk.Payload[:5], fs.writes[0])
	}
	if !bytes.Equal(chunk.Payload[5:], fs.writes[1]) {
		fmt.Println(fs.writes)
		t.Errorf("Expected write: '%s' recieved: '%s'", chunk.Payload[5:], fs.writes[1])
	}
}

func TestWrite_Offset(t *testing.T) {
	fs := NewTestFS()
	api := NewApiServer(fs, 1, nil)
	api.blocksize = 10
	chunk := pb.WriteRequest{
		Offset:  5,
		Payload: []byte("12345"),
		Inode:   0,
	}
	r, err := api.Write(getContext(), &chunk)
	if err != nil {
		t.Error("Write Failed: ", err)
	}
	if r.Status != 0 {
		t.Error("Write status expected: 0, received: ", r.Status)
	}
	if !bytes.Equal(chunk.Payload, fs.writes[0][5:]) {
		fmt.Println(fs.writes)
		t.Errorf("Expected write: '%s' recieved: '%s'", chunk.Payload, fs.writes[0][5:])
	}
	fs.clearwrites()
	chunk = pb.WriteRequest{
		Offset:  2,
		Payload: []byte("12345"),
		Inode:   0,
	}
	r, err = api.Write(getContext(), &chunk)
	if err != nil {
		t.Error("Write Failed: ", err)
	}
	if r.Status != 0 {
		t.Error("Write status expected: 0, received: ", r.Status)
	}
	if !bytes.Equal(chunk.Payload, fs.writes[0][2:7]) {
		fmt.Println(fs.writes)
		t.Errorf("Expected write: '%s' recieved: '%s'", chunk.Payload, fs.writes[0][5:])
	}

}

func TestWrite_MultiOffset(t *testing.T) {
	fs := NewTestFS()
	api := NewApiServer(fs, 1, nil)
	api.blocksize = 20
	chunk := pb.WriteRequest{
		Offset:  5,
		Payload: []byte("12345"),
		Inode:   0,
	}
	r, err := api.Write(getContext(), &chunk)
	if err != nil {
		t.Error("Write Failed: ", err)
	}
	if r.Status != 0 {
		t.Error("Write status expected: 0, received: ", r.Status)
	}
	if !bytes.Equal(chunk.Payload, fs.writes[0][5:]) {
		fmt.Println(fs.writes)
		t.Errorf("Expected write: '%s' recieved: '%s'", chunk.Payload, fs.writes[0][5:])
	}
}

func TestRead_Basic(t *testing.T) {
	fs := NewTestFS()
	api := NewApiServer(fs, 1, nil)
	api.blocksize = 10
	write := []byte("0123456789")
	fs.addread(write)
	data, err := api.Read(getContext(), &pb.ReadRequest{Inode: 0, Offset: 0, Size: 10})
	if err != nil {
		t.Error("Read Failed: ", err)
	}
	if !bytes.Equal(data.Payload, write) {
		t.Errorf("Expected read: '%s' received: '%s'", write, data)
	}
}

func TestRead_Offset(t *testing.T) {
	fs := NewTestFS()
	api := NewApiServer(fs, 1, nil)
	api.blocksize = 10
	write := []byte("0123456789")
	fs.addread(write)
	data, err := api.Read(getContext(), &pb.ReadRequest{Inode: 0, Offset: 5, Size: 5})
	if err != nil {
		t.Error("Read Failed: ", err)
	}
	if !bytes.Equal(data.Payload, write[5:]) {
		t.Errorf("Expected read: '%s' received: '%s'", write[5:], data)
	}
}

func TestRead_Chunk(t *testing.T) {
	fs := NewTestFS()
	api := NewApiServer(fs, 1, nil)
	api.blocksize = 10
	write1 := []byte("0123456789")
	write2 := []byte("9876543210")
	fs.addread(write1)
	fs.addread(write2)
	data, err := api.Read(getContext(), &pb.ReadRequest{Inode: 0, Offset: 0, Size: 20})
	if err != nil {
		t.Error("Read Failed: ", err)
	}
	if !bytes.Equal(data.Payload[:10], write1) {
		t.Errorf("Expected read: '%s' received: '%s'", write1, data.Payload[:10])
	}
	if !bytes.Equal(data.Payload[10:], write2) {
		t.Errorf("Expected read: '%s' received: '%s'", write2, data.Payload[10:])
	}
}

func TestProtoWriteSize(t *testing.T) {
	data := make([]byte, 64*1024)
	block := &pb.FileBlock{
		Data:     data,
		Checksum: uint32(8),
	}
	b, _ := proto.Marshal(block)
	fmt.Printf("Storing 64K and checksum in protobufs takes %d bytes.", len(b))
}
<commit_msg>Fixed tests<commit_after>package main

import (
	"bytes"
	"fmt"
	"testing"
	"time"

	"google.golang.org/grpc/metadata"
	"google.golang.org/grpc/peer"

	"golang.org/x/net/context"

	"github.com/getcfs/megacfs/formic"
	pb "github.com/getcfs/megacfs/formic/proto"
	"github.com/gogo/protobuf/proto"
	uuid "github.com/satori/go.uuid"
	"github.com/uber-go/zap"
)

// Minimal FileService for testing
type TestFS struct {
	writes [][]byte
	reads  [][]byte
}

func NewTestFS() *TestFS {
	return &TestFS{
		writes: make([][]byte, 0),
		reads:  make([][]byte, 0),
	}
}

func (fs *TestFS) InitFs(ctx context.Context, fsid []byte) error {
	return nil
}

func (fs *TestFS) GetDirent(ctx context.Context, parent []byte, name string) (*pb.DirEntry, error) {
	return nil, nil
}

func (fs *TestFS) GetInode(ctx context.Context, id []byte) (*pb.InodeEntry, error) {
	return nil, nil
}

func (fs *TestFS) GetChunk(ctx context.Context, id []byte) ([]byte, error) {
	if len(fs.reads) > 0 {
		chunk := fs.reads[0]
		fs.reads = fs.reads[1:]
		return chunk, nil
	} else {
		return []byte(""), nil
	}
}

func (fs *TestFS) WriteChunk(ctx context.Context, id, data []byte) error {
	fs.writes = append(fs.writes, data)
	return nil
}

func (fs *TestFS) DeleteChunk(ctx context.Context, id []byte, tsm int64) error {
	return nil
}

func (fs *TestFS) DeleteListing(ctx context.Context, parent []byte, name string, tsm int64) error {
	return nil
}

func (fs *TestFS) clearwrites() {
	fs.writes = make([][]byte, 0)
}

func (fs *TestFS) addread(d []byte) {
	fs.reads = append(fs.reads, d)
}

func (ds *TestFS) GetAttr(ctx context.Context, id []byte) (*pb.Attr, error) {
	return &pb.Attr{}, nil
}

func (ds *TestFS) SetAttr(ctx context.Context, id []byte, attr *pb.Attr, valid uint32) (*pb.Attr, error) {
	return &pb.Attr{}, nil
}

func (ds *TestFS) Create(ctx context.Context, parent, id []byte, inode uint64, name string, attr *pb.Attr, isdir bool) (string, *pb.Attr, error) {
	return name, attr, nil
}

func (ds *TestFS) Lookup(ctx context.Context, parent []byte, name string) (string, *pb.Attr, error) {
	return "", &pb.Attr{}, nil
}

func (ds *TestFS) ReadDirAll(ctx context.Context, id []byte) (*pb.ReadDirAllResponse, error) {
	return &pb.ReadDirAllResponse{}, nil
}

func (ds *TestFS) Remove(ctx context.Context, parent []byte, name string) (int32, error) {
	return 1, nil
}

func (ds *TestFS) Update(ctx context.Context, id []byte, block, blocksize, size uint64, mtime int64) error {
	return nil
}

func (ds *TestFS) Symlink(ctx context.Context, parent, id []byte, name string, target string, attr *pb.Attr, inode uint64) (*pb.SymlinkResponse, error) {
	return &pb.SymlinkResponse{}, nil
}

func (ds *TestFS) Readlink(ctx context.Context, id []byte) (*pb.ReadlinkResponse, error) {
	return &pb.ReadlinkResponse{}, nil
}

func (ds *TestFS) Getxattr(ctx context.Context, id []byte, name string) (*pb.GetxattrResponse, error) {
	return &pb.GetxattrResponse{}, nil
}

func (ds *TestFS) Setxattr(ctx context.Context, id []byte, name string, value []byte) (*pb.SetxattrResponse, error) {
	return &pb.SetxattrResponse{}, nil
}

func (ds *TestFS) Listxattr(ctx context.Context, id []byte) (*pb.ListxattrResponse, error) {
	return &pb.ListxattrResponse{}, nil
}

func (ds *TestFS) Removexattr(ctx context.Context, id []byte, name string) (*pb.RemovexattrResponse, error) {
	return &pb.RemovexattrResponse{}, nil
}

func (ds *TestFS) Rename(ctx context.Context, oldParent, newParent []byte, oldName, newName string) (*pb.RenameResponse, error) {
	return &pb.RenameResponse{}, nil
}

type fakePeerAddr struct {
}

func (f fakePeerAddr) Network() string {
	return "localhost"
}

func (f fakePeerAddr) String() string {
	return "127.0.0.1:1234"
}

func getContext() context.Context {
	fsid := uuid.NewV4()
	c, _ := context.WithTimeout(context.Background(), 5*time.Second)
	c = metadata.NewContext(
		c,
		metadata.Pairs("fsid", fsid.String()),
	)
	p := &peer.Peer{
		Addr: fakePeerAddr{},
	}
	c = peer.NewContext(c, p)
	return c
}

func TestGetID(t *testing.T) {
	id1 := formic.GetID([]byte("1"), uint64(1), uint64(1))
	id2 := formic.GetID([]byte("1"), uint64(1), uint64(1))
	if !bytes.Equal(id1, id2) {
		t.Errorf("Generated IDs not equal")
	}
	id3 := formic.GetID([]byte("1"), uint64(1), uint64(2))
	if bytes.Equal(id1, id3) {
		t.Errorf("Generated IDs were equal")
	}
}

func TestCreate(t *testing.T) {
	logger := zap.New(zap.NewJSONEncoder())
	logger.SetLevel(zap.InfoLevel)
	api := NewApiServer(NewTestFS(), 1, nil, logger)
	_, err := api.Create(getContext(), &pb.CreateRequest{Parent: 1, Name: "Test", Attr: &pb.Attr{Gid: 1001, Uid: 1001}})
	if err != nil {
		t.Error("Create Failed: ", err)
	}

}

func TestWrite_Basic(t *testing.T) {
	fs := NewTestFS()
	logger := zap.New(zap.NewJSONEncoder())
	logger.SetLevel(zap.InfoLevel)
	api := NewApiServer(fs, 1, nil, logger)
	api.blocksize = 10
	chunk := pb.WriteRequest{
		Inode:   0,
		Offset:  0,
		Payload: []byte("1234567890"),
	}
	r, err := api.Write(getContext(), &chunk)
	if err != nil {
		t.Error("Write Failed: ", err)
	}
	if r.Status != 0 {
		t.Error("Write status expected: 0, received: ", r.Status)
	}
	if !bytes.Equal(chunk.Payload, fs.writes[0]) {
		fmt.Println(fs.writes)
		t.Errorf("Expected write: '%s' recieved: '%s'", chunk.Payload, fs.writes[0])
	}
	chunk.Payload = []byte("1")
	fs.clearwrites()
	r, err = api.Write(getContext(), &chunk)
	if err != nil {
		t.Error("Write Failed: ", err)
	}
	if r.Status != 0 {
		t.Error("Write status expected: 0, received: ", r.Status)
	}
	if !bytes.Equal(chunk.Payload, fs.writes[0]) {
		fmt.Println(fs.writes)
		t.Errorf("Expected write: '%s' recieved: '%s'", chunk.Payload, fs.writes[0])
	}

}

func TestWrite_Chunk(t *testing.T) {
	fs := NewTestFS()
	logger := zap.New(zap.NewJSONEncoder())
	logger.SetLevel(zap.InfoLevel)
	api := NewApiServer(fs, 1, nil, logger)
	api.blocksize = 5
	chunk := pb.WriteRequest{
		Inode:   0,
		Offset:  0,
		Payload: []byte("1234567890"),
	}
	r, err := api.Write(getContext(), &chunk)
	if err != nil {
		t.Error("Write Failed: ", err)
	}
	if r.Status != 0 {
		t.Error("Write status expected: 0, received: ", r.Status)
	}
	if !bytes.Equal(chunk.Payload[:5], fs.writes[0]) {
		fmt.Println(fs.writes)
		t.Errorf("Expected write: '%s' recieved: '%s'", chunk.Payload[:5], fs.writes[0])
	}
	if !bytes.Equal(chunk.Payload[5:], fs.writes[1]) {
		fmt.Println(fs.writes)
		t.Errorf("Expected write: '%s' recieved: '%s'", chunk.Payload[5:], fs.writes[1])
	}
}

func TestWrite_Offset(t *testing.T) {
	fs := NewTestFS()
	logger := zap.New(zap.NewJSONEncoder())
	logger.SetLevel(zap.InfoLevel)
	api := NewApiServer(fs, 1, nil, logger)
	api.blocksize = 10
	chunk := pb.WriteRequest{
		Offset:  5,
		Payload: []byte("12345"),
		Inode:   0,
	}
	r, err := api.Write(getContext(), &chunk)
	if err != nil {
		t.Error("Write Failed: ", err)
	}
	if r.Status != 0 {
		t.Error("Write status expected: 0, received: ", r.Status)
	}
	if !bytes.Equal(chunk.Payload, fs.writes[0][5:]) {
		fmt.Println(fs.writes)
		t.Errorf("Expected write: '%s' recieved: '%s'", chunk.Payload, fs.writes[0][5:])
	}
	fs.clearwrites()
	chunk = pb.WriteRequest{
		Offset:  2,
		Payload: []byte("12345"),
		Inode:   0,
	}
	r, err = api.Write(getContext(), &chunk)
	if err != nil {
		t.Error("Write Failed: ", err)
	}
	if r.Status != 0 {
		t.Error("Write status expected: 0, received: ", r.Status)
	}
	if !bytes.Equal(chunk.Payload, fs.writes[0][2:7]) {
		fmt.Println(fs.writes)
		t.Errorf("Expected write: '%s' recieved: '%s'", chunk.Payload, fs.writes[0][5:])
	}

}

func TestWrite_MultiOffset(t *testing.T) {
	fs := NewTestFS()
	logger := zap.New(zap.NewJSONEncoder())
	logger.SetLevel(zap.InfoLevel)
	api := NewApiServer(fs, 1, nil, logger)
	api.blocksize = 20
	chunk := pb.WriteRequest{
		Offset:  5,
		Payload: []byte("12345"),
		Inode:   0,
	}
	r, err := api.Write(getContext(), &chunk)
	if err != nil {
		t.Error("Write Failed: ", err)
	}
	if r.Status != 0 {
		t.Error("Write status expected: 0, received: ", r.Status)
	}
	if !bytes.Equal(chunk.Payload, fs.writes[0][5:]) {
		fmt.Println(fs.writes)
		t.Errorf("Expected write: '%s' recieved: '%s'", chunk.Payload, fs.writes[0][5:])
	}
}

func TestRead_Basic(t *testing.T) {
	fs := NewTestFS()
	logger := zap.New(zap.NewJSONEncoder())
	logger.SetLevel(zap.InfoLevel)
	api := NewApiServer(fs, 1, nil, logger)
	api.blocksize = 10
	write := []byte("0123456789")
	fs.addread(write)
	data, err := api.Read(getContext(), &pb.ReadRequest{Inode: 0, Offset: 0, Size: 10})
	if err != nil {
		t.Error("Read Failed: ", err)
	}
	if !bytes.Equal(data.Payload, write) {
		t.Errorf("Expected read: '%s' received: '%s'", write, data)
	}
}

func TestRead_Offset(t *testing.T) {
	fs := NewTestFS()
	logger := zap.New(zap.NewJSONEncoder())
	logger.SetLevel(zap.InfoLevel)
	api := NewApiServer(fs, 1, nil, logger)
	api.blocksize = 10
	write := []byte("0123456789")
	fs.addread(write)
	data, err := api.Read(getContext(), &pb.ReadRequest{Inode: 0, Offset: 5, Size: 5})
	if err != nil {
		t.Error("Read Failed: ", err)
	}
	if !bytes.Equal(data.Payload, write[5:]) {
		t.Errorf("Expected read: '%s' received: '%s'", write[5:], data)
	}
}

func TestRead_Chunk(t *testing.T) {
	fs := NewTestFS()
	logger := zap.New(zap.NewJSONEncoder())
	logger.SetLevel(zap.InfoLevel)
	api := NewApiServer(fs, 1, nil, logger)
	api.blocksize = 10
	write1 := []byte("0123456789")
	write2 := []byte("9876543210")
	fs.addread(write1)
	fs.addread(write2)
	data, err := api.Read(getContext(), &pb.ReadRequest{Inode: 0, Offset: 0, Size: 20})
	if err != nil {
		t.Error("Read Failed: ", err)
	}
	if !bytes.Equal(data.Payload[:10], write1) {
		t.Errorf("Expected read: '%s' received: '%s'", write1, data.Payload[:10])
	}
	if !bytes.Equal(data.Payload[10:], write2) {
		t.Errorf("Expected read: '%s' received: '%s'", write2, data.Payload[10:])
	}
}

func TestProtoWriteSize(t *testing.T) {
	data := make([]byte, 64*1024)
	block := &pb.FileBlock{
		Data:     data,
		Checksum: uint32(8),
	}
	b, _ := proto.Marshal(block)
	fmt.Printf("Storing 64K and checksum in protobufs takes %d bytes.", len(b))
}
<|endoftext|>


<commit_before>// +build windows

package wca

import (
	"math"
	"syscall"
	"unsafe"
)

func savSetMasterVolume(sav *ISimpleAudioVolume, level float32, eventContext *ole.GUID) (err error) {
	levelValue := math.Float32bits(level)

	hr, _, _ := syscall.Syscall(
		sav.VTable().SetMasterVolume,
		3,
		uintptr(unsafe.Pointer(sav)),
		uintptr(levelValue),
		uintptr(unsafe.Pointer(eventContext)))
	if hr != 0 {
		err = ole.NewError(hr)
	}
	return
}

func savGetMasterVolume(sav *ISimpleAudioVolume, level *float32) (err error) {
	hr, _, _ := syscall.Syscall(
		sav.VTable().GetMasterVolume,
		2,
		uintptr(unsafe.Pointer(sav)),
		uintptr(unsafe.Pointer(level)),
		0)
	if hr != 0 {
		err = ole.NewError(hr)
	}
	return
}

func savSetMute(sav *ISimpleAudioVolume, mute bool, eventContext *ole.GUID) (err error) {
	var muteValue uint32

	if mute {
		muteValue = 1
	}
	hr, _, _ := syscall.Syscall(
		sav.VTable().SetMute,
		3,
		uintptr(unsafe.Pointer(sav)),
		uintptr(muteValue),
		uintptr(unsafe.Pointer(eventContext)))
	if hr != 0 {
		err = ole.NewError(hr)
	}
	return
}

func savGetMute(sav *ISimpleAudioVolume, mute *bool) (err error) {
	hr, _, _ := syscall.Syscall(
		sav.VTable().GetMute,
		2,
		uintptr(unsafe.Pointer(sav)),
		uintptr(unsafe.Pointer(mute)),
		0)
	if hr != 0 {
		err = ole.NewError(hr)
	}
	return
}
<commit_msg>Fix import<commit_after>// +build windows

package wca

import (
	"math"
	"syscall"
	"unsafe"

    "github.com/go-ole/go-ole"
)

func savSetMasterVolume(sav *ISimpleAudioVolume, level float32, eventContext *ole.GUID) (err error) {
	levelValue := math.Float32bits(level)

	hr, _, _ := syscall.Syscall(
		sav.VTable().SetMasterVolume,
		3,
		uintptr(unsafe.Pointer(sav)),
		uintptr(levelValue),
		uintptr(unsafe.Pointer(eventContext)))
	if hr != 0 {
		err = ole.NewError(hr)
	}
	return
}

func savGetMasterVolume(sav *ISimpleAudioVolume, level *float32) (err error) {
	hr, _, _ := syscall.Syscall(
		sav.VTable().GetMasterVolume,
		2,
		uintptr(unsafe.Pointer(sav)),
		uintptr(unsafe.Pointer(level)),
		0)
	if hr != 0 {
		err = ole.NewError(hr)
	}
	return
}

func savSetMute(sav *ISimpleAudioVolume, mute bool, eventContext *ole.GUID) (err error) {
	var muteValue uint32

	if mute {
		muteValue = 1
	}
	hr, _, _ := syscall.Syscall(
		sav.VTable().SetMute,
		3,
		uintptr(unsafe.Pointer(sav)),
		uintptr(muteValue),
		uintptr(unsafe.Pointer(eventContext)))
	if hr != 0 {
		err = ole.NewError(hr)
	}
	return
}

func savGetMute(sav *ISimpleAudioVolume, mute *bool) (err error) {
	hr, _, _ := syscall.Syscall(
		sav.VTable().GetMute,
		2,
		uintptr(unsafe.Pointer(sav)),
		uintptr(unsafe.Pointer(mute)),
		0)
	if hr != 0 {
		err = ole.NewError(hr)
	}
	return
}
<|endoftext|>


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

package net

import (
	"errors"
	"os"
	"runtime"
	"syscall"
	"testing"
)

var multicastListenerTests = []struct {
	net   string
	gaddr *UDPAddr
	flags Flags
	ipv6  bool // test with underlying AF_INET6 socket
}{
	// cf. RFC 4727: Experimental Values in IPv4, IPv6, ICMPv4, ICMPv6, UDP, and TCP Headers

	{"udp", &UDPAddr{IPv4(224, 0, 0, 254), 12345}, FlagUp | FlagLoopback, false},
	{"udp", &UDPAddr{IPv4(224, 0, 0, 254), 12345}, 0, false},
	{"udp", &UDPAddr{ParseIP("ff0e::114"), 12345}, FlagUp | FlagLoopback, true},
	{"udp", &UDPAddr{ParseIP("ff0e::114"), 12345}, 0, true},

	{"udp4", &UDPAddr{IPv4(224, 0, 0, 254), 12345}, FlagUp | FlagLoopback, false},
	{"udp4", &UDPAddr{IPv4(224, 0, 0, 254), 12345}, 0, false},

	{"udp6", &UDPAddr{ParseIP("ff01::114"), 12345}, FlagUp | FlagLoopback, true},
	{"udp6", &UDPAddr{ParseIP("ff01::114"), 12345}, 0, true},
	{"udp6", &UDPAddr{ParseIP("ff02::114"), 12345}, FlagUp | FlagLoopback, true},
	{"udp6", &UDPAddr{ParseIP("ff02::114"), 12345}, 0, true},
	{"udp6", &UDPAddr{ParseIP("ff04::114"), 12345}, FlagUp | FlagLoopback, true},
	{"udp6", &UDPAddr{ParseIP("ff04::114"), 12345}, 0, true},
	{"udp6", &UDPAddr{ParseIP("ff05::114"), 12345}, FlagUp | FlagLoopback, true},
	{"udp6", &UDPAddr{ParseIP("ff05::114"), 12345}, 0, true},
	{"udp6", &UDPAddr{ParseIP("ff08::114"), 12345}, FlagUp | FlagLoopback, true},
	{"udp6", &UDPAddr{ParseIP("ff08::114"), 12345}, 0, true},
	{"udp6", &UDPAddr{ParseIP("ff0e::114"), 12345}, FlagUp | FlagLoopback, true},
	{"udp6", &UDPAddr{ParseIP("ff0e::114"), 12345}, 0, true},
}

// TestMulticastListener tests both single and double listen to a test
// listener with same address family, same group address and same port.
func TestMulticastListener(t *testing.T) {
	switch runtime.GOOS {
	case "netbsd", "openbsd", "plan9", "windows":
		t.Logf("skipping test on %q", runtime.GOOS)
		return
	case "linux":
		if runtime.GOARCH == "arm" || runtime.GOARCH == "alpha" {
			t.Logf("skipping test on %q/%q", runtime.GOOS, runtime.GOARCH)
			return
		}
	}

	for _, tt := range multicastListenerTests {
		if tt.ipv6 && (!supportsIPv6 || os.Getuid() != 0) {
			continue
		}
		ifi, err := availMulticastInterface(t, tt.flags)
		if err != nil {
			continue
		}
		c1, err := ListenMulticastUDP(tt.net, ifi, tt.gaddr)
		if err != nil {
			t.Fatalf("First ListenMulticastUDP failed: %v", err)
		}
		checkMulticastListener(t, err, c1, tt.gaddr)
		c2, err := ListenMulticastUDP(tt.net, ifi, tt.gaddr)
		if err != nil {
			t.Fatalf("Second ListenMulticastUDP failed: %v", err)
		}
		checkMulticastListener(t, err, c2, tt.gaddr)
		c2.Close()
		switch c1.fd.family {
		case syscall.AF_INET:
			testIPv4MulticastSocketOptions(t, c1.fd, ifi)
		case syscall.AF_INET6:
			testIPv6MulticastSocketOptions(t, c1.fd, ifi)
		}
		c1.Close()
	}
}

func TestSimpleMulticastListener(t *testing.T) {
	switch runtime.GOOS {
	case "plan9":
		t.Logf("skipping test on %q", runtime.GOOS)
		return
	}

	for _, tt := range multicastListenerTests {
		if tt.ipv6 {
			continue
		}
		tt.flags = FlagUp | FlagMulticast // for windows testing
		ifi, err := availMulticastInterface(t, tt.flags)
		if err != nil {
			continue
		}
		c1, err := ListenMulticastUDP(tt.net, ifi, tt.gaddr)
		if err != nil {
			t.Fatalf("First ListenMulticastUDP failed: %v", err)
		}
		checkSimpleMulticastListener(t, err, c1, tt.gaddr)
		c2, err := ListenMulticastUDP(tt.net, ifi, tt.gaddr)
		if err != nil {
			t.Fatalf("Second ListenMulticastUDP failed: %v", err)
		}
		checkSimpleMulticastListener(t, err, c2, tt.gaddr)
		c2.Close()
		c1.Close()
	}
}

func checkMulticastListener(t *testing.T, err error, c *UDPConn, gaddr *UDPAddr) {
	if !multicastRIBContains(t, gaddr.IP) {
		t.Fatalf("%q not found in RIB", gaddr.String())
	}
	if c.LocalAddr().String() != gaddr.String() {
		t.Fatalf("LocalAddr returns %q, expected %q", c.LocalAddr().String(), gaddr.String())
	}
}

func checkSimpleMulticastListener(t *testing.T, err error, c *UDPConn, gaddr *UDPAddr) {
	if c.LocalAddr().String() != gaddr.String() {
		t.Fatalf("LocalAddr returns %q, expected %q", c.LocalAddr().String(), gaddr.String())
	}
}

func availMulticastInterface(t *testing.T, flags Flags) (*Interface, error) {
	var ifi *Interface
	if flags != Flags(0) {
		ift, err := Interfaces()
		if err != nil {
			t.Fatalf("Interfaces failed: %v", err)
		}
		for _, x := range ift {
			if x.Flags&flags == flags {
				ifi = &x
				break
			}
		}
		if ifi == nil {
			return nil, errors.New("an appropriate multicast interface not found")
		}
	}
	return ifi, nil
}

func multicastRIBContains(t *testing.T, ip IP) bool {
	ift, err := Interfaces()
	if err != nil {
		t.Fatalf("Interfaces failed: %v", err)
	}
	for _, ifi := range ift {
		ifmat, err := ifi.MulticastAddrs()
		if err != nil {
			t.Fatalf("MulticastAddrs failed: %v", err)
		}
		for _, ifma := range ifmat {
			if ifma.(*IPAddr).IP.Equal(ip) {
				return true
			}
		}
	}
	return false
}

func testIPv4MulticastSocketOptions(t *testing.T, fd *netFD, ifi *Interface) {
	_, err := ipv4MulticastInterface(fd)
	if err != nil {
		t.Fatalf("ipv4MulticastInterface failed: %v", err)
	}
	if ifi != nil {
		err = setIPv4MulticastInterface(fd, ifi)
		if err != nil {
			t.Fatalf("setIPv4MulticastInterface failed: %v", err)
		}
	}
	_, err = ipv4MulticastTTL(fd)
	if err != nil {
		t.Fatalf("ipv4MulticastTTL failed: %v", err)
	}
	err = setIPv4MulticastTTL(fd, 1)
	if err != nil {
		t.Fatalf("setIPv4MulticastTTL failed: %v", err)
	}
	_, err = ipv4MulticastLoopback(fd)
	if err != nil {
		t.Fatalf("ipv4MulticastLoopback failed: %v", err)
	}
	err = setIPv4MulticastLoopback(fd, false)
	if err != nil {
		t.Fatalf("setIPv4MulticastLoopback failed: %v", err)
	}
}

func testIPv6MulticastSocketOptions(t *testing.T, fd *netFD, ifi *Interface) {
	_, err := ipv6MulticastInterface(fd)
	if err != nil {
		t.Fatalf("ipv6MulticastInterface failed: %v", err)
	}
	if ifi != nil {
		err = setIPv6MulticastInterface(fd, ifi)
		if err != nil {
			t.Fatalf("setIPv6MulticastInterface failed: %v", err)
		}
	}
	_, err = ipv6MulticastHopLimit(fd)
	if err != nil {
		t.Fatalf("ipv6MulticastHopLimit failed: %v", err)
	}
	err = setIPv6MulticastHopLimit(fd, 1)
	if err != nil {
		t.Fatalf("setIPv6MulticastHopLimit failed: %v", err)
	}
	_, err = ipv6MulticastLoopback(fd)
	if err != nil {
		t.Fatalf("ipv6MulticastLoopback failed: %v", err)
	}
	err = setIPv6MulticastLoopback(fd, false)
	if err != nil {
		t.Fatalf("setIPv6MulticastLoopback failed: %v", err)
	}
}
<commit_msg>net: disable another external network test<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package net

import (
	"errors"
	"os"
	"runtime"
	"syscall"
	"testing"
)

var multicastListenerTests = []struct {
	net   string
	gaddr *UDPAddr
	flags Flags
	ipv6  bool // test with underlying AF_INET6 socket
}{
	// cf. RFC 4727: Experimental Values in IPv4, IPv6, ICMPv4, ICMPv6, UDP, and TCP Headers

	{"udp", &UDPAddr{IPv4(224, 0, 0, 254), 12345}, FlagUp | FlagLoopback, false},
	{"udp", &UDPAddr{IPv4(224, 0, 0, 254), 12345}, 0, false},
	{"udp", &UDPAddr{ParseIP("ff0e::114"), 12345}, FlagUp | FlagLoopback, true},
	{"udp", &UDPAddr{ParseIP("ff0e::114"), 12345}, 0, true},

	{"udp4", &UDPAddr{IPv4(224, 0, 0, 254), 12345}, FlagUp | FlagLoopback, false},
	{"udp4", &UDPAddr{IPv4(224, 0, 0, 254), 12345}, 0, false},

	{"udp6", &UDPAddr{ParseIP("ff01::114"), 12345}, FlagUp | FlagLoopback, true},
	{"udp6", &UDPAddr{ParseIP("ff01::114"), 12345}, 0, true},
	{"udp6", &UDPAddr{ParseIP("ff02::114"), 12345}, FlagUp | FlagLoopback, true},
	{"udp6", &UDPAddr{ParseIP("ff02::114"), 12345}, 0, true},
	{"udp6", &UDPAddr{ParseIP("ff04::114"), 12345}, FlagUp | FlagLoopback, true},
	{"udp6", &UDPAddr{ParseIP("ff04::114"), 12345}, 0, true},
	{"udp6", &UDPAddr{ParseIP("ff05::114"), 12345}, FlagUp | FlagLoopback, true},
	{"udp6", &UDPAddr{ParseIP("ff05::114"), 12345}, 0, true},
	{"udp6", &UDPAddr{ParseIP("ff08::114"), 12345}, FlagUp | FlagLoopback, true},
	{"udp6", &UDPAddr{ParseIP("ff08::114"), 12345}, 0, true},
	{"udp6", &UDPAddr{ParseIP("ff0e::114"), 12345}, FlagUp | FlagLoopback, true},
	{"udp6", &UDPAddr{ParseIP("ff0e::114"), 12345}, 0, true},
}

// TestMulticastListener tests both single and double listen to a test
// listener with same address family, same group address and same port.
func TestMulticastListener(t *testing.T) {
	switch runtime.GOOS {
	case "netbsd", "openbsd", "plan9", "windows":
		t.Logf("skipping test on %q", runtime.GOOS)
		return
	case "linux":
		if runtime.GOARCH == "arm" || runtime.GOARCH == "alpha" {
			t.Logf("skipping test on %q/%q", runtime.GOOS, runtime.GOARCH)
			return
		}
	}

	for _, tt := range multicastListenerTests {
		if tt.ipv6 && (!supportsIPv6 || os.Getuid() != 0) {
			continue
		}
		ifi, err := availMulticastInterface(t, tt.flags)
		if err != nil {
			continue
		}
		c1, err := ListenMulticastUDP(tt.net, ifi, tt.gaddr)
		if err != nil {
			t.Fatalf("First ListenMulticastUDP failed: %v", err)
		}
		checkMulticastListener(t, err, c1, tt.gaddr)
		c2, err := ListenMulticastUDP(tt.net, ifi, tt.gaddr)
		if err != nil {
			t.Fatalf("Second ListenMulticastUDP failed: %v", err)
		}
		checkMulticastListener(t, err, c2, tt.gaddr)
		c2.Close()
		switch c1.fd.family {
		case syscall.AF_INET:
			testIPv4MulticastSocketOptions(t, c1.fd, ifi)
		case syscall.AF_INET6:
			testIPv6MulticastSocketOptions(t, c1.fd, ifi)
		}
		c1.Close()
	}
}

func TestSimpleMulticastListener(t *testing.T) {
	switch runtime.GOOS {
	case "plan9":
		t.Logf("skipping test on %q", runtime.GOOS)
		return
	case "windows":
		if testing.Short() || !*testExternal {
			t.Logf("skipping test on windows to avoid firewall")
			return
		}
	}

	for _, tt := range multicastListenerTests {
		if tt.ipv6 {
			continue
		}
		tt.flags = FlagUp | FlagMulticast // for windows testing
		ifi, err := availMulticastInterface(t, tt.flags)
		if err != nil {
			continue
		}
		c1, err := ListenMulticastUDP(tt.net, ifi, tt.gaddr)
		if err != nil {
			t.Fatalf("First ListenMulticastUDP failed: %v", err)
		}
		checkSimpleMulticastListener(t, err, c1, tt.gaddr)
		c2, err := ListenMulticastUDP(tt.net, ifi, tt.gaddr)
		if err != nil {
			t.Fatalf("Second ListenMulticastUDP failed: %v", err)
		}
		checkSimpleMulticastListener(t, err, c2, tt.gaddr)
		c2.Close()
		c1.Close()
	}
}

func checkMulticastListener(t *testing.T, err error, c *UDPConn, gaddr *UDPAddr) {
	if !multicastRIBContains(t, gaddr.IP) {
		t.Fatalf("%q not found in RIB", gaddr.String())
	}
	if c.LocalAddr().String() != gaddr.String() {
		t.Fatalf("LocalAddr returns %q, expected %q", c.LocalAddr().String(), gaddr.String())
	}
}

func checkSimpleMulticastListener(t *testing.T, err error, c *UDPConn, gaddr *UDPAddr) {
	if c.LocalAddr().String() != gaddr.String() {
		t.Fatalf("LocalAddr returns %q, expected %q", c.LocalAddr().String(), gaddr.String())
	}
}

func availMulticastInterface(t *testing.T, flags Flags) (*Interface, error) {
	var ifi *Interface
	if flags != Flags(0) {
		ift, err := Interfaces()
		if err != nil {
			t.Fatalf("Interfaces failed: %v", err)
		}
		for _, x := range ift {
			if x.Flags&flags == flags {
				ifi = &x
				break
			}
		}
		if ifi == nil {
			return nil, errors.New("an appropriate multicast interface not found")
		}
	}
	return ifi, nil
}

func multicastRIBContains(t *testing.T, ip IP) bool {
	ift, err := Interfaces()
	if err != nil {
		t.Fatalf("Interfaces failed: %v", err)
	}
	for _, ifi := range ift {
		ifmat, err := ifi.MulticastAddrs()
		if err != nil {
			t.Fatalf("MulticastAddrs failed: %v", err)
		}
		for _, ifma := range ifmat {
			if ifma.(*IPAddr).IP.Equal(ip) {
				return true
			}
		}
	}
	return false
}

func testIPv4MulticastSocketOptions(t *testing.T, fd *netFD, ifi *Interface) {
	_, err := ipv4MulticastInterface(fd)
	if err != nil {
		t.Fatalf("ipv4MulticastInterface failed: %v", err)
	}
	if ifi != nil {
		err = setIPv4MulticastInterface(fd, ifi)
		if err != nil {
			t.Fatalf("setIPv4MulticastInterface failed: %v", err)
		}
	}
	_, err = ipv4MulticastTTL(fd)
	if err != nil {
		t.Fatalf("ipv4MulticastTTL failed: %v", err)
	}
	err = setIPv4MulticastTTL(fd, 1)
	if err != nil {
		t.Fatalf("setIPv4MulticastTTL failed: %v", err)
	}
	_, err = ipv4MulticastLoopback(fd)
	if err != nil {
		t.Fatalf("ipv4MulticastLoopback failed: %v", err)
	}
	err = setIPv4MulticastLoopback(fd, false)
	if err != nil {
		t.Fatalf("setIPv4MulticastLoopback failed: %v", err)
	}
}

func testIPv6MulticastSocketOptions(t *testing.T, fd *netFD, ifi *Interface) {
	_, err := ipv6MulticastInterface(fd)
	if err != nil {
		t.Fatalf("ipv6MulticastInterface failed: %v", err)
	}
	if ifi != nil {
		err = setIPv6MulticastInterface(fd, ifi)
		if err != nil {
			t.Fatalf("setIPv6MulticastInterface failed: %v", err)
		}
	}
	_, err = ipv6MulticastHopLimit(fd)
	if err != nil {
		t.Fatalf("ipv6MulticastHopLimit failed: %v", err)
	}
	err = setIPv6MulticastHopLimit(fd, 1)
	if err != nil {
		t.Fatalf("setIPv6MulticastHopLimit failed: %v", err)
	}
	_, err = ipv6MulticastLoopback(fd)
	if err != nil {
		t.Fatalf("ipv6MulticastLoopback failed: %v", err)
	}
	err = setIPv6MulticastLoopback(fd, false)
	if err != nil {
		t.Fatalf("setIPv6MulticastLoopback failed: %v", err)
	}
}
<|endoftext|>