<commit_before>package engine

import (
	"reflect"
	"testing"

	"github.com/keybase/client/go/libkb"
	keybase_1 "github.com/keybase/client/protocol/go"
)

func runIdentify(username string) (idUI *FakeIdentifyUI, res *IdentifyRes, err error) {
	idUI = &FakeIdentifyUI{Proofs: make(map[string]string)}
	arg := IdentifyEngineArg{
		User: username,
	}
	ctx := Context{
		LogUI:      G.UI.GetLogUI(),
		IdentifyUI: idUI,
	}
	eng := NewIdentifyEngine(&arg)
	err = RunEngine(eng, &ctx, nil, nil)
	res = eng.Result()
	return
}

func checkAliceProofs(t *testing.T, idUI *FakeIdentifyUI, res *IdentifyRes) {
	checkKeyedProfile(t, idUI, res, "alice", true, map[string]string{
		"github":  "kbtester2",
		"twitter": "tacovontaco",
	})
}

func checkBobProofs(t *testing.T, idUI *FakeIdentifyUI, res *IdentifyRes) {
	checkKeyedProfile(t, idUI, res, "bob", true, map[string]string{
		"github":  "kbtester1",
		"twitter": "kbtester1",
	})
}

func checkCharlieProofs(t *testing.T, idUI *FakeIdentifyUI, res *IdentifyRes) {
	checkKeyedProfile(t, idUI, res, "charlie", true, map[string]string{
		"github":  "tacoplusplus",
		"twitter": "tacovontaco",
	})
}

func checkDougProofs(t *testing.T, idUI *FakeIdentifyUI, res *IdentifyRes) {
	checkKeyedProfile(t, idUI, res, "doug", false, map[string]string{})
}

func checkKeyedProfile(t *testing.T, idUI *FakeIdentifyUI, result *IdentifyRes, name string, hasImg bool, expectedProofs map[string]string) {
	if exported := result.User.Export(); !reflect.DeepEqual(idUI.User, exported) {
		t.Fatal("LaunchNetworkChecks User not equal to result user.", idUI.User, exported)
	}

	if hasImg && result.User.Image == nil {
		t.Fatal("Missing user image.")
	} else if !hasImg && result.User.Image != nil {
		t.Fatal("User has an image but shouldn't")
	}

	if !reflect.DeepEqual(expectedProofs, idUI.Proofs) {
		t.Fatal("Wrong proofs.", expectedProofs, idUI.Proofs)
	}
}

func checkDisplayKeys(t *testing.T, idUI *FakeIdentifyUI, callCount, keyCount int) {
	if idUI.DisplayKeyCalls != callCount {
		t.Errorf("DisplayKey calls: %d.  expected %d.", idUI.DisplayKeyCalls, callCount)
	}

	if len(idUI.Keys) != keyCount {
		t.Errorf("keys: %d, expected %d.", len(idUI.Keys), keyCount)
		for k, v := range idUI.Keys {
			t.Logf("key: %+v, %+v", k, v)
		}
	}

	for k := range idUI.Keys {
		if k.PgpFingerprint == nil {
			t.Errorf("key %v: not pgp.  only pgp keys should be displayed.", k)
		}
	}
}

func TestIdAlice(t *testing.T) {
	tc := SetupEngineTest(t, "id")
	defer tc.Cleanup()
	idUI, result, err := runIdentify("t_alice")
	if err != nil {
		t.Fatal(err)
	}
	checkAliceProofs(t, idUI, result)
	checkDisplayKeys(t, idUI, 1, 1)
}

func TestIdBob(t *testing.T) {
	tc := SetupEngineTest(t, "id")
	defer tc.Cleanup()
	idUI, result, err := runIdentify("t_bob")
	if err != nil {
		t.Fatal(err)
	}
	checkBobProofs(t, idUI, result)
	checkDisplayKeys(t, idUI, 1, 1)
}

func TestIdCharlie(t *testing.T) {
	tc := SetupEngineTest(t, "id")
	defer tc.Cleanup()
	idUI, result, err := runIdentify("t_charlie")
	if err != nil {
		t.Fatal(err)
	}
	checkCharlieProofs(t, idUI, result)
	checkDisplayKeys(t, idUI, 1, 1)
}

func TestIdDoug(t *testing.T) {
	tc := SetupEngineTest(t, "id")
	defer tc.Cleanup()
	idUI, result, err := runIdentify("t_doug")
	if err != nil {
		t.Fatal(err)
	}
	checkDougProofs(t, idUI, result)
	checkDisplayKeys(t, idUI, 1, 1)
}

func TestIdEllen(t *testing.T) {
	tc := SetupEngineTest(t, "id")
	defer tc.Cleanup()
	idUI, _, err := runIdentify("t_ellen")
	if err == nil {
		t.Fatal("Expected no public key found error.")
	} else if _, ok := err.(libkb.NoKeyError); !ok {
		t.Fatal("Expected no public key found error. Got instead:", err)
	}
	checkDisplayKeys(t, idUI, 0, 0)
}

// TestIdPGPNotEldest creates a user with a pgp key that isn't
// eldest key, then runs identify to make sure the pgp key is
// still displayed.
func TestIdPGPNotEldest(t *testing.T) {
	tc := SetupEngineTest(t, "id")
	defer tc.Cleanup()

	// create new user, then add pgp key
	u := CreateAndSignupFakeUser(t, "login")
	secui := libkb.TestSecretUI{Passphrase: u.Passphrase}
	ctx := &Context{LogUI: G.UI.GetLogUI(), SecretUI: secui}
	key := armorKey(t, tc, u.Email)
	e := NewPGPSaveArmored(key, true, true)
	if err := RunEngine(e, ctx, nil, nil); err != nil {
		t.Fatal(err)
	}

	idUI, _, err := runIdentify(u.Username)
	if err != nil {
		t.Fatal(err)
	}

	checkDisplayKeys(t, idUI, 1, 1)
}

type FakeIdentifyUI struct {
	Proofs          map[string]string
	User            *keybase_1.User
	Fapr            keybase_1.FinishAndPromptRes
	Keys            map[keybase_1.FOKID]*keybase_1.TrackDiff
	DisplayKeyCalls int
}

func (ui *FakeIdentifyUI) FinishWebProofCheck(proof keybase_1.RemoteProof, result keybase_1.LinkCheckResult) {
	ui.Proofs[proof.Key] = proof.Value
}
func (ui *FakeIdentifyUI) FinishSocialProofCheck(proof keybase_1.RemoteProof, result keybase_1.LinkCheckResult) {
	ui.Proofs[proof.Key] = proof.Value
}
func (ui *FakeIdentifyUI) FinishAndPrompt(*keybase_1.IdentifyOutcome) (res keybase_1.FinishAndPromptRes, err error) {
	res = ui.Fapr
	return
}
func (ui *FakeIdentifyUI) DisplayCryptocurrency(keybase_1.Cryptocurrency) {
}
func (ui *FakeIdentifyUI) DisplayKey(kid keybase_1.FOKID, td *keybase_1.TrackDiff) {
	if ui.Keys == nil {
		ui.Keys = make(map[keybase_1.FOKID]*keybase_1.TrackDiff)
	}
	ui.Keys[kid] = td
	ui.DisplayKeyCalls++
}
func (ui *FakeIdentifyUI) ReportLastTrack(*keybase_1.TrackSummary) {
}
func (ui *FakeIdentifyUI) Start(username string) {
}
func (ui *FakeIdentifyUI) LaunchNetworkChecks(id *keybase_1.Identity, user *keybase_1.User) {
	ui.User = user
}
func (ui *FakeIdentifyUI) DisplayTrackStatement(string) (err error) {
	return
}
func (ui *FakeIdentifyUI) SetStrict(b bool) {
}
<commit_msg>nil map checks<commit_after>package engine

import (
	"reflect"
	"testing"

	"github.com/keybase/client/go/libkb"
	keybase_1 "github.com/keybase/client/protocol/go"
)

func runIdentify(username string) (idUI *FakeIdentifyUI, res *IdentifyRes, err error) {
	idUI = &FakeIdentifyUI{Proofs: make(map[string]string)}
	arg := IdentifyEngineArg{
		User: username,
	}
	ctx := Context{
		LogUI:      G.UI.GetLogUI(),
		IdentifyUI: idUI,
	}
	eng := NewIdentifyEngine(&arg)
	err = RunEngine(eng, &ctx, nil, nil)
	res = eng.Result()
	return
}

func checkAliceProofs(t *testing.T, idUI *FakeIdentifyUI, res *IdentifyRes) {
	checkKeyedProfile(t, idUI, res, "alice", true, map[string]string{
		"github":  "kbtester2",
		"twitter": "tacovontaco",
	})
}

func checkBobProofs(t *testing.T, idUI *FakeIdentifyUI, res *IdentifyRes) {
	checkKeyedProfile(t, idUI, res, "bob", true, map[string]string{
		"github":  "kbtester1",
		"twitter": "kbtester1",
	})
}

func checkCharlieProofs(t *testing.T, idUI *FakeIdentifyUI, res *IdentifyRes) {
	checkKeyedProfile(t, idUI, res, "charlie", true, map[string]string{
		"github":  "tacoplusplus",
		"twitter": "tacovontaco",
	})
}

func checkDougProofs(t *testing.T, idUI *FakeIdentifyUI, res *IdentifyRes) {
	checkKeyedProfile(t, idUI, res, "doug", false, map[string]string{})
}

func checkKeyedProfile(t *testing.T, idUI *FakeIdentifyUI, result *IdentifyRes, name string, hasImg bool, expectedProofs map[string]string) {
	if exported := result.User.Export(); !reflect.DeepEqual(idUI.User, exported) {
		t.Fatal("LaunchNetworkChecks User not equal to result user.", idUI.User, exported)
	}

	if hasImg && result.User.Image == nil {
		t.Fatal("Missing user image.")
	} else if !hasImg && result.User.Image != nil {
		t.Fatal("User has an image but shouldn't")
	}

	if !reflect.DeepEqual(expectedProofs, idUI.Proofs) {
		t.Fatal("Wrong proofs.", expectedProofs, idUI.Proofs)
	}
}

func checkDisplayKeys(t *testing.T, idUI *FakeIdentifyUI, callCount, keyCount int) {
	if idUI.DisplayKeyCalls != callCount {
		t.Errorf("DisplayKey calls: %d.  expected %d.", idUI.DisplayKeyCalls, callCount)
	}

	if len(idUI.Keys) != keyCount {
		t.Errorf("keys: %d, expected %d.", len(idUI.Keys), keyCount)
		for k, v := range idUI.Keys {
			t.Logf("key: %+v, %+v", k, v)
		}
	}

	for k := range idUI.Keys {
		if k.PgpFingerprint == nil {
			t.Errorf("key %v: not pgp.  only pgp keys should be displayed.", k)
		}
	}
}

func TestIdAlice(t *testing.T) {
	tc := SetupEngineTest(t, "id")
	defer tc.Cleanup()
	idUI, result, err := runIdentify("t_alice")
	if err != nil {
		t.Fatal(err)
	}
	checkAliceProofs(t, idUI, result)
	checkDisplayKeys(t, idUI, 1, 1)
}

func TestIdBob(t *testing.T) {
	tc := SetupEngineTest(t, "id")
	defer tc.Cleanup()
	idUI, result, err := runIdentify("t_bob")
	if err != nil {
		t.Fatal(err)
	}
	checkBobProofs(t, idUI, result)
	checkDisplayKeys(t, idUI, 1, 1)
}

func TestIdCharlie(t *testing.T) {
	tc := SetupEngineTest(t, "id")
	defer tc.Cleanup()
	idUI, result, err := runIdentify("t_charlie")
	if err != nil {
		t.Fatal(err)
	}
	checkCharlieProofs(t, idUI, result)
	checkDisplayKeys(t, idUI, 1, 1)
}

func TestIdDoug(t *testing.T) {
	tc := SetupEngineTest(t, "id")
	defer tc.Cleanup()
	idUI, result, err := runIdentify("t_doug")
	if err != nil {
		t.Fatal(err)
	}
	checkDougProofs(t, idUI, result)
	checkDisplayKeys(t, idUI, 1, 1)
}

func TestIdEllen(t *testing.T) {
	tc := SetupEngineTest(t, "id")
	defer tc.Cleanup()
	idUI, _, err := runIdentify("t_ellen")
	if err == nil {
		t.Fatal("Expected no public key found error.")
	} else if _, ok := err.(libkb.NoKeyError); !ok {
		t.Fatal("Expected no public key found error. Got instead:", err)
	}
	checkDisplayKeys(t, idUI, 0, 0)
}

// TestIdPGPNotEldest creates a user with a pgp key that isn't
// eldest key, then runs identify to make sure the pgp key is
// still displayed.
func TestIdPGPNotEldest(t *testing.T) {
	tc := SetupEngineTest(t, "id")
	defer tc.Cleanup()

	// create new user, then add pgp key
	u := CreateAndSignupFakeUser(t, "login")
	secui := libkb.TestSecretUI{Passphrase: u.Passphrase}
	ctx := &Context{LogUI: G.UI.GetLogUI(), SecretUI: secui}
	key := armorKey(t, tc, u.Email)
	e := NewPGPSaveArmored(key, true, true)
	if err := RunEngine(e, ctx, nil, nil); err != nil {
		t.Fatal(err)
	}

	idUI, _, err := runIdentify(u.Username)
	if err != nil {
		t.Fatal(err)
	}

	checkDisplayKeys(t, idUI, 1, 1)
}

