<commit_before>package geometries

import (
	"github.com/go-gl/mathgl/mgl32"
	three "github.com/tobscher/go-three"
)

// Use struct composition
type Box struct {
	geometry three.Geometry

	width  float32
	height float32
	depth  float32
}

func NewBox(width, height, depth float32) *Box {
	box := Box{
		width:  width,
		height: height,
		depth:  depth,
	}

	vertices := make([]mgl32.Vec3, 0)
	vertexUvs := boxUvs()

	halfWidth := width / 2.0
	halfHeight := height / 2.0
	halfDepth := depth / 2.0

	// Bottom plane
	vertices = append(vertices, buildPlane(
		mgl32.Vec3{0 + halfWidth, 0 - halfHeight, 0 + halfDepth},
		mgl32.Vec3{0 - halfWidth, 0 - halfHeight, 0 + halfDepth},
		mgl32.Vec3{0 + halfWidth, 0 - halfHeight, 0 - halfDepth},
		mgl32.Vec3{0 - halfWidth, 0 - halfHeight, 0 - halfDepth},
	)...)

	// Side 1
	vertices = append(vertices, buildPlane(
		mgl32.Vec3{0 + halfWidth, 0 - halfHeight, 0 - halfDepth},
		mgl32.Vec3{0 - halfWidth, 0 - halfHeight, 0 - halfDepth},
		mgl32.Vec3{0 + halfWidth, 0 + halfHeight, 0 - halfDepth},
		mgl32.Vec3{0 - halfWidth, 0 + halfHeight, 0 - halfDepth},
	)...)

	// Side 2
	vertices = append(vertices, buildPlane(
		mgl32.Vec3{0 - halfWidth, 0 - halfHeight, 0 - halfDepth},
		mgl32.Vec3{0 - halfWidth, 0 - halfHeight, 0 + halfDepth},
		mgl32.Vec3{0 - halfWidth, 0 + halfHeight, 0 - halfDepth},
		mgl32.Vec3{0 - halfWidth, 0 + halfHeight, 0 + halfDepth},
	)...)

	// // Side 3
	vertices = append(vertices, buildPlane(
		mgl32.Vec3{0 + halfWidth, 0 - halfHeight, 0 + halfDepth},
		mgl32.Vec3{0 + halfWidth, 0 - halfHeight, 0 - halfDepth},
		mgl32.Vec3{0 + halfWidth, 0 + halfHeight, 0 + halfDepth},
		mgl32.Vec3{0 + halfWidth, 0 + halfHeight, 0 - halfDepth},
	)...)

	// // Side 4
	vertices = append(vertices, buildPlane(
		mgl32.Vec3{0 - halfWidth, 0 - halfHeight, 0 + halfDepth},
		mgl32.Vec3{0 + halfWidth, 0 - halfHeight, 0 + halfDepth},
		mgl32.Vec3{0 - halfWidth, 0 + halfHeight, 0 + halfDepth},
		mgl32.Vec3{0 + halfWidth, 0 + halfHeight, 0 + halfDepth},
	)...)

	// Top plane
	vertices = append(vertices, buildPlane(
		mgl32.Vec3{0 - halfWidth, 0 + halfHeight, 0 + halfDepth},
		mgl32.Vec3{0 + halfWidth, 0 + halfHeight, 0 + halfDepth},
		mgl32.Vec3{0 - halfWidth, 0 + halfHeight, 0 - halfDepth},
		mgl32.Vec3{0 + halfWidth, 0 + halfHeight, 0 - halfDepth},
	)...)

	box.geometry.Vertices = vertices
	box.geometry.VertexUvs = vertexUvs

	return &box
}

func NewCube(size float32) *Box {
	return NewBox(size, size, size)
}

func (b *Box) Vertices() []mgl32.Vec3 {
	return b.geometry.Vertices
}

func (b *Box) VertexUvs() []mgl32.Vec2 {
	return b.geometry.VertexUvs
}

func buildPlane(v1, v2, v3, v4 mgl32.Vec3) []mgl32.Vec3 {
	return []mgl32.Vec3{
		v1,
		v4,
		v3,
		v1,
		v2,
		v4,
	}
}

func boxUvs() []mgl32.Vec2 {
	result := []mgl32.Vec2{}

	for i := 0; i < 6; i++ {
		result = append(result,
			mgl32.Vec2{1, 1},
			mgl32.Vec2{0, 0},
			mgl32.Vec2{1, 0},

			mgl32.Vec2{1, 1},
			mgl32.Vec2{0, 1},
			mgl32.Vec2{0, 0},
		)
	}

	return result
}
<commit_msg>updated geometry documentation<commit_after>package geometries

import (
	"github.com/go-gl/mathgl/mgl32"
	three "github.com/tobscher/go-three"
)

// Box defines a box geometry consisting of 6 faces
type Box struct {
	geometry three.Geometry

	width  float32
	height float32
	depth  float32
}

// NewBox creates a new Box with the given width, height and depth.
// This method will generate the required vertices and its uv mappings.
func NewBox(width, height, depth float32) *Box {
	box := Box{
		width:  width,
		height: height,
		depth:  depth,
	}

	var vertices []mgl32.Vec3
	vertexUvs := boxUvs()

	halfWidth := width / 2.0
	halfHeight := height / 2.0
	halfDepth := depth / 2.0

	// Bottom plane
	vertices = append(vertices, buildPlane(
		mgl32.Vec3{0 + halfWidth, 0 - halfHeight, 0 + halfDepth},
		mgl32.Vec3{0 - halfWidth, 0 - halfHeight, 0 + halfDepth},
		mgl32.Vec3{0 + halfWidth, 0 - halfHeight, 0 - halfDepth},
		mgl32.Vec3{0 - halfWidth, 0 - halfHeight, 0 - halfDepth},
	)...)

	// Side 1
	vertices = append(vertices, buildPlane(
		mgl32.Vec3{0 + halfWidth, 0 - halfHeight, 0 - halfDepth},
		mgl32.Vec3{0 - halfWidth, 0 - halfHeight, 0 - halfDepth},
		mgl32.Vec3{0 + halfWidth, 0 + halfHeight, 0 - halfDepth},
		mgl32.Vec3{0 - halfWidth, 0 + halfHeight, 0 - halfDepth},
	)...)

	// Side 2
	vertices = append(vertices, buildPlane(
		mgl32.Vec3{0 - halfWidth, 0 - halfHeight, 0 - halfDepth},
		mgl32.Vec3{0 - halfWidth, 0 - halfHeight, 0 + halfDepth},
		mgl32.Vec3{0 - halfWidth, 0 + halfHeight, 0 - halfDepth},
		mgl32.Vec3{0 - halfWidth, 0 + halfHeight, 0 + halfDepth},
	)...)

	// // Side 3
	vertices = append(vertices, buildPlane(
		mgl32.Vec3{0 + halfWidth, 0 - halfHeight, 0 + halfDepth},
		mgl32.Vec3{0 + halfWidth, 0 - halfHeight, 0 - halfDepth},
		mgl32.Vec3{0 + halfWidth, 0 + halfHeight, 0 + halfDepth},
		mgl32.Vec3{0 + halfWidth, 0 + halfHeight, 0 - halfDepth},
	)...)

	// // Side 4
	vertices = append(vertices, buildPlane(
		mgl32.Vec3{0 - halfWidth, 0 - halfHeight, 0 + halfDepth},
		mgl32.Vec3{0 + halfWidth, 0 - halfHeight, 0 + halfDepth},
		mgl32.Vec3{0 - halfWidth, 0 + halfHeight, 0 + halfDepth},
		mgl32.Vec3{0 + halfWidth, 0 + halfHeight, 0 + halfDepth},
	)...)

	// Top plane
	vertices = append(vertices, buildPlane(
		mgl32.Vec3{0 - halfWidth, 0 + halfHeight, 0 + halfDepth},
		mgl32.Vec3{0 + halfWidth, 0 + halfHeight, 0 + halfDepth},
		mgl32.Vec3{0 - halfWidth, 0 + halfHeight, 0 - halfDepth},
		mgl32.Vec3{0 + halfWidth, 0 + halfHeight, 0 - halfDepth},
	)...)

	box.geometry.Vertices = vertices
	box.geometry.VertexUvs = vertexUvs

	return &box
}

// NewCube generates a new Box for the given side.
// Vertices and VertexUvs will be created accordingly.
func NewCube(size float32) *Box {
	return NewBox(size, size, size)
}

// Vertices returns the list of used vertices to create a box geometry.
func (b *Box) Vertices() []mgl32.Vec3 {
	return b.geometry.Vertices
}

// VertexUvs returns the uv mapping for each vertex.
func (b *Box) VertexUvs() []mgl32.Vec2 {
	return b.geometry.VertexUvs
}

func buildPlane(v1, v2, v3, v4 mgl32.Vec3) []mgl32.Vec3 {
	return []mgl32.Vec3{
		v1,
		v4,
		v3,
		v1,
		v2,
		v4,
	}
}

func boxUvs() []mgl32.Vec2 {
	result := []mgl32.Vec2{}

	for i := 0; i < 6; i++ {
		result = append(result,
			mgl32.Vec2{1, 1},
			mgl32.Vec2{0, 0},
			mgl32.Vec2{1, 0},

			mgl32.Vec2{1, 1},
			mgl32.Vec2{0, 1},
			mgl32.Vec2{0, 0},
		)
	}

	return result
}
<|endoftext|>


<commit_before>// osop
// Copyright (C) 2014 Karol 'Kenji Takahashi' Woźniak
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

package main

import (
	"fmt"
	"log"
	"strings"
	"time"

	"github.com/pyk/byten"
	"github.com/shirou/gopsutil"
)

func bytonizeUint(i uint64, speed, short bool) string {
	b := byten.Size(int64(i))
	if short {
		p := b[len(b)-2]
		if p < '0' || p > '9' {
			b = b[:len(b)-1]
		}
	}
	if speed {
		b += "/s"
	}
	return b
}

type Sys struct {
	metrics []string
	shorts  bool

	downloaded map[string]uint64
	uploaded   map[string]uint64
	interval   float64
}

type sysResponseNetwork struct {
	Sent     string
	Recv     string
	Download string
	Upload   string
}

type sysResponse struct {
	CPU struct {
		Percent map[string]string
	}
	Uptime uint64
	Memory struct {
		Total string
		UsedF string
		UsedA string
	}
	Swap struct {
		Total string
		Used  string
	}
	Network map[string]sysResponseNetwork
}

