<commit_before>package commands

import (
	"bytes"
	"errors"
	"io"
	"strings"
	"text/template"
	"time"

	cmds "github.com/ipfs/go-ipfs/commands"
	diag "github.com/ipfs/go-ipfs/diagnostics"
)

type DiagnosticConnection struct {
	ID string
	// TODO use milliseconds or microseconds for human readability
	NanosecondsLatency uint64
	Count              int
}

var (
	visD3   = "d3"
	visDot  = "dot"
	visFmts = []string{visD3, visDot}
)

type DiagnosticPeer struct {
	ID                string
	UptimeSeconds     uint64
	BandwidthBytesIn  uint64
	BandwidthBytesOut uint64
	Connections       []DiagnosticConnection
}

type DiagnosticOutput struct {
	Peers []DiagnosticPeer
}

var DefaultDiagnosticTimeout = time.Second * 20

var DiagCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "Generates diagnostic reports.",
	},

	Subcommands: map[string]*cmds.Command{
		"net":  diagNetCmd,
		"sys":  sysDiagCmd,
		"cmds": ActiveReqsCmd,
	},
}

var diagNetCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "Generates a network diagnostics report.",
		ShortDescription: `
Sends out a message to each node in the network recursively
requesting a listing of data about them including number of
connected peers and latencies between them.

The given timeout will be decremented 2s at every network hop,
ensuring peers try to return their diagnostics before the initiator's
timeout. If the timeout is too small, some peers may not be reached.
30s and 60s are reasonable timeout values, though network vary.
The default timeout is 20 seconds.

The 'vis' option may be used to change the output format.
four formats are supported:
 * plain text - easy to read
 * d3 - json ready to be fed into d3view
 * dot - graphviz format

The d3 format will output a json object ready to be consumed by
the chord network viewer, available at the following hash:

    /ipfs/QmbesKpGyQGd5jtJFUGEB1ByPjNFpukhnKZDnkfxUiKn38

To view your diag output, 'ipfs add' the d3 vis output, and
open the following link:

	http://gateway.ipfs.io/ipfs/QmbesKpGyQGd5jtJFUGEB1ByPjNFpukhnKZDnkfxUiKn38/chord#<your hash>

The dot format can be fed into graphviz and other programs
that consume the dot format to generate graphs of the network.
`,
	},

	Options: []cmds.Option{
		cmds.StringOption("vis", "Output vis. one of: "+strings.Join(visFmts, ", ")),
	},

	Run: func(req cmds.Request, res cmds.Response) {
		n, err := req.InvocContext().GetNode()
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		if !n.OnlineMode() {
			res.SetError(errNotOnline, cmds.ErrClient)
			return
		}

		vis, _, err := req.Option("vis").String()
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		timeoutS, _, err := req.Option("timeout").String()
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}
		timeout := DefaultDiagnosticTimeout
		if timeoutS != "" {
			t, err := time.ParseDuration(timeoutS)
			if err != nil {
				res.SetError(errors.New("error parsing timeout"), cmds.ErrNormal)
				return
			}
			timeout = t
		}

		info, err := n.Diagnostics.GetDiagnostic(req.Context(), timeout)
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		switch vis {
		case visD3:
			res.SetOutput(bytes.NewReader(diag.GetGraphJson(info)))
		case visDot:
			buf := new(bytes.Buffer)
			w := diag.DotWriter{W: buf}
			err := w.WriteGraph(info)
			if err != nil {
				res.SetError(err, cmds.ErrNormal)
				return
			}
			res.SetOutput(io.Reader(buf))
		default:
			output, err := stdDiagOutputMarshal(standardDiagOutput(info))
			if err != nil {
				res.SetError(err, cmds.ErrNormal)
				return
			}
			res.SetOutput(output)
		}
	},
}

func stdDiagOutputMarshal(output *DiagnosticOutput) (io.Reader, error) {
	buf := new(bytes.Buffer)
	err := printDiagnostics(buf, output)
	if err != nil {
		return nil, err
	}
	return buf, nil
}

func standardDiagOutput(info []*diag.DiagInfo) *DiagnosticOutput {
	output := make([]DiagnosticPeer, len(info))
	for i, peer := range info {
		connections := make([]DiagnosticConnection, len(peer.Connections))
		for j, conn := range peer.Connections {
			connections[j] = DiagnosticConnection{
				ID:                 conn.ID,
				NanosecondsLatency: uint64(conn.Latency.Nanoseconds()),
				Count:              conn.Count,
			}
		}

		output[i] = DiagnosticPeer{
			ID:                peer.ID,
			UptimeSeconds:     uint64(peer.LifeSpan.Seconds()),
			BandwidthBytesIn:  peer.BwIn,
			BandwidthBytesOut: peer.BwOut,
			Connections:       connections,
		}
	}
	return &DiagnosticOutput{output}
}

func printDiagnostics(out io.Writer, info *DiagnosticOutput) error {
	diagTmpl := `
{{ range $peer := .Peers }}
ID {{ $peer.ID }} up {{ $peer.UptimeSeconds }} seconds connected to {{ len .Connections }}:{{ range $connection := .Connections }}
	ID {{ $connection.ID }} connections: {{ $connection.Count }} latency: {{ $connection.NanosecondsLatency }} ns{{ end }}
{{end}}
`

	templ, err := template.New("DiagnosticOutput").Parse(diagTmpl)
	if err != nil {
		return err
	}

	err = templ.Execute(out, info)
	if err != nil {
		return err
	}

	return nil
}
<commit_msg>Formatted diag net comments<commit_after>package commands

import (
	"bytes"
	"errors"
	"io"
	"strings"
	"text/template"
	"time"

	cmds "github.com/ipfs/go-ipfs/commands"
	diag "github.com/ipfs/go-ipfs/diagnostics"
)

type DiagnosticConnection struct {
	ID string
	// TODO use milliseconds or microseconds for human readability
	NanosecondsLatency uint64
	Count              int
}

var (
	visD3   = "d3"
	visDot  = "dot"
	visFmts = []string{visD3, visDot}
)

type DiagnosticPeer struct {
	ID                string
	UptimeSeconds     uint64
	BandwidthBytesIn  uint64
	BandwidthBytesOut uint64
	Connections       []DiagnosticConnection
}

type DiagnosticOutput struct {
	Peers []DiagnosticPeer
}

var DefaultDiagnosticTimeout = time.Second * 20

var DiagCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "Generates diagnostic reports.",
	},

	Subcommands: map[string]*cmds.Command{
		"net":  diagNetCmd,
		"sys":  sysDiagCmd,
		"cmds": ActiveReqsCmd,
	},
}

var diagNetCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "Generates a network diagnostics report.",
		ShortDescription: `
Sends out a message to each node in the network recursively
requesting a listing of data about them including number of
connected peers and latencies between them.

The given timeout will be decremented 2s at every network hop,
ensuring peers try to return their diagnostics before the initiator's
timeout. If the timeout is too small, some peers may not be reached.
30s and 60s are reasonable timeout values, though network vary.
The default timeout is 20 seconds.

The 'vis' option may be used to change the output format.
Four formats are supported:
 * plain text - Easy to read. Default.
 * d3 - json ready to be fed into d3view
 * dot - graphviz format

The 'd3' format will output a json object ready to be consumed by
the chord network viewer, available at the following hash:

    /ipfs/QmbesKpGyQGd5jtJFUGEB1ByPjNFpukhnKZDnkfxUiKn38

To view your diag output, 'ipfs add' the d3 vis output, and
open the following link:

	http://gateway.ipfs.io/ipfs/QmbesKpGyQGd5jtJFUGEB1ByPjNFpukhnKZDnkfxUiKn38/chord#<your hash>

The dot format can be fed into graphviz and other programs
that consume the dot format to generate graphs of the network.
`,
	},

	Options: []cmds.Option{
		cmds.StringOption("vis", "Output vis. One of: "+strings.Join(visFmts, ", ")),
	},

	Run: func(req cmds.Request, res cmds.Response) {
		n, err := req.InvocContext().GetNode()
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		if !n.OnlineMode() {
			res.SetError(errNotOnline, cmds.ErrClient)
			return
		}

		vis, _, err := req.Option("vis").String()
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		timeoutS, _, err := req.Option("timeout").String()
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}
		timeout := DefaultDiagnosticTimeout
		if timeoutS != "" {
			t, err := time.ParseDuration(timeoutS)
			if err != nil {
				res.SetError(errors.New("error parsing timeout"), cmds.ErrNormal)
				return
			}
			timeout = t
		}

		info, err := n.Diagnostics.GetDiagnostic(req.Context(), timeout)
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		switch vis {
		case visD3:
			res.SetOutput(bytes.NewReader(diag.GetGraphJson(info)))
		case visDot:
			buf := new(bytes.Buffer)
			w := diag.DotWriter{W: buf}
			err := w.WriteGraph(info)
			if err != nil {
				res.SetError(err, cmds.ErrNormal)
				return
			}
			res.SetOutput(io.Reader(buf))
		default:
			output, err := stdDiagOutputMarshal(standardDiagOutput(info))
			if err != nil {
				res.SetError(err, cmds.ErrNormal)
				return
			}
			res.SetOutput(output)
		}
	},
}

func stdDiagOutputMarshal(output *DiagnosticOutput) (io.Reader, error) {
	buf := new(bytes.Buffer)
	err := printDiagnostics(buf, output)
	if err != nil {
		return nil, err
	}
	return buf, nil
}

func standardDiagOutput(info []*diag.DiagInfo) *DiagnosticOutput {
	output := make([]DiagnosticPeer, len(info))
	for i, peer := range info {
		connections := make([]DiagnosticConnection, len(peer.Connections))
		for j, conn := range peer.Connections {
			connections[j] = DiagnosticConnection{
				ID:                 conn.ID,
				NanosecondsLatency: uint64(conn.Latency.Nanoseconds()),
				Count:              conn.Count,
			}
		}

		output[i] = DiagnosticPeer{
			ID:                peer.ID,
			UptimeSeconds:     uint64(peer.LifeSpan.Seconds()),
			BandwidthBytesIn:  peer.BwIn,
			BandwidthBytesOut: peer.BwOut,
			Connections:       connections,
		}
	}
	return &DiagnosticOutput{output}
}