type FakeIdentifyUI struct {
	Proofs          map[string]string
	User            *keybase_1.User
	Fapr            keybase_1.FinishAndPromptRes
	Keys            map[keybase_1.FOKID]*keybase_1.TrackDiff
	DisplayKeyCalls int
}

func (ui *FakeIdentifyUI) FinishWebProofCheck(proof keybase_1.RemoteProof, result keybase_1.LinkCheckResult) {
	if ui.Proofs == nil {
		ui.Proofs = make(map[string]string)
	}
	ui.Proofs[proof.Key] = proof.Value
}
func (ui *FakeIdentifyUI) FinishSocialProofCheck(proof keybase_1.RemoteProof, result keybase_1.LinkCheckResult) {
	if ui.Proofs == nil {
		ui.Proofs = make(map[string]string)
	}
	ui.Proofs[proof.Key] = proof.Value
}
func (ui *FakeIdentifyUI) FinishAndPrompt(*keybase_1.IdentifyOutcome) (res keybase_1.FinishAndPromptRes, err error) {
	res = ui.Fapr
	return
}
func (ui *FakeIdentifyUI) DisplayCryptocurrency(keybase_1.Cryptocurrency) {
}
func (ui *FakeIdentifyUI) DisplayKey(kid keybase_1.FOKID, td *keybase_1.TrackDiff) {
	if ui.Keys == nil {
		ui.Keys = make(map[keybase_1.FOKID]*keybase_1.TrackDiff)
	}
	ui.Keys[kid] = td
	ui.DisplayKeyCalls++
}
func (ui *FakeIdentifyUI) ReportLastTrack(*keybase_1.TrackSummary) {
}
func (ui *FakeIdentifyUI) Start(username string) {
}
func (ui *FakeIdentifyUI) LaunchNetworkChecks(id *keybase_1.Identity, user *keybase_1.User) {
	ui.User = user
}
func (ui *FakeIdentifyUI) DisplayTrackStatement(string) (err error) {
	return
}
func (ui *FakeIdentifyUI) SetStrict(b bool) {
}
<|endoftext|>


<commit_before>package main

import (
  "bufio"
  "io"
  "fmt"
  "log"
  "os"
  "path"
)

func main() {
  if len(os.Args) != 3 {
    log.Fatalf("Usage: %s input-file output-file", path.Base(os.Args[0]))
  }

  i, err := os.Open(os.Args[1])
  if err != nil {
    log.Fatalf("Cannot open %q for reading: %v", os.Args[1], err)
  }
  defer i.Close()
  r := bufio.NewReader(i)

  o, err := os.Create(os.Args[2])
  if err != nil {
    log.Fatalf("Cannot create new file %q: %v", os.Args[2], err)
  }
  defer o.Close()
  w := bufio.NewWriter(o)
  defer w.Flush()

  for {
    err = processBlock(r, w)
    if err == io.EOF {
      log.Println("Successfully reached EOF")
      break
    }
    if err != nil {
      log.Fatalf("Error whilst processing file: %v", err)
    }
  }
}

func processBlock(r *bufio.Reader, w *bufio.Writer) error {
  var err error
  start := true
  for {
    buf, err := r.Peek(1)
    if err != nil {
      return err
    }
    if start && (buf[0] != '0') {
      return fmt.Errorf("expecting %q, got %q", '0', buf[0])
    }
    if (!start) && (buf[0] == '0') {
      break
    }

    line, err := r.ReadString('\n')
    if len(line) > 0 {
      if _, werr := w.WriteString(line); err != nil {
        return werr
      }
    }

    start = false

    if err == io.EOF {
      break
    }
    if err != nil {
      return err
    }
  }
  return err
}
<commit_msg>Detect INDI record types and buffer data before writing (but still do not hide any).<commit_after>package main

import (
  "bufio"
  "io"
  "fmt"
  "log"
  "os"
  "path"
  "strings"
)

type ternary int
const (
  YES ternary = iota
  NO
  MAYBE
)

func main() {
  if len(os.Args) != 3 {
    log.Fatalf("Usage: %s input-file output-file", path.Base(os.Args[0]))
  }

  i, err := os.Open(os.Args[1])
  if err != nil {
    log.Fatalf("Cannot open %q for reading: %v", os.Args[1], err)
  }
  defer i.Close()
  r := bufio.NewReader(i)

  o, err := os.Create(os.Args[2])
  if err != nil {
    log.Fatalf("Cannot create new file %q: %v", os.Args[2], err)
  }
  defer o.Close()
  w := bufio.NewWriter(o)
  defer w.Flush()

  for {
    err = processBlock(r, w)
    if err == io.EOF {
      log.Println("Successfully reached EOF")
      break
    }
    if err != nil {
      log.Fatalf("Error whilst processing file: %v", err)
    }
  }
}

func processBlock(r *bufio.Reader, w *bufio.Writer) error {
  var err error
  var buf strings.Builder
  isIndi := MAYBE

  for {
    ch, err := r.Peek(1)
    if err != nil {
      return err
    }
    if isIndi == MAYBE && ch[0] != '0' {
      return fmt.Errorf("expecting %q, got %q", '0', ch[0])
    }
    if isIndi != MAYBE && ch[0] == '0' {
      break
    }

    line, err := r.ReadString('\n')

    if isIndi == MAYBE {
      if strings.HasSuffix(line, "INDI\n") {
        isIndi = YES
      } else {
        isIndi = NO
      }
    }

    if isIndi == NO {
      if _, werr := w.WriteString(line); werr != nil {
        return werr
      }
    } else {
      buf.WriteString(line)
    }

    if err == io.EOF {
      break
    }
    if err != nil {
      return err
    }
  }

  if _, werr := w.WriteString(buf.String()); werr != nil {
    return werr
  }

  return err
}
<|endoftext|>


<commit_before>package graph

import (
	"testing"
)

func TestTopologicalSort(t *testing.T) {
	graph, err := New("directed")
	if err != nil {
		t.Errorf("TestMakeNode: unable to create directed graph")
	}
	nodes := graph.Nodes()
	// create graph on page 613 of CLRS ed. 3
	nodes = append(nodes, graph.MakeNode("shirt"))
	nodes = append(nodes, graph.MakeNode("tie"))
	nodes = append(nodes, graph.MakeNode("jacket"))
	nodes = append(nodes, graph.MakeNode("belt"))
	nodes = append(nodes, graph.MakeNode("watch"))
	nodes = append(nodes, graph.MakeNode("undershorts"))
	nodes = append(nodes, graph.MakeNode("pants"))
	nodes = append(nodes, graph.MakeNode("shoes"))
	nodes = append(nodes, graph.MakeNode("socks"))
	graph.Connect(nodes[0], nodes[1])
	graph.Connect(nodes[1], nodes[2])
	graph.Connect(nodes[0], nodes[3])
	graph.Connect(nodes[3], nodes[2])
	graph.Connect(nodes[5], nodes[6])
	graph.Connect(nodes[5], nodes[7])
	graph.Connect(nodes[6], nodes[3])
	graph.Connect(nodes[6], nodes[7])
	graph.Connect(nodes[8], nodes[7])
	graph.verify(t)
	wantOrder := make([]*Node, len(graph.Nodes()))
	wantOrder[0] = nodes[8]
	wantOrder[1] = nodes[5]
	wantOrder[2] = nodes[6]
	wantOrder[3] = nodes[7]
	wantOrder[4] = nodes[4]
	wantOrder[5] = nodes[0]
	wantOrder[6] = nodes[3]
	wantOrder[7] = nodes[1]
	wantOrder[8] = nodes[2]
	result := TopologicalSort(graph)
	for i := range result {
		if result[i] != wantOrder[i] {
			t.Errorf("index %v in result != wanted, value: %v, want value: %v", i, result[i].Value, wantOrder[i].Value)
		}
	}
}
<commit_msg>added comments for sorted ordering<commit_after>package graph

import (
	"testing"
)

func TestTopologicalSort(t *testing.T) {
	graph, err := New("directed")
	if err != nil {
		t.Errorf("TestMakeNode: unable to create directed graph")
	}
	nodes := graph.Nodes()
	// create graph on page 613 of CLRS ed. 3
	nodes = append(nodes, graph.MakeNode("shirt"))
	nodes = append(nodes, graph.MakeNode("tie"))
	nodes = append(nodes, graph.MakeNode("jacket"))
	nodes = append(nodes, graph.MakeNode("belt"))
	nodes = append(nodes, graph.MakeNode("watch"))
	nodes = append(nodes, graph.MakeNode("undershorts"))
	nodes = append(nodes, graph.MakeNode("pants"))
	nodes = append(nodes, graph.MakeNode("shoes"))
	nodes = append(nodes, graph.MakeNode("socks"))
	graph.Connect(nodes[0], nodes[1])
	graph.Connect(nodes[1], nodes[2])
	graph.Connect(nodes[0], nodes[3])
	graph.Connect(nodes[3], nodes[2])
	graph.Connect(nodes[5], nodes[6])
	graph.Connect(nodes[5], nodes[7])
	graph.Connect(nodes[6], nodes[3])
	graph.Connect(nodes[6], nodes[7])
	graph.Connect(nodes[8], nodes[7])
	graph.verify(t)
	wantOrder := make([]*Node, len(graph.Nodes()))
	wantOrder[0] = nodes[8] // socks
	wantOrder[1] = nodes[5] // undershorts
	wantOrder[2] = nodes[6] // pants
	wantOrder[3] = nodes[7] // shoes
	wantOrder[4] = nodes[4] // watch
	wantOrder[5] = nodes[0] // shirt
	wantOrder[6] = nodes[3] // belt
	wantOrder[7] = nodes[1] // tie
	wantOrder[8] = nodes[2] // jacket
	result := TopologicalSort(graph)
	for i := range result {
		if result[i] != wantOrder[i] {
			t.Errorf("index %v in result != wanted, value: %v, want value: %v", i, result[i].Value, wantOrder[i].Value)
		}
	}
}
<|endoftext|>


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

package importer

import (
	"bufio"
	"bytes"
	"fmt"
	"go/ast"
	"go/build"
	"go/parser"
	"go/token"
	"os"
	"path/filepath"
	"runtime"
	"sort"
	"strconv"
	"testing"
	"time"

	"code.google.com/p/go.tools/go/gcimporter"
	"code.google.com/p/go.tools/go/types"
)

var tests = []string{
	`package p`,

	// consts
	`package p; const X = true`,
	`package p; const X, y, Z = true, false, 0 != 0`,
	`package p; const ( A float32 = 1<<iota; B; C; D)`,
	`package p; const X = "foo"`,
	`package p; const X string = "foo"`,
	`package p; const X = 0`,
	`package p; const X = -42`,
	`package p; const X = 3.14159265`,
	`package p; const X = -1e-10`,
	`package p; const X = 1.2 + 2.3i`,
	`package p; const X = -1i`,
	`package p; import "math"; const Pi = math.Pi`,
	`package p; import m "math"; const Pi = m.Pi`,

	// types
	`package p; type T int`,
	`package p; type T [10]int`,
	`package p; type T []int`,
	`package p; type T struct{}`,
	`package p; type T struct{x int}`,
	`package p; type T *int`,
	`package p; type T func()`,
	`package p; type T *T`,
	`package p; type T interface{}`,
	`package p; type T interface{ foo() }`,
	`package p; type T interface{ m() T }`,
	// TODO(gri) disabled for now - import/export works but
	// types.Type.String() used in the test cannot handle cases
	// like this yet
	// `package p; type T interface{ m() interface{T} }`,
	`package p; type T map[string]bool`,
	`package p; type T chan int`,
	`package p; type T <-chan complex64`,
	`package p; type T chan<- map[int]string`,
	// test case for issue 8177
	`package p; type T1 interface { F(T2) }; type T2 interface { T1 }`,

	// vars
	`package p; var X int`,
	`package p; var X, Y, Z struct{f int "tag"}`,

	// funcs
	`package p; func F()`,
	`package p; func F(x int, y struct{}) bool`,
	`package p; type T int; func (*T) F(x int, y struct{}) T`,

	// selected special cases
	`package p; type T int`,
	`package p; type T uint8`,
	`package p; type T byte`,
	`package p; type T error`,
	`package p; import "net/http"; type T http.Client`,
	`package p; import "net/http"; type ( T1 http.Client; T2 struct { http.Client } )`,
	`package p; import "unsafe"; type ( T1 unsafe.Pointer; T2 unsafe.Pointer )`,
	`package p; import "unsafe"; type T struct { p unsafe.Pointer }`,
}

func TestImportSrc(t *testing.T) {
	for _, src := range tests {
		pkg, err := pkgForSource(src)
		if err != nil {
			t.Errorf("typecheck failed: %s", err)
			continue
		}
		testExportImport(t, pkg, "")
	}
}