func (s *Sys) Get() (interface{}, error) {
	resp := sysResponse{}
	var err error
	for _, metric := range s.metrics {
		split := strings.Split(strings.ToLower(metric), " ")
		switch split[0] {
		case "cpu":
			if len(split) < 2 {
				err = fmt.Errorf("Sys: `cpu` requires argument")
			}
			switch split[1] {
			case "percent":
				var cpupercents []float32
				if len(split) < 3 || split[2] == "false" {
					cpupercents, err = gopsutil.CPUPercent(0, false)
				} else if split[2] == "true" {
					cpupercents, err = gopsutil.CPUPercent(0, true)
				} else {
					err = fmt.Errorf("Sys: `cpu percent` got wrong argument")
					break
				}
				resp.CPU.Percent = make(map[string]string)
				for i, cpupercent := range cpupercents {
					resp.CPU.Percent[fmt.Sprintf("cpu%d", i)] = fmt.Sprintf("%.2f%%", cpupercent)
				}
			}
		case "uptime":
			resp.Uptime, err = gopsutil.BootTime()
		case "memory":
			var mem *gopsutil.VirtualMemoryStat
			mem, err = gopsutil.VirtualMemory()
			resp.Memory.Total = bytonizeUint(mem.Total, false, s.shorts)
			resp.Memory.UsedF = bytonizeUint(mem.Used, false, s.shorts)
			resp.Memory.UsedA = bytonizeUint(mem.Total-mem.Available, false, s.shorts)
		case "swap":
			var mem *gopsutil.SwapMemoryStat
			mem, err = gopsutil.SwapMemory()
			resp.Swap.Total = bytonizeUint(mem.Total, false, s.shorts)
			resp.Swap.Used = bytonizeUint(mem.Used, false, s.shorts)
		case "network":
			var nic []gopsutil.NetIOCountersStat
			if len(split) < 2 || strings.ToLower(split[1]) == "all" {
				// FIXME: Returns eth0 only, seems gopsutil bug
				//nic, err = gopsutil.NetIOCounters(false)
				//if err != nil || len(nic) == 0 {
				//break
				//}
				//resp.Network = map[string]gopsutil.NetIOCountersStat{"All": nic[0]}
			} else {
				nic, err = gopsutil.NetIOCounters(true)
				if err != nil || len(nic) == 0 {
					break
				}
				resp.Network = make(map[string]sysResponseNetwork)
				for _, iface := range split[1:] {
					resp.Network[iface] = s.getNetworkByName(nic, iface)
				}
			}
		}
		if err != nil {
			log.Printf("Sys: Cannot get `%s`: `%s`\n", metric, err)
		}
	}

	return resp, nil
}

func (s *Sys) getNetworkByName(
	nices []gopsutil.NetIOCountersStat,
	name string,
) sysResponseNetwork {
	net := sysResponseNetwork{}
	for _, nic := range nices {
		if nic.Name == name {
			net.Sent = bytonizeUint(nic.BytesSent, false, s.shorts)
			net.Recv = bytonizeUint(nic.BytesRecv, false, s.shorts)
			net.Download = bytonizeUint(
				uint64((float64(nic.BytesRecv)-float64(s.downloaded[name]))/s.interval),
				true, s.shorts,
			)
			s.downloaded[name] = nic.BytesRecv
			net.Upload = bytonizeUint(
				uint64((float64(nic.BytesSent)-float64(s.uploaded[name]))/s.interval),
				true, s.shorts,
			)
			s.uploaded[name] = nic.BytesSent
		}
	}
	return net
}

func NewSys(config config) (interface{}, error) {
	if config["metrics"] == nil {
		return nil, fmt.Errorf("")
	}
	metrics := config["metrics"].([]interface{})
	s := &Sys{
		metrics:    make([]string, len(metrics)),
		downloaded: make(map[string]uint64),
		uploaded:   make(map[string]uint64),
	}
	for i, metric := range metrics {
		s.metrics[i] = metric.(string)
	}

	interval, _ := time.ParseDuration(config["pollInterval"].(string))
	s.interval = interval.Seconds()

	return s, nil
}

func init() {
	registry.AddReceiver("Sys", NewSys)
}
<commit_msg>Sys: take 'shorts' into account<commit_after>// osop
// Copyright (C) 2014 Karol 'Kenji Takahashi' Woźniak
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

package main

import (
	"fmt"
	"log"
	"strings"
	"time"

	"github.com/pyk/byten"
	"github.com/shirou/gopsutil"
)

func bytonizeUint(i uint64, speed, short bool) string {
	b := byten.Size(int64(i))
	if short {
		p := b[len(b)-2]
		if p < '0' || p > '9' {
			b = b[:len(b)-1]
		}
	}
	if speed {
		b += "/s"
	}
	return b
}

type Sys struct {
	metrics []string
	shorts  bool

	downloaded map[string]uint64
	uploaded   map[string]uint64
	interval   float64
}

type sysResponseNetwork struct {
	Sent     string
	Recv     string
	Download string
	Upload   string
}

type sysResponse struct {
	CPU struct {
		Percent map[string]string
	}
	Uptime uint64
	Memory struct {
		Total string
		UsedF string
		UsedA string
	}
	Swap struct {
		Total string
		Used  string
	}
	Network map[string]sysResponseNetwork
}

func (s *Sys) Get() (interface{}, error) {
	resp := sysResponse{}
	var err error
	for _, metric := range s.metrics {
		split := strings.Split(strings.ToLower(metric), " ")
		switch split[0] {
		case "cpu":
			if len(split) < 2 {
				err = fmt.Errorf("Sys: `cpu` requires argument")
			}
			switch split[1] {
			case "percent":
				var cpupercents []float32
				if len(split) < 3 || split[2] == "false" {
					cpupercents, err = gopsutil.CPUPercent(0, false)
				} else if split[2] == "true" {
					cpupercents, err = gopsutil.CPUPercent(0, true)
				} else {
					err = fmt.Errorf("Sys: `cpu percent` got wrong argument")
					break
				}
				resp.CPU.Percent = make(map[string]string)
				for i, cpupercent := range cpupercents {
					resp.CPU.Percent[fmt.Sprintf("cpu%d", i)] = fmt.Sprintf("%.2f%%", cpupercent)
				}
			}
		case "uptime":
			resp.Uptime, err = gopsutil.BootTime()
		case "memory":
			var mem *gopsutil.VirtualMemoryStat
			mem, err = gopsutil.VirtualMemory()
			resp.Memory.Total = bytonizeUint(mem.Total, false, s.shorts)
			resp.Memory.UsedF = bytonizeUint(mem.Used, false, s.shorts)
			resp.Memory.UsedA = bytonizeUint(mem.Total-mem.Available, false, s.shorts)
		case "swap":
			var mem *gopsutil.SwapMemoryStat
			mem, err = gopsutil.SwapMemory()
			resp.Swap.Total = bytonizeUint(mem.Total, false, s.shorts)
			resp.Swap.Used = bytonizeUint(mem.Used, false, s.shorts)
		case "network":
			var nic []gopsutil.NetIOCountersStat
			if len(split) < 2 || strings.ToLower(split[1]) == "all" {
				// FIXME: Returns eth0 only, seems gopsutil bug
				//nic, err = gopsutil.NetIOCounters(false)
				//if err != nil || len(nic) == 0 {
				//break
				//}
				//resp.Network = map[string]gopsutil.NetIOCountersStat{"All": nic[0]}
			} else {
				nic, err = gopsutil.NetIOCounters(true)
				if err != nil || len(nic) == 0 {
					break
				}
				resp.Network = make(map[string]sysResponseNetwork)
				for _, iface := range split[1:] {
					resp.Network[iface] = s.getNetworkByName(nic, iface)
				}
			}
		}
		if err != nil {
			log.Printf("Sys: Cannot get `%s`: `%s`\n", metric, err)
		}
	}

	return resp, nil
}

func (s *Sys) getNetworkByName(
	nices []gopsutil.NetIOCountersStat,
	name string,
) sysResponseNetwork {
	net := sysResponseNetwork{}
	for _, nic := range nices {
		if nic.Name == name {
			net.Sent = bytonizeUint(nic.BytesSent, false, s.shorts)
			net.Recv = bytonizeUint(nic.BytesRecv, false, s.shorts)
			net.Download = bytonizeUint(
				uint64((float64(nic.BytesRecv)-float64(s.downloaded[name]))/s.interval),
				true, s.shorts,
			)
			s.downloaded[name] = nic.BytesRecv
			net.Upload = bytonizeUint(
				uint64((float64(nic.BytesSent)-float64(s.uploaded[name]))/s.interval),
				true, s.shorts,
			)
			s.uploaded[name] = nic.BytesSent
		}
	}
	return net
}

func NewSys(config config) (interface{}, error) {
	if config["metrics"] == nil {
		return nil, fmt.Errorf("Metrics parameter is required for Sys receiver")
	}
	metrics := config["metrics"].([]interface{})
	s := &Sys{
		metrics:    make([]string, len(metrics)),
		downloaded: make(map[string]uint64),
		uploaded:   make(map[string]uint64),
	}
	for i, metric := range metrics {
		s.metrics[i] = metric.(string)
	}

	interval, _ := time.ParseDuration(config["pollInterval"].(string))
	s.interval = interval.Seconds()

	if config["shorts"] != nil {
		s.shorts = config["shorts"].(bool)
	}

	return s, nil
}

func init() {
	registry.AddReceiver("Sys", NewSys)
}
<|endoftext|>