func printDiagnostics(out io.Writer, info *DiagnosticOutput) error {
	diagTmpl := `
{{ range $peer := .Peers }}
ID {{ $peer.ID }} up {{ $peer.UptimeSeconds }} seconds connected to {{ len .Connections }}:{{ range $connection := .Connections }}
	ID {{ $connection.ID }} connections: {{ $connection.Count }} latency: {{ $connection.NanosecondsLatency }} ns{{ end }}
{{end}}
`

	templ, err := template.New("DiagnosticOutput").Parse(diagTmpl)
	if err != nil {
		return err
	}

	err = templ.Execute(out, info)
	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package visitor

import "testing"

func TestVisitBasicType(t *testing.T) {
	var visitor Visitor
	var visited []interface{}
	visitor = func(v interface{}) Visitor {
		visited = append(visited, v)
		return visitor
	}
	v := 1
	Visit(v, visitor)
	if len(visited) != 1 {
		t.Fatal("visited")
	}
	if v, ok := visited[0].(int); !ok || v != 1 {
		t.Fatal("visited")
	}
}

func TestVisitPointer(t *testing.T) {
	var visitor Visitor
	var visited []interface{}
	visitor = func(v interface{}) Visitor {
		visited = append(visited, v)
		return visitor
	}
	v := 1
	Visit(&v, visitor)
	if len(visited) != 1 {
		t.Fatal("visited")
	}
	if v, ok := visited[0].(int); !ok || v != 1 {
		t.Fatal("visited")
	}
}

func TestVisitSlice(t *testing.T) {
	var visitor Visitor
	var visited []interface{}
	visitor = func(v interface{}) Visitor {
		visited = append(visited, v)
		return visitor
	}
	v := []int{1, 2, 3, 4, 5}
	Visit(v, visitor)
	if len(visited) != 6 {
		t.Fatal("visited")
	}
	if _, ok := visited[0].([]int); !ok {
		t.Fatal("visited")
	}
	for i := 1; i <= 5; i++ {
		if v, ok := visited[i].(int); !ok || v != i {
			t.Fatal("visited")
		}
	}
}

func TestVisitStruct(t *testing.T) {
	var visitor Visitor
	var visited []interface{}
	visitor = func(v interface{}) Visitor {
		visited = append(visited, v)
		return visitor
	}
	type Foo struct {
		Foo int
		Bar string
		Baz bool
	}
	v := Foo{
		42, "foo", true,
	}
	Visit(v, visitor)
	if len(visited) != 4 {
		t.Fatal("visited")
	}
	if _, ok := visited[0].(Foo); !ok {
		t.Fatal("visited")
	}
	if v, ok := visited[1].(int); !ok || v != 42 {
		t.Fatal("visited")
	}
	if v, ok := visited[2].(string); !ok || v != "foo" {
		t.Fatal("visited")
	}
	if v, ok := visited[3].(bool); !ok || v != true {
		t.Fatal("visited")
	}
}

func TestVisitMap(t *testing.T) {
	var visitor Visitor
	var visited []interface{}
	visitor = func(v interface{}) Visitor {
		visited = append(visited, v)
		return visitor
	}
	type Foo map[int]int
	v := Foo{
		1: 1,
		2: 2,
		3: 3,
	}
	Visit(v, visitor)
	if len(visited) != 4 {
		t.Fatal("visited")
	}
	if _, ok := visited[0].(Foo); !ok || len(v) != 3 {
		t.Fatal("visited")
	}
}

func TestPartialVisitSlice(t *testing.T) {
	var visitor Visitor
	var visited []interface{}
	visitor = func(v interface{}) Visitor {
		visited = append(visited, v)
		if v, ok := v.(int); ok && v == 2 {
			return nil
		}
		return visitor
	}
	v := []int{1, 2, 3, 4, 5}
	Visit(v, visitor)
	if len(visited) != 3 {
		t.Fatal("visited")
	}
	if _, ok := visited[0].([]int); !ok {
		t.Fatal("visited")
	}
	if v, ok := visited[1].(int); !ok || v != 1 {
		t.Fatal("visited")
	}
	if v, ok := visited[2].(int); !ok || v != 2 {
		t.Fatal("visited")
	}
}

func TestPartialVisitSlice2(t *testing.T) {
	var visitor Visitor
	var visited []interface{}
	visitor = func(v interface{}) Visitor {
		visited = append(visited, v)
		if _, ok := v.([]int); ok {
			return nil
		}
		return visitor
	}
	v := []int{1, 2, 3, 4, 5}
	Visit(v, visitor)
	if len(visited) != 1 {
		t.Fatal("visited")
	}
	if _, ok := visited[0].([]int); !ok {
		t.Fatal("visited")
	}
}

func TestPartialVisitStruct(t *testing.T) {
	var visitor Visitor
	var visited []interface{}
	type Foo struct {
		I int
	}
	visitor = func(v interface{}) Visitor {
		visited = append(visited, v)
		if v, ok := v.(Foo); ok && v.I == 2 {
			return nil
		}
		return visitor
	}
	v := []Foo{
		{1}, {2}, {3},
	}
	Visit(v, visitor)
	if len(visited) != 4 {
		t.Fatal("visited")
	}
	if _, ok := visited[0].([]Foo); !ok {
		t.Fatal("visited")
	}
	if v, ok := visited[1].(Foo); !ok || v.I != 1 {
		t.Fatal("visited")
	}
	if v, ok := visited[2].(int); !ok || v != 1 {
		t.Fatal("visited")
	}
	if v, ok := visited[3].(Foo); !ok || v.I != 2 {
		t.Fatal("visited")
	}
}

func TestPartialVisitStruct2(t *testing.T) {
	var visitor Visitor
	var visited []interface{}
	type Foo struct {
		I int
	}
	visitor = func(v interface{}) Visitor {
		visited = append(visited, v)
		if v, ok := v.(int); ok && v == 1 {
			return nil
		}
		return visitor
	}
	v := []Foo{
		{1}, {2}, {3},
	}
	Visit(v, visitor)
	if len(visited) != 3 {
		t.Fatal("visited")
	}
	if _, ok := visited[0].([]Foo); !ok {
		t.Fatal("visited")
	}
	if v, ok := visited[1].(Foo); !ok || v.I != 1 {
		t.Fatal("visited")
	}
	if v, ok := visited[2].(int); !ok || v != 1 {
		t.Fatal("visited")
	}
}

func TestPartialVisitMap(t *testing.T) {
	var visitor Visitor
	var visited []interface{}
	visitor = func(v interface{}) Visitor {
		visited = append(visited, v)
		if _, ok := v.(map[int]int); ok {
			return nil
		}
		return visitor
	}
	v := []map[int]int{
		{1: 1},
		{1: 2},
	}
	Visit(v, visitor)
	if len(visited) != 2 {
		t.Fatal("visited")
	}
	if _, ok := visited[0].([]map[int]int); !ok {
		t.Fatal("visited")
	}
	if v, ok := visited[1].(map[int]int); !ok || v[1] != 1 {
		t.Fatal("visited")
	}
}

func TestPartialVisitMap2(t *testing.T) {
	var visitor Visitor
	var visited []interface{}
	visitor = func(v interface{}) Visitor {
		visited = append(visited, v)
		if v, ok := v.(int); ok && v == 2 {
			return nil
		}
		return visitor
	}
	v := []map[int]int{
		{1: 1},
		{1: 2},
		{1: 3},
	}
	Visit(v, visitor)
	if len(visited) != 5 {
		t.Fatal("visited")
	}
	if _, ok := visited[0].([]map[int]int); !ok {
		t.Fatal("visited")
	}
	if v, ok := visited[1].(map[int]int); !ok || v[1] != 1 {
		t.Fatal("visited")
	}
	if v, ok := visited[2].(int); !ok || v != 1 {
		t.Fatal("visited")
	}
	if v, ok := visited[3].(map[int]int); !ok || v[1] != 2 {
		t.Fatal("visited")
	}
	if v, ok := visited[4].(int); !ok || v != 2 {
		t.Fatal("visited")
	}
}
<commit_msg>add test<commit_after>package visitor

import "testing"

func TestVisitBasicType(t *testing.T) {
	var visitor Visitor
	var visited []interface{}
	visitor = func(v interface{}) Visitor {
		visited = append(visited, v)
		return visitor
	}
	v := 1
	Visit(v, visitor)
	if len(visited) != 1 {
		t.Fatal("visited")
	}
	if v, ok := visited[0].(int); !ok || v != 1 {
		t.Fatal("visited")
	}
}

func TestVisitPointer(t *testing.T) {
	var visitor Visitor
	var visited []interface{}
	visitor = func(v interface{}) Visitor {
		visited = append(visited, v)
		return visitor
	}
	v := 1
	Visit(&v, visitor)
	if len(visited) != 1 {
		t.Fatal("visited")
	}
	if v, ok := visited[0].(int); !ok || v != 1 {
		t.Fatal("visited")
	}
}

func TestVisitSlice(t *testing.T) {
	var visitor Visitor
	var visited []interface{}
	visitor = func(v interface{}) Visitor {
		visited = append(visited, v)
		return visitor
	}
	v := []int{1, 2, 3, 4, 5}
	Visit(v, visitor)
	if len(visited) != 6 {
		t.Fatal("visited")
	}
	if _, ok := visited[0].([]int); !ok {
		t.Fatal("visited")
	}
	for i := 1; i <= 5; i++ {
		if v, ok := visited[i].(int); !ok || v != i {
			t.Fatal("visited")
		}
	}
}

func TestVisitSliceOfStruct(t *testing.T) {
	var visitor Visitor
	var visited []interface{}
	type Foo struct {
		I int
	}
	visitor = func(v interface{}) Visitor {
		visited = append(visited, v)
		return visitor
	}
	v := []Foo{
		{1}, {2}, {3},
	}
	Visit(v, visitor)
	if len(visited) != 7 {
		t.Fatal("visited")
	}
	if _, ok := visited[0].([]Foo); !ok {
		t.Fatal("visited")
	}
	if v, ok := visited[1].(Foo); !ok || v.I != 1 {
		t.Fatal("visited")
	}
	if v, ok := visited[2].(int); !ok || v != 1 {
		t.Fatal("visited")
	}
	if v, ok := visited[3].(Foo); !ok || v.I != 2 {
		t.Fatal("visited")
	}
	if v, ok := visited[4].(int); !ok || v != 2 {
		t.Fatal("visited")
	}
	if v, ok := visited[5].(Foo); !ok || v.I != 3 {
		t.Fatal("visited")
	}
	if v, ok := visited[6].(int); !ok || v != 3 {
		t.Fatal("visited")
	}
}

func TestVisitStruct(t *testing.T) {
	var visitor Visitor
	var visited []interface{}
	visitor = func(v interface{}) Visitor {
		visited = append(visited, v)
		return visitor
	}
	type Foo struct {
		Foo int
		Bar string
		Baz bool
	}
	v := Foo{
		42, "foo", true,
	}
	Visit(v, visitor)
	if len(visited) != 4 {
		t.Fatal("visited")
	}
	if _, ok := visited[0].(Foo); !ok {
		t.Fatal("visited")
	}
	if v, ok := visited[1].(int); !ok || v != 42 {
		t.Fatal("visited")
	}
	if v, ok := visited[2].(string); !ok || v != "foo" {
		t.Fatal("visited")
	}
	if v, ok := visited[3].(bool); !ok || v != true {
		t.Fatal("visited")
	}
}

func TestVisitMap(t *testing.T) {
	var visitor Visitor
	var visited []interface{}
	visitor = func(v interface{}) Visitor {
		visited = append(visited, v)
		return visitor
	}
	type Foo map[int]int
	v := Foo{
		1: 1,
		2: 2,
		3: 3,
	}
	Visit(v, visitor)
	if len(visited) != 4 {
		t.Fatal("visited")
	}
	if _, ok := visited[0].(Foo); !ok || len(v) != 3 {
		t.Fatal("visited")
	}
}

func TestPartialVisitSlice(t *testing.T) {
	var visitor Visitor
	var visited []interface{}
	visitor = func(v interface{}) Visitor {
		visited = append(visited, v)
		if v, ok := v.(int); ok && v == 2 {
			return nil
		}
		return visitor
	}
	v := []int{1, 2, 3, 4, 5}
	Visit(v, visitor)
	if len(visited) != 3 {
		t.Fatal("visited")
	}
	if _, ok := visited[0].([]int); !ok {
		t.Fatal("visited")
	}
	if v, ok := visited[1].(int); !ok || v != 1 {
		t.Fatal("visited")
	}
	if v, ok := visited[2].(int); !ok || v != 2 {
		t.Fatal("visited")
	}
}

func TestPartialVisitSlice2(t *testing.T) {
	var visitor Visitor
	var visited []interface{}
	visitor = func(v interface{}) Visitor {
		visited = append(visited, v)
		if _, ok := v.([]int); ok {
			return nil
		}
		return visitor
	}
	v := []int{1, 2, 3, 4, 5}
	Visit(v, visitor)
	if len(visited) != 1 {
		t.Fatal("visited")
	}
	if _, ok := visited[0].([]int); !ok {
		t.Fatal("visited")
	}
}

func TestPartialVisitStruct(t *testing.T) {
	var visitor Visitor
	var visited []interface{}
	type Foo struct {
		I int
	}
	visitor = func(v interface{}) Visitor {
		visited = append(visited, v)
		if v, ok := v.(Foo); ok && v.I == 2 {
			return nil
		}
		return visitor
	}
	v := []Foo{
		{1}, {2}, {3},
	}
	Visit(v, visitor)
	if len(visited) != 4 {
		t.Fatal("visited")
	}
	if _, ok := visited[0].([]Foo); !ok {
		t.Fatal("visited")
	}
	if v, ok := visited[1].(Foo); !ok || v.I != 1 {
		t.Fatal("visited")
	}
	if v, ok := visited[2].(int); !ok || v != 1 {
		t.Fatal("visited")
	}
	if v, ok := visited[3].(Foo); !ok || v.I != 2 {
		t.Fatal("visited")
	}
}

func TestPartialVisitStruct2(t *testing.T) {
	var visitor Visitor
	var visited []interface{}
	type Foo struct {
		I int
	}
	visitor = func(v interface{}) Visitor {
		visited = append(visited, v)
		if v, ok := v.(int); ok && v == 1 {
			return nil
		}
		return visitor
	}
	v := []Foo{
		{1}, {2}, {3},
	}
	Visit(v, visitor)
	if len(visited) != 3 {
		t.Fatal("visited")
	}
	if _, ok := visited[0].([]Foo); !ok {
		t.Fatal("visited")
	}
	if v, ok := visited[1].(Foo); !ok || v.I != 1 {
		t.Fatal("visited")
	}
	if v, ok := visited[2].(int); !ok || v != 1 {
		t.Fatal("visited")
	}
}

func TestPartialVisitMap(t *testing.T) {
	var visitor Visitor
	var visited []interface{}
	visitor = func(v interface{}) Visitor {
		visited = append(visited, v)
		if _, ok := v.(map[int]int); ok {
			return nil
		}
		return visitor
	}
	v := []map[int]int{
		{1: 1},
		{1: 2},
	}
	Visit(v, visitor)
	if len(visited) != 2 {
		t.Fatal("visited")
	}
	if _, ok := visited[0].([]map[int]int); !ok {
		t.Fatal("visited")
	}
	if v, ok := visited[1].(map[int]int); !ok || v[1] != 1 {
		t.Fatal("visited")
	}
}

func TestPartialVisitMap2(t *testing.T) {
	var visitor Visitor
	var visited []interface{}
	visitor = func(v interface{}) Visitor {
		visited = append(visited, v)
		if v, ok := v.(int); ok && v == 2 {
			return nil
		}
		return visitor
	}
	v := []map[int]int{
		{1: 1},
		{1: 2},
		{1: 3},
	}
	Visit(v, visitor)
	if len(visited) != 5 {
		t.Fatal("visited")
	}
	if _, ok := visited[0].([]map[int]int); !ok {
		t.Fatal("visited")
	}
	if v, ok := visited[1].(map[int]int); !ok || v[1] != 1 {
		t.Fatal("visited")
	}
	if v, ok := visited[2].(int); !ok || v != 1 {
		t.Fatal("visited")
	}
	if v, ok := visited[3].(map[int]int); !ok || v[1] != 2 {
		t.Fatal("visited")
	}
	if v, ok := visited[4].(int); !ok || v != 2 {
		t.Fatal("visited")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"appstax-cli/appstax/commands"
	"appstax-cli/appstax/log"
	"appstax-cli/appstax/term"
	"fmt"
	"github.com/codegangsta/cli"
	"os"
	"os/signal"
	"strings"
)

func main() {
	setupSignals()
	cliApp := setupCli()
	log.Infof("Command to execute: %s", strings.Join(os.Args, " "))
	term.Section()
	cliApp.Run(os.Args)
	term.PrintSection()
}

func setupCli() *cli.App {
	app := cli.NewApp()
	app.Name = "appstax"
	app.Usage = "command line interface for appstax.com"
	app.Version = "1.1.2"

	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "verbose",
			Usage: "enable verbose output",
		},
		cli.StringFlag{
			Name:  "baseurl",
			Usage: "set api base url",
		},
	}

	app.Commands = []cli.Command{
		{
			Name:   "signup",
			Usage:  "Create new account",
			Action: commands.DoSignup,
			Flags:  app.Flags,
		},
		{
			Name:   "login",
			Usage:  "Login",
			Action: commands.DoLogin,
			Flags:  app.Flags,
		},
		{
			Name:   "init",
			Usage:  "Initialize current directory as an appstax app",
			Action: commands.DoInit,
			Flags:  app.Flags,
		},
		{
			Name:   "info",
			Usage:  "Info about app configured in current directory",
			Action: commands.DoInfo,
			Flags:  app.Flags,
		},
		{
			Name:   "server",
			Usage:  "Manage your server code",
			Action: commands.DoServer,
			Flags:  app.Flags,
		},
		{
			Name:   "deploy",
			Usage:  "Deploy files to <yourapp>.appstax.io",
			Action: commands.DoDeploy,
			Flags:  app.Flags,
		},
		{
			Name:   "open",
			Usage:  "Open your browser to the specified destination",
			Action: commands.DoOpen,
			Flags:  app.Flags,
		},
		{
			Name:   "logout",
			Usage:  "Logout of current app session",
			Action: commands.DoLogout,
			Flags:  app.Flags,
		},
		{
			Name:   "serve",
			Usage:  "Run development http server",
			Action: commands.DoServe,
			Flags:  app.Flags,
		},
		{
			Name:   "collection",
			Usage:  "Create and view collections",
			Action: commands.DoCollection,
			Flags:  app.Flags,
		},
		{
			Name:   "find",
			Usage:  "Get objects from a collection",
			Action: commands.DoFind,
			Flags:  app.Flags,
		},
		{
			Name:   "relation",
			Usage:  "Create and view relations",
			Action: commands.DoRelation,
			Flags:  app.Flags,
		},
	}

	return app
}