func TestImportStdLib(t *testing.T) {
	start := time.Now()

	libs, err := stdLibs()
	if err != nil {
		t.Fatalf("could not compute list of std libraries: %s", err)
	}

	// make sure printed go/types types and gc-imported types
	// can be compared reasonably well
	types.GcCompatibilityMode = true

	var totSize, totGcSize int
	for _, lib := range libs {
		// limit run time for short tests
		if testing.Short() && time.Since(start) >= 750*time.Millisecond {
			return
		}

		pkg, err := pkgForPath(lib)
		switch err := err.(type) {
		case nil:
			// ok
		case *build.NoGoError:
			// no Go files - ignore
			continue
		default:
			t.Errorf("typecheck failed: %s", err)
			continue
		}

		size, gcsize := testExportImport(t, pkg, lib)
		if gcsize == 0 {
			// if gc import didn't happen, assume same size
			// (and avoid division by zero below)
			gcsize = size
		}

		if testing.Verbose() {
			fmt.Printf("%s\t%d\t%d\t%d%%\n", lib, size, gcsize, int(float64(size)*100/float64(gcsize)))
		}
		totSize += size
		totGcSize += gcsize
	}

	if testing.Verbose() {
		fmt.Printf("\n%d\t%d\t%d%%\n", totSize, totGcSize, int(float64(totSize)*100/float64(totGcSize)))
	}

	types.GcCompatibilityMode = false
}

func testExportImport(t *testing.T, pkg0 *types.Package, path string) (size, gcsize int) {
	data := ExportData(pkg0)
	size = len(data)

	imports := make(map[string]*types.Package)
	n, pkg1, err := ImportData(imports, data)
	if err != nil {
		t.Errorf("package %s: import failed: %s", pkg0.Name(), err)
		return
	}
	if n != size {
		t.Errorf("package %s: not all input data consumed", pkg0.Name())
		return
	}

	s0 := pkgString(pkg0)
	s1 := pkgString(pkg1)
	if s1 != s0 {
		t.Errorf("package %s: \nimport got:\n%s\nwant:\n%s\n", pkg0.Name(), s1, s0)
	}

	// If we have a standard library, compare also against the gcimported package.
	if path == "" {
		return // not std library
	}

	gcdata, err := gcExportData(path)
	gcsize = len(gcdata)

	imports = make(map[string]*types.Package)
	pkg2, err := gcImportData(imports, gcdata, path)
	if err != nil {
		t.Errorf("package %s: gcimport failed: %s", pkg0.Name(), err)
		return
	}

	s2 := pkgString(pkg2)
	if s2 != s0 {
		t.Errorf("package %s: \ngcimport got:\n%s\nwant:\n%s\n", pkg0.Name(), s2, s0)
	}

	return
}

func pkgForSource(src string) (*types.Package, error) {
	// parse file
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, "", src, 0)
	if err != nil {
		return nil, err
	}

	// typecheck file
	conf := types.Config{
		// strconv exports IntSize as a constant. The type-checker must
		// use the same word size otherwise the result of the type-checker
		// and gc imports is different. We don't care about alignment
		// since none of the tests have exported constants depending
		// on alignment (see also issue 8366).
		Sizes: &types.StdSizes{WordSize: strconv.IntSize / 8, MaxAlign: 8},
	}
	return conf.Check("import-test", fset, []*ast.File{f}, nil)
}

func pkgForPath(path string) (*types.Package, error) {
	// collect filenames
	ctxt := build.Default
	pkginfo, err := ctxt.Import(path, "", 0)
	if err != nil {
		return nil, err
	}
	filenames := append(pkginfo.GoFiles, pkginfo.CgoFiles...)

	// parse files
	fset := token.NewFileSet()
	files := make([]*ast.File, len(filenames))
	for i, filename := range filenames {
		var err error
		files[i], err = parser.ParseFile(fset, filepath.Join(pkginfo.Dir, filename), nil, 0)
		if err != nil {
			return nil, err
		}
	}

	// typecheck files
	// (we only care about exports and thus can ignore function bodies)
	conf := types.Config{IgnoreFuncBodies: true, FakeImportC: true}
	return conf.Check(path, fset, files, nil)
}

// pkgString returns a string representation of a package's exported interface.
func pkgString(pkg *types.Package) string {
	var buf bytes.Buffer

	fmt.Fprintf(&buf, "package %s\n", pkg.Name())

	scope := pkg.Scope()
	for _, name := range scope.Names() {
		if exported(name) {
			obj := scope.Lookup(name)
			buf.WriteString(obj.String())

			switch obj := obj.(type) {
			case *types.Const:
				// For now only print constant values if they are not float
				// or complex. This permits comparing go/types results with
				// gc-generated gcimported package interfaces.
				info := obj.Type().Underlying().(*types.Basic).Info()
				if info&types.IsFloat == 0 && info&types.IsComplex == 0 {
					fmt.Fprintf(&buf, " = %s", obj.Val())
				}

			case *types.TypeName:
				// Print associated methods.
				// Basic types (e.g., unsafe.Pointer) have *types.Basic
				// type rather than *types.Named; so we need to check.
				if typ, _ := obj.Type().(*types.Named); typ != nil {
					if n := typ.NumMethods(); n > 0 {
						// Sort methods by name so that we get the
						// same order independent of whether the
						// methods got imported or coming directly
						// for the source.
						// TODO(gri) This should probably be done
						// in go/types.
						list := make([]*types.Func, n)
						for i := 0; i < n; i++ {
							list[i] = typ.Method(i)
						}
						sort.Sort(byName(list))

						buf.WriteString("\nmethods (\n")
						for _, m := range list {
							fmt.Fprintf(&buf, "\t%s\n", m)
						}
						buf.WriteString(")")
					}
				}
			}
			buf.WriteByte('\n')
		}
	}

	return buf.String()
}

var stdLibRoot = filepath.Join(runtime.GOROOT(), "src", "pkg") + string(filepath.Separator)

// The following std libraries are excluded from the stdLibs list.
var excluded = map[string]bool{
	"builtin": true, // contains type declarations with cycles
	"unsafe":  true, // contains fake declarations
}

// stdLibs returns the list if standard library package paths.
func stdLibs() (list []string, err error) {
	err = filepath.Walk(stdLibRoot, func(path string, info os.FileInfo, err error) error {
		if err == nil && info.IsDir() {
			if info.Name() == "testdata" {
				return filepath.SkipDir
			}
			pkgPath := path[len(stdLibRoot):] // remove stdLibRoot
			if len(pkgPath) > 0 && !excluded[pkgPath] {
				list = append(list, pkgPath)
			}
		}
		return nil
	})
	return
}

type byName []*types.Func

func (a byName) Len() int           { return len(a) }
func (a byName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a byName) Less(i, j int) bool { return a[i].Name() < a[j].Name() }

// gcExportData returns the gc-generated export data for the given path.
// It is based on a trimmed-down version of gcimporter.Import which does
// not do the actual import, does not handle package unsafe, and assumes
// that path is a correct standard library package path (no canonicalization,
// or handling of local import paths).
func gcExportData(path string) ([]byte, error) {
	filename, id := gcimporter.FindPkg(path, "")
	if filename == "" {
		return nil, fmt.Errorf("can't find import: %s", path)
	}
	if id != path {
		panic("path should be canonicalized")
	}

	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	buf := bufio.NewReader(f)
	if err = gcimporter.FindExportData(buf); err != nil {
		return nil, err
	}

	var data []byte
	for {
		line, err := buf.ReadBytes('\n')
		if err != nil {
			return nil, err
		}
		data = append(data, line...)
		// export data ends in "$$\n"
		if len(line) == 3 && line[0] == '$' && line[1] == '$' {
			return data, nil
		}
	}
}

func gcImportData(imports map[string]*types.Package, data []byte, path string) (*types.Package, error) {
	filename := fmt.Sprintf("<filename for %s>", path) // so we have a decent error message if necessary
	return gcimporter.ImportData(imports, filename, path, bufio.NewReader(bytes.NewBuffer(data)))
}
<commit_msg>go.tools/go/importer: fix test (src/pkg -> src)<commit_after>// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package importer

import (
	"bufio"
	"bytes"
	"fmt"
	"go/ast"
	"go/build"
	"go/parser"
	"go/token"
	"os"
	"path/filepath"
	"runtime"
	"sort"
	"strconv"
	"testing"
	"time"

	"code.google.com/p/go.tools/go/gcimporter"
	"code.google.com/p/go.tools/go/types"
)

var tests = []string{
	`package p`,

	// consts
	`package p; const X = true`,
	`package p; const X, y, Z = true, false, 0 != 0`,
	`package p; const ( A float32 = 1<<iota; B; C; D)`,
	`package p; const X = "foo"`,
	`package p; const X string = "foo"`,
	`package p; const X = 0`,
	`package p; const X = -42`,
	`package p; const X = 3.14159265`,
	`package p; const X = -1e-10`,
	`package p; const X = 1.2 + 2.3i`,
	`package p; const X = -1i`,
	`package p; import "math"; const Pi = math.Pi`,
	`package p; import m "math"; const Pi = m.Pi`,

	// types
	`package p; type T int`,
	`package p; type T [10]int`,
	`package p; type T []int`,
	`package p; type T struct{}`,
	`package p; type T struct{x int}`,
	`package p; type T *int`,
	`package p; type T func()`,
	`package p; type T *T`,
	`package p; type T interface{}`,
	`package p; type T interface{ foo() }`,
	`package p; type T interface{ m() T }`,
	// TODO(gri) disabled for now - import/export works but
	// types.Type.String() used in the test cannot handle cases
	// like this yet
	// `package p; type T interface{ m() interface{T} }`,
	`package p; type T map[string]bool`,
	`package p; type T chan int`,
	`package p; type T <-chan complex64`,
	`package p; type T chan<- map[int]string`,
	// test case for issue 8177
	`package p; type T1 interface { F(T2) }; type T2 interface { T1 }`,

	// vars
	`package p; var X int`,
	`package p; var X, Y, Z struct{f int "tag"}`,

	// funcs
	`package p; func F()`,
	`package p; func F(x int, y struct{}) bool`,
	`package p; type T int; func (*T) F(x int, y struct{}) T`,

	// selected special cases
	`package p; type T int`,
	`package p; type T uint8`,
	`package p; type T byte`,
	`package p; type T error`,
	`package p; import "net/http"; type T http.Client`,
	`package p; import "net/http"; type ( T1 http.Client; T2 struct { http.Client } )`,
	`package p; import "unsafe"; type ( T1 unsafe.Pointer; T2 unsafe.Pointer )`,
	`package p; import "unsafe"; type T struct { p unsafe.Pointer }`,
}

func TestImportSrc(t *testing.T) {
	for _, src := range tests {
		pkg, err := pkgForSource(src)
		if err != nil {
			t.Errorf("typecheck failed: %s", err)
			continue
		}
		testExportImport(t, pkg, "")
	}
}

func TestImportStdLib(t *testing.T) {
	start := time.Now()

	libs, err := stdLibs()
	if err != nil {
		t.Fatalf("could not compute list of std libraries: %s", err)
	}
	if len(libs) < 100 {
		t.Fatalf("only %d std libraries found - something's not right", len(libs))
	}

	// make sure printed go/types types and gc-imported types
	// can be compared reasonably well
	types.GcCompatibilityMode = true

	var totSize, totGcSize int
	for _, lib := range libs {
		// limit run time for short tests
		if testing.Short() && time.Since(start) >= 750*time.Millisecond {
			return
		}

		pkg, err := pkgForPath(lib)
		switch err := err.(type) {
		case nil:
			// ok
		case *build.NoGoError:
			// no Go files - ignore
			continue
		default:
			t.Errorf("typecheck failed: %s", err)
			continue
		}

		size, gcsize := testExportImport(t, pkg, lib)
		if gcsize == 0 {
			// if gc import didn't happen, assume same size
			// (and avoid division by zero below)
			gcsize = size
		}

		if testing.Verbose() {
			fmt.Printf("%s\t%d\t%d\t%d%%\n", lib, size, gcsize, int(float64(size)*100/float64(gcsize)))
		}
		totSize += size
		totGcSize += gcsize
	}

	if testing.Verbose() {
		fmt.Printf("\n%d\t%d\t%d%%\n", totSize, totGcSize, int(float64(totSize)*100/float64(totGcSize)))
	}

	types.GcCompatibilityMode = false
}

func testExportImport(t *testing.T, pkg0 *types.Package, path string) (size, gcsize int) {
	data := ExportData(pkg0)
	size = len(data)

	imports := make(map[string]*types.Package)
	n, pkg1, err := ImportData(imports, data)
	if err != nil {
		t.Errorf("package %s: import failed: %s", pkg0.Name(), err)
		return
	}
	if n != size {
		t.Errorf("package %s: not all input data consumed", pkg0.Name())
		return
	}

	s0 := pkgString(pkg0)
	s1 := pkgString(pkg1)
	if s1 != s0 {
		t.Errorf("package %s: \nimport got:\n%s\nwant:\n%s\n", pkg0.Name(), s1, s0)
	}

	// If we have a standard library, compare also against the gcimported package.
	if path == "" {
		return // not std library
	}

	gcdata, err := gcExportData(path)
	if err != nil {
		if pkg0.Name() == "main" {
			return // no export data present for main package
		}
		t.Errorf("package %s: couldn't get export data: %s", pkg0.Name(), err)
	}
	gcsize = len(gcdata)

	imports = make(map[string]*types.Package)
	pkg2, err := gcImportData(imports, gcdata, path)
	if err != nil {
		t.Errorf("package %s: gcimport failed: %s", pkg0.Name(), err)
		return
	}

	s2 := pkgString(pkg2)
	if s2 != s0 {
		t.Errorf("package %s: \ngcimport got:\n%s\nwant:\n%s\n", pkg0.Name(), s2, s0)
	}

	return
}