<commit_before>/*
Copyright 2016 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 common

import (
	"context"
	"encoding/json"
	"fmt"
	"time"

	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/util/uuid"
	watch "k8s.io/apimachinery/pkg/watch"
	"k8s.io/client-go/dynamic"
	"k8s.io/client-go/tools/cache"
	watchtools "k8s.io/client-go/tools/watch"
	"k8s.io/kubernetes/test/e2e/framework"
	imageutils "k8s.io/kubernetes/test/utils/image"

	"github.com/onsi/ginkgo"
)

var _ = ginkgo.Describe("[sig-node] ConfigMap", func() {
	f := framework.NewDefaultFramework("configmap")

	var dc dynamic.Interface

	ginkgo.BeforeEach(func() {
		dc = f.DynamicClient
	})

	/*
		Release : v1.9
		Testname: ConfigMap, from environment field
		Description: Create a Pod with an environment variable value set using a value from ConfigMap. A ConfigMap value MUST be accessible in the container environment.
	*/
	framework.ConformanceIt("should be consumable via environment variable [NodeConformance]", func() {
		name := "configmap-test-" + string(uuid.NewUUID())
		configMap := newConfigMap(f, name)
		ginkgo.By(fmt.Sprintf("Creating configMap %v/%v", f.Namespace.Name, configMap.Name))
		var err error
		if configMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(context.TODO(), configMap, metav1.CreateOptions{}); err != nil {
			framework.Failf("unable to create test configMap %s: %v", configMap.Name, err)
		}

		pod := &v1.Pod{
			ObjectMeta: metav1.ObjectMeta{
				Name: "pod-configmaps-" + string(uuid.NewUUID()),
			},
			Spec: v1.PodSpec{
				Containers: []v1.Container{
					{
						Name:    "env-test",
						Image:   imageutils.GetE2EImage(imageutils.BusyBox),
						Command: []string{"sh", "-c", "env"},
						Env: []v1.EnvVar{
							{
								Name: "CONFIG_DATA_1",
								ValueFrom: &v1.EnvVarSource{
									ConfigMapKeyRef: &v1.ConfigMapKeySelector{
										LocalObjectReference: v1.LocalObjectReference{
											Name: name,
										},
										Key: "data-1",
									},
								},
							},
						},
					},
				},
				RestartPolicy: v1.RestartPolicyNever,
			},
		}

		f.TestContainerOutput("consume configMaps", pod, 0, []string{
			"CONFIG_DATA_1=value-1",
		})
	})

	/*
		Release: v1.9
		Testname: ConfigMap, from environment variables
		Description: Create a Pod with a environment source from ConfigMap. All ConfigMap values MUST be available as environment variables in the container.
	*/
	framework.ConformanceIt("should be consumable via the environment [NodeConformance]", func() {
		name := "configmap-test-" + string(uuid.NewUUID())
		configMap := newEnvFromConfigMap(f, name)
		ginkgo.By(fmt.Sprintf("Creating configMap %v/%v", f.Namespace.Name, configMap.Name))
		var err error
		if configMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(context.TODO(), configMap, metav1.CreateOptions{}); err != nil {
			framework.Failf("unable to create test configMap %s: %v", configMap.Name, err)
		}

		pod := &v1.Pod{
			ObjectMeta: metav1.ObjectMeta{
				Name: "pod-configmaps-" + string(uuid.NewUUID()),
			},
			Spec: v1.PodSpec{
				Containers: []v1.Container{
					{
						Name:    "env-test",
						Image:   imageutils.GetE2EImage(imageutils.BusyBox),
						Command: []string{"sh", "-c", "env"},
						EnvFrom: []v1.EnvFromSource{
							{
								ConfigMapRef: &v1.ConfigMapEnvSource{LocalObjectReference: v1.LocalObjectReference{Name: name}},
							},
							{
								Prefix:       "p_",
								ConfigMapRef: &v1.ConfigMapEnvSource{LocalObjectReference: v1.LocalObjectReference{Name: name}},
							},
						},
					},
				},
				RestartPolicy: v1.RestartPolicyNever,
			},
		}

		f.TestContainerOutput("consume configMaps", pod, 0, []string{
			"data_1=value-1", "data_2=value-2", "data_3=value-3",
			"p_data_1=value-1", "p_data_2=value-2", "p_data_3=value-3",
		})
	})

	/*
	   Release : v1.14
	   Testname: ConfigMap, with empty-key
	   Description: Attempt to create a ConfigMap with an empty key. The creation MUST fail.
	*/
	framework.ConformanceIt("should fail to create ConfigMap with empty key", func() {
		configMap, err := newConfigMapWithEmptyKey(f)
		framework.ExpectError(err, "created configMap %q with empty key in namespace %q", configMap.Name, f.Namespace.Name)
	})

	ginkgo.It("should update ConfigMap successfully", func() {
		name := "configmap-test-" + string(uuid.NewUUID())
		configMap := newConfigMap(f, name)
		ginkgo.By(fmt.Sprintf("Creating ConfigMap %v/%v", f.Namespace.Name, configMap.Name))
		_, err := f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(context.TODO(), configMap, metav1.CreateOptions{})
		framework.ExpectNoError(err, "failed to create ConfigMap")

		configMap.Data = map[string]string{
			"data": "value",
		}
		ginkgo.By(fmt.Sprintf("Updating configMap %v/%v", f.Namespace.Name, configMap.Name))
		_, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Update(context.TODO(), configMap, metav1.UpdateOptions{})
		framework.ExpectNoError(err, "failed to update ConfigMap")

		configMapFromUpdate, err := f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Get(context.TODO(), name, metav1.GetOptions{})
		framework.ExpectNoError(err, "failed to get ConfigMap")
		ginkgo.By(fmt.Sprintf("Verifying update of ConfigMap %v/%v", f.Namespace.Name, configMap.Name))
		framework.ExpectEqual(configMapFromUpdate.Data, configMap.Data)
	})

	ginkgo.It("should run through a ConfigMap lifecycle", func() {
		testNamespaceName := f.Namespace.Name
		testConfigMapName := "test-configmap" + string(uuid.NewUUID())

		testConfigMap := v1.ConfigMap{
			ObjectMeta: metav1.ObjectMeta{
				Name: testConfigMapName,
				Labels: map[string]string{
					"test-configmap-static": "true",
				},
			},
			Data: map[string]string{
				"valueName": "value",
			},
		}

		w := &cache.ListWatch{
			WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
				options.LabelSelector = "test-configmap-static=true"
				return f.ClientSet.CoreV1().ConfigMaps(testNamespaceName).Watch(context.TODO(), options)
			},
		}
		cml, err := f.ClientSet.CoreV1().ConfigMaps(testNamespaceName).List(context.TODO(), metav1.ListOptions{LabelSelector: "test-configmap-static=true"})
		framework.ExpectNoError(err)

		ginkgo.By("creating a ConfigMap")
		_, err = f.ClientSet.CoreV1().ConfigMaps(testNamespaceName).Create(context.TODO(), &testConfigMap, metav1.CreateOptions{})
		framework.ExpectNoError(err, "failed to create ConfigMap")

		ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
		defer cancel()
		_, err = watchtools.Until(ctx, cml.ResourceVersion, w, func(event watch.Event) (bool, error) {
			switch event.Type {
			case watch.Added:
				if cm, ok := event.Object.(*v1.ConfigMap); ok {
					found := cm.ObjectMeta.Name == testConfigMap.Name &&
						cm.Labels["test-configmap-static"] == "true" &&
						cm.Data["valueName"] == "value"
					return found, nil
				}
			default:
				framework.Logf("observed event type %v", event.Type)
			}
			return false, nil
		})
		framework.ExpectNoError(err, "failed to see a watch.Added event for the configmap we created")

		configMapPatchPayload, err := json.Marshal(v1.ConfigMap{
			ObjectMeta: metav1.ObjectMeta{
				Labels: map[string]string{
					"test-configmap": "patched",
				},
			},
			Data: map[string]string{
				"valueName": "value1",
			},
		})
		framework.ExpectNoError(err, "failed to marshal patch data")

		ginkgo.By("patching the ConfigMap")
		_, err = f.ClientSet.CoreV1().ConfigMaps(testNamespaceName).Patch(context.TODO(), testConfigMapName, types.StrategicMergePatchType, []byte(configMapPatchPayload), metav1.PatchOptions{})
		framework.ExpectNoError(err, "failed to patch ConfigMap")
		ginkgo.By("waiting for the ConfigMap to be modified")
		ctx, cancel = context.WithTimeout(context.Background(), 30*time.Second)
		defer cancel()
		_, err = watchtools.Until(ctx, cml.ResourceVersion, w, func(event watch.Event) (bool, error) {
			switch event.Type {
			case watch.Modified:
				if cm, ok := event.Object.(*v1.ConfigMap); ok {
					found := cm.ObjectMeta.Name == testConfigMap.Name &&
						cm.Labels["test-configmap-static"] == "true" &&
						cm.Labels["test-configmap"] == "patched" &&
						cm.Data["valueName"] == "value1"
					return found, nil
				}
			default:
				framework.Logf("observed event type %v", event.Type)
			}
			return false, nil
		})
		framework.ExpectNoError(err, "failed to see a watch.Modified event for the configmap we patched")

		ginkgo.By("fetching the ConfigMap")
		configMap, err := f.ClientSet.CoreV1().ConfigMaps(testNamespaceName).Get(context.TODO(), testConfigMapName, metav1.GetOptions{})
		framework.ExpectNoError(err, "failed to get ConfigMap")
		framework.ExpectEqual(configMap.Data["valueName"], "value1", "failed to patch ConfigMap")
		framework.ExpectEqual(configMap.Labels["test-configmap"], "patched", "failed to patch ConfigMap")

		ginkgo.By("listing all ConfigMaps in all namespaces")
		configMapList, err := f.ClientSet.CoreV1().ConfigMaps("").List(context.TODO(), metav1.ListOptions{
			LabelSelector: "test-configmap-static=true",
		})
		framework.ExpectNoError(err, "failed to list ConfigMaps with LabelSelector")
		framework.ExpectNotEqual(len(configMapList.Items), 0, "no ConfigMaps found in ConfigMap list")
		testConfigMapFound := false
		for _, cm := range configMapList.Items {
			if cm.ObjectMeta.Name == testConfigMapName &&
				cm.ObjectMeta.Namespace == testNamespaceName &&
				cm.ObjectMeta.Labels["test-configmap-static"] == "true" &&
				cm.Data["valueName"] == "value1" {
				testConfigMapFound = true
				break
			}
		}
		framework.ExpectEqual(testConfigMapFound, true, "failed to find ConfigMap in list")

		ginkgo.By("deleting the ConfigMap by a collection")
		err = f.ClientSet.CoreV1().ConfigMaps(testNamespaceName).DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{
			LabelSelector: "test-configmap-static=true",
		})
		framework.ExpectNoError(err, "failed to delete ConfigMap collection with LabelSelector")
		ginkgo.By("waiting for the ConfigMap to be deleted")
		ctx, cancel = context.WithTimeout(context.Background(), 30*time.Second)
		defer cancel()
		_, err = watchtools.Until(ctx, cml.ResourceVersion, w, func(event watch.Event) (bool, error) {
			switch event.Type {
			case watch.Deleted:
				if cm, ok := event.Object.(*v1.ConfigMap); ok {
					found := cm.ObjectMeta.Name == testConfigMap.Name &&
						cm.Labels["test-configmap-static"] == "true" &&
						cm.Labels["test-configmap"] == "patched" &&
						cm.Data["valueName"] == "value1"
					return found, nil
				}
			default:
				framework.Logf("observed event type %v", event.Type)
			}
			return false, nil
		})
		framework.ExpectNoError(err, "fasiled to observe a watch.Deleted event for the ConfigMap we deleted")
	})
})

func newEnvFromConfigMap(f *framework.Framework, name string) *v1.ConfigMap {
	return &v1.ConfigMap{
		ObjectMeta: metav1.ObjectMeta{
			Namespace: f.Namespace.Name,
			Name:      name,
		},
		Data: map[string]string{
			"data_1": "value-1",
			"data_2": "value-2",
			"data_3": "value-3",
		},
	}
}