func setupSignals() {
	c := make(chan os.Signal, 10)
	signal.Notify(c, os.Interrupt)
	go func() {
		for _ = range c {
			fmt.Print("\n")
			os.Exit(-1)
		}
	}()
}
<commit_msg>Version 1.2.0<commit_after>package main

import (
	"appstax-cli/appstax/commands"
	"appstax-cli/appstax/log"
	"appstax-cli/appstax/term"
	"fmt"
	"github.com/codegangsta/cli"
	"os"
	"os/signal"
	"strings"
)

func main() {
	setupSignals()
	cliApp := setupCli()
	log.Infof("Command to execute: %s", strings.Join(os.Args, " "))
	term.Section()
	cliApp.Run(os.Args)
	term.PrintSection()
}

func setupCli() *cli.App {
	app := cli.NewApp()
	app.Name = "appstax"
	app.Usage = "command line interface for appstax.com"
	app.Version = "1.2.0"

	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "verbose",
			Usage: "enable verbose output",
		},
		cli.StringFlag{
			Name:  "baseurl",
			Usage: "set api base url",
		},
	}

	app.Commands = []cli.Command{
		{
			Name:   "signup",
			Usage:  "Create new account",
			Action: commands.DoSignup,
			Flags:  app.Flags,
		},
		{
			Name:   "login",
			Usage:  "Login",
			Action: commands.DoLogin,
			Flags:  app.Flags,
		},
		{
			Name:   "init",
			Usage:  "Initialize current directory as an appstax app",
			Action: commands.DoInit,
			Flags:  app.Flags,
		},
		{
			Name:   "info",
			Usage:  "Info about app configured in current directory",
			Action: commands.DoInfo,
			Flags:  app.Flags,
		},
		{
			Name:   "server",
			Usage:  "Manage your server code",
			Action: commands.DoServer,
			Flags:  app.Flags,
		},
		{
			Name:   "deploy",
			Usage:  "Deploy files to <yourapp>.appstax.io",
			Action: commands.DoDeploy,
			Flags:  app.Flags,
		},
		{
			Name:   "open",
			Usage:  "Open your browser to the specified destination",
			Action: commands.DoOpen,
			Flags:  app.Flags,
		},
		{
			Name:   "logout",
			Usage:  "Logout of current app session",
			Action: commands.DoLogout,
			Flags:  app.Flags,
		},
		{
			Name:   "serve",
			Usage:  "Run development http server",
			Action: commands.DoServe,
			Flags:  app.Flags,
		},
		{
			Name:   "collection",
			Usage:  "Create and view collections",
			Action: commands.DoCollection,
			Flags:  app.Flags,
		},
		{
			Name:   "find",
			Usage:  "Get objects from a collection",
			Action: commands.DoFind,
			Flags:  app.Flags,
		},
		{
			Name:   "relation",
			Usage:  "Create and view relations",
			Action: commands.DoRelation,
			Flags:  app.Flags,
		},
	}

	return app
}

func setupSignals() {
	c := make(chan os.Signal, 10)
	signal.Notify(c, os.Interrupt)
	go func() {
		for _ = range c {
			fmt.Print("\n")
			os.Exit(-1)
		}
	}()
}
<|endoftext|>


<commit_before>package voip

import (
	"errors"
	"net"
	"strconv"
)

var (
	ErrKeyNotFound = errors.New("All required keys not found")
	ErrIdNotExists = errors.New("container id doesn't exists")
)

const (
	ReqStartServer = iota
	ReqStartSnort
	ReqStartClient
	ReqStopCont
	ReqRouteCont
	ReqSetRate
)

type Request struct {
	Code   int
	KeyVal map[string]string
}

type Response struct {
	Result string
	Err    string
}

func (vh *VoipHandler) addServer(req *Request) *Response {
	kv := req.KeyVal
	host, ok1 := kv["host"]
	sshares, ok2 := kv["shares"]
	if !ok1 || !ok2 {
		return &Response{Err: ErrKeyNotFound.Error()}
	}

	shares, err := strconv.ParseInt(sshares, 10, 64)
	if err != nil {
		return &Response{Err: err.Error()}
	}

	node, err := vh.cmgr.StartServer(host, shares)
	if err != nil {
		return &Response{Err: err.Error()}
	}

	vh.anodes[node.id] = node
	return &Response{Result: node.id}
}

func (vh *VoipHandler) addSnort(req *Request) *Response {
	kv := req.KeyVal
	host, ok1 := kv["host"]
	sshares, ok2 := kv["shares"]
	if !ok1 || !ok2 {
		return &Response{Err: ErrKeyNotFound.Error()}
	}

	shares, err := strconv.ParseInt(sshares, 10, 64)
	if err != nil {
		return &Response{Err: err.Error()}
	}

	node, err := vh.cmgr.StartSnort(host, shares)
	if err != nil {
		return &Response{Err: err.Error()}
	}

	vh.addMCont(node, shares)
	return &Response{Result: node.id}
}

func (vh *VoipHandler) addClient(req *Request) *Response {
	kv := req.KeyVal
	host, ok1 := kv["host"]
	sshares, ok2 := kv["shares"]
	serverid, ok3 := kv["server"]
	if !ok1 || !ok2 || !ok3 {
		return &Response{Err: ErrKeyNotFound.Error()}
	}

	shares, err := strconv.ParseInt(sshares, 10, 64)
	if err != nil {
		return &Response{Err: err.Error()}
	}
	server, ok := vh.anodes[serverid]
	if !ok {
		return &Response{Err: ErrIdNotExists.Error()}
	}

	node, err := vh.cmgr.StartClient(host, shares, server.ip)
	if err != nil {
		return &Response{Err: err.Error()}
	}

	vh.anodes[node.id] = node
	return &Response{Result: node.id}
}

func (vh *VoipHandler) stopCont(req *Request) *Response {
	kv := req.KeyVal
	contid, ok := kv["cont"]
	if !ok {
		return &Response{Err: ErrKeyNotFound.Error()}
	}

	node, ok := vh.anodes[contid]
	if ok {
		vh.cmgr.StopCont(node)
		delete(vh.anodes, node.id)
	} else {
		mnode, ok := vh.mnodes[contid]
		if ok {
			vh.delMCont(mnode)
			return &Response{Err: ErrIdNotExists.Error()}
		}
	}

	return &Response{}
}

func (vh *VoipHandler) route(req *Request) *Response {
	kv := req.KeyVal
	client, ok1 := kv["client"]
	server, ok2 := kv["server"]
	router, ok3 := kv["router"]
	if !ok1 || !ok2 || !ok3 {
		return &Response{Err: ErrKeyNotFound.Error()}
	}

	cnode, ok1 := vh.anodes[client]
	rcont, ok2 := vh.mnodes[router]
	snode, ok3 := vh.anodes[server]
	if !ok1 || !ok2 || !ok3 {
		return &Response{Err: ErrIdNotExists.Error()}
	}

	err := vh.cmgr.Route(cnode, rcont.node, snode)
	if err != nil {
		return &Response{Err: err.Error()}
	} else {
		return &Response{}
	}
}

func (vh *VoipHandler) setRate(req *Request) *Response {
	kv := req.KeyVal
	client, ok1 := kv["client"]
	rate, ok2 := kv["rate"]
	if !(ok1 && ok2) {
		return &Response{Err: ErrKeyNotFound.Error()}
	}

	cnode, ok1 := vh.anodes[client]
	if !ok1 {
		return &Response{Err: ErrIdNotExists.Error()}
	}
	irate, err := strconv.ParseInt(rate, 10, 32)
	if err != nil {
		return &Response{Err: err.Error()}
	}

	err = vh.setClientRate(cnode, int(irate))
	if err != nil {
		return &Response{Err: err.Error()}
	} else {
		return &Response{}
	}
}

func (vh *VoipHandler) addMCont(node *Node, shares int64) {
	vh.mnodes[node.id] = NewMContainer(node, vh.step_length, vh.period_length, shares, vh.reference)
}

func (vh *VoipHandler) delMCont(mcont *MContainer) {
	delete(vh.mnodes, mcont.node.id)
}

func (vh *VoipHandler) setClientRate(cnode *Node, rate int) error {
	addr, err := net.ResolveUDPAddr("udp", cnode.ip+":8888")
	if err != nil {
		return err
	}
	conn, err := net.DialUDP("udp", nil, addr)
	if err != nil {
		return err
	}
	defer conn.Close()
	_, err = conn.Write([]byte("cset rate " + strconv.Itoa(rate)))
	if err != nil {
		return err
	}
	return nil
}
<commit_msg>control : stop snort (bug)<commit_after>package voip

import (
	"errors"
	"net"
	"strconv"
)

var (
	ErrKeyNotFound = errors.New("All required keys not found")
	ErrIdNotExists = errors.New("container id doesn't exists")
)

const (
	ReqStartServer = iota
	ReqStartSnort
	ReqStartClient
	ReqStopCont
	ReqRouteCont
	ReqSetRate
)

type Request struct {
	Code   int
	KeyVal map[string]string
}

type Response struct {
	Result string
	Err    string
}

func (vh *VoipHandler) addServer(req *Request) *Response {
	kv := req.KeyVal
	host, ok1 := kv["host"]
	sshares, ok2 := kv["shares"]
	if !ok1 || !ok2 {
		return &Response{Err: ErrKeyNotFound.Error()}
	}

	shares, err := strconv.ParseInt(sshares, 10, 64)
	if err != nil {
		return &Response{Err: err.Error()}
	}

	node, err := vh.cmgr.StartServer(host, shares)
	if err != nil {
		return &Response{Err: err.Error()}
	}

	vh.anodes[node.id] = node
	return &Response{Result: node.id}
}

func (vh *VoipHandler) addSnort(req *Request) *Response {
	kv := req.KeyVal
	host, ok1 := kv["host"]
	sshares, ok2 := kv["shares"]
	if !ok1 || !ok2 {
		return &Response{Err: ErrKeyNotFound.Error()}
	}

	shares, err := strconv.ParseInt(sshares, 10, 64)
	if err != nil {
		return &Response{Err: err.Error()}
	}

	node, err := vh.cmgr.StartSnort(host, shares)
	if err != nil {
		return &Response{Err: err.Error()}
	}

	vh.addMCont(node, shares)
	return &Response{Result: node.id}
}

func (vh *VoipHandler) addClient(req *Request) *Response {
	kv := req.KeyVal
	host, ok1 := kv["host"]
	sshares, ok2 := kv["shares"]
	serverid, ok3 := kv["server"]
	if !ok1 || !ok2 || !ok3 {
		return &Response{Err: ErrKeyNotFound.Error()}
	}

	shares, err := strconv.ParseInt(sshares, 10, 64)
	if err != nil {
		return &Response{Err: err.Error()}
	}
	server, ok := vh.anodes[serverid]
	if !ok {
		return &Response{Err: ErrIdNotExists.Error()}
	}

	node, err := vh.cmgr.StartClient(host, shares, server.ip)
	if err != nil {
		return &Response{Err: err.Error()}
	}

	vh.anodes[node.id] = node
	return &Response{Result: node.id}
}

func (vh *VoipHandler) stopCont(req *Request) *Response {
	kv := req.KeyVal
	contid, ok := kv["cont"]
	if !ok {
		return &Response{Err: ErrKeyNotFound.Error()}
	}

	node, ok := vh.anodes[contid]
	if ok {
		vh.cmgr.StopCont(node)
		delete(vh.anodes, node.id)
	} else {
		mnode, ok := vh.mnodes[contid]
		if ok {
			vh.cmgr.StopCont(mnode.node)
			vh.delMCont(mnode)
		} else {
			return &Response{Err: ErrIdNotExists.Error()}
		}
	}

	return &Response{}
}

func (vh *VoipHandler) route(req *Request) *Response {
	kv := req.KeyVal
	client, ok1 := kv["client"]
	server, ok2 := kv["server"]
	router, ok3 := kv["router"]
	if !ok1 || !ok2 || !ok3 {
		return &Response{Err: ErrKeyNotFound.Error()}
	}

	cnode, ok1 := vh.anodes[client]
	rcont, ok2 := vh.mnodes[router]
	snode, ok3 := vh.anodes[server]
	if !ok1 || !ok2 || !ok3 {
		return &Response{Err: ErrIdNotExists.Error()}
	}

	err := vh.cmgr.Route(cnode, rcont.node, snode)
	if err != nil {
		return &Response{Err: err.Error()}
	} else {
		return &Response{}
	}
}