func pkgForSource(src string) (*types.Package, error) {
	// parse file
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, "", src, 0)
	if err != nil {
		return nil, err
	}

	// typecheck file
	conf := types.Config{
		// strconv exports IntSize as a constant. The type-checker must
		// use the same word size otherwise the result of the type-checker
		// and gc imports is different. We don't care about alignment
		// since none of the tests have exported constants depending
		// on alignment (see also issue 8366).
		Sizes: &types.StdSizes{WordSize: strconv.IntSize / 8, MaxAlign: 8},
	}
	return conf.Check("import-test", fset, []*ast.File{f}, nil)
}

func pkgForPath(path string) (*types.Package, error) {
	// collect filenames
	ctxt := build.Default
	pkginfo, err := ctxt.Import(path, "", 0)
	if err != nil {
		return nil, err
	}
	filenames := append(pkginfo.GoFiles, pkginfo.CgoFiles...)

	// parse files
	fset := token.NewFileSet()
	files := make([]*ast.File, len(filenames))
	for i, filename := range filenames {
		var err error
		files[i], err = parser.ParseFile(fset, filepath.Join(pkginfo.Dir, filename), nil, 0)
		if err != nil {
			return nil, err
		}
	}

	// typecheck files
	// (we only care about exports and thus can ignore function bodies)
	conf := types.Config{IgnoreFuncBodies: true, FakeImportC: true}
	return conf.Check(path, fset, files, nil)
}

// pkgString returns a string representation of a package's exported interface.
func pkgString(pkg *types.Package) string {
	var buf bytes.Buffer

	fmt.Fprintf(&buf, "package %s\n", pkg.Name())

	scope := pkg.Scope()
	for _, name := range scope.Names() {
		if exported(name) {
			obj := scope.Lookup(name)
			buf.WriteString(obj.String())

			switch obj := obj.(type) {
			case *types.Const:
				// For now only print constant values if they are not float
				// or complex. This permits comparing go/types results with
				// gc-generated gcimported package interfaces.
				info := obj.Type().Underlying().(*types.Basic).Info()
				if info&types.IsFloat == 0 && info&types.IsComplex == 0 {
					fmt.Fprintf(&buf, " = %s", obj.Val())
				}

			case *types.TypeName:
				// Print associated methods.
				// Basic types (e.g., unsafe.Pointer) have *types.Basic
				// type rather than *types.Named; so we need to check.
				if typ, _ := obj.Type().(*types.Named); typ != nil {
					if n := typ.NumMethods(); n > 0 {
						// Sort methods by name so that we get the
						// same order independent of whether the
						// methods got imported or coming directly
						// for the source.
						// TODO(gri) This should probably be done
						// in go/types.
						list := make([]*types.Func, n)
						for i := 0; i < n; i++ {
							list[i] = typ.Method(i)
						}
						sort.Sort(byName(list))

						buf.WriteString("\nmethods (\n")
						for _, m := range list {
							fmt.Fprintf(&buf, "\t%s\n", m)
						}
						buf.WriteString(")")
					}
				}
			}
			buf.WriteByte('\n')
		}
	}

	return buf.String()
}

var stdLibRoot = filepath.Join(runtime.GOROOT(), "src") + string(filepath.Separator)

// The following std libraries are excluded from the stdLibs list.
var excluded = map[string]bool{
	"builtin": true, // contains type declarations with cycles
	"unsafe":  true, // contains fake declarations
}

// stdLibs returns the list of standard library package paths.
func stdLibs() (list []string, err error) {
	err = filepath.Walk(stdLibRoot, func(path string, info os.FileInfo, err error) error {
		if err == nil && info.IsDir() {
			// testdata directories don't contain importable libraries
			if info.Name() == "testdata" {
				return filepath.SkipDir
			}
			pkgPath := path[len(stdLibRoot):] // remove stdLibRoot
			if len(pkgPath) > 0 && !excluded[pkgPath] {
				list = append(list, pkgPath)
			}
		}
		return nil
	})
	return
}

type byName []*types.Func

func (a byName) Len() int           { return len(a) }
func (a byName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a byName) Less(i, j int) bool { return a[i].Name() < a[j].Name() }

// gcExportData returns the gc-generated export data for the given path.
// It is based on a trimmed-down version of gcimporter.Import which does
// not do the actual import, does not handle package unsafe, and assumes
// that path is a correct standard library package path (no canonicalization,
// or handling of local import paths).
func gcExportData(path string) ([]byte, error) {
	filename, id := gcimporter.FindPkg(path, "")
	if filename == "" {
		return nil, fmt.Errorf("can't find import: %s", path)
	}
	if id != path {
		panic("path should be canonicalized")
	}

	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	buf := bufio.NewReader(f)
	if err = gcimporter.FindExportData(buf); err != nil {
		return nil, err
	}

	var data []byte
	for {
		line, err := buf.ReadBytes('\n')
		if err != nil {
			return nil, err
		}
		data = append(data, line...)
		// export data ends in "$$\n"
		if len(line) == 3 && line[0] == '$' && line[1] == '$' {
			return data, nil
		}
	}
}