func newConfigMapWithEmptyKey(f *framework.Framework) (*v1.ConfigMap, error) {
	name := "configmap-test-emptyKey-" + string(uuid.NewUUID())
	configMap := &v1.ConfigMap{
		ObjectMeta: metav1.ObjectMeta{
			Namespace: f.Namespace.Name,
			Name:      name,
		},
		Data: map[string]string{
			"": "value-1",
		},
	}

	ginkgo.By(fmt.Sprintf("Creating configMap that has name %s", configMap.Name))
	return f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(context.TODO(), configMap, metav1.CreateOptions{})
}
<commit_msg>Use different resource versions each time<commit_after>/*
Copyright 2016 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 common

import (
	"context"
	"encoding/json"
	"fmt"
	"time"

	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/util/uuid"
	watch "k8s.io/apimachinery/pkg/watch"
	"k8s.io/client-go/dynamic"
	"k8s.io/client-go/tools/cache"
	watchtools "k8s.io/client-go/tools/watch"
	"k8s.io/kubernetes/test/e2e/framework"
	imageutils "k8s.io/kubernetes/test/utils/image"

	"github.com/onsi/ginkgo"
)

var _ = ginkgo.Describe("[sig-node] ConfigMap", func() {
	f := framework.NewDefaultFramework("configmap")

	var dc dynamic.Interface

	ginkgo.BeforeEach(func() {
		dc = f.DynamicClient
	})

	/*
		Release : v1.9
		Testname: ConfigMap, from environment field
		Description: Create a Pod with an environment variable value set using a value from ConfigMap. A ConfigMap value MUST be accessible in the container environment.
	*/
	framework.ConformanceIt("should be consumable via environment variable [NodeConformance]", func() {
		name := "configmap-test-" + string(uuid.NewUUID())
		configMap := newConfigMap(f, name)
		ginkgo.By(fmt.Sprintf("Creating configMap %v/%v", f.Namespace.Name, configMap.Name))
		var err error
		if configMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(context.TODO(), configMap, metav1.CreateOptions{}); err != nil {
			framework.Failf("unable to create test configMap %s: %v", configMap.Name, err)
		}

		pod := &v1.Pod{
			ObjectMeta: metav1.ObjectMeta{
				Name: "pod-configmaps-" + string(uuid.NewUUID()),
			},
			Spec: v1.PodSpec{
				Containers: []v1.Container{
					{
						Name:    "env-test",
						Image:   imageutils.GetE2EImage(imageutils.BusyBox),
						Command: []string{"sh", "-c", "env"},
						Env: []v1.EnvVar{
							{
								Name: "CONFIG_DATA_1",
								ValueFrom: &v1.EnvVarSource{
									ConfigMapKeyRef: &v1.ConfigMapKeySelector{
										LocalObjectReference: v1.LocalObjectReference{
											Name: name,
										},
										Key: "data-1",
									},
								},
							},
						},
					},
				},
				RestartPolicy: v1.RestartPolicyNever,
			},
		}

		f.TestContainerOutput("consume configMaps", pod, 0, []string{
			"CONFIG_DATA_1=value-1",
		})
	})

	/*
		Release: v1.9
		Testname: ConfigMap, from environment variables
		Description: Create a Pod with a environment source from ConfigMap. All ConfigMap values MUST be available as environment variables in the container.
	*/
	framework.ConformanceIt("should be consumable via the environment [NodeConformance]", func() {
		name := "configmap-test-" + string(uuid.NewUUID())
		configMap := newEnvFromConfigMap(f, name)
		ginkgo.By(fmt.Sprintf("Creating configMap %v/%v", f.Namespace.Name, configMap.Name))
		var err error
		if configMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(context.TODO(), configMap, metav1.CreateOptions{}); err != nil {
			framework.Failf("unable to create test configMap %s: %v", configMap.Name, err)
		}

		pod := &v1.Pod{
			ObjectMeta: metav1.ObjectMeta{
				Name: "pod-configmaps-" + string(uuid.NewUUID()),
			},
			Spec: v1.PodSpec{
				Containers: []v1.Container{
					{
						Name:    "env-test",
						Image:   imageutils.GetE2EImage(imageutils.BusyBox),
						Command: []string{"sh", "-c", "env"},
						EnvFrom: []v1.EnvFromSource{
							{
								ConfigMapRef: &v1.ConfigMapEnvSource{LocalObjectReference: v1.LocalObjectReference{Name: name}},
							},
							{
								Prefix:       "p_",
								ConfigMapRef: &v1.ConfigMapEnvSource{LocalObjectReference: v1.LocalObjectReference{Name: name}},
							},
						},
					},
				},
				RestartPolicy: v1.RestartPolicyNever,
			},
		}

		f.TestContainerOutput("consume configMaps", pod, 0, []string{
			"data_1=value-1", "data_2=value-2", "data_3=value-3",
			"p_data_1=value-1", "p_data_2=value-2", "p_data_3=value-3",
		})
	})

	/*
	   Release : v1.14
	   Testname: ConfigMap, with empty-key
	   Description: Attempt to create a ConfigMap with an empty key. The creation MUST fail.
	*/
	framework.ConformanceIt("should fail to create ConfigMap with empty key", func() {
		configMap, err := newConfigMapWithEmptyKey(f)
		framework.ExpectError(err, "created configMap %q with empty key in namespace %q", configMap.Name, f.Namespace.Name)
	})

	ginkgo.It("should update ConfigMap successfully", func() {
		name := "configmap-test-" + string(uuid.NewUUID())
		configMap := newConfigMap(f, name)
		ginkgo.By(fmt.Sprintf("Creating ConfigMap %v/%v", f.Namespace.Name, configMap.Name))
		_, err := f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(context.TODO(), configMap, metav1.CreateOptions{})
		framework.ExpectNoError(err, "failed to create ConfigMap")

		configMap.Data = map[string]string{
			"data": "value",
		}
		ginkgo.By(fmt.Sprintf("Updating configMap %v/%v", f.Namespace.Name, configMap.Name))
		_, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Update(context.TODO(), configMap, metav1.UpdateOptions{})
		framework.ExpectNoError(err, "failed to update ConfigMap")

		configMapFromUpdate, err := f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Get(context.TODO(), name, metav1.GetOptions{})
		framework.ExpectNoError(err, "failed to get ConfigMap")
		ginkgo.By(fmt.Sprintf("Verifying update of ConfigMap %v/%v", f.Namespace.Name, configMap.Name))
		framework.ExpectEqual(configMapFromUpdate.Data, configMap.Data)
	})

	ginkgo.It("should run through a ConfigMap lifecycle", func() {
		testNamespaceName := f.Namespace.Name
		testConfigMapName := "test-configmap" + string(uuid.NewUUID())

		testConfigMap := v1.ConfigMap{
			ObjectMeta: metav1.ObjectMeta{
				Name: testConfigMapName,
				Labels: map[string]string{
					"test-configmap-static": "true",
				},
			},
			Data: map[string]string{
				"valueName": "value",
			},
		}

		w := &cache.ListWatch{
			WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
				options.LabelSelector = "test-configmap-static=true"
				return f.ClientSet.CoreV1().ConfigMaps(testNamespaceName).Watch(context.TODO(), options)
			},
		}
		cml, err := f.ClientSet.CoreV1().ConfigMaps(testNamespaceName).List(context.TODO(), metav1.ListOptions{LabelSelector: "test-configmap-static=true"})
		framework.ExpectNoError(err)

		ginkgo.By("creating a ConfigMap")
		cm, err := f.ClientSet.CoreV1().ConfigMaps(testNamespaceName).Create(context.TODO(), &testConfigMap, metav1.CreateOptions{})
		framework.ExpectNoError(err, "failed to create ConfigMap")

		ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
		defer cancel()
		_, err = watchtools.Until(ctx, cml.ResourceVersion, w, func(event watch.Event) (bool, error) {
			switch event.Type {
			case watch.Added:
				if cm, ok := event.Object.(*v1.ConfigMap); ok {
					found := cm.ObjectMeta.Name == testConfigMap.Name &&
						cm.Labels["test-configmap-static"] == "true" &&
						cm.Data["valueName"] == "value"
					return found, nil
				}
			default:
				framework.Logf("observed event type %v", event.Type)
			}
			return false, nil
		})
		framework.ExpectNoError(err, "failed to see a watch.Added event for the configmap we created")

		configMapPatchPayload, err := json.Marshal(v1.ConfigMap{
			ObjectMeta: metav1.ObjectMeta{
				Labels: map[string]string{
					"test-configmap": "patched",
				},
			},
			Data: map[string]string{
				"valueName": "value1",
			},
		})
		framework.ExpectNoError(err, "failed to marshal patch data")

		ginkgo.By("patching the ConfigMap")
		cm2, err := f.ClientSet.CoreV1().ConfigMaps(testNamespaceName).Patch(context.TODO(), testConfigMapName, types.StrategicMergePatchType, []byte(configMapPatchPayload), metav1.PatchOptions{})
		framework.ExpectNoError(err, "failed to patch ConfigMap")
		ginkgo.By("waiting for the ConfigMap to be modified")
		ctx, cancel = context.WithTimeout(context.Background(), 30*time.Second)
		defer cancel()
		_, err = watchtools.Until(ctx, cm.ResourceVersion, w, func(event watch.Event) (bool, error) {
			switch event.Type {
			case watch.Modified:
				if cm, ok := event.Object.(*v1.ConfigMap); ok {
					found := cm.ObjectMeta.Name == testConfigMap.Name &&
						cm.Labels["test-configmap-static"] == "true" &&
						cm.Labels["test-configmap"] == "patched" &&
						cm.Data["valueName"] == "value1"
					return found, nil
				}
			default:
				framework.Logf("observed event type %v", event.Type)
			}
			return false, nil
		})
		framework.ExpectNoError(err, "failed to see a watch.Modified event for the configmap we patched")

		ginkgo.By("fetching the ConfigMap")
		configMap, err := f.ClientSet.CoreV1().ConfigMaps(testNamespaceName).Get(context.TODO(), testConfigMapName, metav1.GetOptions{})
		framework.ExpectNoError(err, "failed to get ConfigMap")
		framework.ExpectEqual(configMap.Data["valueName"], "value1", "failed to patch ConfigMap")
		framework.ExpectEqual(configMap.Labels["test-configmap"], "patched", "failed to patch ConfigMap")

		ginkgo.By("listing all ConfigMaps in all namespaces")
		configMapList, err := f.ClientSet.CoreV1().ConfigMaps("").List(context.TODO(), metav1.ListOptions{
			LabelSelector: "test-configmap-static=true",
		})
		framework.ExpectNoError(err, "failed to list ConfigMaps with LabelSelector")
		framework.ExpectNotEqual(len(configMapList.Items), 0, "no ConfigMaps found in ConfigMap list")
		testConfigMapFound := false
		for _, cm := range configMapList.Items {
			if cm.ObjectMeta.Name == testConfigMapName &&
				cm.ObjectMeta.Namespace == testNamespaceName &&
				cm.ObjectMeta.Labels["test-configmap-static"] == "true" &&
				cm.Data["valueName"] == "value1" {
				testConfigMapFound = true
				break
			}
		}
		framework.ExpectEqual(testConfigMapFound, true, "failed to find ConfigMap in list")

		ginkgo.By("deleting the ConfigMap by a collection")
		err = f.ClientSet.CoreV1().ConfigMaps(testNamespaceName).DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{
			LabelSelector: "test-configmap-static=true",
		})
		framework.ExpectNoError(err, "failed to delete ConfigMap collection with LabelSelector")
		ginkgo.By("waiting for the ConfigMap to be deleted")
		ctx, cancel = context.WithTimeout(context.Background(), 30*time.Second)
		defer cancel()
		_, err = watchtools.Until(ctx, cm2.ResourceVersion, w, func(event watch.Event) (bool, error) {
			switch event.Type {
			case watch.Deleted:
				if cm, ok := event.Object.(*v1.ConfigMap); ok {
					found := cm.ObjectMeta.Name == testConfigMap.Name &&
						cm.Labels["test-configmap-static"] == "true" &&
						cm.Labels["test-configmap"] == "patched" &&
						cm.Data["valueName"] == "value1"
					return found, nil
				}
			default:
				framework.Logf("observed event type %v", event.Type)
			}
			return false, nil
		})
		framework.ExpectNoError(err, "fasiled to observe a watch.Deleted event for the ConfigMap we deleted")
	})
})