func (vh *VoipHandler) setRate(req *Request) *Response {
	kv := req.KeyVal
	client, ok1 := kv["client"]
	rate, ok2 := kv["rate"]
	if !(ok1 && ok2) {
		return &Response{Err: ErrKeyNotFound.Error()}
	}

	cnode, ok1 := vh.anodes[client]
	if !ok1 {
		return &Response{Err: ErrIdNotExists.Error()}
	}
	irate, err := strconv.ParseInt(rate, 10, 32)
	if err != nil {
		return &Response{Err: err.Error()}
	}

	err = vh.setClientRate(cnode, int(irate))
	if err != nil {
		return &Response{Err: err.Error()}
	} else {
		return &Response{}
	}
}

func (vh *VoipHandler) addMCont(node *Node, shares int64) {
	vh.mnodes[node.id] = NewMContainer(node, vh.step_length, vh.period_length, shares, vh.reference)
}

func (vh *VoipHandler) delMCont(mcont *MContainer) {
	delete(vh.mnodes, mcont.node.id)
}

func (vh *VoipHandler) setClientRate(cnode *Node, rate int) error {
	addr, err := net.ResolveUDPAddr("udp", cnode.ip+":8888")
	if err != nil {
		return err
	}
	conn, err := net.DialUDP("udp", nil, addr)
	if err != nil {
		return err
	}
	defer conn.Close()
	_, err = conn.Write([]byte("cset rate " + strconv.Itoa(rate)))
	if err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Kubernetes Authors.

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

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

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

package node

import (
	"errors"
	"testing"

	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/client-go/kubernetes/fake"
	k8stesting "k8s.io/client-go/testing"
)

// TestCheckReadyForTests specifically is concerned about the multi-node logic
// since single node checks are in TestReadyForTests.
func TestCheckReadyForTests(t *testing.T) {
	// This is a duplicate definition of the constant in pkg/controller/service/controller.go
	labelNodeRoleControlPlane := "node-role.kubernetes.io/controlPlane"

	fromVanillaNode := func(f func(*v1.Node)) v1.Node {
		vanillaNode := &v1.Node{
			ObjectMeta: metav1.ObjectMeta{Name: "test-node"},
			Status: v1.NodeStatus{
				Conditions: []v1.NodeCondition{
					{Type: v1.NodeReady, Status: v1.ConditionTrue},
				},
			},
		}
		f(vanillaNode)
		return *vanillaNode
	}

	tcs := []struct {
		desc                 string
		nonblockingTaints    string
		allowedNotReadyNodes int
		nodes                []v1.Node
		nodeListErr          error
		expected             bool
		expectedErr          string
	}{
		{
			desc: "Vanilla node should pass",
			nodes: []v1.Node{
				fromVanillaNode(func(n *v1.Node) {}),
			},
			expected: true,
		}, {
			desc:              "Default value for nonblocking taints tolerates control plane taint",
			nonblockingTaints: `node-role.kubernetes.io/controlPlane`,
			nodes: []v1.Node{
				fromVanillaNode(func(n *v1.Node) {
					n.Spec.Taints = []v1.Taint{{Key: labelNodeRoleControlPlane, Effect: v1.TaintEffectNoSchedule}}
				}),
			},
			expected: true,
		}, {
			desc:              "Tainted node should fail if effect is TaintEffectNoExecute",
			nonblockingTaints: "bar",
			nodes: []v1.Node{
				fromVanillaNode(func(n *v1.Node) {
					n.Spec.Taints = []v1.Taint{{Key: "foo", Effect: v1.TaintEffectNoExecute}}
				})},
			expected: false,
		}, {
			desc:                 "Tainted node can be allowed via allowedNotReadyNodes",
			nonblockingTaints:    "bar",
			allowedNotReadyNodes: 1,
			nodes: []v1.Node{
				fromVanillaNode(func(n *v1.Node) {
					n.Spec.Taints = []v1.Taint{{Key: "foo", Effect: v1.TaintEffectNoExecute}}
				})},
			expected: true,
		}, {
			desc: "Multi-node, all OK",
			nodes: []v1.Node{
				fromVanillaNode(func(n *v1.Node) {}),
				fromVanillaNode(func(n *v1.Node) {}),
			},
			expected: true,
		}, {
			desc: "Multi-node, single blocking node blocks",
			nodes: []v1.Node{
				fromVanillaNode(func(n *v1.Node) {}),
				fromVanillaNode(func(n *v1.Node) {
					n.Spec.Taints = []v1.Taint{{Key: "foo", Effect: v1.TaintEffectNoSchedule}}
				}),
			},
			expected: false,
		}, {
			desc:                 "Multi-node, single blocking node allowed via allowedNotReadyNodes",
			allowedNotReadyNodes: 1,
			nodes: []v1.Node{
				fromVanillaNode(func(n *v1.Node) {}),
				fromVanillaNode(func(n *v1.Node) {
					n.Spec.Taints = []v1.Taint{{Key: "foo", Effect: v1.TaintEffectNoSchedule}}
				}),
			},
			expected: true,
		}, {
			desc:              "Multi-node, single blocking node allowed via nonblocking taint",
			nonblockingTaints: "foo",
			nodes: []v1.Node{
				fromVanillaNode(func(n *v1.Node) {}),
				fromVanillaNode(func(n *v1.Node) {
					n.Spec.Taints = []v1.Taint{{Key: "foo", Effect: v1.TaintEffectNoSchedule}}
				}),
			},
			expected: true,
		}, {
			desc:              "Multi-node, both blocking nodes allowed via separate nonblocking taints",
			nonblockingTaints: "foo,bar",
			nodes: []v1.Node{
				fromVanillaNode(func(n *v1.Node) {}),
				fromVanillaNode(func(n *v1.Node) {
					n.Spec.Taints = []v1.Taint{{Key: "foo", Effect: v1.TaintEffectNoSchedule}}
				}),
				fromVanillaNode(func(n *v1.Node) {
					n.Spec.Taints = []v1.Taint{{Key: "bar", Effect: v1.TaintEffectNoSchedule}}
				}),
			},
			expected: true,
		}, {
			desc:              "Multi-node, one blocking node allowed via nonblocking taints still blocked",
			nonblockingTaints: "foo,notbar",
			nodes: []v1.Node{
				fromVanillaNode(func(n *v1.Node) {}),
				fromVanillaNode(func(n *v1.Node) {
					n.Spec.Taints = []v1.Taint{{Key: "foo", Effect: v1.TaintEffectNoSchedule}}
				}),
				fromVanillaNode(func(n *v1.Node) {
					n.Spec.Taints = []v1.Taint{{Key: "bar", Effect: v1.TaintEffectNoSchedule}}
				}),
			},
			expected: false,
		}, {
			desc:        "Errors from node list are reported",
			nodeListErr: errors.New("Forced error"),
			expected:    false,
			expectedErr: "Forced error",
		},
	}

	// Only determines some logging functionality; not relevant so set to a large value.
	testLargeClusterThreshold := 1000

	for _, tc := range tcs {
		t.Run(tc.desc, func(t *testing.T) {
			c := fake.NewSimpleClientset()
			c.PrependReactor("list", "nodes", func(action k8stesting.Action) (handled bool, ret runtime.Object, err error) {
				nodeList := &v1.NodeList{Items: tc.nodes}
				return true, nodeList, tc.nodeListErr
			})
			checkFunc := CheckReadyForTests(c, tc.nonblockingTaints, tc.allowedNotReadyNodes, testLargeClusterThreshold)
			out, err := checkFunc()
			if out != tc.expected {
				t.Errorf("Expected %v but got %v", tc.expected, out)
			}
			switch {
			case err == nil && len(tc.expectedErr) > 0:
				t.Errorf("Expected error %q nil", tc.expectedErr)
			case err != nil && err.Error() != tc.expectedErr:
				t.Errorf("Expected error %q but got %q", tc.expectedErr, err.Error())
			}
		})
	}
}

func TestReadyForTests(t *testing.T) {
	fromVanillaNode := func(f func(*v1.Node)) *v1.Node {
		vanillaNode := &v1.Node{
			ObjectMeta: metav1.ObjectMeta{Name: "test-node"},
			Status: v1.NodeStatus{
				Conditions: []v1.NodeCondition{
					{Type: v1.NodeReady, Status: v1.ConditionTrue},
				},
			},
		}
		f(vanillaNode)
		return vanillaNode
	}
	_ = fromVanillaNode
	tcs := []struct {
		desc              string
		node              *v1.Node
		nonblockingTaints string
		expected          bool
	}{
		{
			desc: "Vanilla node should pass",
			node: fromVanillaNode(func(n *v1.Node) {
			}),
			expected: true,
		}, {
			desc:              "Vanilla node should pass with non-applicable nonblocking taint",
			nonblockingTaints: "foo",
			node: fromVanillaNode(func(n *v1.Node) {
			}),
			expected: true,
		}, {
			desc: "Tainted node should pass if effect is TaintEffectPreferNoSchedule",
			node: fromVanillaNode(func(n *v1.Node) {
				n.Spec.Taints = []v1.Taint{{Key: "foo", Effect: v1.TaintEffectPreferNoSchedule}}
			}),
			expected: true,
		}, {
			desc: "Tainted node should fail if effect is TaintEffectNoExecute",
			node: fromVanillaNode(func(n *v1.Node) {
				n.Spec.Taints = []v1.Taint{{Key: "foo", Effect: v1.TaintEffectNoExecute}}
			}),
			expected: false,
		}, {
			desc: "Tainted node should fail",
			node: fromVanillaNode(func(n *v1.Node) {
				n.Spec.Taints = []v1.Taint{{Key: "foo", Effect: v1.TaintEffectNoSchedule}}
			}),
			expected: false,
		}, {
			desc:              "Tainted node should pass if nonblocking",
			nonblockingTaints: "foo",
			node: fromVanillaNode(func(n *v1.Node) {
				n.Spec.Taints = []v1.Taint{{Key: "foo", Effect: v1.TaintEffectNoSchedule}}
			}),
			expected: true,
		}, {
			desc: "Node with network not ready fails",
			node: fromVanillaNode(func(n *v1.Node) {
				n.Status.Conditions = append(n.Status.Conditions,
					v1.NodeCondition{Type: v1.NodeNetworkUnavailable, Status: v1.ConditionTrue},
				)
			}),
			expected: false,
		}, {
			desc: "Node fails unless NodeReady status",
			node: fromVanillaNode(func(n *v1.Node) {
				n.Status.Conditions = []v1.NodeCondition{}
			}),
			expected: false,
		},
	}

	for _, tc := range tcs {
		t.Run(tc.desc, func(t *testing.T) {
			out := readyForTests(tc.node, tc.nonblockingTaints)
			if out != tc.expected {
				t.Errorf("Expected %v but got %v", tc.expected, out)
			}
		})
	}
}
<commit_msg>control plane typo in node role path<commit_after>/*
Copyright 2019 The Kubernetes Authors.

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

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

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

package node

import (
	"errors"
	"testing"

	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/client-go/kubernetes/fake"
	k8stesting "k8s.io/client-go/testing"
)

// TestCheckReadyForTests specifically is concerned about the multi-node logic
// since single node checks are in TestReadyForTests.
func TestCheckReadyForTests(t *testing.T) {
	// This is a duplicate definition of the constant in pkg/controller/service/controller.go
	labelNodeRoleControlPlane := "node-role.kubernetes.io/control-plane"

	fromVanillaNode := func(f func(*v1.Node)) v1.Node {
		vanillaNode := &v1.Node{
			ObjectMeta: metav1.ObjectMeta{Name: "test-node"},
			Status: v1.NodeStatus{
				Conditions: []v1.NodeCondition{
					{Type: v1.NodeReady, Status: v1.ConditionTrue},
				},
			},
		}
		f(vanillaNode)
		return *vanillaNode
	}

	tcs := []struct {
		desc                 string
		nonblockingTaints    string
		allowedNotReadyNodes int
		nodes                []v1.Node
		nodeListErr          error
		expected             bool
		expectedErr          string
	}{
		{
			desc: "Vanilla node should pass",
			nodes: []v1.Node{
				fromVanillaNode(func(n *v1.Node) {}),
			},
			expected: true,
		}, {
			desc:              "Default value for nonblocking taints tolerates control plane taint",
			nonblockingTaints: `node-role.kubernetes.io/control-plane`,
			nodes: []v1.Node{
				fromVanillaNode(func(n *v1.Node) {
					n.Spec.Taints = []v1.Taint{{Key: labelNodeRoleControlPlane, Effect: v1.TaintEffectNoSchedule}}
				}),
			},
			expected: true,
		}, {
			desc:              "Tainted node should fail if effect is TaintEffectNoExecute",
			nonblockingTaints: "bar",
			nodes: []v1.Node{
				fromVanillaNode(func(n *v1.Node) {
					n.Spec.Taints = []v1.Taint{{Key: "foo", Effect: v1.TaintEffectNoExecute}}
				})},
			expected: false,
		}, {
			desc:                 "Tainted node can be allowed via allowedNotReadyNodes",
			nonblockingTaints:    "bar",
			allowedNotReadyNodes: 1,
			nodes: []v1.Node{
				fromVanillaNode(func(n *v1.Node) {
					n.Spec.Taints = []v1.Taint{{Key: "foo", Effect: v1.TaintEffectNoExecute}}
				})},
			expected: true,
		}, {
			desc: "Multi-node, all OK",
			nodes: []v1.Node{
				fromVanillaNode(func(n *v1.Node) {}),
				fromVanillaNode(func(n *v1.Node) {}),
			},
			expected: true,
		}, {
			desc: "Multi-node, single blocking node blocks",
			nodes: []v1.Node{
				fromVanillaNode(func(n *v1.Node) {}),
				fromVanillaNode(func(n *v1.Node) {
					n.Spec.Taints = []v1.Taint{{Key: "foo", Effect: v1.TaintEffectNoSchedule}}
				}),
			},
			expected: false,
		}, {
			desc:                 "Multi-node, single blocking node allowed via allowedNotReadyNodes",
			allowedNotReadyNodes: 1,
			nodes: []v1.Node{
				fromVanillaNode(func(n *v1.Node) {}),
				fromVanillaNode(func(n *v1.Node) {
					n.Spec.Taints = []v1.Taint{{Key: "foo", Effect: v1.TaintEffectNoSchedule}}
				}),
			},
			expected: true,
		}, {
			desc:              "Multi-node, single blocking node allowed via nonblocking taint",
			nonblockingTaints: "foo",
			nodes: []v1.Node{
				fromVanillaNode(func(n *v1.Node) {}),
				fromVanillaNode(func(n *v1.Node) {
					n.Spec.Taints = []v1.Taint{{Key: "foo", Effect: v1.TaintEffectNoSchedule}}
				}),
			},
			expected: true,
		}, {
			desc:              "Multi-node, both blocking nodes allowed via separate nonblocking taints",
			nonblockingTaints: "foo,bar",
			nodes: []v1.Node{
				fromVanillaNode(func(n *v1.Node) {}),
				fromVanillaNode(func(n *v1.Node) {
					n.Spec.Taints = []v1.Taint{{Key: "foo", Effect: v1.TaintEffectNoSchedule}}
				}),
				fromVanillaNode(func(n *v1.Node) {
					n.Spec.Taints = []v1.Taint{{Key: "bar", Effect: v1.TaintEffectNoSchedule}}
				}),
			},
			expected: true,
		}, {
			desc:              "Multi-node, one blocking node allowed via nonblocking taints still blocked",
			nonblockingTaints: "foo,notbar",
			nodes: []v1.Node{
				fromVanillaNode(func(n *v1.Node) {}),
				fromVanillaNode(func(n *v1.Node) {
					n.Spec.Taints = []v1.Taint{{Key: "foo", Effect: v1.TaintEffectNoSchedule}}
				}),
				fromVanillaNode(func(n *v1.Node) {
					n.Spec.Taints = []v1.Taint{{Key: "bar", Effect: v1.TaintEffectNoSchedule}}
				}),
			},
			expected: false,
		}, {
			desc:        "Errors from node list are reported",
			nodeListErr: errors.New("Forced error"),
			expected:    false,
			expectedErr: "Forced error",
		},
	}

	// Only determines some logging functionality; not relevant so set to a large value.
	testLargeClusterThreshold := 1000

	for _, tc := range tcs {
		t.Run(tc.desc, func(t *testing.T) {
			c := fake.NewSimpleClientset()
			c.PrependReactor("list", "nodes", func(action k8stesting.Action) (handled bool, ret runtime.Object, err error) {
				nodeList := &v1.NodeList{Items: tc.nodes}
				return true, nodeList, tc.nodeListErr
			})
			checkFunc := CheckReadyForTests(c, tc.nonblockingTaints, tc.allowedNotReadyNodes, testLargeClusterThreshold)
			out, err := checkFunc()
			if out != tc.expected {
				t.Errorf("Expected %v but got %v", tc.expected, out)
			}
			switch {
			case err == nil && len(tc.expectedErr) > 0:
				t.Errorf("Expected error %q nil", tc.expectedErr)
			case err != nil && err.Error() != tc.expectedErr:
				t.Errorf("Expected error %q but got %q", tc.expectedErr, err.Error())
			}
		})
	}
}

func TestReadyForTests(t *testing.T) {
	fromVanillaNode := func(f func(*v1.Node)) *v1.Node {
		vanillaNode := &v1.Node{
			ObjectMeta: metav1.ObjectMeta{Name: "test-node"},
			Status: v1.NodeStatus{
				Conditions: []v1.NodeCondition{
					{Type: v1.NodeReady, Status: v1.ConditionTrue},
				},
			},
		}
		f(vanillaNode)
		return vanillaNode
	}
	_ = fromVanillaNode
	tcs := []struct {
		desc              string
		node              *v1.Node
		nonblockingTaints string
		expected          bool
	}{
		{
			desc: "Vanilla node should pass",
			node: fromVanillaNode(func(n *v1.Node) {
			}),
			expected: true,
		}, {
			desc:              "Vanilla node should pass with non-applicable nonblocking taint",
			nonblockingTaints: "foo",
			node: fromVanillaNode(func(n *v1.Node) {
			}),
			expected: true,
		}, {
			desc: "Tainted node should pass if effect is TaintEffectPreferNoSchedule",
			node: fromVanillaNode(func(n *v1.Node) {
				n.Spec.Taints = []v1.Taint{{Key: "foo", Effect: v1.TaintEffectPreferNoSchedule}}
			}),
			expected: true,
		}, {
			desc: "Tainted node should fail if effect is TaintEffectNoExecute",
			node: fromVanillaNode(func(n *v1.Node) {
				n.Spec.Taints = []v1.Taint{{Key: "foo", Effect: v1.TaintEffectNoExecute}}
			}),
			expected: false,
		}, {
			desc: "Tainted node should fail",
			node: fromVanillaNode(func(n *v1.Node) {
				n.Spec.Taints = []v1.Taint{{Key: "foo", Effect: v1.TaintEffectNoSchedule}}
			}),
			expected: false,
		}, {
			desc:              "Tainted node should pass if nonblocking",
			nonblockingTaints: "foo",
			node: fromVanillaNode(func(n *v1.Node) {
				n.Spec.Taints = []v1.Taint{{Key: "foo", Effect: v1.TaintEffectNoSchedule}}
			}),
			expected: true,
		}, {
			desc: "Node with network not ready fails",
			node: fromVanillaNode(func(n *v1.Node) {
				n.Status.Conditions = append(n.Status.Conditions,
					v1.NodeCondition{Type: v1.NodeNetworkUnavailable, Status: v1.ConditionTrue},
				)
			}),
			expected: false,
		}, {
			desc: "Node fails unless NodeReady status",
			node: fromVanillaNode(func(n *v1.Node) {
				n.Status.Conditions = []v1.NodeCondition{}
			}),
			expected: false,
		},
	}

	for _, tc := range tcs {
		t.Run(tc.desc, func(t *testing.T) {
			out := readyForTests(tc.node, tc.nonblockingTaints)
			if out != tc.expected {
				t.Errorf("Expected %v but got %v", tc.expected, out)
			}
		})
	}
}
<|endoftext|>


<commit_before>package image_ecosystem

import (
	"context"
	"fmt"
	"strings"
	"time"

	g "github.com/onsi/ginkgo"
	o "github.com/onsi/gomega"

	kapiv1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/kubernetes/pkg/client/conditions"
	e2e "k8s.io/kubernetes/test/e2e/framework"
	e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
	e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper"

	exutil "github.com/openshift/origin/test/extended/util"
)

func skipArch(oc *exutil.CLI, arches []string) bool {
	allWorkerNodes, err := oc.AsAdmin().KubeClient().CoreV1().Nodes().List(context.Background(), metav1.ListOptions{
		LabelSelector: "node-role.kubernetes.io/worker",
	})
	if err != nil {
		e2e.Logf("problem getting nodes for arch check: %s", err)
	}
	for _, node := range allWorkerNodes.Items {
		for _, arch := range arches {
			if node.Status.NodeInfo.Architecture == arch {
				return false
			}
		}
	}
	return true
}

// defineTest will create the gingko test.  This ensures the test
// is created with a local copy of all variables the test will need,
// since the test may not run immediately and may run in parallel with other
// tests, so sharing a variable reference is problematic.  (Sharing the oc client
// is ok for these tests).
func defineTest(name string, t tc, oc *exutil.CLI) {
	g.Describe("returning s2i usage when running the image", func() {
		g.It(fmt.Sprintf("%q should print the usage", t.DockerImageReference), func() {
			e2e.Logf("checking %s/%s for architecture compatibility", name, t.Version)
			if skipArch(oc, t.Arches) {
				e2eskipper.Skipf("skipping %s/%s because not available on cluster architecture", name, t.Version)
				return
			}
			e2e.Logf("%s/%s passed architecture compatibility", name, t.Version)
			g.By(fmt.Sprintf("creating a sample pod for %q", t.DockerImageReference))
			pod := exutil.GetPodForContainer(kapiv1.Container{
				Name:  "test",
				Image: t.DockerImageReference,
			})
			_, err := oc.KubeClient().CoreV1().Pods(oc.Namespace()).Create(context.Background(), pod, metav1.CreateOptions{})
			o.Expect(err).NotTo(o.HaveOccurred())

			g.By("waiting for the pod to be running")
			err = e2epod.WaitForPodRunningInNamespaceSlow(oc.KubeClient(), pod.Name, oc.Namespace())
			if err != nil {
				p, e := oc.KubeClient().CoreV1().Pods(oc.Namespace()).Get(context.Background(), pod.Name, metav1.GetOptions{})
				if e != nil {
					e2e.Logf("error %v getting pod", e)
				}
				e2e.Logf("error %v waiting for pod %v: ", err, p)
				o.Expect(err).To(o.Equal(conditions.ErrPodCompleted))
			}

			g.By("checking the log of the pod")
			err = wait.Poll(1*time.Second, 10*time.Second, func() (bool, error) {
				log, err := oc.KubeClient().CoreV1().Pods(oc.Namespace()).GetLogs(pod.Name, &kapiv1.PodLogOptions{}).DoRaw(context.Background())
				if err != nil {
					return false, err
				}
				e2e.Logf("got log %v from pod %v", string(log), pod.Name)
				if strings.Contains(string(log), "Sample invocation") {
					return true, nil
				}
				if strings.Contains(string(log), "oc new-app") {
					return true, nil
				}
				if strings.Contains(string(log), "OpenShift") {
					return true, nil
				}
				if strings.Contains(string(log), "Openshift") {
					return true, nil
				}
				return false, nil
			})
			o.Expect(err).NotTo(o.HaveOccurred())

		})
	})
	g.Describe("using the SCL in s2i images", func() {
		g.It(fmt.Sprintf("%q should be SCL enabled", t.DockerImageReference), func() {
			e2e.Logf("checking %s/%s for architecture compatibility", name, t.Version)
			if skipArch(oc, t.Arches) {
				e2eskipper.Skipf("skipping %s/%s because not available on cluster architecture", name, t.Version)
				return
			}
			e2e.Logf("%s/%s passed architecture compatibility", name, t.Version)
			g.By(fmt.Sprintf("creating a sample pod for %q with /bin/bash -c command", t.DockerImageReference))
			pod := exutil.GetPodForContainer(kapiv1.Container{
				Image:   t.DockerImageReference,
				Name:    "test",
				Command: []string{"/bin/bash", "-c", t.Cmd},
			})

			_, err := oc.KubeClient().CoreV1().Pods(oc.Namespace()).Create(context.Background(), pod, metav1.CreateOptions{})
			o.Expect(err).NotTo(o.HaveOccurred())

			err = e2epod.WaitForPodRunningInNamespaceSlow(oc.KubeClient(), pod.Name, oc.Namespace())
			if err != nil {
				p, e := oc.KubeClient().CoreV1().Pods(oc.Namespace()).Get(context.Background(), pod.Name, metav1.GetOptions{})
				if e != nil {
					e2e.Logf("error %v getting pod", e)
				}
				e2e.Logf("error %v waiting for pod %v: ", err, p)
				o.Expect(err).To(o.Equal(conditions.ErrPodCompleted))
			}

			g.By("checking the log of the pod")
			err = wait.Poll(1*time.Second, 10*time.Second, func() (bool, error) {
				log, err := oc.KubeClient().CoreV1().Pods(oc.Namespace()).GetLogs(pod.Name, &kapiv1.PodLogOptions{}).DoRaw(context.Background())
				if err != nil {
					return false, err
				}
				e2e.Logf("got log %v from pod %v", string(log), pod.Name)
				if strings.Contains(string(log), t.Expected) {
					return true, nil
				}
				return false, nil
			})
			o.Expect(err).NotTo(o.HaveOccurred())

			g.By(fmt.Sprintf("creating a sample pod for %q", t.DockerImageReference))
			pod = exutil.GetPodForContainer(kapiv1.Container{
				Image:   t.DockerImageReference,
				Name:    "test",
				Command: []string{"/usr/bin/sleep", "infinity"},
			})
			_, err = oc.KubeClient().CoreV1().Pods(oc.Namespace()).Create(context.Background(), pod, metav1.CreateOptions{})
			o.Expect(err).NotTo(o.HaveOccurred())

			err = e2epod.WaitForPodRunningInNamespaceSlow(oc.KubeClient(), pod.Name, oc.Namespace())
			o.Expect(err).NotTo(o.HaveOccurred())

			g.By("calling the binary using 'oc exec /bin/bash -c'")
			out, err := oc.Run("exec").Args(pod.Name, "--", "/bin/bash", "-c", t.Cmd).Output()
			o.Expect(err).NotTo(o.HaveOccurred())
			o.Expect(out).Should(o.ContainSubstring(t.Expected))

			g.By("calling the binary using 'oc exec /bin/sh -ic'")
			out, err = oc.Run("exec").Args(pod.Name, "--", "/bin/sh", "-ic", t.Cmd).Output()
			o.Expect(err).NotTo(o.HaveOccurred())
			o.Expect(out).Should(o.ContainSubstring(t.Expected))
		})
	})
}

var _ = g.Describe("[sig-devex][Feature:ImageEcosystem][Slow] openshift images should be SCL enabled", func() {
	defer g.GinkgoRecover()
	var oc = exutil.NewCLI("s2i-usage")

	g.Context("", func() {
		g.JustBeforeEach(func() {
			exutil.PreTestDump()
		})

		g.AfterEach(func() {
			if g.CurrentGinkgoTestDescription().Failed {
				exutil.DumpPodStates(oc)
				exutil.DumpPodLogsStartingWith("", oc)
			}
		})

		for name, tcs := range GetTestCaseForImages() {
			for _, t := range tcs {
				defineTest(name, t, oc)
			}
		}
	})
})
<commit_msg>image_ecosystem: use unique tags in test logs<commit_after>package image_ecosystem

import (
	"context"
	"fmt"
	"strings"
	"time"

	g "github.com/onsi/ginkgo"
	o "github.com/onsi/gomega"

	kapiv1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/kubernetes/pkg/client/conditions"
	e2e "k8s.io/kubernetes/test/e2e/framework"
	e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
	e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper"

	exutil "github.com/openshift/origin/test/extended/util"
)

func skipArch(oc *exutil.CLI, arches []string) bool {
	allWorkerNodes, err := oc.AsAdmin().KubeClient().CoreV1().Nodes().List(context.Background(), metav1.ListOptions{
		LabelSelector: "node-role.kubernetes.io/worker",
	})
	if err != nil {
		e2e.Logf("problem getting nodes for arch check: %s", err)
	}
	for _, node := range allWorkerNodes.Items {
		for _, arch := range arches {
			if node.Status.NodeInfo.Architecture == arch {
				return false
			}
		}
	}
	return true
}

// defineTest will create the gingko test.  This ensures the test
// is created with a local copy of all variables the test will need,
// since the test may not run immediately and may run in parallel with other
// tests, so sharing a variable reference is problematic.  (Sharing the oc client
// is ok for these tests).
func defineTest(name string, t tc, oc *exutil.CLI) {
	g.Describe("returning s2i usage when running the image", func() {
		g.It(fmt.Sprintf("%q should print the usage", t.DockerImageReference), func() {
			e2e.Logf("checking %s:%s for architecture compatibility", name, t.Tag)
			if skipArch(oc, t.Arches) {
				e2eskipper.Skipf("skipping %s:%s because not available on cluster architecture", name, t.Tag)
				return
			}
			e2e.Logf("%s:%s passed architecture compatibility", name, t.Tag)
			g.By(fmt.Sprintf("creating a sample pod for %q", t.DockerImageReference))
			pod := exutil.GetPodForContainer(kapiv1.Container{
				Name:  "test",
				Image: t.DockerImageReference,
			})
			_, err := oc.KubeClient().CoreV1().Pods(oc.Namespace()).Create(context.Background(), pod, metav1.CreateOptions{})
			o.Expect(err).NotTo(o.HaveOccurred())

			g.By("waiting for the pod to be running")
			err = e2epod.WaitForPodRunningInNamespaceSlow(oc.KubeClient(), pod.Name, oc.Namespace())
			if err != nil {
				p, e := oc.KubeClient().CoreV1().Pods(oc.Namespace()).Get(context.Background(), pod.Name, metav1.GetOptions{})
				if e != nil {
					e2e.Logf("error %v getting pod", e)
				}
				e2e.Logf("error %v waiting for pod %v: ", err, p)
				o.Expect(err).To(o.Equal(conditions.ErrPodCompleted))
			}

			g.By("checking the log of the pod")
			err = wait.Poll(1*time.Second, 10*time.Second, func() (bool, error) {
				log, err := oc.KubeClient().CoreV1().Pods(oc.Namespace()).GetLogs(pod.Name, &kapiv1.PodLogOptions{}).DoRaw(context.Background())
				if err != nil {
					return false, err
				}
				e2e.Logf("got log %v from pod %v", string(log), pod.Name)
				if strings.Contains(string(log), "Sample invocation") {
					return true, nil
				}
				if strings.Contains(string(log), "oc new-app") {
					return true, nil
				}
				if strings.Contains(string(log), "OpenShift") {
					return true, nil
				}
				if strings.Contains(string(log), "Openshift") {
					return true, nil
				}
				return false, nil
			})
			o.Expect(err).NotTo(o.HaveOccurred())

		})
	})
	g.Describe("using the SCL in s2i images", func() {
		g.It(fmt.Sprintf("%q should be SCL enabled", t.DockerImageReference), func() {
			e2e.Logf("checking %s:%s for architecture compatibility", name, t.Tag)
			if skipArch(oc, t.Arches) {
				e2eskipper.Skipf("skipping %s:%s because not available on cluster architecture", name, t.Tag)
				return
			}
			e2e.Logf("%s:%s passed architecture compatibility", name, t.Tag)
			g.By(fmt.Sprintf("creating a sample pod for %q with /bin/bash -c command", t.DockerImageReference))
			pod := exutil.GetPodForContainer(kapiv1.Container{
				Image:   t.DockerImageReference,
				Name:    "test",
				Command: []string{"/bin/bash", "-c", t.Cmd},
			})

			_, err := oc.KubeClient().CoreV1().Pods(oc.Namespace()).Create(context.Background(), pod, metav1.CreateOptions{})
			o.Expect(err).NotTo(o.HaveOccurred())

			err = e2epod.WaitForPodRunningInNamespaceSlow(oc.KubeClient(), pod.Name, oc.Namespace())
			if err != nil {
				p, e := oc.KubeClient().CoreV1().Pods(oc.Namespace()).Get(context.Background(), pod.Name, metav1.GetOptions{})
				if e != nil {
					e2e.Logf("error %v getting pod", e)
				}
				e2e.Logf("error %v waiting for pod %v: ", err, p)
				o.Expect(err).To(o.Equal(conditions.ErrPodCompleted))
			}

			g.By("checking the log of the pod")
			err = wait.Poll(1*time.Second, 10*time.Second, func() (bool, error) {
				log, err := oc.KubeClient().CoreV1().Pods(oc.Namespace()).GetLogs(pod.Name, &kapiv1.PodLogOptions{}).DoRaw(context.Background())
				if err != nil {
					return false, err
				}
				e2e.Logf("got log %v from pod %v", string(log), pod.Name)
				if strings.Contains(string(log), t.Expected) {
					return true, nil
				}
				return false, nil
			})
			o.Expect(err).NotTo(o.HaveOccurred())

			g.By(fmt.Sprintf("creating a sample pod for %q", t.DockerImageReference))
			pod = exutil.GetPodForContainer(kapiv1.Container{
				Image:   t.DockerImageReference,
				Name:    "test",
				Command: []string{"/usr/bin/sleep", "infinity"},
			})
			_, err = oc.KubeClient().CoreV1().Pods(oc.Namespace()).Create(context.Background(), pod, metav1.CreateOptions{})
			o.Expect(err).NotTo(o.HaveOccurred())

			err = e2epod.WaitForPodRunningInNamespaceSlow(oc.KubeClient(), pod.Name, oc.Namespace())
			o.Expect(err).NotTo(o.HaveOccurred())

			g.By("calling the binary using 'oc exec /bin/bash -c'")
			out, err := oc.Run("exec").Args(pod.Name, "--", "/bin/bash", "-c", t.Cmd).Output()
			o.Expect(err).NotTo(o.HaveOccurred())
			o.Expect(out).Should(o.ContainSubstring(t.Expected))

			g.By("calling the binary using 'oc exec /bin/sh -ic'")
			out, err = oc.Run("exec").Args(pod.Name, "--", "/bin/sh", "-ic", t.Cmd).Output()
			o.Expect(err).NotTo(o.HaveOccurred())
			o.Expect(out).Should(o.ContainSubstring(t.Expected))
		})
	})
}

var _ = g.Describe("[sig-devex][Feature:ImageEcosystem][Slow] openshift images should be SCL enabled", func() {
	defer g.GinkgoRecover()
	var oc = exutil.NewCLI("s2i-usage")

	g.Context("", func() {
		g.JustBeforeEach(func() {
			exutil.PreTestDump()
		})

		g.AfterEach(func() {
			if g.CurrentGinkgoTestDescription().Failed {
				exutil.DumpPodStates(oc)
				exutil.DumpPodLogsStartingWith("", oc)
			}
		})

		for name, tcs := range GetTestCaseForImages() {
			for _, t := range tcs {
				defineTest(name, t, oc)
			}
		}
	})
})
<|endoftext|>


<commit_before>package image_ecosystem

import (
	"fmt"

	g "github.com/onsi/ginkgo"
	o "github.com/onsi/gomega"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	kapiv1 "k8s.io/kubernetes/pkg/api/v1"
	"k8s.io/kubernetes/pkg/client/conditions"
	e2e "k8s.io/kubernetes/test/e2e/framework"

	exutil "github.com/openshift/origin/test/extended/util"
)

func getPodNameForTest(image string, t tc) string {
	return fmt.Sprintf("%s-%s-centos7", image, t.Version)
}

// defineTest will create the gingko test.  This ensures the test
// is created with a local copy of all variables the test will need,
// since the test may not run immediately and may run in parallel with other
// tests, so sharing a variable reference is problematic.  (Sharing the oc client
// is ok for these tests).
func defineTest(image string, t tc, oc *exutil.CLI) {
	g.Describe("returning s2i usage when running the image", func() {
		g.It(fmt.Sprintf("%q should print the usage", t.DockerImageReference), func() {
			g.By(fmt.Sprintf("creating a sample pod for %q", t.DockerImageReference))
			pod := exutil.GetPodForContainer(kapiv1.Container{
				Name:  "test",
				Image: t.DockerImageReference,
			})
			_, err := oc.KubeClient().CoreV1().Pods(oc.Namespace()).Create(pod)
			o.Expect(err).NotTo(o.HaveOccurred())

			g.By("waiting for the pod to be running")
			err = oc.KubeFramework().WaitForPodRunningSlow(pod.Name)
			if err != nil {
				p, e := oc.KubeClient().CoreV1().Pods(oc.Namespace()).Get(pod.Name, metav1.GetOptions{})
				e2e.Logf("error %v waiting for pod %v: ", p, e)
				o.Expect(err).To(o.Equal(conditions.ErrPodCompleted))
			}

			g.By("checking the log of the pod")
			log, err := oc.KubeClient().CoreV1().Pods(oc.Namespace()).GetLogs(pod.Name, &kapiv1.PodLogOptions{}).DoRaw()
			o.Expect(err).NotTo(o.HaveOccurred())

			o.Expect(string(log)).To(o.ContainSubstring("Sample invocation"))
		})
	})
	g.Describe("using the SCL in s2i images", func() {
		g.It(fmt.Sprintf("%q should be SCL enabled", t.DockerImageReference), func() {
			g.By(fmt.Sprintf("creating a sample pod for %q with /bin/bash -c command", t.DockerImageReference))
			pod := exutil.GetPodForContainer(kapiv1.Container{
				Image:   t.DockerImageReference,
				Name:    "test",
				Command: []string{"/bin/bash", "-c", t.Cmd},
			})

			_, err := oc.KubeClient().CoreV1().Pods(oc.Namespace()).Create(pod)
			o.Expect(err).NotTo(o.HaveOccurred())

			err = oc.KubeFramework().WaitForPodRunningSlow(pod.Name)
			if err != nil {
				p, e := oc.KubeClient().CoreV1().Pods(oc.Namespace()).Get(pod.Name, metav1.GetOptions{})
				e2e.Logf("error %v waiting for pod %v: ", p, e)
				o.Expect(err).To(o.Equal(conditions.ErrPodCompleted))
			}

			log, err := oc.KubeClient().CoreV1().Pods(oc.Namespace()).GetLogs(pod.Name, &kapiv1.PodLogOptions{}).DoRaw()
			o.Expect(err).NotTo(o.HaveOccurred())
			o.Expect(string(log)).To(o.ContainSubstring(t.Expected))

			g.By(fmt.Sprintf("creating a sample pod for %q", t.DockerImageReference))
			pod = exutil.GetPodForContainer(kapiv1.Container{
				Image:   t.DockerImageReference,
				Name:    "test",
				Command: []string{"/usr/bin/sleep", "infinity"},
			})
			_, err = oc.KubeClient().CoreV1().Pods(oc.Namespace()).Create(pod)
			o.Expect(err).NotTo(o.HaveOccurred())

			err = oc.KubeFramework().WaitForPodRunningSlow(pod.Name)
			o.Expect(err).NotTo(o.HaveOccurred())

			g.By("calling the binary using 'oc exec /bin/bash -c'")
			out, err := oc.Run("exec").Args("-p", pod.Name, "--", "/bin/bash", "-c", t.Cmd).Output()
			o.Expect(err).NotTo(o.HaveOccurred())
			o.Expect(out).Should(o.ContainSubstring(t.Expected))

			g.By("calling the binary using 'oc exec /bin/sh -ic'")
			out, err = oc.Run("exec").Args("-p", pod.Name, "--", "/bin/sh", "-ic", t.Cmd).Output()
			o.Expect(err).NotTo(o.HaveOccurred())
			o.Expect(out).Should(o.ContainSubstring(t.Expected))
		})
	})
}

var _ = g.Describe("[image_ecosystem][Slow] openshift images should be SCL enabled", func() {
	defer g.GinkgoRecover()
	var oc = exutil.NewCLI("s2i-usage", exutil.KubeConfigPath())

	g.Context("", func() {
		g.JustBeforeEach(func() {
			g.By("waiting for builder service account")
			err := exutil.WaitForBuilderAccount(oc.KubeClient().CoreV1().ServiceAccounts(oc.Namespace()))
			o.Expect(err).NotTo(o.HaveOccurred())
		})

		g.AfterEach(func() {
			if g.CurrentGinkgoTestDescription().Failed {
				exutil.DumpPodStates(oc)
				exutil.DumpPodLogsStartingWith("", oc)
			}
		})

		for image, tcs := range GetTestCaseForImages() {
			for _, t := range tcs {
				defineTest(image, t, oc)
			}
		}
	})
})
<commit_msg>add toleration for slow logs in scl tests<commit_after>package image_ecosystem

import (
	"fmt"
	"strings"
	"time"

	g "github.com/onsi/ginkgo"
	o "github.com/onsi/gomega"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/wait"
	kapiv1 "k8s.io/kubernetes/pkg/api/v1"
	"k8s.io/kubernetes/pkg/client/conditions"
	e2e "k8s.io/kubernetes/test/e2e/framework"

	exutil "github.com/openshift/origin/test/extended/util"
)

func getPodNameForTest(image string, t tc) string {
	return fmt.Sprintf("%s-%s-centos7", image, t.Version)
}

// defineTest will create the gingko test.  This ensures the test
// is created with a local copy of all variables the test will need,
// since the test may not run immediately and may run in parallel with other
// tests, so sharing a variable reference is problematic.  (Sharing the oc client
// is ok for these tests).
func defineTest(image string, t tc, oc *exutil.CLI) {
	g.Describe("returning s2i usage when running the image", func() {
		g.It(fmt.Sprintf("%q should print the usage", t.DockerImageReference), func() {
			g.By(fmt.Sprintf("creating a sample pod for %q", t.DockerImageReference))
			pod := exutil.GetPodForContainer(kapiv1.Container{
				Name:  "test",
				Image: t.DockerImageReference,
			})
			_, err := oc.KubeClient().CoreV1().Pods(oc.Namespace()).Create(pod)
			o.Expect(err).NotTo(o.HaveOccurred())

			g.By("waiting for the pod to be running")
			err = oc.KubeFramework().WaitForPodRunningSlow(pod.Name)
			if err != nil {
				p, e := oc.KubeClient().CoreV1().Pods(oc.Namespace()).Get(pod.Name, metav1.GetOptions{})
				e2e.Logf("error %v waiting for pod %v: ", p, e)
				o.Expect(err).To(o.Equal(conditions.ErrPodCompleted))
			}

			g.By("checking the log of the pod")
			err = wait.Poll(1*time.Second, 10*time.Second, func() (bool, error) {
				log, err := oc.KubeClient().CoreV1().Pods(oc.Namespace()).GetLogs(pod.Name, &kapiv1.PodLogOptions{}).DoRaw()
				if err != nil {
					return false, err
				}
				e2e.Logf("got log %v from pod %v", string(log), pod.Name)
				if strings.Contains(string(log), "Sample invocation") {
					return true, nil
				}
				return false, nil
			})
			o.Expect(err).NotTo(o.HaveOccurred())

		})
	})
	g.Describe("using the SCL in s2i images", func() {
		g.It(fmt.Sprintf("%q should be SCL enabled", t.DockerImageReference), func() {
			g.By(fmt.Sprintf("creating a sample pod for %q with /bin/bash -c command", t.DockerImageReference))
			pod := exutil.GetPodForContainer(kapiv1.Container{
				Image:   t.DockerImageReference,
				Name:    "test",
				Command: []string{"/bin/bash", "-c", t.Cmd},
			})

			_, err := oc.KubeClient().CoreV1().Pods(oc.Namespace()).Create(pod)
			o.Expect(err).NotTo(o.HaveOccurred())

			err = oc.KubeFramework().WaitForPodRunningSlow(pod.Name)
			if err != nil {
				p, e := oc.KubeClient().CoreV1().Pods(oc.Namespace()).Get(pod.Name, metav1.GetOptions{})
				e2e.Logf("error %v waiting for pod %v: ", p, e)
				o.Expect(err).To(o.Equal(conditions.ErrPodCompleted))
			}

			log, err := oc.KubeClient().CoreV1().Pods(oc.Namespace()).GetLogs(pod.Name, &kapiv1.PodLogOptions{}).DoRaw()
			o.Expect(err).NotTo(o.HaveOccurred())
			o.Expect(string(log)).To(o.ContainSubstring(t.Expected))

			g.By(fmt.Sprintf("creating a sample pod for %q", t.DockerImageReference))
			pod = exutil.GetPodForContainer(kapiv1.Container{
				Image:   t.DockerImageReference,
				Name:    "test",
				Command: []string{"/usr/bin/sleep", "infinity"},
			})
			_, err = oc.KubeClient().CoreV1().Pods(oc.Namespace()).Create(pod)
			o.Expect(err).NotTo(o.HaveOccurred())

			err = oc.KubeFramework().WaitForPodRunningSlow(pod.Name)
			o.Expect(err).NotTo(o.HaveOccurred())

			g.By("calling the binary using 'oc exec /bin/bash -c'")
			out, err := oc.Run("exec").Args("-p", pod.Name, "--", "/bin/bash", "-c", t.Cmd).Output()
			o.Expect(err).NotTo(o.HaveOccurred())
			o.Expect(out).Should(o.ContainSubstring(t.Expected))

			g.By("calling the binary using 'oc exec /bin/sh -ic'")
			out, err = oc.Run("exec").Args("-p", pod.Name, "--", "/bin/sh", "-ic", t.Cmd).Output()
			o.Expect(err).NotTo(o.HaveOccurred())
			o.Expect(out).Should(o.ContainSubstring(t.Expected))
		})
	})
}

var _ = g.Describe("[image_ecosystem][Slow] openshift images should be SCL enabled", func() {
	defer g.GinkgoRecover()
	var oc = exutil.NewCLI("s2i-usage", exutil.KubeConfigPath())

	g.Context("", func() {
		g.JustBeforeEach(func() {
			g.By("waiting for builder service account")
			err := exutil.WaitForBuilderAccount(oc.KubeClient().CoreV1().ServiceAccounts(oc.Namespace()))
			o.Expect(err).NotTo(o.HaveOccurred())
		})

		g.AfterEach(func() {
			if g.CurrentGinkgoTestDescription().Failed {
				exutil.DumpPodStates(oc)
				exutil.DumpPodLogsStartingWith("", oc)
			}
		})

		for image, tcs := range GetTestCaseForImages() {
			for _, t := range tcs {
				defineTest(image, t, oc)
			}
		}
	})
})
<|endoftext|>


<commit_before>package operators

import (
	"bytes"
	"context"
	"fmt"
	"os"
	"sort"
	"strings"
	"text/tabwriter"
	"time"

	g "github.com/onsi/ginkgo"
	o "github.com/onsi/gomega"
	"github.com/stretchr/objx"

	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/client-go/dynamic"
	coreclient "k8s.io/client-go/kubernetes/typed/core/v1"
	e2e "k8s.io/kubernetes/test/e2e/framework"
	e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper"

	configv1 "github.com/openshift/api/config/v1"
	configclient "github.com/openshift/client-go/config/clientset/versioned"
)

const (
	operatorWait = 1 * time.Minute
	cvoWait      = 5 * time.Minute
)

var _ = g.Describe("[sig-arch][Early] Managed cluster should", func() {
	defer g.GinkgoRecover()

	g.It("start all core operators", func() {
		cfg, err := e2e.LoadConfig()
		o.Expect(err).NotTo(o.HaveOccurred())
		c, err := e2e.LoadClientset()
		o.Expect(err).NotTo(o.HaveOccurred())
		dc, err := dynamic.NewForConfig(cfg)
		o.Expect(err).NotTo(o.HaveOccurred())

		// presence of the CVO namespace gates this test
		g.By("checking for the cluster version operator")
		skipUnlessCVO(c.CoreV1().Namespaces())

		g.By("waiting for the cluster version to be applied")
		cvc := dc.Resource(schema.GroupVersionResource{Group: "config.openshift.io", Resource: "clusterversions", Version: "v1"})
		var lastErr error
		var lastCV objx.Map
		if err := wait.PollImmediate(3*time.Second, cvoWait, func() (bool, error) {
			obj, err := cvc.Get(context.Background(), "version", metav1.GetOptions{})
			if err != nil {
				lastErr = err
				e2e.Logf("Unable to check for cluster version: %v", err)
				return false, nil
			}
			cv := objx.Map(obj.UnstructuredContent())
			lastErr = nil
			lastCV = cv
			if cond := condition(cv, "Progressing"); cond.Get("status").String() != "False" {
				e2e.Logf("ClusterVersion is still progressing: %s", cond.Get("message").String())
				return false, nil
			}
			if cond := condition(cv, "Available"); cond.Get("status").String() != "True" {
				e2e.Logf("ClusterVersion is not available: %s", cond.Get("message").String())
				return false, nil
			}
			e2e.Logf("ClusterVersion available: %s", condition(cv, "Progressing").Get("message").String())
			return true, nil
		}); err != nil {
			o.Expect(lastErr).NotTo(o.HaveOccurred())
			e2e.Logf("Last cluster version seen: %s", lastCV)
			if msg := condition(lastCV, "Failing").Get("message").String(); len(msg) > 0 {
				e2e.Logf("ClusterVersion is reporting a failure: %s", msg)
			}
			e2e.Failf("ClusterVersion never became available: %s", condition(lastCV, "Progressing").Get("message").String())
		}

		// gate on all clusteroperators being ready
		g.By(fmt.Sprintf("waiting for all cluster operators to be stable at the same time"))
		coc := dc.Resource(schema.GroupVersionResource{Group: "config.openshift.io", Resource: "clusteroperators", Version: "v1"})
		lastErr = nil
		var lastCOs []objx.Map
		wait.PollImmediate(time.Second, operatorWait, func() (bool, error) {
			obj, err := coc.List(context.Background(), metav1.ListOptions{})
			if err != nil {
				lastErr = err
				e2e.Logf("Unable to check for cluster operators: %v", err)
				return false, nil
			}
			cv := objx.Map(obj.UnstructuredContent())
			lastErr = nil
			items := objects(cv.Get("items"))
			lastCOs = items

			if len(items) == 0 {
				return false, nil
			}

			var unready []string
			for _, co := range items {
				badConditions, missingTypes := surprisingConditions(co)
				if len(badConditions) > 0 || len(missingTypes) > 0 {
					unready = append(unready, co.Get("metadata.name").String())
				}
			}
			if len(unready) > 0 {
				sort.Strings(unready)
				e2e.Logf("Operators still unready: %s", strings.Join(unready, ", "))
				return false, nil
			}
			return true, nil
		})

		o.Expect(lastErr).NotTo(o.HaveOccurred())
		ready := 0
		var unready []string
		buf := &bytes.Buffer{}
		w := tabwriter.NewWriter(buf, 0, 4, 1, ' ', 0)
		fmt.Fprintf(w, "NAME\tTYPE\tSTATUS\tREASON\tMESSAGE\n")
		for _, co := range lastCOs {
			name := co.Get("metadata.name").String()
			badConditions, missingTypes := surprisingConditions(co)
			if len(badConditions) > 0 {
				worstCondition := badConditions[0]
				unready = append(unready, fmt.Sprintf("%s (%s=%s %s: %s)",
					name,
					worstCondition.Type,
					worstCondition.Status,
					worstCondition.Reason,
					worstCondition.Message,
				))
				fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n",
					name,
					worstCondition.Type,
					worstCondition.Status,
					worstCondition.Reason,
					worstCondition.Message,
				)
			} else if len(missingTypes) > 0 {
				missingTypeStrings := make([]string, 0, len(missingTypes))
				for _, missingType := range missingTypes {
					missingTypeStrings = append(missingTypeStrings, string(missingType))
				}
				unready = append(unready, fmt.Sprintf("%s (missing: %s)", name, strings.Join(missingTypeStrings, ", ")))
			} else {
				ready++
			}
		}
		w.Flush()
		e2e.Logf("ClusterOperators:\n%s", buf.String())

		if len(unready) > 0 {
			sort.Strings(unready)
			e2e.Failf("Some cluster operators never became ready: %s", strings.Join(unready, ", "))
		}
		// Check at least one core operator is ready
		if ready == 0 {
			e2e.Failf("There must be at least one cluster operator")
		}
	})
})

var _ = g.Describe("[sig-arch] Managed cluster should", func() {
	defer g.GinkgoRecover()

	g.It("have operators on the cluster version", func() {
		if len(os.Getenv("TEST_UNSUPPORTED_ALLOW_VERSION_SKEW")) > 0 {
			e2eskipper.Skipf("Test is disabled to allow cluster components to have different versions")
		}
		cfg, err := e2e.LoadConfig()
		o.Expect(err).NotTo(o.HaveOccurred())
		c := configclient.NewForConfigOrDie(cfg)
		coreclient, err := e2e.LoadClientset()
		o.Expect(err).NotTo(o.HaveOccurred())

		// presence of the CVO namespace gates this test
		g.By("checking for the cluster version operator")
		skipUnlessCVO(coreclient.CoreV1().Namespaces())

		// we need to get the list of versions
		cv, err := c.ConfigV1().ClusterVersions().Get(context.Background(), "version", metav1.GetOptions{})
		o.Expect(err).NotTo(o.HaveOccurred())
		coList, err := c.ConfigV1().ClusterOperators().List(context.Background(), metav1.ListOptions{})
		o.Expect(err).NotTo(o.HaveOccurred())
		o.Expect(coList.Items).NotTo(o.BeEmpty())

		g.By("all cluster operators report an operator version in the first position equal to the cluster version")
		for _, co := range coList.Items {
			msg := fmt.Sprintf("unexpected operator status versions %s:\n%#v", co.Name, co.Status.Versions)
			o.Expect(co.Status.Versions).NotTo(o.BeEmpty(), msg)
			operator := findOperatorVersion(co.Status.Versions, "operator")
			o.Expect(operator).NotTo(o.BeNil(), msg)
			o.Expect(operator.Name).To(o.Equal("operator"), msg)
			o.Expect(operator.Version).To(o.Equal(cv.Status.Desired.Version), msg)
		}
	})
})

func skipUnlessCVO(c coreclient.NamespaceInterface) {
	err := wait.PollImmediate(time.Second, time.Minute, func() (bool, error) {
		_, err := c.Get(context.Background(), "openshift-cluster-version", metav1.GetOptions{})
		if err == nil {
			return true, nil
		}
		if errors.IsNotFound(err) {
			e2eskipper.Skipf("The cluster is not managed by a cluster-version operator")
		}
		e2e.Logf("Unable to check for cluster version operator: %v", err)
		return false, nil
	})
	o.Expect(err).NotTo(o.HaveOccurred())
}

func findOperatorVersion(versions []configv1.OperandVersion, name string) *configv1.OperandVersion {
	for i := range versions {
		if versions[i].Name == name {
			return &versions[i]
		}
	}
	return nil
}

func contains(names []string, name string) bool {
	for _, s := range names {
		if s == name {
			return true
		}
	}
	return false
}

func jsonString(from objx.Map) string {
	s, _ := from.JSON()
	return s
}

func objects(from *objx.Value) []objx.Map {
	var values []objx.Map
	switch {
	case from.IsObjxMapSlice():
		return from.ObjxMapSlice()
	case from.IsInterSlice():
		for _, i := range from.InterSlice() {
			if msi, ok := i.(map[string]interface{}); ok {
				values = append(values, objx.Map(msi))
			}
		}
	}
	return values
}

func condition(cv objx.Map, condition string) objx.Map {
	for _, obj := range objects(cv.Get("status.conditions")) {
		if obj.Get("type").String() == condition {
			return obj
		}
	}
	return objx.Map(nil)
}

// surprisingConditions returns conditions with surprising statuses
// (Available=False, Degraded=True, etc.) in order of descending
// severity (e.g. Available=False is more severe than Degraded=True).
// It also returns a slice of types for which a condition entry was
// expected but not supplied on the ClusterOperator.
func surprisingConditions(co objx.Map) ([]configv1.ClusterOperatorStatusCondition, []configv1.ClusterStatusConditionType) {
	var badConditions []configv1.ClusterOperatorStatusCondition
	var missingTypes []configv1.ClusterStatusConditionType
	for _, conditionType := range []configv1.ClusterStatusConditionType{
		configv1.OperatorAvailable,
		configv1.OperatorDegraded,
		configv1.OperatorProgressing,
	} {
		cond := condition(co, string(conditionType))
		if len(cond) == 0 {
			missingTypes = append(missingTypes, conditionType)
		} else {
			expected := configv1.ConditionFalse
			if conditionType == configv1.OperatorAvailable {
				expected = configv1.ConditionTrue
			}
			if cond.Get("status").String() != string(expected) {
				badConditions = append(badConditions, configv1.ClusterOperatorStatusCondition{
					Type:    conditionType,
					Status:  configv1.ConditionStatus(cond.Get("status").String()),
					Reason:  cond.Get("reason").String(),
					Message: cond.Get("message").String(),
				})
			}
		}
	}
	return badConditions, missingTypes
}
<commit_msg>test/extended/operators/operators: Don't worry about Progressing ClusterOperator<commit_after>package operators

import (
	"bytes"
	"context"
	"fmt"
	"os"
	"sort"
	"strings"
	"text/tabwriter"
	"time"

	g "github.com/onsi/ginkgo"
	o "github.com/onsi/gomega"
	"github.com/stretchr/objx"

	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/client-go/dynamic"
	coreclient "k8s.io/client-go/kubernetes/typed/core/v1"
	e2e "k8s.io/kubernetes/test/e2e/framework"
	e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper"

	configv1 "github.com/openshift/api/config/v1"
	configclient "github.com/openshift/client-go/config/clientset/versioned"
)

const (
	operatorWait = 1 * time.Minute
	cvoWait      = 5 * time.Minute
)

var _ = g.Describe("[sig-arch][Early] Managed cluster should", func() {
	defer g.GinkgoRecover()

	g.It("start all core operators", func() {
		cfg, err := e2e.LoadConfig()
		o.Expect(err).NotTo(o.HaveOccurred())
		c, err := e2e.LoadClientset()
		o.Expect(err).NotTo(o.HaveOccurred())
		dc, err := dynamic.NewForConfig(cfg)
		o.Expect(err).NotTo(o.HaveOccurred())

		// presence of the CVO namespace gates this test
		g.By("checking for the cluster version operator")
		skipUnlessCVO(c.CoreV1().Namespaces())

		g.By("waiting for the cluster version to be applied")
		cvc := dc.Resource(schema.GroupVersionResource{Group: "config.openshift.io", Resource: "clusterversions", Version: "v1"})
		var lastErr error
		var lastCV objx.Map
		if err := wait.PollImmediate(3*time.Second, cvoWait, func() (bool, error) {
			obj, err := cvc.Get(context.Background(), "version", metav1.GetOptions{})
			if err != nil {
				lastErr = err
				e2e.Logf("Unable to check for cluster version: %v", err)
				return false, nil
			}
			cv := objx.Map(obj.UnstructuredContent())
			lastErr = nil
			lastCV = cv
			if cond := condition(cv, "Progressing"); cond.Get("status").String() != "False" {
				e2e.Logf("ClusterVersion is still progressing: %s", cond.Get("message").String())
				return false, nil
			}
			if cond := condition(cv, "Available"); cond.Get("status").String() != "True" {
				e2e.Logf("ClusterVersion is not available: %s", cond.Get("message").String())
				return false, nil
			}
			e2e.Logf("ClusterVersion available: %s", condition(cv, "Progressing").Get("message").String())
			return true, nil
		}); err != nil {
			o.Expect(lastErr).NotTo(o.HaveOccurred())
			e2e.Logf("Last cluster version seen: %s", lastCV)
			if msg := condition(lastCV, "Failing").Get("message").String(); len(msg) > 0 {
				e2e.Logf("ClusterVersion is reporting a failure: %s", msg)
			}
			e2e.Failf("ClusterVersion never became available: %s", condition(lastCV, "Progressing").Get("message").String())
		}

		// gate on all clusteroperators being ready
		g.By(fmt.Sprintf("waiting for all cluster operators to be stable at the same time"))
		coc := dc.Resource(schema.GroupVersionResource{Group: "config.openshift.io", Resource: "clusteroperators", Version: "v1"})
		lastErr = nil
		var lastCOs []objx.Map
		wait.PollImmediate(time.Second, operatorWait, func() (bool, error) {
			obj, err := coc.List(context.Background(), metav1.ListOptions{})
			if err != nil {
				lastErr = err
				e2e.Logf("Unable to check for cluster operators: %v", err)
				return false, nil
			}
			cv := objx.Map(obj.UnstructuredContent())
			lastErr = nil
			items := objects(cv.Get("items"))
			lastCOs = items

			if len(items) == 0 {
				return false, nil
			}

			var unready []string
			for _, co := range items {
				badConditions, missingTypes := surprisingConditions(co)
				if len(badConditions) > 0 || len(missingTypes) > 0 {
					unready = append(unready, co.Get("metadata.name").String())
				}
			}
			if len(unready) > 0 {
				sort.Strings(unready)
				e2e.Logf("Operators still unready: %s", strings.Join(unready, ", "))
				return false, nil
			}
			return true, nil
		})

		o.Expect(lastErr).NotTo(o.HaveOccurred())
		ready := 0
		var unready []string
		buf := &bytes.Buffer{}
		w := tabwriter.NewWriter(buf, 0, 4, 1, ' ', 0)
		fmt.Fprintf(w, "NAME\tTYPE\tSTATUS\tREASON\tMESSAGE\n")
		for _, co := range lastCOs {
			name := co.Get("metadata.name").String()
			badConditions, missingTypes := surprisingConditions(co)
			if len(badConditions) > 0 {
				worstCondition := badConditions[0]
				unready = append(unready, fmt.Sprintf("%s (%s=%s %s: %s)",
					name,
					worstCondition.Type,
					worstCondition.Status,
					worstCondition.Reason,
					worstCondition.Message,
				))
				fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n",
					name,
					worstCondition.Type,
					worstCondition.Status,
					worstCondition.Reason,
					worstCondition.Message,
				)
			} else if len(missingTypes) > 0 {
				missingTypeStrings := make([]string, 0, len(missingTypes))
				for _, missingType := range missingTypes {
					missingTypeStrings = append(missingTypeStrings, string(missingType))
				}
				unready = append(unready, fmt.Sprintf("%s (missing: %s)", name, strings.Join(missingTypeStrings, ", ")))
			} else {
				ready++
			}
		}
		w.Flush()
		e2e.Logf("ClusterOperators:\n%s", buf.String())

		if len(unready) > 0 {
			sort.Strings(unready)
			e2e.Failf("Some cluster operators never became ready: %s", strings.Join(unready, ", "))
		}
		// Check at least one core operator is ready
		if ready == 0 {
			e2e.Failf("There must be at least one cluster operator")
		}
	})
})

var _ = g.Describe("[sig-arch] Managed cluster should", func() {
	defer g.GinkgoRecover()

	g.It("have operators on the cluster version", func() {
		if len(os.Getenv("TEST_UNSUPPORTED_ALLOW_VERSION_SKEW")) > 0 {
			e2eskipper.Skipf("Test is disabled to allow cluster components to have different versions")
		}
		cfg, err := e2e.LoadConfig()
		o.Expect(err).NotTo(o.HaveOccurred())
		c := configclient.NewForConfigOrDie(cfg)
		coreclient, err := e2e.LoadClientset()
		o.Expect(err).NotTo(o.HaveOccurred())

		// presence of the CVO namespace gates this test
		g.By("checking for the cluster version operator")
		skipUnlessCVO(coreclient.CoreV1().Namespaces())

		// we need to get the list of versions
		cv, err := c.ConfigV1().ClusterVersions().Get(context.Background(), "version", metav1.GetOptions{})
		o.Expect(err).NotTo(o.HaveOccurred())
		coList, err := c.ConfigV1().ClusterOperators().List(context.Background(), metav1.ListOptions{})
		o.Expect(err).NotTo(o.HaveOccurred())
		o.Expect(coList.Items).NotTo(o.BeEmpty())

		g.By("all cluster operators report an operator version in the first position equal to the cluster version")
		for _, co := range coList.Items {
			msg := fmt.Sprintf("unexpected operator status versions %s:\n%#v", co.Name, co.Status.Versions)
			o.Expect(co.Status.Versions).NotTo(o.BeEmpty(), msg)
			operator := findOperatorVersion(co.Status.Versions, "operator")
			o.Expect(operator).NotTo(o.BeNil(), msg)
			o.Expect(operator.Name).To(o.Equal("operator"), msg)
			o.Expect(operator.Version).To(o.Equal(cv.Status.Desired.Version), msg)
		}
	})
})

func skipUnlessCVO(c coreclient.NamespaceInterface) {
	err := wait.PollImmediate(time.Second, time.Minute, func() (bool, error) {
		_, err := c.Get(context.Background(), "openshift-cluster-version", metav1.GetOptions{})
		if err == nil {
			return true, nil
		}
		if errors.IsNotFound(err) {
			e2eskipper.Skipf("The cluster is not managed by a cluster-version operator")
		}
		e2e.Logf("Unable to check for cluster version operator: %v", err)
		return false, nil
	})
	o.Expect(err).NotTo(o.HaveOccurred())
}

func findOperatorVersion(versions []configv1.OperandVersion, name string) *configv1.OperandVersion {
	for i := range versions {
		if versions[i].Name == name {
			return &versions[i]
		}
	}
	return nil
}

func contains(names []string, name string) bool {
	for _, s := range names {
		if s == name {
			return true
		}
	}
	return false
}

func jsonString(from objx.Map) string {
	s, _ := from.JSON()
	return s
}

func objects(from *objx.Value) []objx.Map {
	var values []objx.Map
	switch {
	case from.IsObjxMapSlice():
		return from.ObjxMapSlice()
	case from.IsInterSlice():
		for _, i := range from.InterSlice() {
			if msi, ok := i.(map[string]interface{}); ok {
				values = append(values, objx.Map(msi))
			}
		}
	}
	return values
}

func condition(cv objx.Map, condition string) objx.Map {
	for _, obj := range objects(cv.Get("status.conditions")) {
		if obj.Get("type").String() == condition {
			return obj
		}
	}
	return objx.Map(nil)
}

// surprisingConditions returns conditions with surprising statuses
// (Available=False, Degraded=True, etc.) in order of descending
// severity (e.g. Available=False is more severe than Degraded=True).
// It also returns a slice of types for which a condition entry was
// expected but not supplied on the ClusterOperator.
func surprisingConditions(co objx.Map) ([]configv1.ClusterOperatorStatusCondition, []configv1.ClusterStatusConditionType) {
	var badConditions []configv1.ClusterOperatorStatusCondition
	var missingTypes []configv1.ClusterStatusConditionType
	for _, conditionType := range []configv1.ClusterStatusConditionType{
		configv1.OperatorAvailable,
		configv1.OperatorDegraded,
	} {
		cond := condition(co, string(conditionType))
		if len(cond) == 0 {
			missingTypes = append(missingTypes, conditionType)
		} else {
			expected := configv1.ConditionFalse
			if conditionType == configv1.OperatorAvailable {
				expected = configv1.ConditionTrue
			}
			if cond.Get("status").String() != string(expected) {
				badConditions = append(badConditions, configv1.ClusterOperatorStatusCondition{
					Type:    conditionType,
					Status:  configv1.ConditionStatus(cond.Get("status").String()),
					Reason:  cond.Get("reason").String(),
					Message: cond.Get("message").String(),
				})
			}
		}
	}
	return badConditions, missingTypes
}
<|endoftext|>