func gcImportData(imports map[string]*types.Package, data []byte, path string) (*types.Package, error) {
	filename := fmt.Sprintf("<filename for %s>", path) // so we have a decent error message if necessary
	return gcimporter.ImportData(imports, filename, path, bufio.NewReader(bytes.NewBuffer(data)))
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Vitess Authors.

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

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

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

package netutil

import (
	"math/rand"
	"net"
	"testing"
)

func checkDistribution(t *testing.T, data []*net.SRV, margin float64) {
	sum := 0
	for _, srv := range data {
		sum += int(srv.Weight)
	}

	results := make(map[string]int)

	count := 1000
	for j := 0; j < count; j++ {
		d := make([]*net.SRV, len(data))
		copy(d, data)
		byPriorityWeight(d).shuffleByWeight()
		key := d[0].Target
		results[key] = results[key] + 1
	}

	actual := results[data[0].Target]
	expected := float64(count) * float64(data[0].Weight) / float64(sum)
	diff := float64(actual) - expected
	t.Logf("actual: %v diff: %v e: %v m: %v", actual, diff, expected, margin)
	if diff < 0 {
		diff = -diff
	}
	if diff > (expected * margin) {
		t.Errorf("missed target weight: expected %v, %v", expected, actual)
	}
}

func testUniformity(t *testing.T, size int, margin float64) {
	rand.Seed(1)
	data := make([]*net.SRV, size)
	for i := 0; i < size; i++ {
		data[i] = &net.SRV{Target: string('a' + i), Weight: 1}
	}
	checkDistribution(t, data, margin)
}

func TestUniformity(t *testing.T) {
	testUniformity(t, 2, 0.05)
	testUniformity(t, 3, 0.10)
	testUniformity(t, 10, 0.20)
	testWeighting(t, 0.05)
}

func testWeighting(t *testing.T, margin float64) {
	rand.Seed(1)
	data := []*net.SRV{
		{Target: "a", Weight: 60},
		{Target: "b", Weight: 30},
		{Target: "c", Weight: 10},
	}
	checkDistribution(t, data, margin)
}

func TestWeighting(t *testing.T) {
	testWeighting(t, 0.05)
}

func TestSplitHostPort(t *testing.T) {
	type addr struct {
		host string
		port int
	}
	table := map[string]addr{
		"host-name:132":  {host: "host-name", port: 132},
		"hostname:65535": {host: "hostname", port: 65535},
		"[::1]:321":      {host: "::1", port: 321},
		"::1:432":        {host: "::1", port: 432},
	}
	for input, want := range table {
		gotHost, gotPort, err := SplitHostPort(input)
		if err != nil {
			t.Errorf("SplitHostPort error: %v", err)
		}
		if gotHost != want.host || gotPort != want.port {
			t.Errorf("SplitHostPort(%#v) = (%v, %v), want (%v, %v)", input, gotHost, gotPort, want.host, want.port)
		}
	}
}

func TestSplitHostPortFail(t *testing.T) {
	// These cases should all fail to parse.
	inputs := []string{
		"host-name",
		"host-name:123abc",
	}
	for _, input := range inputs {
		_, _, err := SplitHostPort(input)
		if err == nil {
			t.Errorf("expected error from SplitHostPort(%q), but got none", input)
		}
	}
}

func TestJoinHostPort(t *testing.T) {
	type addr struct {
		host string
		port int32
	}
	table := map[string]addr{
		"host-name:132": {host: "host-name", port: 132},
		"[::1]:321":     {host: "::1", port: 321},
	}
	for want, input := range table {
		if got := JoinHostPort(input.host, input.port); got != want {
			t.Errorf("SplitHostPort(%v, %v) = %#v, want %#v", input.host, input.port, got, want)
		}
	}
}
<commit_msg>Add unit test for function:ResolveIPv4Addrs<commit_after>/*
Copyright 2019 The Vitess Authors.

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

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

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

package netutil

import (
	"math/rand"
	"net"
	"reflect"
	"testing"
)

func checkDistribution(t *testing.T, data []*net.SRV, margin float64) {
	sum := 0
	for _, srv := range data {
		sum += int(srv.Weight)
	}

	results := make(map[string]int)

	count := 1000
	for j := 0; j < count; j++ {
		d := make([]*net.SRV, len(data))
		copy(d, data)
		byPriorityWeight(d).shuffleByWeight()
		key := d[0].Target
		results[key] = results[key] + 1
	}

	actual := results[data[0].Target]
	expected := float64(count) * float64(data[0].Weight) / float64(sum)
	diff := float64(actual) - expected
	t.Logf("actual: %v diff: %v e: %v m: %v", actual, diff, expected, margin)
	if diff < 0 {
		diff = -diff
	}
	if diff > (expected * margin) {
		t.Errorf("missed target weight: expected %v, %v", expected, actual)
	}
}

func testUniformity(t *testing.T, size int, margin float64) {
	rand.Seed(1)
	data := make([]*net.SRV, size)
	for i := 0; i < size; i++ {
		data[i] = &net.SRV{Target: string('a' + i), Weight: 1}
	}
	checkDistribution(t, data, margin)
}

func TestUniformity(t *testing.T) {
	testUniformity(t, 2, 0.05)
	testUniformity(t, 3, 0.10)
	testUniformity(t, 10, 0.20)
	testWeighting(t, 0.05)
}

func testWeighting(t *testing.T, margin float64) {
	rand.Seed(1)
	data := []*net.SRV{
		{Target: "a", Weight: 60},
		{Target: "b", Weight: 30},
		{Target: "c", Weight: 10},
	}
	checkDistribution(t, data, margin)
}

func TestWeighting(t *testing.T) {
	testWeighting(t, 0.05)
}

func TestSplitHostPort(t *testing.T) {
	type addr struct {
		host string
		port int
	}
	table := map[string]addr{
		"host-name:132":  {host: "host-name", port: 132},
		"hostname:65535": {host: "hostname", port: 65535},
		"[::1]:321":      {host: "::1", port: 321},
		"::1:432":        {host: "::1", port: 432},
	}
	for input, want := range table {
		gotHost, gotPort, err := SplitHostPort(input)
		if err != nil {
			t.Errorf("SplitHostPort error: %v", err)
		}
		if gotHost != want.host || gotPort != want.port {
			t.Errorf("SplitHostPort(%#v) = (%v, %v), want (%v, %v)", input, gotHost, gotPort, want.host, want.port)
		}
	}
}

func TestSplitHostPortFail(t *testing.T) {
	// These cases should all fail to parse.
	inputs := []string{
		"host-name",
		"host-name:123abc",
	}
	for _, input := range inputs {
		_, _, err := SplitHostPort(input)
		if err == nil {
			t.Errorf("expected error from SplitHostPort(%q), but got none", input)
		}
	}
}

func TestJoinHostPort(t *testing.T) {
	type addr struct {
		host string
		port int32
	}
	table := map[string]addr{
		"host-name:132": {host: "host-name", port: 132},
		"[::1]:321":     {host: "::1", port: 321},
	}
	for want, input := range table {
		if got := JoinHostPort(input.host, input.port); got != want {
			t.Errorf("SplitHostPort(%v, %v) = %#v, want %#v", input.host, input.port, got, want)
		}
	}
}

func TestResolveIPv4Addrs(t *testing.T) {
	cases := []struct {
		address       string
		expected      []string
		expectedError bool
	}{
		{
			address:  "localhost:3306",
			expected: []string{"127.0.0.1:3306"},
		},
		{
			address:       "127.0.0.256:3306",
			expectedError: true,
		},
		{
			address:       "localhost",
			expectedError: true,
		},
		{
			address:       "InvalidHost:3306",
			expectedError: true,
		},
	}

	for _, c := range cases {
		t.Run(c.address, func(t *testing.T) {
			got, err := ResolveIPv4Addrs(c.address)
			if (err != nil) != c.expectedError {
				t.Errorf("expected error but got: %v", err)
			}
			if !reflect.DeepEqual(got, c.expected) {
				t.Errorf("expected: %v, got: %v", c.expected, got)
			}
		})
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2017 Google Inc.

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

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

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

package mysqlctl

/*
This file contains the reparenting methods for mysqlctl.

TODO(alainjobart) Once refactoring is done, remove unused code paths.
*/

import (
	"fmt"
	"time"

	"vitess.io/vitess/go/mysql"

	"golang.org/x/net/context"
)

// CreateReparentJournal returns the commands to execute to create
// the _vt.reparent_journal table. It is safe to run these commands
// even if the table already exists.
//
// If the table was created by Vitess version 2.0, the following command
// may need to be run:
// ALTER TABLE _vt.reparent_journal MODIFY COLUMN replication_position VARBINARY(64000);
func CreateReparentJournal() []string {
	return []string{
		"CREATE DATABASE IF NOT EXISTS _vt",
		fmt.Sprintf(`CREATE TABLE IF NOT EXISTS _vt.reparent_journal (
  time_created_ns BIGINT UNSIGNED NOT NULL,
  action_name VARBINARY(250) NOT NULL,
  master_alias VARBINARY(32) NOT NULL,
  replication_position VARBINARY(%v) DEFAULT NULL,
  PRIMARY KEY (time_created_ns))
ENGINE=InnoDB`, mysql.MaximumPositionSize)}
}

// PopulateReparentJournal returns the SQL command to use to populate
// the _vt.reparent_journal table, as well as the time_created_ns
// value used.
func PopulateReparentJournal(timeCreatedNS int64, actionName, masterAlias string, pos mysql.Position) string {
	posStr := mysql.EncodePosition(pos)
	if len(posStr) > mysql.MaximumPositionSize {
		posStr = posStr[:mysql.MaximumPositionSize]
	}
	return fmt.Sprintf("INSERT INTO _vt.reparent_journal "+
		"(time_created_ns, action_name, master_alias, replication_position) "+
		"VALUES (%v, '%v', '%v', '%v')",
		timeCreatedNS, actionName, masterAlias, posStr)
}

// queryReparentJournal returns the SQL query to use to query the database
// for a reparent_journal row.
func queryReparentJournal(timeCreatedNS int64) string {
	return fmt.Sprintf("SELECT action_name, master_alias, replication_position FROM _vt.reparent_journal WHERE time_created_ns=%v", timeCreatedNS)
}

// WaitForReparentJournal will wait until the context is done for
// the row in the reparent_journal table.
func (mysqld *Mysqld) WaitForReparentJournal(ctx context.Context, timeCreatedNS int64) error {
	for {
		qr, err := mysqld.FetchSuperQuery(ctx, queryReparentJournal(timeCreatedNS))
		if err == nil && len(qr.Rows) == 1 {
			// we have the row, we're done
			return nil
		}

		// wait a little bit, interrupt if context is done
		t := time.After(100 * time.Millisecond)
		select {
		case <-ctx.Done():
			return ctx.Err()
		case <-t:
		}
	}
}

// Deprecated: use mysqld.MasterPosition() instead
func (mysqld *Mysqld) DemoteMaster() (rp mysql.Position, err error) {
	return mysqld.MasterPosition()
}

// PromoteSlave will promote a slave to be the new master.
func (mysqld *Mysqld) PromoteSlave(hookExtraEnv map[string]string) (mysql.Position, error) {
	ctx := context.TODO()
	conn, err := getPoolReconnect(ctx, mysqld.dbaPool)
	if err != nil {
		return mysql.Position{}, err
	}
	defer conn.Recycle()

	// Since we handle replication, just stop it.
	cmds := []string{
		conn.StopSlaveCommand(),
		"RESET SLAVE ALL", // "ALL" makes it forget master host:port.
		// When using semi-sync and GTID, a replica first connects to the new master with a given GTID set,
		// it can take a long time to scan the current binlog file to find the corresponding position.
		// This can cause commits that occur soon after the master is promoted to take a long time waiting
		// for a semi-sync ACK, since replication is not fully set up.
		// More details in: https://github.com/vitessio/vitess/issues/4161
		"FLUSH BINARY LOGS",
	}

	if err := mysqld.executeSuperQueryListConn(ctx, conn, cmds); err != nil {
		return mysql.Position{}, err
	}
	return conn.MasterPosition()
}
<commit_msg>Add log line indicating when WaitForReparentJournal fails<commit_after>/*
Copyright 2017 Google Inc.

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

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

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

package mysqlctl

/*
This file contains the reparenting methods for mysqlctl.

TODO(alainjobart) Once refactoring is done, remove unused code paths.
*/

import (
	"fmt"
	"time"

	"vitess.io/vitess/go/mysql"
	"vitess.io/vitess/go/vt/log"

	"golang.org/x/net/context"
)

// CreateReparentJournal returns the commands to execute to create
// the _vt.reparent_journal table. It is safe to run these commands
// even if the table already exists.
//
// If the table was created by Vitess version 2.0, the following command
// may need to be run:
// ALTER TABLE _vt.reparent_journal MODIFY COLUMN replication_position VARBINARY(64000);
func CreateReparentJournal() []string {
	return []string{
		"CREATE DATABASE IF NOT EXISTS _vt",
		fmt.Sprintf(`CREATE TABLE IF NOT EXISTS _vt.reparent_journal (
  time_created_ns BIGINT UNSIGNED NOT NULL,
  action_name VARBINARY(250) NOT NULL,
  master_alias VARBINARY(32) NOT NULL,
  replication_position VARBINARY(%v) DEFAULT NULL,
  PRIMARY KEY (time_created_ns))
ENGINE=InnoDB`, mysql.MaximumPositionSize)}
}

// PopulateReparentJournal returns the SQL command to use to populate
// the _vt.reparent_journal table, as well as the time_created_ns
// value used.
func PopulateReparentJournal(timeCreatedNS int64, actionName, masterAlias string, pos mysql.Position) string {
	posStr := mysql.EncodePosition(pos)
	if len(posStr) > mysql.MaximumPositionSize {
		posStr = posStr[:mysql.MaximumPositionSize]
	}
	return fmt.Sprintf("INSERT INTO _vt.reparent_journal "+
		"(time_created_ns, action_name, master_alias, replication_position) "+
		"VALUES (%v, '%v', '%v', '%v')",
		timeCreatedNS, actionName, masterAlias, posStr)
}

// queryReparentJournal returns the SQL query to use to query the database
// for a reparent_journal row.
func queryReparentJournal(timeCreatedNS int64) string {
	return fmt.Sprintf("SELECT action_name, master_alias, replication_position FROM _vt.reparent_journal WHERE time_created_ns=%v", timeCreatedNS)
}

// WaitForReparentJournal will wait until the context is done for
// the row in the reparent_journal table.
func (mysqld *Mysqld) WaitForReparentJournal(ctx context.Context, timeCreatedNS int64) error {
	for {
		qr, err := mysqld.FetchSuperQuery(ctx, queryReparentJournal(timeCreatedNS))
		if err == nil && len(qr.Rows) == 1 {
			// we have the row, we're done
			return nil
		}

		// wait a little bit, interrupt if context is done
		t := time.After(100 * time.Millisecond)
		select {
		case <-ctx.Done():
			log.Warning("WaitForReparentJournal failed to see row before timeout.")
			return ctx.Err()
		case <-t:
		}
	}
}

// Deprecated: use mysqld.MasterPosition() instead
func (mysqld *Mysqld) DemoteMaster() (rp mysql.Position, err error) {
	return mysqld.MasterPosition()
}

// PromoteSlave will promote a slave to be the new master.
func (mysqld *Mysqld) PromoteSlave(hookExtraEnv map[string]string) (mysql.Position, error) {
	ctx := context.TODO()
	conn, err := getPoolReconnect(ctx, mysqld.dbaPool)
	if err != nil {
		return mysql.Position{}, err
	}
	defer conn.Recycle()

	// Since we handle replication, just stop it.
	cmds := []string{
		conn.StopSlaveCommand(),
		"RESET SLAVE ALL", // "ALL" makes it forget master host:port.
		// When using semi-sync and GTID, a replica first connects to the new master with a given GTID set,
		// it can take a long time to scan the current binlog file to find the corresponding position.
		// This can cause commits that occur soon after the master is promoted to take a long time waiting
		// for a semi-sync ACK, since replication is not fully set up.
		// More details in: https://github.com/vitessio/vitess/issues/4161
		"FLUSH BINARY LOGS",
	}

	if err := mysqld.executeSuperQueryListConn(ctx, conn, cmds); err != nil {
		return mysql.Position{}, err
	}
	return conn.MasterPosition()
}
<|endoftext|>


<commit_before>package gqt_test

import (
	"encoding/json"
	"fmt"
	"math/rand"
	"net"
	"os/exec"
	"strings"
	"sync"
	"time"

	"code.cloudfoundry.org/garden"
	"code.cloudfoundry.org/guardian/gqt/runner"
	uuid "github.com/nu7hatch/gouuid"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Networking Uniqueness", func() {
	var (
		client *runner.RunningGarden
	)

	BeforeEach(func() {
		config.LogLevel = "error"
		client = runner.Start(config)
	})

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

	It("should not allocate duplicate subnets", func() {
		skipIfDev()
		routines := 25
		containersPerRoutine := 10
		allContainerInfos := []garden.ContainerInfo{}
		var mutex = &sync.Mutex{}

		wg := &sync.WaitGroup{}
		wg.Add(routines)
		for i := 0; i < routines; i++ {
			go func() {
				defer GinkgoRecover()
				defer wg.Done()

				containerInfos := create(client, containersPerRoutine)

				mutex.Lock()
				defer mutex.Unlock()
				allContainerInfos = append(allContainerInfos, containerInfos...)
			}()
		}

		wg.Wait()
		Expect(numContainers(client)).To(Equal(routines * containersPerRoutine))
		Expect(numBridges()).To(Equal(routines*containersPerRoutine), diagnose(allContainerInfos))
	})
})

func diagnose(containerInfos []garden.ContainerInfo) string {
	ifconfigBytes, err := exec.Command("ifconfig").CombinedOutput()
	interfaceInfo := string(ifconfigBytes)
	if err != nil {
		interfaceInfo += fmt.Sprintf("\nifconfig error: %v\n", err)
	}

	var allContainersInfo string
	bytes, err := json.Marshal(containerInfos)
	if err != nil {
		allContainersInfo = fmt.Sprintf("Could not marshal containers due to %v; raw containers data:\n %#v", err, containerInfos)
	} else {
		allContainersInfo = string(bytes)
	}

	return fmt.Sprintf("%s\n%s\n", interfaceInfo, allContainersInfo)
}

func create(client *runner.RunningGarden, n int) []garden.ContainerInfo {
	containerInfos := []garden.ContainerInfo{}
	for i := 0; i < n; i++ {
		time.Sleep(randomSleepDuration())

		id, err := uuid.NewV4()
		Expect(err).NotTo(HaveOccurred())
		randomID := "net-uniq-" + id.String()
		container, err := client.Create(garden.ContainerSpec{Handle: randomID})
		Expect(err).NotTo(HaveOccurred())
		containerInfo, err := container.Info()
		Expect(err).NotTo(HaveOccurred())
		containerInfos = append(containerInfos, containerInfo)

	}
	return containerInfos
}

func randomSleepDuration() time.Duration {
	random := rand.New(rand.NewSource(time.Now().UnixNano()))
	duration := time.Duration(50+random.Intn(500)) * time.Millisecond
	return duration
}

func numContainers(client *runner.RunningGarden) int {
	containers, err := client.Containers(nil)
	Expect(err).NotTo(HaveOccurred())
	return len(containers)
}

func numBridges() int {
	intfs, err := net.Interfaces()
	Expect(err).NotTo(HaveOccurred())

	bridgeCount := 0

	for _, intf := range intfs {
		if strings.Contains(intf.Name, fmt.Sprintf("w%dbrdg", GinkgoParallelNode())) {
			bridgeCount++
		}
	}

	return bridgeCount
}
<commit_msg>Filter out bridges to prevent test flakiness<commit_after>package gqt_test

import (
	"encoding/json"
	"fmt"
	"math/rand"
	"net"
	"os/exec"
	"strings"
	"sync"
	"time"

	"code.cloudfoundry.org/garden"
	"code.cloudfoundry.org/guardian/gqt/runner"
	uuid "github.com/nu7hatch/gouuid"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Networking Uniqueness", func() {
	var (
		client *runner.RunningGarden
	)

	BeforeEach(func() {
		config.LogLevel = "error"
		client = runner.Start(config)
	})

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

	It("should not allocate duplicate subnets", func() {
		skipIfDev()
		routines := 25
		containersPerRoutine := 10
		allContainerInfos := []garden.ContainerInfo{}
		var mutex = &sync.Mutex{}

		wg := &sync.WaitGroup{}
		wg.Add(routines)
		for i := 0; i < routines; i++ {
			go func() {
				defer GinkgoRecover()
				defer wg.Done()

				containerInfos := create(client, containersPerRoutine)

				mutex.Lock()
				defer mutex.Unlock()
				allContainerInfos = append(allContainerInfos, containerInfos...)
			}()
		}

		wg.Wait()
		Expect(numContainers(client)).To(Equal(routines * containersPerRoutine))
		Expect(numBridges()).To(Equal(routines*containersPerRoutine), diagnose(allContainerInfos))
	})
})