func newEnvFromConfigMap(f *framework.Framework, name string) *v1.ConfigMap {
	return &v1.ConfigMap{
		ObjectMeta: metav1.ObjectMeta{
			Namespace: f.Namespace.Name,
			Name:      name,
		},
		Data: map[string]string{
			"data_1": "value-1",
			"data_2": "value-2",
			"data_3": "value-3",
		},
	}
}

func newConfigMapWithEmptyKey(f *framework.Framework) (*v1.ConfigMap, error) {
	name := "configmap-test-emptyKey-" + string(uuid.NewUUID())
	configMap := &v1.ConfigMap{
		ObjectMeta: metav1.ObjectMeta{
			Namespace: f.Namespace.Name,
			Name:      name,
		},
		Data: map[string]string{
			"": "value-1",
		},
	}

	ginkgo.By(fmt.Sprintf("Creating configMap that has name %s", configMap.Name))
	return f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(context.TODO(), configMap, metav1.CreateOptions{})
}
<|endoftext|>


<commit_before>// Copyright 2016 Albert Nigmatzianov. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package id3v2

import (
	"bytes"
	"errors"
	"io"
	"io/ioutil"
	"os"

	"github.com/bogem/id3v2/bytesbufferpool"
	"github.com/bogem/id3v2/util"
)

type Tag struct {
	frames       map[string]Framer
	sequences    map[string]sequencer
	commonIDs    map[string]string
	file         *os.File
	originalSize uint32
}

func (t *Tag) AddFrame(id string, f Framer) {
	if t.frames == nil {
		t.frames = make(map[string]Framer)
	}
	t.frames[id] = f
}

func (t *Tag) AddAttachedPicture(pf PictureFrame) {
	id := t.commonIDs["Attached picture"]
	t.checkExistenceOfSequence(id, newPictureSequence)
	t.addFrameToSequence(pf, id)
}

func (t *Tag) AddUnsynchronisedLyricsFrame(uslf UnsynchronisedLyricsFrame) {
	id := t.commonIDs["Unsynchronised lyrics/text transcription"]
	t.checkExistenceOfSequence(id, newUSLFSequence)
	t.addFrameToSequence(uslf, id)
}

func (t *Tag) AddCommentFrame(cf CommentFrame) {
	id := t.commonIDs["Comments"]
	t.checkExistenceOfSequence(id, newCommentSequence)
	t.addFrameToSequence(cf, id)
}

func (t *Tag) checkExistenceOfSequence(id string, newSequence func() sequencer) {
	if t.sequences == nil {
		t.sequences = make(map[string]sequencer)
	}
	if t.sequences[id] == nil {
		t.sequences[id] = newSequence()
	}
}

func (t *Tag) addFrameToSequence(f Framer, id string) {
	t.sequences[id].AddFrame(f)
}

func (t *Tag) SetTitle(title string) {
	t.AddFrame(t.commonIDs["Title/Songname/Content description"], TextFrame{Encoding: ENUTF8, Text: title})
}

func (t *Tag) SetArtist(artist string) {
	t.AddFrame(t.commonIDs["Lead artist/Lead performer/Soloist/Performing group"], TextFrame{Encoding: ENUTF8, Text: artist})
}

func (t *Tag) SetAlbum(album string) {
	t.AddFrame(t.commonIDs["Album/Movie/Show title"], TextFrame{Encoding: ENUTF8, Text: album})
}

func (t *Tag) SetYear(year string) {
	t.AddFrame(t.commonIDs["Recording time"], TextFrame{Encoding: ENUTF8, Text: year})
}

func (t *Tag) SetGenre(genre string) {
	t.AddFrame(t.commonIDs["Content type"], TextFrame{Encoding: ENUTF8, Text: genre})
}

func newTag(file *os.File, size uint32) *Tag {
	return &Tag{
		commonIDs: V24CommonIDs,

		file:         file,
		originalSize: size,
	}
}

func parseTag(file *os.File) (*Tag, error) {
	header, err := parseHeader(file)
	if err != nil {
		err = errors.New("Trying to parse tag header: " + err.Error())
		return nil, err
	}
	if header == nil {
		return newTag(file, 0), nil
	}
	if header.Version < 3 {
		err = errors.New("Unsupported version of ID3 tag")
		return nil, err
	}

	return newTag(file, tagHeaderSize+header.FramesSize), nil
}

// Flush writes tag to the file.
func (t Tag) Flush() error {
	// Forming new frames
	frames := t.formAllFrames()

	// Forming size of new frames
	framesSize := util.FormSize(uint32(len(frames)))

	// Creating a temp file for mp3 file, which will contain new tag
	newFile, err := ioutil.TempFile("", "")
	if err != nil {
		return err
	}

	// Writing to new file new tag header
	if _, err := newFile.Write(formTagHeader(framesSize)); err != nil {
		return err
	}

	// Writing to new file new frames
	if _, err := newFile.Write(frames); err != nil {
		return err
	}

	// Seeking to a music part of mp3
	originalFile := t.file
	defer originalFile.Close()
	if _, err := originalFile.Seek(int64(t.originalSize), os.SEEK_SET); err != nil {
		return err
	}

	// Writing to new file the music part
	if _, err = io.Copy(newFile, originalFile); err != nil {
		return err
	}

	// Replacing original file with new file
	if err = os.Rename(newFile.Name(), originalFile.Name()); err != nil {
		return err
	}

	// And closing it
	if err = newFile.Close(); err != nil {
		return err
	}

	return nil
}

func (t Tag) formAllFrames() []byte {
	frames := bytesbufferpool.Get()
	defer bytesbufferpool.Put(frames)

	t.writeFrames(frames)
	t.writeSequences(frames)

	return frames.Bytes()
}

func (t Tag) writeFrames(w io.Writer) {
	for id, f := range t.frames {
		w.Write(formFrame(id, f))
	}
}

func (t Tag) writeSequences(w io.Writer) {
	for id, s := range t.sequences {
		for _, f := range s.Frames() {
			w.Write(formFrame(id, f))
		}
	}
}

func formFrame(id string, frame Framer) []byte {
	if id == "" {
		panic("there is blank ID in frames")
	}

	frameBuffer := bytesbufferpool.Get()
	defer bytesbufferpool.Put(frameBuffer)

	frameBody := frame.Body()
	writeFrameHeader(frameBuffer, id, uint32(len(frameBody)))
	frameBuffer.Write(frameBody)

	return frameBuffer.Bytes()
}

func writeFrameHeader(framesBuffer *bytes.Buffer, id string, frameSize uint32) {
	framesBuffer.WriteString(id)
	framesBuffer.Write(util.FormSize(frameSize))
	framesBuffer.Write([]byte{0, 0})
}
<commit_msg>Small refactoring in tag.Close()<commit_after>// Copyright 2016 Albert Nigmatzianov. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package id3v2

import (
	"bytes"
	"errors"
	"io"
	"io/ioutil"
	"os"

	"github.com/bogem/id3v2/bytesbufferpool"
	"github.com/bogem/id3v2/util"
)

type Tag struct {
	frames       map[string]Framer
	sequences    map[string]sequencer
	commonIDs    map[string]string
	file         *os.File
	originalSize uint32
}

func (t *Tag) AddFrame(id string, f Framer) {
	if t.frames == nil {
		t.frames = make(map[string]Framer)
	}
	t.frames[id] = f
}

func (t *Tag) AddAttachedPicture(pf PictureFrame) {
	id := t.commonIDs["Attached picture"]
	t.checkExistenceOfSequence(id, newPictureSequence)
	t.addFrameToSequence(pf, id)
}

func (t *Tag) AddUnsynchronisedLyricsFrame(uslf UnsynchronisedLyricsFrame) {
	id := t.commonIDs["Unsynchronised lyrics/text transcription"]
	t.checkExistenceOfSequence(id, newUSLFSequence)
	t.addFrameToSequence(uslf, id)
}

func (t *Tag) AddCommentFrame(cf CommentFrame) {
	id := t.commonIDs["Comments"]
	t.checkExistenceOfSequence(id, newCommentSequence)
	t.addFrameToSequence(cf, id)
}

func (t *Tag) checkExistenceOfSequence(id string, newSequence func() sequencer) {
	if t.sequences == nil {
		t.sequences = make(map[string]sequencer)
	}
	if t.sequences[id] == nil {
		t.sequences[id] = newSequence()
	}
}

func (t *Tag) addFrameToSequence(f Framer, id string) {
	t.sequences[id].AddFrame(f)
}

func (t *Tag) SetTitle(title string) {
	t.AddFrame(t.commonIDs["Title/Songname/Content description"], TextFrame{Encoding: ENUTF8, Text: title})
}

func (t *Tag) SetArtist(artist string) {
	t.AddFrame(t.commonIDs["Lead artist/Lead performer/Soloist/Performing group"], TextFrame{Encoding: ENUTF8, Text: artist})
}

func (t *Tag) SetAlbum(album string) {
	t.AddFrame(t.commonIDs["Album/Movie/Show title"], TextFrame{Encoding: ENUTF8, Text: album})
}

func (t *Tag) SetYear(year string) {
	t.AddFrame(t.commonIDs["Recording time"], TextFrame{Encoding: ENUTF8, Text: year})
}

func (t *Tag) SetGenre(genre string) {
	t.AddFrame(t.commonIDs["Content type"], TextFrame{Encoding: ENUTF8, Text: genre})
}

func newTag(file *os.File, size uint32) *Tag {
	return &Tag{
		commonIDs: V24CommonIDs,

		file:         file,
		originalSize: size,
	}
}

func parseTag(file *os.File) (*Tag, error) {
	header, err := parseHeader(file)
	if err != nil {
		err = errors.New("Trying to parse tag header: " + err.Error())
		return nil, err
	}
	if header == nil {
		return newTag(file, 0), nil
	}
	if header.Version < 3 {
		err = errors.New("Unsupported version of ID3 tag")
		return nil, err
	}

	return newTag(file, tagHeaderSize+header.FramesSize), nil
}

// Flush writes tag to the file.
func (t Tag) Flush() error {
	// Forming new frames
	frames := t.formAllFrames()

	// Forming size of new frames
	framesSize := util.FormSize(uint32(len(frames)))

	// Creating a temp file for mp3 file, which will contain new tag
	newFile, err := ioutil.TempFile("", "")
	defer newFile.Close()
	if err != nil {
		return err
	}

	// Writing to new file new tag header
	if _, err := newFile.Write(formTagHeader(framesSize)); err != nil {
		return err
	}

	// Writing to new file new frames
	if _, err := newFile.Write(frames); err != nil {
		return err
	}

	// Seeking to a music part of mp3
	originalFile := t.file
	defer originalFile.Close()
	if _, err := originalFile.Seek(int64(t.originalSize), os.SEEK_SET); err != nil {
		return err
	}

	// Writing to new file the music part
	if _, err = io.Copy(newFile, originalFile); err != nil {
		return err
	}

	// Replacing original file with new file
	if err = os.Rename(newFile.Name(), originalFile.Name()); err != nil {
		return err
	}

	return nil
}

func (t Tag) formAllFrames() []byte {
	frames := bytesbufferpool.Get()
	defer bytesbufferpool.Put(frames)

	t.writeFrames(frames)
	t.writeSequences(frames)

	return frames.Bytes()
}

func (t Tag) writeFrames(w io.Writer) {
	for id, f := range t.frames {
		w.Write(formFrame(id, f))
	}
}

func (t Tag) writeSequences(w io.Writer) {
	for id, s := range t.sequences {
		for _, f := range s.Frames() {
			w.Write(formFrame(id, f))
		}
	}
}

func formFrame(id string, frame Framer) []byte {
	if id == "" {
		panic("there is blank ID in frames")
	}

	frameBuffer := bytesbufferpool.Get()
	defer bytesbufferpool.Put(frameBuffer)

	frameBody := frame.Body()
	writeFrameHeader(frameBuffer, id, uint32(len(frameBody)))
	frameBuffer.Write(frameBody)

	return frameBuffer.Bytes()
}

func writeFrameHeader(framesBuffer *bytes.Buffer, id string, frameSize uint32) {
	framesBuffer.WriteString(id)
	framesBuffer.Write(util.FormSize(frameSize))
	framesBuffer.Write([]byte{0, 0})
}
<|endoftext|>


<commit_before>package test

import (
	"flag"
	"sync"
	"testing"

	"github.com/neptulon/neptulon"
	"github.com/neptulon/neptulon/middleware"
)

var ext = flag.Bool("ext", false, "Run external client test case.")

// Helper method for testing client implementations in other languages.
// Flow of events for this function is:
// * Send a {"method":"echo", "params":{"message": "..."}} request to client upon connection,
//   and verify that message body is echoed properly in the response body.
// * Echo any incoming request message body as is within a response message.
// * Repeat ad infinitum, until {"method":"close", "params":"{"message": "..."}"} is received. Close message body is logged.
func TestExternalClient(t *testing.T) {
	sh := NewServerHelper(t).Start()
	defer sh.CloseWait()
	var wg sync.WaitGroup
	wg.Add(2) // one for response handler below, other for "close" request handler

	m := "Hello!"

	sh.Server.ConnHandler(func(c *neptulon.Conn) error {
		c.SendRequest("echo", echoMsg{Message: m}, func(ctx *neptulon.ResCtx) error {
			defer wg.Done()
			var msg echoMsg
			if err := ctx.Result(&msg); err != nil {
				t.Fatal(err)
			}
			if msg.Message != m {
				t.Fatalf("server: expected: %v got: %v", m, msg.Message)
			}
			t.Logf("server: client sent 'echo' request message: %v", msg.Message)
			return nil
		})
		return nil
	})

	rout := middleware.NewRouter()
	sh.Middleware(rout.Middleware)
	rout.Request("echo", middleware.Echo)

	rout.Request("close", func(ctx *neptulon.ReqCtx) error {
		defer wg.Done()
		if err := ctx.Params(&ctx.Res); err != nil {
			return err
		}
		err := ctx.Next()
		ctx.Conn.Close()
		t.Logf("server: closed connection with message from client: %v\n", ctx.Res)
		return err
	})

	if *ext {
		t.Log("Starter server waiting for external client integration test since.")
		wg.Wait()
		return
	}

	// use internal conn implementation instead to test the test case itself
	t.Log("Skipping external client integration test since -ext flag is not provided.")
	ch := sh.GetConnHelper().Connect()
	defer ch.CloseWait()
	cm := "Thanks for echoing! Over and out."

	// todo: handle server's echo request with a client router here!!!!!!!!!!!!!!!!!!

	ch.SendRequest("echo", echoMsg{Message: m}, func(ctx *neptulon.ResCtx) error {
		var msg echoMsg
		if err := ctx.Result(&msg); err != nil {
			t.Fatal(err)
		}
		if msg.Message != m {
			t.Fatalf("client: expected: %v got: %v", m, msg.Message)
		}
		t.Log("client: server accepted and echoed 'echo' request message body")

		// send close request after getting our echo message back
		ch.SendRequest("close", echoMsg{Message: cm}, func(ctx *neptulon.ResCtx) error {
			var msg echoMsg
			if err := ctx.Result(&msg); err != nil {
				t.Fatal(err)
			}
			if msg.Message != cm {
				t.Fatalf("client: expected: %v got: %v", cm, msg.Message)
			}
			t.Log("client: server accepted and echoed 'close' request message body. bye!")
			return nil
		})

		return nil
	})

	wg.Wait()
}
<commit_msg>wording<commit_after>package test

import (
	"flag"
	"sync"
	"testing"

	"github.com/neptulon/neptulon"
	"github.com/neptulon/neptulon/middleware"
)

var ext = flag.Bool("ext", false, "Run external client test case.")

// Helper method for testing client implementations in other languages.
// Flow of events for this function is:
// * Send a {"method":"echo", "params":{"message": "..."}} request to client upon connection,
//   and verify that message body is echoed properly in the response body.
// * Echo any incoming request message body as is within a response message.
// * Repeat ad infinitum, until {"method":"close", "params":"{"message": "..."}"} is received. Close message body is logged.
func TestExternalClient(t *testing.T) {
	sh := NewServerHelper(t).Start()
	defer sh.CloseWait()
	var wg sync.WaitGroup
	wg.Add(2) // one for response handler below, other for "close" request handler

	m := "Hello!"

	sh.Server.ConnHandler(func(c *neptulon.Conn) error {
		c.SendRequest("echo", echoMsg{Message: m}, func(ctx *neptulon.ResCtx) error {
			defer wg.Done()
			var msg echoMsg
			if err := ctx.Result(&msg); err != nil {
				t.Fatal(err)
			}
			if msg.Message != m {
				t.Fatalf("server: expected: %v got: %v", m, msg.Message)
			}
			t.Logf("server: client sent 'echo' response message: %v", msg.Message)
			return nil
		})
		return nil
	})

	rout := middleware.NewRouter()
	sh.Middleware(rout.Middleware)
	rout.Request("echo", middleware.Echo)

	rout.Request("close", func(ctx *neptulon.ReqCtx) error {
		defer wg.Done()
		if err := ctx.Params(&ctx.Res); err != nil {
			return err
		}
		err := ctx.Next()
		ctx.Conn.Close()
		t.Logf("server: closed connection with message from client: %v\n", ctx.Res)
		return err
	})

	if *ext {
		t.Log("Starter server waiting for external client integration test since.")
		wg.Wait()
		return
	}

	// use internal conn implementation instead to test the test case itself
	t.Log("Skipping external client integration test since -ext flag is not provided.")
	ch := sh.GetConnHelper().Connect()
	defer ch.CloseWait()
	cm := "Thanks for echoing! Over and out."

	// todo: handle server's echo request with a client router here!!!!!!!!!!!!!!!!!!

	ch.SendRequest("echo", echoMsg{Message: m}, func(ctx *neptulon.ResCtx) error {
		var msg echoMsg
		if err := ctx.Result(&msg); err != nil {
			t.Fatal(err)
		}
		if msg.Message != m {
			t.Fatalf("client: expected: %v got: %v", m, msg.Message)
		}
		t.Log("client: server accepted and echoed 'echo' request message body")

		// send close request after getting our echo message back
		ch.SendRequest("close", echoMsg{Message: cm}, func(ctx *neptulon.ResCtx) error {
			var msg echoMsg
			if err := ctx.Result(&msg); err != nil {
				t.Fatal(err)
			}
			if msg.Message != cm {
				t.Fatalf("client: expected: %v got: %v", cm, msg.Message)
			}
			t.Log("client: server accepted and echoed 'close' request message body. bye!")
			return nil
		})

		return nil
	})

	wg.Wait()
}
<|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 main

import (
	"fmt"
	"k8s.io/test-infra/testgrid/config"
	"path"
	"strconv"
	"strings"

	prowapi "k8s.io/test-infra/prow/apis/prowjobs/v1"
	prowConfig "k8s.io/test-infra/prow/config"
	"k8s.io/test-infra/prow/pod-utils/downwardapi"
	prowGCS "k8s.io/test-infra/prow/pod-utils/gcs"
)

const testgridCreateTestGroupAnnotation = "testgrid-create-test-group"
const testgridDashboardsAnnotation = "testgrid-dashboards"
const testgridTabNameAnnotation = "testgrid-tab-name"
const testgridEmailAnnotation = "testgrid-alert-email"
const testgridNumColumnsRecentAnnotation = "testgrid-num-columns-recent"
const testgridAlertStaleResultsHoursAnnotation = "testgrid-alert-stale-results-hours"
const testgridNumFailuresToAlertAnnotation = "testgrid-num-failures-to-alert"
const descriptionAnnotation = "description"

// Talk to @michelle192837 if you're thinking about adding more of these!