func diagnose(containerInfos []garden.ContainerInfo) string {
	ifconfigBytes, err := exec.Command("ifconfig").CombinedOutput()
	interfaceInfo := string(ifconfigBytes)
	if err != nil {
		interfaceInfo += fmt.Sprintf("\nifconfig error: %v\n", err)
	}

	var allContainersInfo string
	bytes, err := json.Marshal(containerInfos)
	if err != nil {
		allContainersInfo = fmt.Sprintf("Could not marshal containers due to %v; raw containers data:\n %#v", err, containerInfos)
	} else {
		allContainersInfo = string(bytes)
	}

	return fmt.Sprintf("%s\n%s\n", interfaceInfo, allContainersInfo)
}

func create(client *runner.RunningGarden, n int) []garden.ContainerInfo {
	containerInfos := []garden.ContainerInfo{}
	for i := 0; i < n; i++ {
		time.Sleep(randomSleepDuration())

		id, err := uuid.NewV4()
		Expect(err).NotTo(HaveOccurred())
		randomID := "net-uniq-" + id.String()
		container, err := client.Create(garden.ContainerSpec{Handle: randomID})
		Expect(err).NotTo(HaveOccurred())
		containerInfo, err := container.Info()
		Expect(err).NotTo(HaveOccurred())
		containerInfos = append(containerInfos, containerInfo)

	}
	return containerInfos
}

func randomSleepDuration() time.Duration {
	random := rand.New(rand.NewSource(time.Now().UnixNano()))
	duration := time.Duration(50+random.Intn(500)) * time.Millisecond
	return duration
}

func numContainers(client *runner.RunningGarden) int {
	containers, err := client.Containers(nil)
	Expect(err).NotTo(HaveOccurred())
	return len(containers)
}

func numBridges() int {
	intfs, err := net.Interfaces()
	Expect(err).NotTo(HaveOccurred())

	bridgeCount := 0

	for _, intf := range intfs {
		if strings.Contains(intf.Name, fmt.Sprintf("w%dbrdg-0afe", GinkgoParallelNode())) {
			bridgeCount++
		}
	}

	return bridgeCount
}
<|endoftext|>


<commit_before>/*                          _       _
 *__      _____  __ ___   ___  __ _| |_ ___
 *\ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
 * \ V  V /  __/ (_| |\ V /| | (_| | ||  __/
 *  \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
 *
 * Copyright © 2016 - 2018 Weaviate. All rights reserved.
 * LICENSE: https://github.com/creativesoftwarefdn/weaviate/blob/develop/LICENSE.md
 * AUTHOR: Bob van Luijt (bob@kub.design)
 * See www.creativesoftwarefdn.org for details
 * Contact: @CreativeSofwFdn / bob@kub.design
 */

package graphqlapi

import (
	"bytes"
	"fmt"
	"github.com/graphql-go/graphql"
)

// Build the GraphQL schema based on
// 1) the static query structure (e.g. LocalFetch)
// 2) the (dynamic) database schema from Weaviate

func (g *GraphQL) genGraphqlSchema() error {

	rootFieldsObject, err := g.assembleFullSchema()

	if err != nil {
		return fmt.Errorf("Could not build GraphQL schema, because: %v", err)
	}

	schemaObject := graphql.ObjectConfig{
		Name:        "WeaviateObj",
		Fields:      rootFieldsObject,
		Description: "Location of the root query",
	}

	// Run grahql.NewSchema in a sub-closure, so that we can recover from panics.
	// We need to use panics to return errors deep inside the dynamic generation of the GraphQL schema,
	// inside the FieldThunks. There is _no_ way to bubble up an error besides panicking.
	func() {
		defer func() {
			if r := recover(); r != nil {
				var ok bool
				err, ok = r.(error) // can't shadow err here; we need the err from outside the function closure.
				if !ok {
					err = fmt.Errorf("%v", err)
				}
			}
		}()

		g.weaviateGraphQLSchema, err = graphql.NewSchema(graphql.SchemaConfig{
			Query: graphql.NewObject(schemaObject),
		})
	}()

	if err != nil {
		return fmt.Errorf("Could not build GraphQL schema, because: %v", err)
	} else {
		return nil
	}
}

// check: regel class refs voor meerdere objecten als datatype (union)
// check: maak dit ook voor Things
// check: refactor naar objects returnen ipv object configs
// check: check all Things strings
// check: confirm output of dynamic schema generation; classes as properties in lists y/n?
// check: implement metafetch
// TODO: implement filters

func (g *GraphQL) assembleFullSchema() (graphql.Fields, error) {

	// This map is used to store all the Thing and Action ObjectConfigs, so that we can use them in references.
	convertedFetchActionsAndThings := make(map[string]*graphql.Object)

	localConvertedFetchActions, err := g.genActionClassFieldsFromSchema(&convertedFetchActionsAndThings)

	if err != nil {
		return nil, fmt.Errorf("Failed to generate action fields from schema for local convertedfetch because: %v", err)
	}

	localConvertedFetchThings, err := g.genThingClassFieldsFromSchema(&convertedFetchActionsAndThings)

	if err != nil {
		return nil, fmt.Errorf("Failed to generate thing fields from schema for local convertedfetch because: %v", err)
	}

	localMetaFetchActions, err := g.genMetaClassFieldsFromSchema(g.databaseSchema.ActionSchema.Schema.Classes, true)
	if err != nil {
		return nil, fmt.Errorf("Failed to generate action fields from schema for local metafetch because: %v", err)
	}

	localMetaFetchThings, err := g.genMetaClassFieldsFromSchema(g.databaseSchema.ThingSchema.Schema.Classes, false)
	if err != nil {
		return nil, fmt.Errorf("Failed to generate thing fields from schema for local metafetch because: %v", err)
	}

	localConvertedFetchObject, err := g.genThingsAndActionsFieldsForWeaviateLocalConvertedFetchObj(localConvertedFetchActions, localConvertedFetchThings)
	if err != nil {
		return nil, fmt.Errorf("Failed to generate things and action fields for local convertedfetch because: %v", err)
	}

	localMetaFetchObject, err := g.genThingsAndActionsFieldsForWeaviateLocalMetaFetchGenericsObj(localMetaFetchActions, localMetaFetchThings)
	if err != nil {
		return nil, fmt.Errorf("Failed to generate things and action fields for local metafetch because: %v", err)
	}

	localMetaGenericsObject, err := g.genGenericsFieldForWeaviateLocalMetaFetchObj(localMetaFetchObject)
	if err != nil {
		return nil, fmt.Errorf("Failed to generate generics field for local metafetch because: %v", err)
	}

	localMetaAndConvertedFetchObject, err := g.genConvertedFetchAndMetaGenericsFields(localConvertedFetchObject, localMetaGenericsObject)
	if err != nil {
		return nil, fmt.Errorf("Failed to generate meta and convertedfetch fields for local weaviateobject because: %v", err)
	}

	localObject, err := g.genLocalField(localMetaAndConvertedFetchObject)
	if err != nil {
		return nil, fmt.Errorf("Failed to generate local field for local weaviateobject because: %v", err)
	}

	rootFieldsObject, err := g.genRootQueryFields(localObject)
	if err != nil {
		return nil, fmt.Errorf("Failed to generate root query because: %v", err)
	}

	return rootFieldsObject, nil
}

// generate the static parts of the schema
func (g *GraphQL) genThingsAndActionsFieldsForWeaviateLocalConvertedFetchObj(localConvertedFetchActions *graphql.Object,
	localConvertedFetchThings *graphql.Object) (*graphql.Object, error) {

	convertedFetchThingsAndActionFields := graphql.Fields{
		"Actions": &graphql.Field{
			Name:        "WeaviateLocalConvertedFetchActions",
			Description: "Locate Actions on the local Weaviate",
			Type:        localConvertedFetchActions,
			Resolve: func(p graphql.ResolveParams) (interface{}, error) {
				return nil, fmt.Errorf("Not supported")
			},
		},
		"Things": &graphql.Field{
			Name:        "WeaviateLocalConvertedFetchThings",
			Description: "Locate Things on the local Weaviate",
			Type:        localConvertedFetchThings,
			Resolve: func(p graphql.ResolveParams) (interface{}, error) {
				return nil, fmt.Errorf("Not supported")
			},
		},
	}
	convertedFetchThingsAndActionFieldsObject := graphql.ObjectConfig{
		Name:        "WeaviateLocalConvertedFetchObj",
		Fields:      convertedFetchThingsAndActionFields,
		Description: "Fetch things or actions on the internal Weaviate",
	}
	return graphql.NewObject(convertedFetchThingsAndActionFieldsObject), nil
}

func (g *GraphQL) genThingsAndActionsFieldsForWeaviateLocalMetaFetchGenericsObj(localMetaFetchActions *graphql.Object, localMetaFetchThings *graphql.Object) (*graphql.Object, error) {

	metaFetchGenericsThingsAndActionFields := graphql.Fields{
		"Actions": &graphql.Field{
			Name:        "WeaviateLocalMetaFetchGenericsActions",
			Description: "Action to fetch for meta generic fetch",
			Type:        localMetaFetchActions,
			Resolve: func(p graphql.ResolveParams) (interface{}, error) {
				return nil, fmt.Errorf("Not supported")
			},
		},
		"Things": &graphql.Field{
			Name:        "WeaviateLocalMetaFetchGenericsThings",
			Description: "Thing to fetch for meta generic fetch",
			Type:        localMetaFetchThings,
			Resolve: func(p graphql.ResolveParams) (interface{}, error) {
				return nil, fmt.Errorf("Not supported")
			},
		},
	}
	metaFetchGenericsThingsAndActionFieldsObject := graphql.ObjectConfig{
		Name:        "WeaviateLocalMetaFetchGenericsObj",
		Fields:      metaFetchGenericsThingsAndActionFields,
		Description: "Object type to fetch",
	}
	return graphql.NewObject(metaFetchGenericsThingsAndActionFieldsObject), nil
}

func (g *GraphQL) genGenericsFieldForWeaviateLocalMetaFetchObj(localMetaFetchObject *graphql.Object) (*graphql.Object, error) {

	metaFetchGenericsField := graphql.Fields{
		"Generics": &graphql.Field{
			Name:        "WeaviateLocalMetaFetchGenericsObj",
			Description: "Fetch generic meta information based on the type",
			Type:        localMetaFetchObject,
			Resolve: func(p graphql.ResolveParams) (interface{}, error) {
				return nil, fmt.Errorf("Not supported")
			},
		},
	}
	metaFetchGenericsFieldObject := graphql.ObjectConfig{
		Name:        "WeaviateLocalMetaFetchObj",
		Fields:      metaFetchGenericsField,
		Description: "Fetch things or actions on the internal Weaviate",
	}
	return graphql.NewObject(metaFetchGenericsFieldObject), nil
}

func (g *GraphQL) genConvertedFetchAndMetaGenericsFields(
	localConvertedFetchObject *graphql.Object,
	localMetaGenericsObject *graphql.Object) (*graphql.Object, error) {

	convertedAndMetaFetchFields := graphql.Fields{
		"ConvertedFetch": &graphql.Field{
			Name:        "WeaviateLocalConvertedFetch",
			Type:        localConvertedFetchObject,
			Description: "Do a converted fetch to search Things or Actions on the local weaviate",
			Resolve: func(p graphql.ResolveParams) (interface{}, error) {
				return nil, fmt.Errorf("Not supported")
			},
		},
		"MetaFetch": &graphql.Field{
			Name:        "WeaviateLocalMetaFetch",
			Type:        localMetaGenericsObject,
			Description: "Fetch meta information about Things or Actions on the local weaviate",
			Resolve: func(p graphql.ResolveParams) (interface{}, error) {
				return nil, fmt.Errorf("Not supported")
			},
		},
	}
	weaviateLocalObject := &graphql.ObjectConfig{
		Name:        "WeaviateLocalObj",
		Fields:      convertedAndMetaFetchFields,
		Description: "Type of fetch on the internal Weaviate",
	}
	return graphql.NewObject(*weaviateLocalObject), nil
}

func (g *GraphQL) genLocalField(localMetaAndConvertedFetchObject *graphql.Object) (*graphql.Field, error) {

	field := graphql.Field{
		Type:        localMetaAndConvertedFetchObject,
		Description: "Locate on the local Weaviate",
		Resolve: func(p graphql.ResolveParams) (interface{}, error) {
			return nil, fmt.Errorf("Not supported")
		},
	}
	return &field, nil
}

func (g *GraphQL) genRootQueryFields(localField *graphql.Field) (graphql.Fields, error) {

	var rootQueryFields = graphql.Fields{
		"Local":   localField,
		"Network": nil,
	}
	return rootQueryFields, nil
}

func mergeStrings(stringParts ...string) string {

	var buffer bytes.Buffer
	for _, stringPart := range stringParts {
		buffer.WriteString(stringPart)
	}

	return buffer.String()
}
<commit_msg>gh-384: minor bug fix<commit_after>/*                          _       _
 *__      _____  __ ___   ___  __ _| |_ ___
 *\ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
 * \ V  V /  __/ (_| |\ V /| | (_| | ||  __/
 *  \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
 *
 * Copyright © 2016 - 2018 Weaviate. All rights reserved.
 * LICENSE: https://github.com/creativesoftwarefdn/weaviate/blob/develop/LICENSE.md
 * AUTHOR: Bob van Luijt (bob@kub.design)
 * See www.creativesoftwarefdn.org for details
 * Contact: @CreativeSofwFdn / bob@kub.design
 */

package graphqlapi

import (
	"bytes"
	"fmt"
	"github.com/graphql-go/graphql"
)

// Build the GraphQL schema based on
// 1) the static query structure (e.g. LocalFetch)
// 2) the (dynamic) database schema from Weaviate

func (g *GraphQL) buildGraphqlSchema() error {

	rootFieldsObject, err := g.assembleFullSchema()

	if err != nil {
		return fmt.Errorf("Could not build GraphQL schema, because: %v", err)
	}

	schemaObject := graphql.ObjectConfig{
		Name:        "WeaviateObj",
		Fields:      rootFieldsObject,
		Description: "Location of the root query",
	}

	// Run grahql.NewSchema in a sub-closure, so that we can recover from panics.
	// We need to use panics to return errors deep inside the dynamic generation of the GraphQL schema,
	// inside the FieldThunks. There is _no_ way to bubble up an error besides panicking.
	func() {
		defer func() {
			if r := recover(); r != nil {
				var ok bool
				err, ok = r.(error) // can't shadow err here; we need the err from outside the function closure.
				if !ok {
					err = fmt.Errorf("%v", err)
				}
			}
		}()

		g.weaviateGraphQLSchema, err = graphql.NewSchema(graphql.SchemaConfig{
			Query: graphql.NewObject(schemaObject),
		})
	}()

	if err != nil {
		return fmt.Errorf("Could not build GraphQL schema, because: %v", err)
	} else {
		return nil
	}
}

// check: regel class refs voor meerdere objecten als datatype (union)
// check: maak dit ook voor Things
// check: refactor naar objects returnen ipv object configs
// check: check all Things strings
// check: confirm output of dynamic schema generation; classes as properties in lists y/n?
// check: implement metafetch
// TODO: implement filters

func (g *GraphQL) assembleFullSchema() (graphql.Fields, error) {

	// This map is used to store all the Thing and Action ObjectConfigs, so that we can use them in references.
	convertedFetchActionsAndThings := make(map[string]*graphql.Object)

	localConvertedFetchActions, err := g.genActionClassFieldsFromSchema(&convertedFetchActionsAndThings)

	if err != nil {
		return nil, fmt.Errorf("Failed to generate action fields from schema for local convertedfetch because: %v", err)
	}

	localConvertedFetchThings, err := g.genThingClassFieldsFromSchema(&convertedFetchActionsAndThings)

	if err != nil {
		return nil, fmt.Errorf("Failed to generate thing fields from schema for local convertedfetch because: %v", err)
	}

	localMetaFetchActions, err := g.genMetaClassFieldsFromSchema(g.databaseSchema.ActionSchema.Schema.Classes, true)
	if err != nil {
		return nil, fmt.Errorf("Failed to generate action fields from schema for local metafetch because: %v", err)
	}

	localMetaFetchThings, err := g.genMetaClassFieldsFromSchema(g.databaseSchema.ThingSchema.Schema.Classes, false)
	if err != nil {
		return nil, fmt.Errorf("Failed to generate thing fields from schema for local metafetch because: %v", err)
	}

	localConvertedFetchObject, err := g.genThingsAndActionsFieldsForWeaviateLocalConvertedFetchObj(localConvertedFetchActions, localConvertedFetchThings)
	if err != nil {
		return nil, fmt.Errorf("Failed to generate things and action fields for local convertedfetch because: %v", err)
	}

	localMetaFetchObject, err := g.genThingsAndActionsFieldsForWeaviateLocalMetaFetchGenericsObj(localMetaFetchActions, localMetaFetchThings)
	if err != nil {
		return nil, fmt.Errorf("Failed to generate things and action fields for local metafetch because: %v", err)
	}

	localMetaGenericsObject, err := g.genGenericsFieldForWeaviateLocalMetaFetchObj(localMetaFetchObject)
	if err != nil {
		return nil, fmt.Errorf("Failed to generate generics field for local metafetch because: %v", err)
	}

	localMetaAndConvertedFetchObject, err := g.genConvertedFetchAndMetaGenericsFields(localConvertedFetchObject, localMetaGenericsObject)
	if err != nil {
		return nil, fmt.Errorf("Failed to generate meta and convertedfetch fields for local weaviateobject because: %v", err)
	}

	localObject, err := g.genLocalField(localMetaAndConvertedFetchObject)
	if err != nil {
		return nil, fmt.Errorf("Failed to generate local field for local weaviateobject because: %v", err)
	}

	rootFieldsObject, err := g.genRootQueryFields(localObject)
	if err != nil {
		return nil, fmt.Errorf("Failed to generate root query because: %v", err)
	}

	return rootFieldsObject, nil
}

// generate the static parts of the schema
func (g *GraphQL) genThingsAndActionsFieldsForWeaviateLocalConvertedFetchObj(localConvertedFetchActions *graphql.Object,
	localConvertedFetchThings *graphql.Object) (*graphql.Object, error) {

	convertedFetchThingsAndActionFields := graphql.Fields{
		"Actions": &graphql.Field{
			Name:        "WeaviateLocalConvertedFetchActions",
			Description: "Locate Actions on the local Weaviate",
			Type:        localConvertedFetchActions,
			Resolve: func(p graphql.ResolveParams) (interface{}, error) {
				return nil, fmt.Errorf("Not supported")
			},
		},
		"Things": &graphql.Field{
			Name:        "WeaviateLocalConvertedFetchThings",
			Description: "Locate Things on the local Weaviate",
			Type:        localConvertedFetchThings,
			Resolve: func(p graphql.ResolveParams) (interface{}, error) {
				return nil, fmt.Errorf("Not supported")
			},
		},
	}
	convertedFetchThingsAndActionFieldsObject := graphql.ObjectConfig{
		Name:        "WeaviateLocalConvertedFetchObj",
		Fields:      convertedFetchThingsAndActionFields,
		Description: "Fetch things or actions on the internal Weaviate",
	}
	return graphql.NewObject(convertedFetchThingsAndActionFieldsObject), nil
}

func (g *GraphQL) genThingsAndActionsFieldsForWeaviateLocalMetaFetchGenericsObj(localMetaFetchActions *graphql.Object, localMetaFetchThings *graphql.Object) (*graphql.Object, error) {

	metaFetchGenericsThingsAndActionFields := graphql.Fields{
		"Actions": &graphql.Field{
			Name:        "WeaviateLocalMetaFetchGenericsActions",
			Description: "Action to fetch for meta generic fetch",
			Type:        localMetaFetchActions,
			Resolve: func(p graphql.ResolveParams) (interface{}, error) {
				return nil, fmt.Errorf("Not supported")
			},
		},
		"Things": &graphql.Field{
			Name:        "WeaviateLocalMetaFetchGenericsThings",
			Description: "Thing to fetch for meta generic fetch",
			Type:        localMetaFetchThings,
			Resolve: func(p graphql.ResolveParams) (interface{}, error) {
				return nil, fmt.Errorf("Not supported")
			},
		},
	}
	metaFetchGenericsThingsAndActionFieldsObject := graphql.ObjectConfig{
		Name:        "WeaviateLocalMetaFetchGenericsObj",
		Fields:      metaFetchGenericsThingsAndActionFields,
		Description: "Object type to fetch",
	}
	return graphql.NewObject(metaFetchGenericsThingsAndActionFieldsObject), nil
}

func (g *GraphQL) genGenericsFieldForWeaviateLocalMetaFetchObj(localMetaFetchObject *graphql.Object) (*graphql.Object, error) {

	metaFetchGenericsField := graphql.Fields{
		"Generics": &graphql.Field{
			Name:        "WeaviateLocalMetaFetchGenericsObj",
			Description: "Fetch generic meta information based on the type",
			Type:        localMetaFetchObject,
			Resolve: func(p graphql.ResolveParams) (interface{}, error) {
				return nil, fmt.Errorf("Not supported")
			},
		},
	}
	metaFetchGenericsFieldObject := graphql.ObjectConfig{
		Name:        "WeaviateLocalMetaFetchObj",
		Fields:      metaFetchGenericsField,
		Description: "Fetch things or actions on the internal Weaviate",
	}
	return graphql.NewObject(metaFetchGenericsFieldObject), nil
}

func (g *GraphQL) genConvertedFetchAndMetaGenericsFields(
	localConvertedFetchObject *graphql.Object,
	localMetaGenericsObject *graphql.Object) (*graphql.Object, error) {

	convertedAndMetaFetchFields := graphql.Fields{
		"ConvertedFetch": &graphql.Field{
			Name:        "WeaviateLocalConvertedFetch",
			Type:        localConvertedFetchObject,
			Description: "Do a converted fetch to search Things or Actions on the local weaviate",
			Resolve: func(p graphql.ResolveParams) (interface{}, error) {
				return nil, fmt.Errorf("Not supported")
			},
		},
		"MetaFetch": &graphql.Field{
			Name:        "WeaviateLocalMetaFetch",
			Type:        localMetaGenericsObject,
			Description: "Fetch meta information about Things or Actions on the local weaviate",
			Resolve: func(p graphql.ResolveParams) (interface{}, error) {
				return nil, fmt.Errorf("Not supported")
			},
		},
	}
	weaviateLocalObject := &graphql.ObjectConfig{
		Name:        "WeaviateLocalObj",
		Fields:      convertedAndMetaFetchFields,
		Description: "Type of fetch on the internal Weaviate",
	}
	return graphql.NewObject(*weaviateLocalObject), nil
}

func (g *GraphQL) genLocalField(localMetaAndConvertedFetchObject *graphql.Object) (*graphql.Field, error) {

	field := graphql.Field{
		Type:        localMetaAndConvertedFetchObject,
		Description: "Locate on the local Weaviate",
		Resolve: func(p graphql.ResolveParams) (interface{}, error) {
			return nil, fmt.Errorf("Not supported")
		},
	}
	return &field, nil
}

func (g *GraphQL) genRootQueryFields(localField *graphql.Field) (graphql.Fields, error) {

	var rootQueryFields = graphql.Fields{
		"Local":   localField,
		"Network": nil,
	}
	return rootQueryFields, nil
}

func mergeStrings(stringParts ...string) string {

	var buffer bytes.Buffer
	for _, stringPart := range stringParts {
		buffer.WriteString(stringPart)
	}

	return buffer.String()
}
<|endoftext|>


<commit_before>package qingcloud

import (
	"fmt"
	"log"
	"os"
	"testing"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/terraform"
	qc "github.com/yunify/qingcloud-sdk-go/service"
)

func TestAccQingcloudVxNet_basic(t *testing.T) {
	var vxnet qc.DescribeVxNetsOutput

	resource.Test(t, resource.TestCase{
		PreCheck: func() {
			testAccPreCheck(t)
		},

		// module name
		IDRefreshName: "qingcloud_vxnet.foo",
		Providers:     testAccProviders,
		CheckDestroy:  testAccCheckVxNetDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccVxNetConfig,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckVxNetExists(
						"qingcloud_vxnet.foo", &vxnet),
					resource.TestCheckResourceAttr(
						"qingcloud_vxnet.foo", "type", "1"),
				),
			},
			resource.TestStep{
				Config: testAccVxNetConfigTwo,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckVxNetExists(
						"qingcloud_vxnet.foo", &vxnet),
					resource.TestCheckResourceAttr(
						"qingcloud_vxnet.foo", "type", "1"),
					resource.TestCheckResourceAttr(
						"qingcloud_vxnet.foo", "description", "vxnet"),
					resource.TestCheckResourceAttr(
						"qingcloud_vxnet.foo", "name", "vxnet"),
				),
			},
			resource.TestStep{
				Config: testAccVxNetConfigThree,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckVxNetExists(
						"qingcloud_vxnet.foo", &vxnet),
					resource.TestCheckResourceAttr(
						"qingcloud_vxnet.foo", "type", "0"),
					resource.TestCheckResourceAttr(
						"qingcloud_vxnet.foo", "description", "vxnet"),
					resource.TestCheckResourceAttr(
						"qingcloud_vxnet.foo", "name", "vxnet"),
				),
			},
		},
	})

}

func TestAccQingcloudVxNet_tag(t *testing.T) {
	var vxnet qc.DescribeVxNetsOutput
	vxnetTag1Name := os.Getenv("TRAVIS_BUILD_ID") + "-" + os.Getenv("TRAVIS_JOB_NUMBER") + "-vxnet-tag1"
	vxnetTag2Name := os.Getenv("TRAVIS_BUILD_ID") + "-" + os.Getenv("TRAVIS_JOB_NUMBER") + "-vxnet-tag2"

	testTagNameValue := func(names ...string) resource.TestCheckFunc {
		return func(state *terraform.State) error {
			tags := vxnet.VxNetSet[0].Tags
			same_count := 0
			for _, tag := range tags {
				for _, name := range names {
					if qc.StringValue(tag.TagName) == name {
						same_count++
					}
					if same_count == len(vxnet.VxNetSet[0].Tags) {
						return nil
					}
				}
			}
			return fmt.Errorf("tag name error %#v", names)
		}
	}
	testTagDetach := func() resource.TestCheckFunc {
		return func(state *terraform.State) error {
			if len(vxnet.VxNetSet[0].Tags) != 0 {
				return fmt.Errorf("tag not detach ")
			}
			return nil
		}
	}

	resource.Test(t, resource.TestCase{
		PreCheck: func() {
			testAccPreCheck(t)
		},

		// module name
		IDRefreshName: "qingcloud_vxnet.foo",
		Providers:     testAccProviders,
		CheckDestroy:  testAccCheckVxNetDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: fmt.Sprintf(testAccVxNetConfigTagTemplate, vxnetTag1Name, vxnetTag2Name),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckVxNetExists(
						"qingcloud_vxnet.foo", &vxnet),
					testTagNameValue(vxnetTag1Name, vxnetTag2Name),
				),
			},
			resource.TestStep{
				Config: fmt.Sprintf(testAccVxNetConfigTagTwoTemplate, vxnetTag1Name, vxnetTag2Name),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckVxNetExists(
						"qingcloud_vxnet.foo", &vxnet),
					testTagDetach(),
				),
			},
		},
	})

}