func applySingleProwjobAnnotations(c *Config, pc *prowConfig.Config, j prowConfig.JobBase, jobType prowapi.ProwJobType) error {
	tabName := j.Name
	testGroupName := j.Name
	description := j.Name

	mustMakeGroup := j.Annotations[testgridCreateTestGroupAnnotation] == "true"
	mustNotMakeGroup := j.Annotations[testgridCreateTestGroupAnnotation] == "false"
	dashboards, addToDashboards := j.Annotations[testgridDashboardsAnnotation]
	mightMakeGroup := (mustMakeGroup || addToDashboards || jobType != prowapi.PresubmitJob) && !mustNotMakeGroup
	var testGroup *config.TestGroup

	if mightMakeGroup {
		if testGroup = c.config.FindTestGroup(testGroupName); testGroup != nil {
			if mustMakeGroup {
				return fmt.Errorf("test group %q already exists", testGroupName)
			}
		} else {
			var prefix string
			if j.DecorationConfig != nil && j.DecorationConfig.GCSConfiguration != nil {
				prefix = path.Join(j.DecorationConfig.GCSConfiguration.Bucket, j.DecorationConfig.GCSConfiguration.PathPrefix)
			} else if pc.Plank.DefaultDecorationConfig != nil && pc.Plank.DefaultDecorationConfig.GCSConfiguration != nil {
				prefix = path.Join(pc.Plank.DefaultDecorationConfig.GCSConfiguration.Bucket, pc.Plank.DefaultDecorationConfig.GCSConfiguration.PathPrefix)
			} else {
				return fmt.Errorf("job %s: couldn't figure out a default decoration config", j.Name)
			}

			testGroup = &config.TestGroup{
				Name:      testGroupName,
				GcsPrefix: path.Join(prefix, prowGCS.RootForSpec(&downwardapi.JobSpec{Job: j.Name, Type: jobType})),
			}
			ReconcileTestGroup(testGroup, c.defaultConfig.DefaultTestGroup)
			c.config.TestGroups = append(c.config.TestGroups, testGroup)
		}
	}

	if ncr, ok := j.Annotations[testgridNumColumnsRecentAnnotation]; ok {
		ncrInt, err := strconv.ParseInt(ncr, 10, 32)
		if err != nil {
			return fmt.Errorf("%s value %q is not a valid integer", testgridNumColumnsRecentAnnotation, ncr)
		}
		testGroup.NumColumnsRecent = int32(ncrInt)
	}

	if srh, ok := j.Annotations[testgridAlertStaleResultsHoursAnnotation]; ok {
		srhInt, err := strconv.ParseInt(srh, 10, 32)
		if err != nil {
			return fmt.Errorf("%s value %q is not a valid integer", testgridAlertStaleResultsHoursAnnotation, srh)
		}
		testGroup.AlertStaleResultsHours = int32(srhInt)
	}

	if nfta, ok := j.Annotations[testgridNumFailuresToAlertAnnotation]; ok {
		nftaInt, err := strconv.ParseInt(nfta, 10, 32)
		if err != nil {
			return fmt.Errorf("%s value %q is not a valid integer", testgridNumFailuresToAlertAnnotation, nfta)
		}
		testGroup.NumFailuresToAlert = int32(nftaInt)
	}

	if tn, ok := j.Annotations[testgridTabNameAnnotation]; ok {
		tabName = tn
	}
	if d := j.Annotations[descriptionAnnotation]; d != "" {
		description = d
	}

	if addToDashboards {
		firstDashboard := true
		for _, dashboardName := range strings.Split(dashboards, ",") {
			dashboardName = strings.TrimSpace(dashboardName)
			d := c.config.FindDashboard(dashboardName)
			if d == nil {
				return fmt.Errorf("couldn't find dashboard %q for job %q", dashboardName, j.Name)
			}
			dt := &config.DashboardTab{
				Name:          tabName,
				TestGroupName: testGroupName,
				Description:   description,
			}
			if firstDashboard {
				firstDashboard = false
				if emails, ok := j.Annotations[testgridEmailAnnotation]; ok {
					dt.AlertOptions = &config.DashboardTabAlertOptions{AlertMailToAddresses: emails}
				}
			}
			ReconcileDashboardTab(dt, c.defaultConfig.DefaultDashboardTab)
			d.DashboardTab = append(d.DashboardTab, dt)
		}
	}

	return nil
}

func applyProwjobAnnotations(c *Config, prowConfigAgent *prowConfig.Agent) error {
	pc := prowConfigAgent.Config()
	if pc == nil {
		return nil
	}
	jobs := prowConfigAgent.Config().JobConfig
	for _, j := range jobs.AllPeriodics() {
		if err := applySingleProwjobAnnotations(c, pc, j.JobBase, prowapi.PeriodicJob); err != nil {
			return err
		}
	}
	for _, j := range jobs.AllPostsubmits(nil) {
		if err := applySingleProwjobAnnotations(c, pc, j.JobBase, prowapi.PostsubmitJob); err != nil {
			return err
		}
	}
	for _, j := range jobs.AllPresubmits(nil) {
		if err := applySingleProwjobAnnotations(c, pc, j.JobBase, prowapi.PresubmitJob); err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>Handle jobs without test groups (presubmit jobs) better.<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 main

import (
	"fmt"
	"k8s.io/test-infra/testgrid/config"
	"path"
	"strconv"
	"strings"

	prowapi "k8s.io/test-infra/prow/apis/prowjobs/v1"
	prowConfig "k8s.io/test-infra/prow/config"
	"k8s.io/test-infra/prow/pod-utils/downwardapi"
	prowGCS "k8s.io/test-infra/prow/pod-utils/gcs"
)

const testgridCreateTestGroupAnnotation = "testgrid-create-test-group"
const testgridDashboardsAnnotation = "testgrid-dashboards"
const testgridTabNameAnnotation = "testgrid-tab-name"
const testgridEmailAnnotation = "testgrid-alert-email"
const testgridNumColumnsRecentAnnotation = "testgrid-num-columns-recent"
const testgridAlertStaleResultsHoursAnnotation = "testgrid-alert-stale-results-hours"
const testgridNumFailuresToAlertAnnotation = "testgrid-num-failures-to-alert"
const descriptionAnnotation = "description"

// Talk to @michelle192837 if you're thinking about adding more of these!

func applySingleProwjobAnnotations(c *Config, pc *prowConfig.Config, j prowConfig.JobBase, jobType prowapi.ProwJobType) error {
	tabName := j.Name
	testGroupName := j.Name
	description := j.Name

	mustMakeGroup := j.Annotations[testgridCreateTestGroupAnnotation] == "true"
	mustNotMakeGroup := j.Annotations[testgridCreateTestGroupAnnotation] == "false"
	dashboards, addToDashboards := j.Annotations[testgridDashboardsAnnotation]
	mightMakeGroup := (mustMakeGroup || addToDashboards || jobType != prowapi.PresubmitJob) && !mustNotMakeGroup
	var testGroup *config.TestGroup

	if mightMakeGroup {
		if testGroup = c.config.FindTestGroup(testGroupName); testGroup != nil {
			if mustMakeGroup {
				return fmt.Errorf("test group %q already exists", testGroupName)
			}
		} else {
			var prefix string
			if j.DecorationConfig != nil && j.DecorationConfig.GCSConfiguration != nil {
				prefix = path.Join(j.DecorationConfig.GCSConfiguration.Bucket, j.DecorationConfig.GCSConfiguration.PathPrefix)
			} else if pc.Plank.DefaultDecorationConfig != nil && pc.Plank.DefaultDecorationConfig.GCSConfiguration != nil {
				prefix = path.Join(pc.Plank.DefaultDecorationConfig.GCSConfiguration.Bucket, pc.Plank.DefaultDecorationConfig.GCSConfiguration.PathPrefix)
			} else {
				return fmt.Errorf("job %s: couldn't figure out a default decoration config", j.Name)
			}

			testGroup = &config.TestGroup{
				Name:      testGroupName,
				GcsPrefix: path.Join(prefix, prowGCS.RootForSpec(&downwardapi.JobSpec{Job: j.Name, Type: jobType})),
			}
			ReconcileTestGroup(testGroup, c.defaultConfig.DefaultTestGroup)
			c.config.TestGroups = append(c.config.TestGroups, testGroup)
		}
	} else {
		testGroup = c.config.FindTestGroup(testGroupName)
	}

	if testGroup == nil {
		for _, a := range []string{testgridNumColumnsRecentAnnotation, testgridAlertStaleResultsHoursAnnotation,
			testgridNumFailuresToAlertAnnotation, testgridTabNameAnnotation, testgridEmailAnnotation} {
			_, ok := j.Annotations[a]
			if ok {
				return fmt.Errorf("no testgroup exists for job %q, but annotation %q implies one should exist", j.Name, a)
			}
		}
		// exit early: with no test group, there's nothing else for us to usefully do with the job.
		return nil
	}

	if ncr, ok := j.Annotations[testgridNumColumnsRecentAnnotation]; ok {
		ncrInt, err := strconv.ParseInt(ncr, 10, 32)
		if err != nil {
			return fmt.Errorf("%s value %q is not a valid integer", testgridNumColumnsRecentAnnotation, ncr)
		}
		testGroup.NumColumnsRecent = int32(ncrInt)
	}

	if srh, ok := j.Annotations[testgridAlertStaleResultsHoursAnnotation]; ok {
		srhInt, err := strconv.ParseInt(srh, 10, 32)
		if err != nil {
			return fmt.Errorf("%s value %q is not a valid integer", testgridAlertStaleResultsHoursAnnotation, srh)
		}
		testGroup.AlertStaleResultsHours = int32(srhInt)
	}

	if nfta, ok := j.Annotations[testgridNumFailuresToAlertAnnotation]; ok {
		nftaInt, err := strconv.ParseInt(nfta, 10, 32)
		if err != nil {
			return fmt.Errorf("%s value %q is not a valid integer", testgridNumFailuresToAlertAnnotation, nfta)
		}
		testGroup.NumFailuresToAlert = int32(nftaInt)
	}

	if tn, ok := j.Annotations[testgridTabNameAnnotation]; ok {
		tabName = tn
	}
	if d := j.Annotations[descriptionAnnotation]; d != "" {
		description = d
	}

	if addToDashboards {
		firstDashboard := true
		for _, dashboardName := range strings.Split(dashboards, ",") {
			dashboardName = strings.TrimSpace(dashboardName)
			d := c.config.FindDashboard(dashboardName)
			if d == nil {
				return fmt.Errorf("couldn't find dashboard %q for job %q", dashboardName, j.Name)
			}
			dt := &config.DashboardTab{
				Name:          tabName,
				TestGroupName: testGroupName,
				Description:   description,
			}
			if firstDashboard {
				firstDashboard = false
				if emails, ok := j.Annotations[testgridEmailAnnotation]; ok {
					dt.AlertOptions = &config.DashboardTabAlertOptions{AlertMailToAddresses: emails}
				}
			}
			ReconcileDashboardTab(dt, c.defaultConfig.DefaultDashboardTab)
			d.DashboardTab = append(d.DashboardTab, dt)
		}
	}

	return nil
}

func applyProwjobAnnotations(c *Config, prowConfigAgent *prowConfig.Agent) error {
	pc := prowConfigAgent.Config()
	if pc == nil {
		return nil
	}
	jobs := prowConfigAgent.Config().JobConfig
	for _, j := range jobs.AllPeriodics() {
		if err := applySingleProwjobAnnotations(c, pc, j.JobBase, prowapi.PeriodicJob); err != nil {
			return err
		}
	}
	for _, j := range jobs.AllPostsubmits(nil) {
		if err := applySingleProwjobAnnotations(c, pc, j.JobBase, prowapi.PostsubmitJob); err != nil {
			return err
		}
	}
	for _, j := range jobs.AllPresubmits(nil) {
		if err := applySingleProwjobAnnotations(c, pc, j.JobBase, prowapi.PresubmitJob); err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


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

package github

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"reflect"
	"testing"
)

func TestActivityService_ListWatchers(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/repos/o/r/subscribers", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "GET")
		testFormValues(t, r, values{
			"page": "2",
		})

		fmt.Fprint(w, `[{"id":1}]`)
	})

	ctx := context.Background()
	watchers, _, err := client.Activity.ListWatchers(ctx, "o", "r", &ListOptions{Page: 2})
	if err != nil {
		t.Errorf("Activity.ListWatchers returned error: %v", err)
	}

	want := []*User{{ID: Int64(1)}}
	if !reflect.DeepEqual(watchers, want) {
		t.Errorf("Activity.ListWatchers returned %+v, want %+v", watchers, want)
	}
}

func TestActivityService_ListWatched_authenticatedUser(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/user/subscriptions", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "GET")
		testFormValues(t, r, values{
			"page": "2",
		})
		fmt.Fprint(w, `[{"id":1}]`)
	})

	ctx := context.Background()
	watched, _, err := client.Activity.ListWatched(ctx, "", &ListOptions{Page: 2})
	if err != nil {
		t.Errorf("Activity.ListWatched returned error: %v", err)
	}

	want := []*Repository{{ID: Int64(1)}}
	if !reflect.DeepEqual(watched, want) {
		t.Errorf("Activity.ListWatched returned %+v, want %+v", watched, want)
	}
}