func testAccCheckVxNetExists(n string, eip *qc.DescribeVxNetsOutput) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[n]
		if !ok {
			return fmt.Errorf("Not found: %s", n)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("No VxNet ID is set")
		}

		client := testAccProvider.Meta().(*QingCloudClient)
		input := new(qc.DescribeVxNetsInput)
		input.VxNets = []*string{qc.String(rs.Primary.ID)}
		d, err := client.vxnet.DescribeVxNets(input)

		log.Printf("[WARN] eip id %#v", rs.Primary.ID)

		if err != nil {
			return err
		}

		if d == nil || len(d.VxNetSet) == 0 {
			return fmt.Errorf("VxNet not found")
		}

		*eip = *d
		return nil
	}
}

func testAccCheckVxNetDestroy(s *terraform.State) error {
	return testAccCheckVxNetDestroyWithProvider(s, testAccProvider)
}

func testAccCheckVxNetDestroyWithProvider(s *terraform.State, provider *schema.Provider) error {
	client := provider.Meta().(*QingCloudClient)
	for _, rs := range s.RootModule().Resources {
		if rs.Type != "qingcloud_vxnet" {
			continue
		}
		// Try to find the resource
		input := new(qc.DescribeVxNetsInput)
		input.VxNets = []*string{qc.String(rs.Primary.ID)}
		output, err := client.vxnet.DescribeVxNets(input)
		if err == nil && qc.IntValue(output.RetCode) == 0 {
			if len(output.VxNetSet) != 0 {
				return fmt.Errorf("Found  VxNet: %s", rs.Primary.ID)
			}
		}
	}
	return nil
}

const testAccVxNetConfig = `
resource "qingcloud_vxnet" "foo" {
    type = 1
} `

const testAccVxNetConfigTwo = `
resource "qingcloud_vxnet" "foo" {
    name = "vxnet"
    description = "vxnet"
	type = 1
} `
const testAccVxNetConfigThree = `
resource "qingcloud_vxnet" "foo" {
    name = "vxnet"
    description = "vxnet"
	type = 0
} `

const testAccVxNetConfigTagTemplate = `

resource "qingcloud_vxnet" "foo" {
    type = 1
	tag_ids = ["${qingcloud_tag.test.id}",
				"${qingcloud_tag.test2.id}"]
}
resource "qingcloud_tag" "test"{
	name="%v"
}
resource "qingcloud_tag" "test2"{
	name="%v"
}
`

const testAccVxNetConfigTagTwoTemplate = `

resource "qingcloud_vxnet" "foo" {
    type = 1
}
resource "qingcloud_tag" "test"{
	name="%v"
}
resource "qingcloud_tag" "test2"{
	name="%v"
}
`
<commit_msg>Add vxnet with vpc test<commit_after>package qingcloud

import (
	"fmt"
	"log"
	"os"
	"testing"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/terraform"
	qc "github.com/yunify/qingcloud-sdk-go/service"
)

func TestAccQingcloudVxNet_basic(t *testing.T) {
	var vxnet qc.DescribeVxNetsOutput

	resource.Test(t, resource.TestCase{
		PreCheck: func() {
			testAccPreCheck(t)
		},

		// module name
		IDRefreshName: "qingcloud_vxnet.foo",
		Providers:     testAccProviders,
		CheckDestroy:  testAccCheckVxNetDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccVxNetConfig,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckVxNetExists(
						"qingcloud_vxnet.foo", &vxnet),
					resource.TestCheckResourceAttr(
						"qingcloud_vxnet.foo", "type", "1"),
				),
			},
			resource.TestStep{
				Config: testAccVxNetConfigTwo,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckVxNetExists(
						"qingcloud_vxnet.foo", &vxnet),
					resource.TestCheckResourceAttr(
						"qingcloud_vxnet.foo", "type", "1"),
					resource.TestCheckResourceAttr(
						"qingcloud_vxnet.foo", "description", "vxnet"),
					resource.TestCheckResourceAttr(
						"qingcloud_vxnet.foo", "name", "vxnet"),
				),
			},
			resource.TestStep{
				Config: testAccVxNetConfigThree,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckVxNetExists(
						"qingcloud_vxnet.foo", &vxnet),
					resource.TestCheckResourceAttr(
						"qingcloud_vxnet.foo", "type", "0"),
					resource.TestCheckResourceAttr(
						"qingcloud_vxnet.foo", "description", "vxnet"),
					resource.TestCheckResourceAttr(
						"qingcloud_vxnet.foo", "name", "vxnet"),
				),
			},
		},
	})

}

func TestAccQingcloudVxNet_tag(t *testing.T) {
	var vxnet qc.DescribeVxNetsOutput
	vxnetTag1Name := os.Getenv("TRAVIS_BUILD_ID") + "-" + os.Getenv("TRAVIS_JOB_NUMBER") + "-vxnet-tag1"
	vxnetTag2Name := os.Getenv("TRAVIS_BUILD_ID") + "-" + os.Getenv("TRAVIS_JOB_NUMBER") + "-vxnet-tag2"

	testTagNameValue := func(names ...string) resource.TestCheckFunc {
		return func(state *terraform.State) error {
			tags := vxnet.VxNetSet[0].Tags
			same_count := 0
			for _, tag := range tags {
				for _, name := range names {
					if qc.StringValue(tag.TagName) == name {
						same_count++
					}
					if same_count == len(vxnet.VxNetSet[0].Tags) {
						return nil
					}
				}
			}
			return fmt.Errorf("tag name error %#v", names)
		}
	}
	testTagDetach := func() resource.TestCheckFunc {
		return func(state *terraform.State) error {
			if len(vxnet.VxNetSet[0].Tags) != 0 {
				return fmt.Errorf("tag not detach ")
			}
			return nil
		}
	}

	resource.Test(t, resource.TestCase{
		PreCheck: func() {
			testAccPreCheck(t)
		},

		// module name
		IDRefreshName: "qingcloud_vxnet.foo",
		Providers:     testAccProviders,
		CheckDestroy:  testAccCheckVxNetDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: fmt.Sprintf(testAccVxNetConfigTagTemplate, vxnetTag1Name, vxnetTag2Name),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckVxNetExists(
						"qingcloud_vxnet.foo", &vxnet),
					testTagNameValue(vxnetTag1Name, vxnetTag2Name),
				),
			},
			resource.TestStep{
				Config: fmt.Sprintf(testAccVxNetConfigTagTwoTemplate, vxnetTag1Name, vxnetTag2Name),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckVxNetExists(
						"qingcloud_vxnet.foo", &vxnet),
					testTagDetach(),
				),
			},
		},
	})

}

func TestAccQingcloudVxNet_vpc(t *testing.T) {
	var vxnet qc.DescribeVxNetsOutput

	testVpcAttach := func() resource.TestCheckFunc {
		return func(state *terraform.State) error {
			if vxnet.VxNetSet[0].Router != nil {
				input := new(qc.DescribeRouterVxNetsInput)
				input.Router = vxnet.VxNetSet[0].VpcRouterID
				input.Verbose = qc.Int(1)
				client := testAccProvider.Meta().(*QingCloudClient)
				d, err := client.router.DescribeRouterVxNets(input)
				if err != nil {
					return err
				}
				if d == nil || len(d.RouterVxNetSet) == 0 {
					return fmt.Errorf("Router not found ")
				}
				haveVxnet := false
				for _, oneVxnet := range d.RouterVxNetSet {
					if qc.StringValue(oneVxnet.VxNetID) == qc.StringValue(vxnet.VxNetSet[0].VxNetID) {
						haveVxnet = true
					}
				}
				if !haveVxnet {
					return fmt.Errorf("Router not match ")
				}
				return nil
			} else {
				return fmt.Errorf("Can not find router ")
			}
		}
	}
	testVpcDetach := func() resource.TestCheckFunc {
		return func(state *terraform.State) error {
			if vxnet.VxNetSet[0].Router != nil && qc.StringValue(vxnet.VxNetSet[0].Router.RouterID) != "" {
				return fmt.Errorf("Router not detach ")
			}
			return nil
		}
	}
	resource.Test(t, resource.TestCase{
		PreCheck: func() {
			testAccPreCheck(t)
		},

		// module name
		IDRefreshName: "qingcloud_vxnet.foo",
		Providers:     testAccProviders,
		CheckDestroy:  testAccCheckVxNetDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccVxNetConfigVpc,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckVxNetExists(
						"qingcloud_vxnet.foo", &vxnet),
					testVpcAttach(),
				),
			},
			resource.TestStep{
				Config: testAccVxNetConfigVpcTwo,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckVxNetExists(
						"qingcloud_vxnet.foo", &vxnet),
					testVpcDetach(),
				),
			},
			resource.TestStep{
				Config: testAccVxNetConfigVpcThree,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckVxNetExists(
						"qingcloud_vxnet.foo", &vxnet),
				),
			},
		},
	})

}

func testAccCheckVxNetExists(n string, eip *qc.DescribeVxNetsOutput) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[n]
		if !ok {
			return fmt.Errorf("Not found: %s", n)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("No VxNet ID is set")
		}

		client := testAccProvider.Meta().(*QingCloudClient)
		input := new(qc.DescribeVxNetsInput)
		input.VxNets = []*string{qc.String(rs.Primary.ID)}
		d, err := client.vxnet.DescribeVxNets(input)

		log.Printf("[WARN] eip id %#v", rs.Primary.ID)

		if err != nil {
			return err
		}

		if d == nil || len(d.VxNetSet) == 0 {
			return fmt.Errorf("VxNet not found")
		}

		*eip = *d
		return nil
	}
}

func testAccCheckVxNetDestroy(s *terraform.State) error {
	return testAccCheckVxNetDestroyWithProvider(s, testAccProvider)
}

func testAccCheckVxNetDestroyWithProvider(s *terraform.State, provider *schema.Provider) error {
	client := provider.Meta().(*QingCloudClient)
	for _, rs := range s.RootModule().Resources {
		if rs.Type != "qingcloud_vxnet" {
			continue
		}
		// Try to find the resource
		input := new(qc.DescribeVxNetsInput)
		input.VxNets = []*string{qc.String(rs.Primary.ID)}
		output, err := client.vxnet.DescribeVxNets(input)
		if err == nil && qc.IntValue(output.RetCode) == 0 {
			if len(output.VxNetSet) != 0 {
				return fmt.Errorf("Found  VxNet: %s", rs.Primary.ID)
			}
		}
	}
	return nil
}

const testAccVxNetConfig = `
resource "qingcloud_vxnet" "foo" {
    type = 1
} `

const testAccVxNetConfigTwo = `
resource "qingcloud_vxnet" "foo" {
    name = "vxnet"
    description = "vxnet"
	type = 1
} `
const testAccVxNetConfigThree = `
resource "qingcloud_vxnet" "foo" {
    name = "vxnet"
    description = "vxnet"
	type = 0
} `

const testAccVxNetConfigTagTemplate = `

resource "qingcloud_vxnet" "foo" {
    type = 1
	tag_ids = ["${qingcloud_tag.test.id}",
				"${qingcloud_tag.test2.id}"]
}
resource "qingcloud_tag" "test"{
	name="%v"
}
resource "qingcloud_tag" "test2"{
	name="%v"
}
`

const testAccVxNetConfigTagTwoTemplate = `

resource "qingcloud_vxnet" "foo" {
    type = 1
}
resource "qingcloud_tag" "test"{
	name="%v"
}
resource "qingcloud_tag" "test2"{
	name="%v"
}
`

const testAccVxNetConfigVpc = `

resource "qingcloud_security_group" "foo" {
    name = "first_sg"
}
resource "qingcloud_vpc" "foo" {
	security_group_id = "${qingcloud_security_group.foo.id}"
	vpc_network = "192.168.0.0/16"
}

resource "qingcloud_vxnet" "foo" {
    type = 1
	vpc_id = "${qingcloud_vpc.foo.id}"
	ip_network = "192.168.0.0/24"
}
`

const testAccVxNetConfigVpcTwo = `

resource "qingcloud_security_group" "foo" {
    name = "first_sg"
}
resource "qingcloud_vpc" "foo" {
	security_group_id = "${qingcloud_security_group.foo.id}"
	vpc_network = "192.168.0.0/16"
}

resource "qingcloud_vxnet" "foo" {
    type = 1
}
`
const testAccVxNetConfigVpcThree = `

resource "qingcloud_security_group" "foo" {
    name = "first_sg"
}
resource "qingcloud_vpc" "foo" {
	security_group_id = "${qingcloud_security_group.foo.id}"
	vpc_network = "192.168.0.0/16"
}

resource "qingcloud_vxnet" "foo" {
    type = 1
	vpc_id = "${qingcloud_vpc.foo.id}"
	ip_network = "192.168.0.0/24"
}
`
<|endoftext|>