func TestActivityService_ListWatched_specifiedUser(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/users/u/subscriptions", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "GET")
		testFormValues(t, r, values{
			"page": "2",
		})
		fmt.Fprint(w, `[{"id":1}]`)
	})

	ctx := context.Background()
	watched, _, err := client.Activity.ListWatched(ctx, "u", &ListOptions{Page: 2})
	if err != nil {
		t.Errorf("Activity.ListWatched returned error: %v", err)
	}

	want := []*Repository{{ID: Int64(1)}}
	if !reflect.DeepEqual(watched, want) {
		t.Errorf("Activity.ListWatched returned %+v, want %+v", watched, want)
	}
}

func TestActivityService_GetRepositorySubscription_true(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/repos/o/r/subscription", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "GET")
		fmt.Fprint(w, `{"subscribed":true}`)
	})

	ctx := context.Background()
	sub, _, err := client.Activity.GetRepositorySubscription(ctx, "o", "r")
	if err != nil {
		t.Errorf("Activity.GetRepositorySubscription returned error: %v", err)
	}

	want := &Subscription{Subscribed: Bool(true)}
	if !reflect.DeepEqual(sub, want) {
		t.Errorf("Activity.GetRepositorySubscription returned %+v, want %+v", sub, want)
	}
}

func TestActivityService_GetRepositorySubscription_false(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/repos/o/r/subscription", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "GET")
		w.WriteHeader(http.StatusNotFound)
	})

	ctx := context.Background()
	sub, _, err := client.Activity.GetRepositorySubscription(ctx, "o", "r")
	if err != nil {
		t.Errorf("Activity.GetRepositorySubscription returned error: %v", err)
	}

	var want *Subscription
	if !reflect.DeepEqual(sub, want) {
		t.Errorf("Activity.GetRepositorySubscription returned %+v, want %+v", sub, want)
	}
}

func TestActivityService_GetRepositorySubscription_error(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/repos/o/r/subscription", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "GET")
		w.WriteHeader(http.StatusBadRequest)
	})

	ctx := context.Background()
	_, _, err := client.Activity.GetRepositorySubscription(ctx, "o", "r")
	if err == nil {
		t.Errorf("Expected HTTP 400 response")
	}
}

func TestActivityService_SetRepositorySubscription(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	input := &Subscription{Subscribed: Bool(true)}

	mux.HandleFunc("/repos/o/r/subscription", func(w http.ResponseWriter, r *http.Request) {
		v := new(Subscription)
		json.NewDecoder(r.Body).Decode(v)

		testMethod(t, r, "PUT")
		if !reflect.DeepEqual(v, input) {
			t.Errorf("Request body = %+v, want %+v", v, input)
		}

		fmt.Fprint(w, `{"ignored":true}`)
	})

	ctx := context.Background()
	sub, _, err := client.Activity.SetRepositorySubscription(ctx, "o", "r", input)
	if err != nil {
		t.Errorf("Activity.SetRepositorySubscription returned error: %v", err)
	}

	want := &Subscription{Ignored: Bool(true)}
	if !reflect.DeepEqual(sub, want) {
		t.Errorf("Activity.SetRepositorySubscription returned %+v, want %+v", sub, want)
	}
}

func TestActivityService_DeleteRepositorySubscription(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/repos/o/r/subscription", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "DELETE")
		w.WriteHeader(http.StatusNoContent)
	})

	ctx := context.Background()
	_, err := client.Activity.DeleteRepositorySubscription(ctx, "o", "r")
	if err != nil {
		t.Errorf("Activity.DeleteRepositorySubscription returned error: %v", err)
	}
}
<commit_msg>Improve activity_watching.go coverage (#1706)<commit_after>// Copyright 2014 The go-github AUTHORS. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package github

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"reflect"
	"testing"
)

func TestActivityService_ListWatchers(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/repos/o/r/subscribers", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "GET")
		testFormValues(t, r, values{
			"page": "2",
		})

		fmt.Fprint(w, `[{"id":1}]`)
	})

	ctx := context.Background()
	watchers, _, err := client.Activity.ListWatchers(ctx, "o", "r", &ListOptions{Page: 2})
	if err != nil {
		t.Errorf("Activity.ListWatchers returned error: %v", err)
	}

	want := []*User{{ID: Int64(1)}}
	if !reflect.DeepEqual(watchers, want) {
		t.Errorf("Activity.ListWatchers returned %+v, want %+v", watchers, want)
	}

	const methodName = "ListWatchers"
	testBadOptions(t, methodName, func() (err error) {
		_, _, err = client.Activity.ListWatchers(ctx, "\n", "\n", &ListOptions{Page: 2})
		return err
	})

	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
		got, resp, err := client.Activity.ListWatchers(ctx, "o", "r", &ListOptions{Page: 2})
		if got != nil {
			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
		}
		return resp, err
	})
}

func TestActivityService_ListWatched_authenticatedUser(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/user/subscriptions", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "GET")
		testFormValues(t, r, values{
			"page": "2",
		})
		fmt.Fprint(w, `[{"id":1}]`)
	})

	ctx := context.Background()
	watched, _, err := client.Activity.ListWatched(ctx, "", &ListOptions{Page: 2})
	if err != nil {
		t.Errorf("Activity.ListWatched returned error: %v", err)
	}

	want := []*Repository{{ID: Int64(1)}}
	if !reflect.DeepEqual(watched, want) {
		t.Errorf("Activity.ListWatched returned %+v, want %+v", watched, want)
	}

	const methodName = "ListWatched"
	testBadOptions(t, methodName, func() (err error) {
		_, _, err = client.Activity.ListWatched(ctx, "\n", &ListOptions{Page: 2})
		return err
	})

	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
		got, resp, err := client.Activity.ListWatched(ctx, "", &ListOptions{Page: 2})
		if got != nil {
			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
		}
		return resp, err
	})
}

func TestActivityService_ListWatched_specifiedUser(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/users/u/subscriptions", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "GET")
		testFormValues(t, r, values{
			"page": "2",
		})
		fmt.Fprint(w, `[{"id":1}]`)
	})

	ctx := context.Background()
	watched, _, err := client.Activity.ListWatched(ctx, "u", &ListOptions{Page: 2})
	if err != nil {
		t.Errorf("Activity.ListWatched returned error: %v", err)
	}

	want := []*Repository{{ID: Int64(1)}}
	if !reflect.DeepEqual(watched, want) {
		t.Errorf("Activity.ListWatched returned %+v, want %+v", watched, want)
	}
}

func TestActivityService_GetRepositorySubscription_true(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/repos/o/r/subscription", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "GET")
		fmt.Fprint(w, `{"subscribed":true}`)
	})

	ctx := context.Background()
	sub, _, err := client.Activity.GetRepositorySubscription(ctx, "o", "r")
	if err != nil {
		t.Errorf("Activity.GetRepositorySubscription returned error: %v", err)
	}

	want := &Subscription{Subscribed: Bool(true)}
	if !reflect.DeepEqual(sub, want) {
		t.Errorf("Activity.GetRepositorySubscription returned %+v, want %+v", sub, want)
	}

	const methodName = "GetRepositorySubscription"
	testBadOptions(t, methodName, func() (err error) {
		_, _, err = client.Activity.GetRepositorySubscription(ctx, "\n", "\n")
		return err
	})

	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
		got, resp, err := client.Activity.GetRepositorySubscription(ctx, "o", "r")
		if got != nil {
			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
		}
		return resp, err
	})
}

func TestActivityService_GetRepositorySubscription_false(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/repos/o/r/subscription", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "GET")
		w.WriteHeader(http.StatusNotFound)
	})

	ctx := context.Background()
	sub, _, err := client.Activity.GetRepositorySubscription(ctx, "o", "r")
	if err != nil {
		t.Errorf("Activity.GetRepositorySubscription returned error: %v", err)
	}

	var want *Subscription
	if !reflect.DeepEqual(sub, want) {
		t.Errorf("Activity.GetRepositorySubscription returned %+v, want %+v", sub, want)
	}
}

func TestActivityService_GetRepositorySubscription_error(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/repos/o/r/subscription", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "GET")
		w.WriteHeader(http.StatusBadRequest)
	})

	ctx := context.Background()
	_, _, err := client.Activity.GetRepositorySubscription(ctx, "o", "r")
	if err == nil {
		t.Errorf("Expected HTTP 400 response")
	}
}

func TestActivityService_SetRepositorySubscription(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	input := &Subscription{Subscribed: Bool(true)}

	mux.HandleFunc("/repos/o/r/subscription", func(w http.ResponseWriter, r *http.Request) {
		v := new(Subscription)
		json.NewDecoder(r.Body).Decode(v)

		testMethod(t, r, "PUT")
		if !reflect.DeepEqual(v, input) {
			t.Errorf("Request body = %+v, want %+v", v, input)
		}

		fmt.Fprint(w, `{"ignored":true}`)
	})

	ctx := context.Background()
	sub, _, err := client.Activity.SetRepositorySubscription(ctx, "o", "r", input)
	if err != nil {
		t.Errorf("Activity.SetRepositorySubscription returned error: %v", err)
	}

	want := &Subscription{Ignored: Bool(true)}
	if !reflect.DeepEqual(sub, want) {
		t.Errorf("Activity.SetRepositorySubscription returned %+v, want %+v", sub, want)
	}

	const methodName = "SetRepositorySubscription"
	testBadOptions(t, methodName, func() (err error) {
		_, _, err = client.Activity.SetRepositorySubscription(ctx, "\n", "\n", input)
		return err
	})

	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
		got, resp, err := client.Activity.SetRepositorySubscription(ctx, "o", "r", input)
		if got != nil {
			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
		}
		return resp, err
	})
}

func TestActivityService_DeleteRepositorySubscription(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/repos/o/r/subscription", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "DELETE")
		w.WriteHeader(http.StatusNoContent)
	})

	ctx := context.Background()
	_, err := client.Activity.DeleteRepositorySubscription(ctx, "o", "r")
	if err != nil {
		t.Errorf("Activity.DeleteRepositorySubscription returned error: %v", err)
	}

	const methodName = "DeleteRepositorySubscription"
	testBadOptions(t, methodName, func() (err error) {
		_, err = client.Activity.DeleteRepositorySubscription(ctx, "\n", "\n")
		return err
	})

	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
		return client.Activity.DeleteRepositorySubscription(ctx, "o", "r")
	})
}
<|endoftext|>