<commit_before>package main

import (
	"fmt"
	"github.com/mikee385/GolangRayTracer/color"
	"github.com/mikee385/GolangRayTracer/geometry"
	"github.com/mikee385/GolangRayTracer/image"
	"github.com/mikee385/GolangRayTracer/material"
	"github.com/mikee385/GolangRayTracer/scene"
	"github.com/mikee385/GolangRayTracer/table"
)

var EXAMPLE_TO_RUN = 1

func main() {

	var camera scene.Camera
	var imageScene scene.Scene

	if EXAMPLE_TO_RUN == 1 {
		//----------------------------------------------------------------------
		// Scratchapixel Tutorial
		//----------------------------------------------------------------------

		var backgroundColor = color.New(2.0, 2.0, 2.0)
		imageScene = scene.NewScene(backgroundColor, 1.0, 5)

		var groundSphere = scene.NewSphere(geometry.NewPoint(0.0, -10004.0, 20.0), 10000.0, material.NewBuilder().
			Color(color.New(0.2, 0.2, 0.2)).
			Diffuse(1.0).
			Specular(0.0).
			Shininess(0).
			Reflection(0.0).
			Refraction(0.0).
			RefractiveIndex(0.0).
			ToMaterial())
		imageScene.AddObject(groundSphere)

		var sphere1 = scene.NewSphere(geometry.NewPoint(0.0, 0.0, 20.0), 4.0, material.NewBuilder().
			Color(color.New(1.0, 0.32, 0.36)).
			Diffuse(1.0).
			Specular(0.0).
			Shininess(0).
			Reflection(1.0).
			Refraction(0.5).
			RefractiveIndex(1.1).
			ToMaterial())
		imageScene.AddObject(sphere1)

		var sphere2 = scene.NewSphere(geometry.NewPoint(5.0, -1.0, 15.0), 2.0, material.NewBuilder().
			Color(color.New(0.9, 0.76, 0.46)).
			Diffuse(1.0).
			Specular(0.0).
			Shininess(0).
			Reflection(1.0).
			Refraction(0.0).
			RefractiveIndex(0.0).
			ToMaterial())
		imageScene.AddObject(sphere2)

		var sphere3 = scene.NewSphere(geometry.NewPoint(5.0, 0.0, 25.0), 3.0, material.NewBuilder().
			Color(color.New(0.65, 0.77, 0.97)).
			Diffuse(1.0).
			Specular(0.0).
			Shininess(0).
			Reflection(1.0).
			Refraction(0.0).
			RefractiveIndex(0.0).
			ToMaterial())
		imageScene.AddObject(sphere3)

		var sphere4 = scene.NewSphere(geometry.NewPoint(-5.5, 0.0, 15.0), 3.0, material.NewBuilder().
			Color(color.New(0.90, 0.90, 0.90)).
			Diffuse(1.0).
			Specular(0.0).
			Shininess(0).
			Reflection(1.0).
			Refraction(0.0).
			RefractiveIndex(0.0).
			ToMaterial())
		imageScene.AddObject(sphere4)

		var lightSource = scene.NewLight(geometry.NewPoint(0.0, 20.0, 30.0), 3.0, color.New(3.0, 3.0, 3.0))
		imageScene.AddLightSource(&lightSource)

		var imageWidth = 640
		var imageHeight = 480
		var fieldOfView float32 = 30.0
		camera = scene.NewCamera_FromFOV(imageWidth, imageHeight, fieldOfView, 1.0, geometry.Origin(), geometry.NewPoint(0.0, 0.0, 1.0))

	} else if EXAMPLE_TO_RUN == 2 {
		//----------------------------------------------------------------------
		// flipcode Tutorial, version 1 & version 2
		//----------------------------------------------------------------------

		imageScene = scene.NewScene(color.Black(), 1.0, 5)

		var groundPlane = scene.NewPlane_FromDVector(4.4, geometry.NewVector(0.0, 1.0, 0.0), material.NewBuilder().
			Color(color.New(0.4, 0.3, 0.3)).
			Diffuse(1.0).
			Specular(0.0).
			Shininess(0).
			Reflection(0.0).
			ToMaterial())
		imageScene.AddObject(groundPlane)

		var bigSphere = scene.NewSphere(geometry.NewPoint(1.0, -0.8, 3.0), 2.5, material.NewBuilder().
			Color(color.New(0.7, 0.7, 0.7)).
			Diffuse(0.2).
			Specular(0.8).
			Shininess(20).
			Reflection(0.6).
			ToMaterial())
		imageScene.AddObject(bigSphere)

		var smallSphere = scene.NewSphere(geometry.NewPoint(-5.5, -0.5, 7.0), 2.0, material.NewBuilder().
			Color(color.New(0.7, 0.7, 1.0)).
			Diffuse(0.1).
			Specular(0.9).
			Shininess(20).
			Reflection(1.0).
			ToMaterial())
		imageScene.AddObject(smallSphere)

		var lightSource1 = scene.NewLight(geometry.NewPoint(0.0, 5.0, 5.0), 0.1, color.New(0.6, 0.6, 0.6))
		imageScene.AddLightSource(&lightSource1)

		var lightSource2 = scene.NewLight(geometry.NewPoint(2.0, 5.0, 1.0), 0.1, color.New(0.7, 0.7, 0.9))
		imageScene.AddLightSource(&lightSource2)

		var imageWidth = 800
		var imageHeight = 600
		camera = scene.NewCamera_FromDimensions(imageWidth, imageHeight, 8.0, 6.0, 5.0, geometry.NewPoint(0.0, 0.0, -5.0), geometry.NewPoint(0.0, 0.0, 1.0))

	} else if EXAMPLE_TO_RUN == 3 {
		//----------------------------------------------------------------------
		// flipcode Tutorial, version 3
		//----------------------------------------------------------------------

		imageScene = scene.NewScene(color.Black(), 1.0, 5)

		var groundPlane = scene.NewPlane_FromDVector(4.4, geometry.NewVector(0.0, 1.0, 0.0), material.NewBuilder().
			Color(color.New(0.4, 0.3, 0.3)).
			Diffuse(1.0).
			Specular(0.8).
			Shininess(20).
			Reflection(0.0).
			Refraction(0.0).
			RefractiveIndex(0.0).
			ToMaterial())
		imageScene.AddObject(groundPlane)

		var bigSphere = scene.NewSphere(geometry.NewPoint(2.0, 0.8, 3.0), 2.5, material.NewBuilder().
			Color(color.New(0.7, 0.7, 1.0)).
			Diffuse(0.2).
			Specular(0.8).
			Shininess(20).
			Reflection(0.2).
			Refraction(0.8).
			RefractiveIndex(1.3).
			ToMaterial())
		imageScene.AddObject(bigSphere)

		var smallSphere = scene.NewSphere(geometry.NewPoint(-5.5, -0.5, 7.0), 2.0, material.NewBuilder().
			Color(color.New(0.7, 0.7, 1.0)).
			Diffuse(0.1).
			Specular(0.8).
			Shininess(20).
			Reflection(0.5).
			Refraction(0.0).
			RefractiveIndex(1.3).
			ToMaterial())
		imageScene.AddObject(smallSphere)

		var lightSource1 = scene.NewLight(geometry.NewPoint(0.0, 5.0, 5.0), 0.1, color.New(0.4, 0.4, 0.4))
		imageScene.AddLightSource(&lightSource1)

		var lightSource2 = scene.NewLight(geometry.NewPoint(-3.0, 5.0, 1.0), 0.1, color.New(0.6, 0.6, 0.8))
		imageScene.AddLightSource(&lightSource2)

		var extraSphere = scene.NewSphere(geometry.NewPoint(-1.5, -3.8, 1.0), 1.5, material.NewBuilder().
			Color(color.New(1.0, 0.4, 0.4)).
			Diffuse(0.2).
			Specular(0.8).
			Shininess(20).
			Reflection(0.0).
			Refraction(0.8).
			RefractiveIndex(1.5).
			ToMaterial())
		imageScene.AddObject(extraSphere)

		var backPlane = scene.NewPlane_FromDVector(12.0, geometry.NewVector(0.4, 0.0, -1.0), material.NewBuilder().
			Color(color.New(0.5, 0.3, 0.5)).
			Diffuse(0.6).
			Specular(0.0).
			Shininess(0).
			Reflection(0.0).
			Refraction(0.0).
			RefractiveIndex(0.0).
			ToMaterial())
		imageScene.AddObject(backPlane)

		var ceilingPlane = scene.NewPlane_FromDVector(7.4, geometry.NewVector(0.0, -1.0, 0.0), material.NewBuilder().
			Color(color.New(0.4, 0.7, 0.7)).
			Diffuse(0.5).
			Specular(0.0).
			Shininess(0).
			Reflection(0.0).
			Refraction(0.0).
			RefractiveIndex(0.0).
			ToMaterial())
		imageScene.AddObject(ceilingPlane)

		var gridSpheres = make([]scene.Sphere, 0, 8*7)
		for x := 0; x < 8; x++ {
			for y := 0; y < 7; y++ {
				gridSpheres = append(gridSpheres, scene.NewSphere(geometry.NewPoint(-4.5+float32(x)*1.5, -4.3+float32(y)*1.5, 10.0), 0.3, material.NewBuilder().
					Color(color.New(0.3, 1.0, 0.4)).
					Diffuse(0.6).
					Specular(0.6).
					Shininess(20).
					Reflection(0.0).
					Refraction(0.0).
					RefractiveIndex(0.0).
					ToMaterial()))
			}
		}
		for _, gridSphere := range gridSpheres {
			imageScene.AddObject(gridSphere)
		}

		var imageWidth = 800
		var imageHeight = 600
		camera = scene.NewCamera_FromDimensions(imageWidth, imageHeight, 8.0, 6.0, 5.0, geometry.NewPoint(0.0, 0.0, -5.0), geometry.NewPoint(0.0, 0.0, 1.0))
	}

	var pixelTable = render(&imageScene, &camera)
	var image = image.NewPPMImage(fmt.Sprintf("example%v.ppm", EXAMPLE_TO_RUN))
	var err = image.Save(pixelTable)
	if err != nil {
		panic(err)
	}
}

func render(imageScene *scene.Scene, camera *scene.Camera) *table.Table {
	var width = camera.ImageWidth()
	var height = camera.ImageHeight()
	var pixelTable = table.New(width, height)

	for row := 0; row < height; row++ {
		for column := 0; column < width; column++ {
			pixelTable.Set(row, column, color.Green())
		}
	}

	return &pixelTable
}
<commit_msg>Completes to `render` function of `main`.<commit_after>package main

import (
	"fmt"
	"github.com/mikee385/GolangRayTracer/color"
	"github.com/mikee385/GolangRayTracer/geometry"
	"github.com/mikee385/GolangRayTracer/image"
	"github.com/mikee385/GolangRayTracer/material"
	"github.com/mikee385/GolangRayTracer/scene"
	"github.com/mikee385/GolangRayTracer/table"
	"math"
)

var EXAMPLE_TO_RUN = 1

func main() {

	var camera scene.Camera
	var imageScene scene.Scene

	if EXAMPLE_TO_RUN == 1 {
		//----------------------------------------------------------------------
		// Scratchapixel Tutorial
		//----------------------------------------------------------------------

		var backgroundColor = color.New(2.0, 2.0, 2.0)
		imageScene = scene.NewScene(backgroundColor, 1.0, 5)

		var groundSphere = scene.NewSphere(geometry.NewPoint(0.0, -10004.0, 20.0), 10000.0, material.NewBuilder().
			Color(color.New(0.2, 0.2, 0.2)).
			Diffuse(1.0).
			Specular(0.0).
			Shininess(0).
			Reflection(0.0).
			Refraction(0.0).
			RefractiveIndex(0.0).
			ToMaterial())
		imageScene.AddObject(groundSphere)

		var sphere1 = scene.NewSphere(geometry.NewPoint(0.0, 0.0, 20.0), 4.0, material.NewBuilder().
			Color(color.New(1.0, 0.32, 0.36)).
			Diffuse(1.0).
			Specular(0.0).
			Shininess(0).
			Reflection(1.0).
			Refraction(0.5).
			RefractiveIndex(1.1).
			ToMaterial())
		imageScene.AddObject(sphere1)

		var sphere2 = scene.NewSphere(geometry.NewPoint(5.0, -1.0, 15.0), 2.0, material.NewBuilder().
			Color(color.New(0.9, 0.76, 0.46)).
			Diffuse(1.0).
			Specular(0.0).
			Shininess(0).
			Reflection(1.0).
			Refraction(0.0).
			RefractiveIndex(0.0).
			ToMaterial())
		imageScene.AddObject(sphere2)

		var sphere3 = scene.NewSphere(geometry.NewPoint(5.0, 0.0, 25.0), 3.0, material.NewBuilder().
			Color(color.New(0.65, 0.77, 0.97)).
			Diffuse(1.0).
			Specular(0.0).
			Shininess(0).
			Reflection(1.0).
			Refraction(0.0).
			RefractiveIndex(0.0).
			ToMaterial())
		imageScene.AddObject(sphere3)

		var sphere4 = scene.NewSphere(geometry.NewPoint(-5.5, 0.0, 15.0), 3.0, material.NewBuilder().
			Color(color.New(0.90, 0.90, 0.90)).
			Diffuse(1.0).
			Specular(0.0).
			Shininess(0).
			Reflection(1.0).
			Refraction(0.0).
			RefractiveIndex(0.0).
			ToMaterial())
		imageScene.AddObject(sphere4)

		var lightSource = scene.NewLight(geometry.NewPoint(0.0, 20.0, 30.0), 3.0, color.New(3.0, 3.0, 3.0))
		imageScene.AddLightSource(&lightSource)

		var imageWidth = 640
		var imageHeight = 480
		var fieldOfView float32 = 30.0
		camera = scene.NewCamera_FromFOV(imageWidth, imageHeight, fieldOfView, 1.0, geometry.Origin(), geometry.NewPoint(0.0, 0.0, 1.0))

	} else if EXAMPLE_TO_RUN == 2 {
		//----------------------------------------------------------------------
		// flipcode Tutorial, version 1 & version 2
		//----------------------------------------------------------------------

		imageScene = scene.NewScene(color.Black(), 1.0, 5)

		var groundPlane = scene.NewPlane_FromDVector(4.4, geometry.NewVector(0.0, 1.0, 0.0), material.NewBuilder().
			Color(color.New(0.4, 0.3, 0.3)).
			Diffuse(1.0).
			Specular(0.0).
			Shininess(0).
			Reflection(0.0).
			ToMaterial())
		imageScene.AddObject(groundPlane)

		var bigSphere = scene.NewSphere(geometry.NewPoint(1.0, -0.8, 3.0), 2.5, material.NewBuilder().
			Color(color.New(0.7, 0.7, 0.7)).
			Diffuse(0.2).
			Specular(0.8).
			Shininess(20).
			Reflection(0.6).
			ToMaterial())
		imageScene.AddObject(bigSphere)

		var smallSphere = scene.NewSphere(geometry.NewPoint(-5.5, -0.5, 7.0), 2.0, material.NewBuilder().
			Color(color.New(0.7, 0.7, 1.0)).
			Diffuse(0.1).
			Specular(0.9).
			Shininess(20).
			Reflection(1.0).
			ToMaterial())
		imageScene.AddObject(smallSphere)

		var lightSource1 = scene.NewLight(geometry.NewPoint(0.0, 5.0, 5.0), 0.1, color.New(0.6, 0.6, 0.6))
		imageScene.AddLightSource(&lightSource1)

		var lightSource2 = scene.NewLight(geometry.NewPoint(2.0, 5.0, 1.0), 0.1, color.New(0.7, 0.7, 0.9))
		imageScene.AddLightSource(&lightSource2)

		var imageWidth = 800
		var imageHeight = 600
		camera = scene.NewCamera_FromDimensions(imageWidth, imageHeight, 8.0, 6.0, 5.0, geometry.NewPoint(0.0, 0.0, -5.0), geometry.NewPoint(0.0, 0.0, 1.0))

	} else if EXAMPLE_TO_RUN == 3 {
		//----------------------------------------------------------------------
		// flipcode Tutorial, version 3
		//----------------------------------------------------------------------

		imageScene = scene.NewScene(color.Black(), 1.0, 5)

		var groundPlane = scene.NewPlane_FromDVector(4.4, geometry.NewVector(0.0, 1.0, 0.0), material.NewBuilder().
			Color(color.New(0.4, 0.3, 0.3)).
			Diffuse(1.0).
			Specular(0.8).
			Shininess(20).
			Reflection(0.0).
			Refraction(0.0).
			RefractiveIndex(0.0).
			ToMaterial())
		imageScene.AddObject(groundPlane)

		var bigSphere = scene.NewSphere(geometry.NewPoint(2.0, 0.8, 3.0), 2.5, material.NewBuilder().
			Color(color.New(0.7, 0.7, 1.0)).
			Diffuse(0.2).
			Specular(0.8).
			Shininess(20).
			Reflection(0.2).
			Refraction(0.8).
			RefractiveIndex(1.3).
			ToMaterial())
		imageScene.AddObject(bigSphere)

		var smallSphere = scene.NewSphere(geometry.NewPoint(-5.5, -0.5, 7.0), 2.0, material.NewBuilder().
			Color(color.New(0.7, 0.7, 1.0)).
			Diffuse(0.1).
			Specular(0.8).
			Shininess(20).
			Reflection(0.5).
			Refraction(0.0).
			RefractiveIndex(1.3).
			ToMaterial())
		imageScene.AddObject(smallSphere)

		var lightSource1 = scene.NewLight(geometry.NewPoint(0.0, 5.0, 5.0), 0.1, color.New(0.4, 0.4, 0.4))
		imageScene.AddLightSource(&lightSource1)

		var lightSource2 = scene.NewLight(geometry.NewPoint(-3.0, 5.0, 1.0), 0.1, color.New(0.6, 0.6, 0.8))
		imageScene.AddLightSource(&lightSource2)

		var extraSphere = scene.NewSphere(geometry.NewPoint(-1.5, -3.8, 1.0), 1.5, material.NewBuilder().
			Color(color.New(1.0, 0.4, 0.4)).
			Diffuse(0.2).
			Specular(0.8).
			Shininess(20).
			Reflection(0.0).
			Refraction(0.8).
			RefractiveIndex(1.5).
			ToMaterial())
		imageScene.AddObject(extraSphere)

		var backPlane = scene.NewPlane_FromDVector(12.0, geometry.NewVector(0.4, 0.0, -1.0), material.NewBuilder().
			Color(color.New(0.5, 0.3, 0.5)).
			Diffuse(0.6).
			Specular(0.0).
			Shininess(0).
			Reflection(0.0).
			Refraction(0.0).
			RefractiveIndex(0.0).
			ToMaterial())
		imageScene.AddObject(backPlane)

		var ceilingPlane = scene.NewPlane_FromDVector(7.4, geometry.NewVector(0.0, -1.0, 0.0), material.NewBuilder().
			Color(color.New(0.4, 0.7, 0.7)).
			Diffuse(0.5).
			Specular(0.0).
			Shininess(0).
			Reflection(0.0).
			Refraction(0.0).
			RefractiveIndex(0.0).
			ToMaterial())
		imageScene.AddObject(ceilingPlane)

		var gridSpheres = make([]scene.Sphere, 0, 8*7)
		for x := 0; x < 8; x++ {
			for y := 0; y < 7; y++ {
				gridSpheres = append(gridSpheres, scene.NewSphere(geometry.NewPoint(-4.5+float32(x)*1.5, -4.3+float32(y)*1.5, 10.0), 0.3, material.NewBuilder().
					Color(color.New(0.3, 1.0, 0.4)).
					Diffuse(0.6).
					Specular(0.6).
					Shininess(20).
					Reflection(0.0).
					Refraction(0.0).
					RefractiveIndex(0.0).
					ToMaterial()))
			}
		}
		for _, gridSphere := range gridSpheres {
			imageScene.AddObject(gridSphere)
		}

		var imageWidth = 800
		var imageHeight = 600
		camera = scene.NewCamera_FromDimensions(imageWidth, imageHeight, 8.0, 6.0, 5.0, geometry.NewPoint(0.0, 0.0, -5.0), geometry.NewPoint(0.0, 0.0, 1.0))
	}

	var pixelTable = render(&imageScene, &camera)
	var image = image.NewPPMImage(fmt.Sprintf("example%v.ppm", EXAMPLE_TO_RUN))
	var err = image.Save(pixelTable)
	if err != nil {
		panic(err)
	}
}

func render(imageScene *scene.Scene, camera *scene.Camera) *table.Table {
	var width = camera.ImageWidth()
	var height = camera.ImageHeight()
	var pixelTable = table.New(width, height)

	for row := 0; row < height; row++ {
		for column := 0; column < width; column++ {
			var ray = camera.PrimaryRay(row, column)
			var result = imageScene.Trace(ray, 0)

			var resultColor = color.New(
				float32(math.Min(float64(result.Color.Red), 1.0)),
				float32(math.Min(float64(result.Color.Green), 1.0)),
				float32(math.Min(float64(result.Color.Blue), 1.0)))

			pixelTable.Set(row, column, resultColor)
		}
	}

	var isEdge = table.New(width, height)
	isEdge.Fill(false)
	for row := 1; row < height-1; row++ {
		for column := 1; column < width-1; column++ {
			var p1 = pixelTable.Get(row-1, column-1).(color.ColorRGB)
			var p2 = pixelTable.Get(row-1, column).(color.ColorRGB)
			var p3 = pixelTable.Get(row-1, column+1).(color.ColorRGB)
			var p4 = pixelTable.Get(row, column-1).(color.ColorRGB)
			var p6 = pixelTable.Get(row, column+1).(color.ColorRGB)
			var p7 = pixelTable.Get(row+1, column-1).(color.ColorRGB)
			var p8 = pixelTable.Get(row+1, column).(color.ColorRGB)
			var p9 = pixelTable.Get(row+1, column+1).(color.ColorRGB)

			var r = calculateGradient(p1.Red, p2.Red, p3.Red, p4.Red, p6.Red, p7.Red, p8.Red, p9.Red)
			var g = calculateGradient(p1.Green, p2.Green, p3.Green, p4.Green, p6.Green, p7.Green, p8.Green, p9.Green)
			var b = calculateGradient(p1.Blue, p2.Blue, p3.Blue, p4.Blue, p6.Blue, p7.Blue, p8.Blue, p9.Blue)

			if r+b+g > 0.5 {
				isEdge.Set(row, column, true)
			} else {
				isEdge.Set(row, column, false)
			}
		}
	}

	var subWidth = 3
	var subHeight = 3
	var subSize = subWidth * subHeight
	var invSubSize = 1.0 / float32(subSize)
	var subRays = table.New(subWidth, subHeight)
	for row := 0; row < height; row++ {
		for column := 0; column < width; column++ {
			if isEdge.Get(row, column).(bool) {
				var pixelColor = color.Black()

				camera.SubRays(row, column, &subRays)
				for subRow := 0; subRow < subHeight; subRow++ {
					for subColumn := 0; subColumn < subWidth; subColumn++ {
						var result = imageScene.Trace(subRays.Get(subRow, subColumn).(geometry.Ray3D), 0)

						pixelColor = pixelColor.Add(result.Color.Scale(invSubSize))
					}
				}

				pixelTable.Set(row, column, pixelColor)
			}
		}
	}

	return &pixelTable
}

func calculateGradient(p1 float32, p2 float32, p3 float32, p4 float32, p6 float32, p7 float32, p8 float32, p9 float32) float32 {
	var gx = (p3 + 2*p6 + p9) - (p1 + 2*p4 + p7)
	var gy = (p1 + 2*p2 + p3) - (p7 + 2*p8 + p9)
	return float32(math.Sqrt(float64(gx*gx + gy*gy)))
}
<|endoftext|>


<commit_before>/*
Copyright 2016 Citrix Systems, Inc. All rights reserved.

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

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

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

package netscaler

import (
	"encoding/json"
	"fmt"
	"log"
)

//BindResource binds the 'bindingResourceName' to the 'bindToResourceName'.
func (c *NitroClient) BindResource(bindToResourceType string, bindToResourceName string, bindingResourceType string, bindingResourceName string, bindingStruct interface{}) error {
	if c.ResourceExists(bindToResourceType, bindToResourceName) == false {
		return fmt.Errorf("BindTo Resource %s of type %s does not exist", bindToResourceType, bindToResourceName)
	}

	if c.ResourceExists(bindingResourceType, bindingResourceName) == false {
		return fmt.Errorf("Binding Resource %s of type %s does not exist", bindingResourceType, bindingResourceName)
	}
	bindingName := bindToResourceType + "_" + bindingResourceType + "_binding"
	nsBinding := make(map[string]interface{})
	nsBinding[bindingName] = bindingStruct

	resourceJSON, err := json.Marshal(nsBinding)

	body, err := c.createResource(bindingName, resourceJSON)
	if err != nil {
		log.Fatal("Failed to bind resource %s to resource %s, err=%s", bindToResourceName, bindingResourceName, err)
		return err
	}
	_ = body
	return nil
}

//AddResource adds a resource of supplied type and name
func (c *NitroClient) AddResource(resourceType string, name string, resourceStruct interface{}) (string, error) {

	if c.ResourceExists(resourceType, name) == false {

		nsResource := make(map[string]interface{})
		nsResource[resourceType] = resourceStruct

		resourceJSON, err := json.Marshal(nsResource)

		log.Println("Resourcejson is " + string(resourceJSON))

		body, err := c.createResource(resourceType, resourceJSON)
		if err != nil {
			log.Fatal("Failed to create resource of type %s, name=%s, err=%s", resourceType, name, err)
			return "", err
		}
		_ = body
	}

	return name, nil
}

//UpdateResource updates a resource of supplied type and name
func (c *NitroClient) UpdateResource(resourceType string, name string, resourceStruct interface{}) (string, error) {

	if c.ResourceExists(resourceType, name) == true {
		nsResource := make(map[string]interface{})
		nsResource[resourceType] = resourceStruct
		resourceJSON, err := json.Marshal(nsResource)

		log.Println("Resourcejson is " + string(resourceJSON))

		body, err := c.updateResource(resourceType, name, resourceJSON)
		if err != nil {
			log.Fatal(fmt.Sprintf("Failed to update resource of type %s, name=%s err=%s", resourceType, name, err))
			return "", err
		}
		_ = body
	}

	return name, nil
}

//DeleteResource deletes a resource of supplied type and name
func (c *NitroClient) DeleteResource(resourceType string, resourceName string) error {

	_, err := c.listResource(resourceType, resourceName)
	if err == nil { // resource exists
		log.Printf("Found resource of type %s: %s", resourceType, resourceName)
		_, err = c.deleteResource(resourceType, resourceName)
		if err != nil {
			log.Println(fmt.Sprintf("Failed to delete resourceType %s: %s, err=%s", resourceType, resourceName, err))
			return err
		}
	} else {
		log.Printf("Resource %s already deleted ", resourceName)
	}
	return nil
}

//UnbindResource unbinds 'boundResourceName' from 'boundToResource'
func (c *NitroClient) UnbindResource(boundToResourceType string, boundToResourceName string, boundResourceType string, boundResourceName string, bindingFilterName string) error {

	if c.ResourceExists(boundToResourceType, boundToResourceName) == false {
		log.Println(fmt.Sprintf("Unbind: BoundTo Resource %s of type %s does not exist", boundToResourceType, boundToResourceName))
		return nil
	}

	if c.ResourceExists(boundResourceType, boundResourceName) == false {
		log.Println("Unbind: Bound Resource %s of type %s does not exist", boundResourceType, boundResourceName)
		return nil
	}

	_, err := c.unbindResource(boundToResourceType, boundToResourceName, boundResourceType, boundResourceName, bindingFilterName)
	if err != nil {
		return fmt.Errorf("Failed to unbind  %s:%s from %s:%s, err=%s", boundResourceType, boundResourceName, boundToResourceType, boundToResourceName, err)
	}

	return nil
}

//ResourceExists returns true if supplied resource name and type exists
func (c *NitroClient) ResourceExists(resourceType string, resourceName string) bool {
	_, err := c.listResource(resourceType, resourceName)
	if err != nil {
		log.Printf("No %s %s found", resourceType, resourceName)
		return false
	}
	log.Printf("%s %s is already present", resourceType, resourceName)
	return true
}

//FindResource returns the config of the supplied resource name and type if it exists
func (c *NitroClient) FindResource(resourceType string, resourceName string) (map[string]interface{}, error) {
	var data map[string]interface{}
	result, err := c.listResource(resourceType, resourceName)
	if err != nil {
		log.Printf("No %s %s found", resourceType, resourceName)
		return data, fmt.Errorf("No resource %s of type %s found", resourceName, resourceType)
	}
	if err = json.Unmarshal(result, &data); err != nil {
		log.Println("Failed to unmarshal Netscaler Response!")
		return data, fmt.Errorf("Failed to unmarshal Netscaler Response:resource %s of type %s", resourceName, resourceType)
	}
	if data[resourceType] == nil {
		log.Printf("No %s %s found", resourceType, resourceName)
		return data, fmt.Errorf("No resource %s of type %s found", resourceName, resourceType)
	}
	resource := data[resourceType].([]interface{})[0] //only one resource obviously

	return resource.(map[string]interface{}), nil
}

//ResourceBindingExists returns true if the supplied binding exists
func (c *NitroClient) ResourceBindingExists(resourceType string, resourceName string, boundResourceType string, boundResourceFilterName string, boundResourceFilterValue string) bool {
	result, err := c.listBoundResources(resourceName, resourceType, boundResourceType, boundResourceFilterName, boundResourceFilterValue)
	if err != nil {
		log.Printf("No %s %s to %s %s binding found", resourceType, resourceName, boundResourceType, boundResourceFilterValue)
		return false
	}

	var data map[string]interface{}
	if err := json.Unmarshal(result, &data); err != nil {
		log.Println("Failed to unmarshal Netscaler Response!")
		return false
	}
	if data[fmt.Sprintf("%s_%s_binding", resourceType, boundResourceType)] == nil {
		return false
	}

	log.Printf("%s of type  %s is bound to %s type and name %s", resourceType, resourceName, boundResourceType, boundResourceFilterValue)
	return true
}
<commit_msg>re-arrange functions<commit_after>/*
Copyright 2016 Citrix Systems, Inc. All rights reserved.

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

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

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

package netscaler

import (
	"encoding/json"
	"fmt"
	"log"
)

//AddResource adds a resource of supplied type and name
func (c *NitroClient) AddResource(resourceType string, name string, resourceStruct interface{}) (string, error) {

	if c.ResourceExists(resourceType, name) == false {

		nsResource := make(map[string]interface{})
		nsResource[resourceType] = resourceStruct

		resourceJSON, err := json.Marshal(nsResource)

		log.Println("Resourcejson is " + string(resourceJSON))

		body, err := c.createResource(resourceType, resourceJSON)
		if err != nil {
			log.Fatal("Failed to create resource of type %s, name=%s, err=%s", resourceType, name, err)
			return "", err
		}
		_ = body
	}

	return name, nil
}

//UpdateResource updates a resource of supplied type and name
func (c *NitroClient) UpdateResource(resourceType string, name string, resourceStruct interface{}) (string, error) {

	if c.ResourceExists(resourceType, name) == true {
		nsResource := make(map[string]interface{})
		nsResource[resourceType] = resourceStruct
		resourceJSON, err := json.Marshal(nsResource)

		log.Println("Resourcejson is " + string(resourceJSON))

		body, err := c.updateResource(resourceType, name, resourceJSON)
		if err != nil {
			log.Fatal(fmt.Sprintf("Failed to update resource of type %s, name=%s err=%s", resourceType, name, err))
			return "", err
		}
		_ = body
	}

	return name, nil
}

//DeleteResource deletes a resource of supplied type and name
func (c *NitroClient) DeleteResource(resourceType string, resourceName string) error {

	_, err := c.listResource(resourceType, resourceName)
	if err == nil { // resource exists
		log.Printf("Found resource of type %s: %s", resourceType, resourceName)
		_, err = c.deleteResource(resourceType, resourceName)
		if err != nil {
			log.Println(fmt.Sprintf("Failed to delete resourceType %s: %s, err=%s", resourceType, resourceName, err))
			return err
		}
	} else {
		log.Printf("Resource %s already deleted ", resourceName)
	}
	return nil
}

//BindResource binds the 'bindingResourceName' to the 'bindToResourceName'.
func (c *NitroClient) BindResource(bindToResourceType string, bindToResourceName string, bindingResourceType string, bindingResourceName string, bindingStruct interface{}) error {
	if c.ResourceExists(bindToResourceType, bindToResourceName) == false {
		return fmt.Errorf("BindTo Resource %s of type %s does not exist", bindToResourceType, bindToResourceName)
	}

	if c.ResourceExists(bindingResourceType, bindingResourceName) == false {
		return fmt.Errorf("Binding Resource %s of type %s does not exist", bindingResourceType, bindingResourceName)
	}
	bindingName := bindToResourceType + "_" + bindingResourceType + "_binding"
	nsBinding := make(map[string]interface{})
	nsBinding[bindingName] = bindingStruct

	resourceJSON, err := json.Marshal(nsBinding)

	body, err := c.createResource(bindingName, resourceJSON)
	if err != nil {
		log.Fatal("Failed to bind resource %s to resource %s, err=%s", bindToResourceName, bindingResourceName, err)
		return err
	}
	_ = body
	return nil
}

//UnbindResource unbinds 'boundResourceName' from 'boundToResource'
func (c *NitroClient) UnbindResource(boundToResourceType string, boundToResourceName string, boundResourceType string, boundResourceName string, bindingFilterName string) error {

	if c.ResourceExists(boundToResourceType, boundToResourceName) == false {
		log.Println(fmt.Sprintf("Unbind: BoundTo Resource %s of type %s does not exist", boundToResourceType, boundToResourceName))
		return nil
	}

	if c.ResourceExists(boundResourceType, boundResourceName) == false {
		log.Println("Unbind: Bound Resource %s of type %s does not exist", boundResourceType, boundResourceName)
		return nil
	}

	_, err := c.unbindResource(boundToResourceType, boundToResourceName, boundResourceType, boundResourceName, bindingFilterName)
	if err != nil {
		return fmt.Errorf("Failed to unbind  %s:%s from %s:%s, err=%s", boundResourceType, boundResourceName, boundToResourceType, boundToResourceName, err)
	}

	return nil
}

//ResourceExists returns true if supplied resource name and type exists
func (c *NitroClient) ResourceExists(resourceType string, resourceName string) bool {
	_, err := c.listResource(resourceType, resourceName)
	if err != nil {
		log.Printf("No %s %s found", resourceType, resourceName)
		return false
	}
	log.Printf("%s %s is already present", resourceType, resourceName)
	return true
}

//FindResource returns the config of the supplied resource name and type if it exists
func (c *NitroClient) FindResource(resourceType string, resourceName string) (map[string]interface{}, error) {
	var data map[string]interface{}
	result, err := c.listResource(resourceType, resourceName)
	if err != nil {
		log.Printf("No %s %s found", resourceType, resourceName)
		return data, fmt.Errorf("No resource %s of type %s found", resourceName, resourceType)
	}
	if err = json.Unmarshal(result, &data); err != nil {
		log.Println("Failed to unmarshal Netscaler Response!")
		return data, fmt.Errorf("Failed to unmarshal Netscaler Response:resource %s of type %s", resourceName, resourceType)
	}
	if data[resourceType] == nil {
		log.Printf("No %s %s found", resourceType, resourceName)
		return data, fmt.Errorf("No resource %s of type %s found", resourceName, resourceType)
	}
	resource := data[resourceType].([]interface{})[0] //only one resource obviously

	return resource.(map[string]interface{}), nil
}

//ResourceBindingExists returns true if the supplied binding exists
func (c *NitroClient) ResourceBindingExists(resourceType string, resourceName string, boundResourceType string, boundResourceFilterName string, boundResourceFilterValue string) bool {
	result, err := c.listBoundResources(resourceName, resourceType, boundResourceType, boundResourceFilterName, boundResourceFilterValue)
	if err != nil {
		log.Printf("No %s %s to %s %s binding found", resourceType, resourceName, boundResourceType, boundResourceFilterValue)
		return false
	}

	var data map[string]interface{}
	if err := json.Unmarshal(result, &data); err != nil {
		log.Println("Failed to unmarshal Netscaler Response!")
		return false
	}
	if data[fmt.Sprintf("%s_%s_binding", resourceType, boundResourceType)] == nil {
		return false
	}

	log.Printf("%s of type  %s is bound to %s type and name %s", resourceType, resourceName, boundResourceType, boundResourceFilterValue)
	return true
}
<|endoftext|>


<commit_before>/*
Copyright 2015 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 schedulercache

import (
	"fmt"
	"sync"
	"time"

	"github.com/golang/glog"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/labels"
	"k8s.io/kubernetes/pkg/util/wait"
)

var (
	cleanAssumedPeriod = 1 * time.Second
)

// New returns a Cache implementation.
// It automatically starts a go routine that manages expiration of assumed pods.
// "ttl" is how long the assumed pod will get expired.
// "stop" is the channel that would close the background goroutine.
func New(ttl time.Duration, stop <-chan struct{}) Cache {
	cache := newSchedulerCache(ttl, cleanAssumedPeriod, stop)
	cache.run()
	return cache
}

type schedulerCache struct {
	stop   <-chan struct{}
	ttl    time.Duration
	period time.Duration

	// This mutex guards all fields within this cache struct.
	mu sync.Mutex
	// a set of assumed pod keys.
	// The key could further be used to get an entry in podStates.
	assumedPods map[string]bool
	// a map from pod key to podState.
	podStates map[string]*podState
	nodes     map[string]*NodeInfo
}

type podState struct {
	pod *api.Pod
	// Used by assumedPod to determinate expiration.
	deadline *time.Time
}

func newSchedulerCache(ttl, period time.Duration, stop <-chan struct{}) *schedulerCache {
	return &schedulerCache{
		ttl:    ttl,
		period: period,
		stop:   stop,

		nodes:       make(map[string]*NodeInfo),
		assumedPods: make(map[string]bool),
		podStates:   make(map[string]*podState),
	}
}

func (cache *schedulerCache) UpdateNodeNameToInfoMap(nodeNameToInfo map[string]*NodeInfo) error {
	cache.mu.Lock()
	defer cache.mu.Unlock()
	for name, info := range cache.nodes {
		if current, ok := nodeNameToInfo[name]; !ok || current.generation != info.generation {
			nodeNameToInfo[name] = info.Clone()
		}
	}
	for name := range nodeNameToInfo {
		if _, ok := cache.nodes[name]; !ok {
			delete(nodeNameToInfo, name)
		}
	}
	return nil
}

func (cache *schedulerCache) List(selector labels.Selector) ([]*api.Pod, error) {
	cache.mu.Lock()
	defer cache.mu.Unlock()
	var pods []*api.Pod
	for _, info := range cache.nodes {
		for _, pod := range info.pods {
			if selector.Matches(labels.Set(pod.Labels)) {
				pods = append(pods, pod)
			}
		}
	}
	return pods, nil
}

func (cache *schedulerCache) AssumePod(pod *api.Pod) error {
	return cache.assumePod(pod, time.Now())
}

// assumePod exists for making test deterministic by taking time as input argument.
func (cache *schedulerCache) assumePod(pod *api.Pod, now time.Time) error {
	cache.mu.Lock()
	defer cache.mu.Unlock()

	key, err := getPodKey(pod)
	if err != nil {
		return err
	}
	if _, ok := cache.podStates[key]; ok {
		return fmt.Errorf("pod state wasn't initial but get assumed. Pod key: %v", key)
	}

	cache.addPod(pod)
	dl := now.Add(cache.ttl)
	ps := &podState{
		pod:      pod,
		deadline: &dl,
	}
	cache.podStates[key] = ps
	cache.assumedPods[key] = true
	return nil
}

func (cache *schedulerCache) ForgetPod(pod *api.Pod) error {
	key, err := getPodKey(pod)
	if err != nil {
		return err
	}

	cache.mu.Lock()
	defer cache.mu.Unlock()

	_, ok := cache.podStates[key]
	switch {
	// Only assumed pod can be forgotten.
	case ok && cache.assumedPods[key]:
		err := cache.removePod(pod)
		if err != nil {
			return err
		}
		delete(cache.assumedPods, key)
		delete(cache.podStates, key)
	default:
		return fmt.Errorf("pod state wasn't assumed but get forgotten. Pod key: %v", key)
	}
	return nil
}

func (cache *schedulerCache) AddPod(pod *api.Pod) error {
	key, err := getPodKey(pod)
	if err != nil {
		return err
	}

	cache.mu.Lock()
	defer cache.mu.Unlock()

	_, ok := cache.podStates[key]
	switch {
	case ok && cache.assumedPods[key]:
		delete(cache.assumedPods, key)
		cache.podStates[key].deadline = nil
	case !ok:
		// Pod was expired. We should add it back.
		cache.addPod(pod)
		ps := &podState{
			pod: pod,
		}
		cache.podStates[key] = ps
	default:
		return fmt.Errorf("pod was already in added state. Pod key: %v", key)
	}
	return nil
}

func (cache *schedulerCache) UpdatePod(oldPod, newPod *api.Pod) error {
	key, err := getPodKey(oldPod)
	if err != nil {
		return err
	}

	cache.mu.Lock()
	defer cache.mu.Unlock()

	_, ok := cache.podStates[key]
	switch {
	// An assumed pod won't have Update/Remove event. It needs to have Add event
	// before Update event, in which case the state would change from Assumed to Added.
	case ok && !cache.assumedPods[key]:
		if err := cache.updatePod(oldPod, newPod); err != nil {
			return err
		}
	default:
		return fmt.Errorf("pod state wasn't added but get updated. Pod key: %v", key)
	}
	return nil
}

func (cache *schedulerCache) updatePod(oldPod, newPod *api.Pod) error {
	if err := cache.removePod(oldPod); err != nil {
		return err
	}
	cache.addPod(newPod)
	return nil
}

func (cache *schedulerCache) addPod(pod *api.Pod) {
	n, ok := cache.nodes[pod.Spec.NodeName]
	if !ok {
		n = NewNodeInfo()
		cache.nodes[pod.Spec.NodeName] = n
	}
	n.addPod(pod)
}

func (cache *schedulerCache) removePod(pod *api.Pod) error {
	n := cache.nodes[pod.Spec.NodeName]
	if err := n.removePod(pod); err != nil {
		return err
	}
	if len(n.pods) == 0 && n.node == nil {
		delete(cache.nodes, pod.Spec.NodeName)
	}
	return nil
}

func (cache *schedulerCache) RemovePod(pod *api.Pod) error {
	key, err := getPodKey(pod)
	if err != nil {
		return err
	}

	cache.mu.Lock()
	defer cache.mu.Unlock()

	_, ok := cache.podStates[key]
	switch {
	// An assumed pod won't have Delete/Remove event. It needs to have Add event
	// before Remove event, in which case the state would change from Assumed to Added.
	case ok && !cache.assumedPods[key]:
		err := cache.removePod(pod)
		if err != nil {
			return err
		}
		delete(cache.podStates, key)
	default:
		return fmt.Errorf("pod state wasn't added but get removed. Pod key: %v", key)
	}
	return nil
}

func (cache *schedulerCache) AddNode(node *api.Node) error {
	cache.mu.Lock()
	defer cache.mu.Unlock()

	n, ok := cache.nodes[node.Name]
	if !ok {
		n = NewNodeInfo()
		cache.nodes[node.Name] = n
	}
	return n.SetNode(node)
}

func (cache *schedulerCache) UpdateNode(oldNode, newNode *api.Node) error {
	cache.mu.Lock()
	defer cache.mu.Unlock()

	n, ok := cache.nodes[newNode.Name]
	if !ok {
		n = NewNodeInfo()
		cache.nodes[newNode.Name] = n
	}
	return n.SetNode(newNode)
}

func (cache *schedulerCache) RemoveNode(node *api.Node) error {
	cache.mu.Lock()
	defer cache.mu.Unlock()

	n := cache.nodes[node.Name]
	if err := n.RemoveNode(node); err != nil {
		return err
	}
	// We remove NodeInfo for this node only if there aren't any pods on this node.
	// We can't do it unconditionally, because notifications about pods are delivered
	// in a different watch, and thus can potentially be observed later, even though
	// they happened before node removal.
	if len(n.pods) == 0 && n.node == nil {
		delete(cache.nodes, node.Name)
	}
	return nil
}

func (cache *schedulerCache) run() {
	go wait.Until(cache.cleanupExpiredAssumedPods, cache.period, cache.stop)
}

func (cache *schedulerCache) cleanupExpiredAssumedPods() {
	cache.cleanupAssumedPods(time.Now())
}

// cleanupAssumedPods exists for making test deterministic by taking time as input argument.
func (cache *schedulerCache) cleanupAssumedPods(now time.Time) {
	cache.mu.Lock()
	defer cache.mu.Unlock()

	// The size of assumedPods should be small
	for key := range cache.assumedPods {
		ps, ok := cache.podStates[key]
		if !ok {
			panic("Key found in assumed set but not in podStates. Potentially a logical error.")
		}
		if now.After(*ps.deadline) {
			if err := cache.expirePod(key, ps); err != nil {
				glog.Errorf(" expirePod failed for %s: %v", key, err)
			}
		}
	}
}

func (cache *schedulerCache) expirePod(key string, ps *podState) error {
	if err := cache.removePod(ps.pod); err != nil {
		return err
	}
	delete(cache.assumedPods, key)
	delete(cache.podStates, key)
	return nil
}
<commit_msg>UPSTREAM: 33968: scheduler: initialize podsWithAffinity<commit_after>/*
Copyright 2015 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 schedulercache

import (
	"fmt"
	"sync"
	"time"

	"github.com/golang/glog"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/labels"
	"k8s.io/kubernetes/pkg/util/wait"
)

var (
	cleanAssumedPeriod = 1 * time.Second
)

// New returns a Cache implementation.
// It automatically starts a go routine that manages expiration of assumed pods.
// "ttl" is how long the assumed pod will get expired.
// "stop" is the channel that would close the background goroutine.
func New(ttl time.Duration, stop <-chan struct{}) Cache {
	cache := newSchedulerCache(ttl, cleanAssumedPeriod, stop)
	cache.run()
	return cache
}

type schedulerCache struct {
	stop   <-chan struct{}
	ttl    time.Duration
	period time.Duration

	// This mutex guards all fields within this cache struct.
	mu sync.Mutex
	// a set of assumed pod keys.
	// The key could further be used to get an entry in podStates.
	assumedPods map[string]bool
	// a map from pod key to podState.
	podStates map[string]*podState
	nodes     map[string]*NodeInfo
}

type podState struct {
	pod *api.Pod
	// Used by assumedPod to determinate expiration.
	deadline *time.Time
}

func newSchedulerCache(ttl, period time.Duration, stop <-chan struct{}) *schedulerCache {
	return &schedulerCache{
		ttl:    ttl,
		period: period,
		stop:   stop,

		nodes:       make(map[string]*NodeInfo),
		assumedPods: make(map[string]bool),
		podStates:   make(map[string]*podState),
	}
}

func (cache *schedulerCache) UpdateNodeNameToInfoMap(nodeNameToInfo map[string]*NodeInfo) error {
	cache.mu.Lock()
	defer cache.mu.Unlock()
	for name, info := range cache.nodes {
		if current, ok := nodeNameToInfo[name]; !ok || current.generation != info.generation {
			nodeNameToInfo[name] = info.Clone()
		}
	}
	for name := range nodeNameToInfo {
		if _, ok := cache.nodes[name]; !ok {
			delete(nodeNameToInfo, name)
		}
	}
	return nil
}

func (cache *schedulerCache) List(selector labels.Selector) ([]*api.Pod, error) {
	cache.mu.Lock()
	defer cache.mu.Unlock()
	var pods []*api.Pod
	for _, info := range cache.nodes {
		for _, pod := range info.pods {
			if selector.Matches(labels.Set(pod.Labels)) {
				pods = append(pods, pod)
			}
		}
	}
	return pods, nil
}

func (cache *schedulerCache) AssumePod(pod *api.Pod) error {
	return cache.assumePod(pod, time.Now())
}

// assumePod exists for making test deterministic by taking time as input argument.
func (cache *schedulerCache) assumePod(pod *api.Pod, now time.Time) error {
	cache.mu.Lock()
	defer cache.mu.Unlock()

	key, err := getPodKey(pod)
	if err != nil {
		return err
	}
	if _, ok := cache.podStates[key]; ok {
		return fmt.Errorf("pod state wasn't initial but get assumed. Pod key: %v", key)
	}

	cache.addPod(pod)
	dl := now.Add(cache.ttl)
	ps := &podState{
		pod:      pod,
		deadline: &dl,
	}
	cache.podStates[key] = ps
	cache.assumedPods[key] = true
	return nil
}

func (cache *schedulerCache) ForgetPod(pod *api.Pod) error {
	key, err := getPodKey(pod)
	if err != nil {
		return err
	}

	cache.mu.Lock()
	defer cache.mu.Unlock()

	_, ok := cache.podStates[key]
	switch {
	// Only assumed pod can be forgotten.
	case ok && cache.assumedPods[key]:
		err := cache.removePod(pod)
		if err != nil {
			return err
		}
		delete(cache.assumedPods, key)
		delete(cache.podStates, key)
	default:
		return fmt.Errorf("pod state wasn't assumed but get forgotten. Pod key: %v", key)
	}
	return nil
}

func (cache *schedulerCache) AddPod(pod *api.Pod) error {
	key, err := getPodKey(pod)
	if err != nil {
		return err
	}

	cache.mu.Lock()
	defer cache.mu.Unlock()

	_, ok := cache.podStates[key]
	switch {
	case ok && cache.assumedPods[key]:
		delete(cache.assumedPods, key)
		cache.podStates[key].deadline = nil
	case !ok:
		// Pod was expired. We should add it back.
		cache.addPod(pod)
		ps := &podState{
			pod: pod,
		}
		cache.podStates[key] = ps
	default:
		return fmt.Errorf("pod was already in added state. Pod key: %v", key)
	}
	return nil
}

func (cache *schedulerCache) UpdatePod(oldPod, newPod *api.Pod) error {
	key, err := getPodKey(oldPod)
	if err != nil {
		return err
	}

	cache.mu.Lock()
	defer cache.mu.Unlock()

	_, ok := cache.podStates[key]
	switch {
	// An assumed pod won't have Update/Remove event. It needs to have Add event
	// before Update event, in which case the state would change from Assumed to Added.
	case ok && !cache.assumedPods[key]:
		if err := cache.updatePod(oldPod, newPod); err != nil {
			return err
		}
	default:
		return fmt.Errorf("pod state wasn't added but get updated. Pod key: %v", key)
	}
	return nil
}

func (cache *schedulerCache) updatePod(oldPod, newPod *api.Pod) error {
	if err := cache.removePod(oldPod); err != nil {
		return err
	}
	cache.addPod(newPod)
	return nil
}

func (cache *schedulerCache) addPod(pod *api.Pod) {
	n, ok := cache.nodes[pod.Spec.NodeName]
	if !ok {
		n = NewNodeInfo()
		cache.nodes[pod.Spec.NodeName] = n
	}
	n.addPod(pod)
}

func (cache *schedulerCache) removePod(pod *api.Pod) error {
	n := cache.nodes[pod.Spec.NodeName]
	if err := n.removePod(pod); err != nil {
		return err
	}
	if len(n.pods) == 0 && n.node == nil {
		delete(cache.nodes, pod.Spec.NodeName)
	}
	return nil
}

func (cache *schedulerCache) RemovePod(pod *api.Pod) error {
	key, err := getPodKey(pod)
	if err != nil {
		return err
	}

	cache.mu.Lock()
	defer cache.mu.Unlock()

	cachedstate, ok := cache.podStates[key]
	switch {
	// An assumed pod won't have Delete/Remove event. It needs to have Add event
	// before Remove event, in which case the state would change from Assumed to Added.
	case ok && !cache.assumedPods[key]:
		err := cache.removePod(cachedstate.pod)
		if err != nil {
			return err
		}
		delete(cache.podStates, key)
	default:
		return fmt.Errorf("pod state wasn't added but get removed. Pod key: %v", key)
	}
	return nil
}

func (cache *schedulerCache) AddNode(node *api.Node) error {
	cache.mu.Lock()
	defer cache.mu.Unlock()

	n, ok := cache.nodes[node.Name]
	if !ok {
		n = NewNodeInfo()
		cache.nodes[node.Name] = n
	}
	return n.SetNode(node)
}

func (cache *schedulerCache) UpdateNode(oldNode, newNode *api.Node) error {
	cache.mu.Lock()
	defer cache.mu.Unlock()

	n, ok := cache.nodes[newNode.Name]
	if !ok {
		n = NewNodeInfo()
		cache.nodes[newNode.Name] = n
	}
	return n.SetNode(newNode)
}

func (cache *schedulerCache) RemoveNode(node *api.Node) error {
	cache.mu.Lock()
	defer cache.mu.Unlock()

	n := cache.nodes[node.Name]
	if err := n.RemoveNode(node); err != nil {
		return err
	}
	// We remove NodeInfo for this node only if there aren't any pods on this node.
	// We can't do it unconditionally, because notifications about pods are delivered
	// in a different watch, and thus can potentially be observed later, even though
	// they happened before node removal.
	if len(n.pods) == 0 && n.node == nil {
		delete(cache.nodes, node.Name)
	}
	return nil
}

func (cache *schedulerCache) run() {
	go wait.Until(cache.cleanupExpiredAssumedPods, cache.period, cache.stop)
}

func (cache *schedulerCache) cleanupExpiredAssumedPods() {
	cache.cleanupAssumedPods(time.Now())
}

// cleanupAssumedPods exists for making test deterministic by taking time as input argument.
func (cache *schedulerCache) cleanupAssumedPods(now time.Time) {
	cache.mu.Lock()
	defer cache.mu.Unlock()

	// The size of assumedPods should be small
	for key := range cache.assumedPods {
		ps, ok := cache.podStates[key]
		if !ok {
			panic("Key found in assumed set but not in podStates. Potentially a logical error.")
		}
		if now.After(*ps.deadline) {
			if err := cache.expirePod(key, ps); err != nil {
				glog.Errorf(" expirePod failed for %s: %v", key, err)
			}
		}
	}
}

func (cache *schedulerCache) expirePod(key string, ps *podState) error {
	if err := cache.removePod(ps.pod); err != nil {
		return err
	}
	delete(cache.assumedPods, key)
	delete(cache.podStates, key)
	return nil
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 Red Hat, Inc.
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 probes

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"strings"
	"sync"
	"syscall"
	"time"

	"gopkg.in/fsnotify.v1"

	"github.com/skydive-project/skydive/common"
	"github.com/skydive-project/skydive/logging"
	"github.com/skydive-project/skydive/topology"
	"github.com/skydive-project/skydive/topology/graph"
	"github.com/vishvananda/netns"
)

// NetNSProbe describes a netlink probe in a network namespace
type NetNSProbe struct {
	sync.RWMutex
	Graph              *graph.Graph
	Root               *graph.Node
	NetLinkProbe       *NetLinkProbe
	pathToNetNS        map[string]*NetNs
	netNsNetLinkProbes map[string]*netNsNetLinkProbe
	rootNs             *NetNs
	watcher            *fsnotify.Watcher
	pending            chan string
}

// NetNs describes a network namespace path associated with a device / inode
type NetNs struct {
	path string
	dev  uint64
	ino  uint64
}

// extends the original struct to add use count number
type netNsNetLinkProbe struct {
	*NetNsNetLinkProbe
	useCount int
}

func getNetNSName(path string) string {
	s := strings.Split(path, "/")
	return s[len(s)-1]
}

func (ns *NetNs) String() string {
	return fmt.Sprintf("%d,%d", ns.dev, ns.ino)
}

// Equal compares two NetNs objects
func (ns *NetNs) Equal(o *NetNs) bool {
	return (ns.dev == o.dev && ns.ino == o.ino)
}

// Register a new network namespace path
func (u *NetNSProbe) Register(path string, name string) *graph.Node {
	logging.GetLogger().Debugf("Register Network Namespace: %s", path)

	// When a new network namespace has been seen by inotify, the path to
	// the namespace may still be a regular file, not a bind mount to the
	// file in /proc/<pid>/tasks/<tid>/ns/net yet, so we wait a bit for the
	// bind mount to be set up
	var newns *NetNs
	err := common.Retry(func() error {
		var stats syscall.Stat_t
		fd, err := syscall.Open(path, syscall.O_RDONLY, 0)
		if err != nil {
			return err
		}

		err = syscall.Fstat(fd, &stats)
		syscall.Close(fd)
		if err != nil {
			return err
		}

		if stats.Dev != u.rootNs.dev {
			return fmt.Errorf("%s does not seem to be a valid namespace", path)
		}

		newns = &NetNs{path: path, dev: stats.Dev, ino: stats.Ino}
		return nil
	}, 10, time.Millisecond*100)

	if err != nil {
		logging.GetLogger().Errorf("Could not register namespace: %s", err.Error())
		return nil
	}

	// avoid hard link to root ns
	if u.rootNs.Equal(newns) {
		return u.Root
	}

	u.Lock()
	defer u.Unlock()

	_, ok := u.pathToNetNS[path]
	if !ok {
		u.pathToNetNS[path] = newns
	}

	nsString := newns.String()
	if probe, ok := u.netNsNetLinkProbes[nsString]; ok {
		probe.useCount++
		logging.GetLogger().Debugf("Increasing counter for namespace %s to %d", nsString, probe.useCount)
		return probe.Root
	}

	u.Graph.Lock()

	logging.GetLogger().Debugf("Network Namespace added: %s", nsString)
	metadata := graph.Metadata{
		"Name":   name,
		"Type":   "netns",
		"Path":   path,
		"Inode":  int64(newns.ino),
		"Device": int64(newns.dev),
	}

	n := u.Graph.NewNode(graph.GenID(), metadata)
	topology.AddOwnershipLink(u.Graph, u.Root, n, nil)

	u.Graph.Unlock()

	logging.GetLogger().Debugf("Registering Namespace: %s", nsString)
	probe, err := u.NetLinkProbe.Register(path, n)
	if err != nil {
		logging.GetLogger().Errorf("Could not register netlink probe within namespace: %s", err.Error())
	}
	u.netNsNetLinkProbes[nsString] = &netNsNetLinkProbe{NetNsNetLinkProbe: probe, useCount: 1}

	return n
}

// Unregister a network namespace path
func (u *NetNSProbe) Unregister(path string) {
	logging.GetLogger().Debugf("Unregister Network Namespace: %s", path)

	u.Lock()
	defer u.Unlock()

	ns, ok := u.pathToNetNS[path]
	if !ok {
		return
	}

	delete(u.pathToNetNS, path)
	nsString := ns.String()
	probe, ok := u.netNsNetLinkProbes[nsString]
	if !ok {
		logging.GetLogger().Debugf("No existing Network Namespace found: %s (%s)", nsString)
		return
	}

	if probe.useCount > 1 {
		probe.useCount--
		logging.GetLogger().Debugf("Decremented counter for namespace %s to %d", nsString, probe.useCount)
		return
	}

	u.NetLinkProbe.Unregister(path)
	logging.GetLogger().Debugf("Network Namespace deleted: %s", nsString)

	u.Graph.Lock()
	defer u.Graph.Unlock()

	for _, child := range u.Graph.LookupChildren(probe.Root, graph.Metadata{}, graph.Metadata{}) {
		u.Graph.DelNode(child)
	}
	u.Graph.DelNode(probe.Root)

	delete(u.netNsNetLinkProbes, nsString)
}

func (u *NetNSProbe) initializeRunPath(path string) {
	for {
		if _, err := os.Stat(path); err == nil {
			break
		}
		time.Sleep(time.Second)
	}

	if err := u.watcher.Add(path); err != nil {
		logging.GetLogger().Errorf("Unable to Watch %s: %s", path, err.Error())
	}

	files, _ := ioutil.ReadDir(path)
	for _, f := range files {
		u.Register(path+"/"+f.Name(), f.Name())
	}
	logging.GetLogger().Debugf("NetNSProbe initialized %s", path)
}

func (u *NetNSProbe) start() {
	logging.GetLogger().Debugf("NetNSProbe initialized")
	for {
		select {
		case path := <-u.pending:
			go u.initializeRunPath(path)
		case ev := <-u.watcher.Events:
			if ev.Op&fsnotify.Create == fsnotify.Create {
				u.Register(ev.Name, getNetNSName(ev.Name))
			}
			if ev.Op&fsnotify.Remove == fsnotify.Remove {
				u.Unregister(ev.Name)
			}

		case err := <-u.watcher.Errors:
			logging.GetLogger().Errorf("Error while watching network namespace: %s", err.Error())
		}
	}
}

// Watch add a path to the inotify watcher
func (u *NetNSProbe) Watch(path string) {
	u.pending <- path
}

// Start the probe
func (u *NetNSProbe) Start() {
	go u.start()
}

// Stop the probe
func (u *NetNSProbe) Stop() {
	u.NetLinkProbe.Stop()
}

// NewNetNSProbe creates a new network namespace probe
func NewNetNSProbe(g *graph.Graph, n *graph.Node, nlProbe *NetLinkProbe) (*NetNSProbe, error) {
	if uid := os.Geteuid(); uid != 0 {
		return nil, errors.New("NetNS probe has to be run as root")
	}

	ns, err := netns.Get()
	if err != nil {
		return nil, errors.New("Failed to get root namespace")
	}
	defer ns.Close()

	var stats syscall.Stat_t
	if err = syscall.Fstat(int(ns), &stats); err != nil {
		return nil, errors.New("Failed to stat root namespace")
	}
	rootNs := &NetNs{dev: stats.Dev, ino: stats.Ino}

	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return nil, fmt.Errorf("Unable to create a new Watcher: %s", err.Error())
	}

	return &NetNSProbe{
		Graph:              g,
		Root:               n,
		NetLinkProbe:       nlProbe,
		pathToNetNS:        make(map[string]*NetNs),
		netNsNetLinkProbes: make(map[string]*netNsNetLinkProbe),
		rootNs:             rootNs,
		watcher:            watcher,
		pending:            make(chan string, 10),
	}, nil
}
<commit_msg>netns: change wrong check for valid namespace<commit_after>/*
 * Copyright (C) 2015 Red Hat, Inc.
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 probes

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"syscall"
	"time"

	"gopkg.in/fsnotify.v1"

	"github.com/skydive-project/skydive/common"
	"github.com/skydive-project/skydive/logging"
	"github.com/skydive-project/skydive/topology"
	"github.com/skydive-project/skydive/topology/graph"
	"github.com/vishvananda/netns"
)

// NetNSProbe describes a netlink probe in a network namespace
type NetNSProbe struct {
	sync.RWMutex
	Graph              *graph.Graph
	Root               *graph.Node
	NetLinkProbe       *NetLinkProbe
	pathToNetNS        map[string]*NetNs
	netNsNetLinkProbes map[string]*netNsNetLinkProbe
	rootNs             *NetNs
	watcher            *fsnotify.Watcher
	pending            chan string
}

// NetNs describes a network namespace path associated with a device / inode
type NetNs struct {
	path string
	dev  uint64
	ino  uint64
}

// extends the original struct to add use count number
type netNsNetLinkProbe struct {
	*NetNsNetLinkProbe
	useCount int
}

func getNetNSName(path string) string {
	s := strings.Split(path, "/")
	return s[len(s)-1]
}

func (ns *NetNs) String() string {
	return fmt.Sprintf("%d,%d", ns.dev, ns.ino)
}

// Equal compares two NetNs objects
func (ns *NetNs) Equal(o *NetNs) bool {
	return (ns.dev == o.dev && ns.ino == o.ino)
}

func (u *NetNSProbe) checkNamespace(path string) error {
	// When a new network namespace has been seen by inotify, the path to
	// the namespace may still be a regular file, not a bind mount to the
	// file in /proc/<pid>/tasks/<tid>/ns/net yet, so we wait a bit for the
	// bind mount to be set up

	return common.Retry(func() error {
		var stats, parentStats syscall.Stat_t
		fd, err := syscall.Open(path, syscall.O_RDONLY, 0)
		if err != nil {
			return err
		}

		err = syscall.Fstat(fd, &stats)
		syscall.Close(fd)
		if err != nil {
			return err
		}

		if parent := filepath.Dir(path); parent != "" {
			if err := syscall.Stat(parent, &parentStats); err == nil {
				if stats.Dev == parentStats.Dev {
					return fmt.Errorf("%s does not seem to be a valid namespace", path)
				}
			}
		}

		return nil
	}, 10, time.Millisecond*100)
}

// Register a new network namespace path
func (u *NetNSProbe) Register(path string, name string) *graph.Node {
	logging.GetLogger().Debugf("Register Network Namespace: %s", path)

	var stats syscall.Stat_t
	if err := syscall.Stat(path, &stats); err != nil {
		logging.GetLogger().Errorf("Failed to stat namespace %s: %s", path, err.Error())
		return nil
	}

	newns := &NetNs{path: path, dev: stats.Dev, ino: stats.Ino}

	// avoid hard link to root ns
	if u.rootNs.Equal(newns) {
		return u.Root
	}

	u.Lock()
	defer u.Unlock()

	_, ok := u.pathToNetNS[path]
	if !ok {
		u.pathToNetNS[path] = newns
	}

	nsString := newns.String()
	if probe, ok := u.netNsNetLinkProbes[nsString]; ok {
		probe.useCount++
		logging.GetLogger().Debugf("Increasing counter for namespace %s to %d", nsString, probe.useCount)
		return probe.Root
	}

	u.Graph.Lock()

	logging.GetLogger().Debugf("Network Namespace added: %s", nsString)
	metadata := graph.Metadata{
		"Name":   name,
		"Type":   "netns",
		"Path":   path,
		"Inode":  int64(newns.ino),
		"Device": int64(newns.dev),
	}

	n := u.Graph.NewNode(graph.GenID(), metadata)
	topology.AddOwnershipLink(u.Graph, u.Root, n, nil)

	u.Graph.Unlock()

	logging.GetLogger().Debugf("Registering Namespace: %s", nsString)
	probe, err := u.NetLinkProbe.Register(path, n)
	if err != nil {
		logging.GetLogger().Errorf("Could not register netlink probe within namespace: %s", err.Error())
	}
	u.netNsNetLinkProbes[nsString] = &netNsNetLinkProbe{NetNsNetLinkProbe: probe, useCount: 1}

	return n
}

// Unregister a network namespace path
func (u *NetNSProbe) Unregister(path string) {
	logging.GetLogger().Debugf("Unregister Network Namespace: %s", path)

	u.Lock()
	defer u.Unlock()

	ns, ok := u.pathToNetNS[path]
	if !ok {
		return
	}

	delete(u.pathToNetNS, path)
	nsString := ns.String()
	probe, ok := u.netNsNetLinkProbes[nsString]
	if !ok {
		logging.GetLogger().Debugf("No existing Network Namespace found: %s (%s)", nsString)
		return
	}

	if probe.useCount > 1 {
		probe.useCount--
		logging.GetLogger().Debugf("Decremented counter for namespace %s to %d", nsString, probe.useCount)
		return
	}

	u.NetLinkProbe.Unregister(path)
	logging.GetLogger().Debugf("Network Namespace deleted: %s", nsString)

	u.Graph.Lock()
	defer u.Graph.Unlock()

	for _, child := range u.Graph.LookupChildren(probe.Root, graph.Metadata{}, graph.Metadata{}) {
		u.Graph.DelNode(child)
	}
	u.Graph.DelNode(probe.Root)

	delete(u.netNsNetLinkProbes, nsString)
}

func (u *NetNSProbe) initializeRunPath(path string) {
	for {
		if _, err := os.Stat(path); err == nil {
			break
		}
		time.Sleep(time.Second)
	}

	if err := u.watcher.Add(path); err != nil {
		logging.GetLogger().Errorf("Unable to Watch %s: %s", path, err.Error())
	}

	files, _ := ioutil.ReadDir(path)
	for _, f := range files {
		if err := u.checkNamespace(path + "/" + f.Name()); err != nil {
			logging.GetLogger().Errorf("Failed to register namespace %s: %s", path+"/"+f.Name(), err.Error())
			continue
		}
		u.Register(path+"/"+f.Name(), f.Name())
	}
	logging.GetLogger().Debugf("NetNSProbe initialized %s", path)
}

func (u *NetNSProbe) start() {
	logging.GetLogger().Debugf("NetNSProbe initialized")
	for {
		select {
		case path := <-u.pending:
			go u.initializeRunPath(path)
		case ev := <-u.watcher.Events:
			if ev.Op&fsnotify.Create == fsnotify.Create {
				if err := u.checkNamespace(ev.Name); err != nil {
					logging.GetLogger().Errorf("Failed to register namespace %s: %s", ev.Name, err.Error())
					continue
				}
				u.Register(ev.Name, getNetNSName(ev.Name))
			}
			if ev.Op&fsnotify.Remove == fsnotify.Remove {
				u.Unregister(ev.Name)
			}

		case err := <-u.watcher.Errors:
			logging.GetLogger().Errorf("Error while watching network namespace: %s", err.Error())
		}
	}
}

// Watch add a path to the inotify watcher
func (u *NetNSProbe) Watch(path string) {
	u.pending <- path
}

// Start the probe
func (u *NetNSProbe) Start() {
	go u.start()
}

// Stop the probe
func (u *NetNSProbe) Stop() {
	u.NetLinkProbe.Stop()
}

// NewNetNSProbe creates a new network namespace probe
func NewNetNSProbe(g *graph.Graph, n *graph.Node, nlProbe *NetLinkProbe) (*NetNSProbe, error) {
	if uid := os.Geteuid(); uid != 0 {
		return nil, errors.New("NetNS probe has to be run as root")
	}

	ns, err := netns.Get()
	if err != nil {
		return nil, errors.New("Failed to get root namespace")
	}
	defer ns.Close()

	var stats syscall.Stat_t
	if err = syscall.Fstat(int(ns), &stats); err != nil {
		return nil, errors.New("Failed to stat root namespace")
	}
	rootNs := &NetNs{dev: stats.Dev, ino: stats.Ino}

	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return nil, fmt.Errorf("Unable to create a new Watcher: %s", err.Error())
	}

	return &NetNSProbe{
		Graph:              g,
		Root:               n,
		NetLinkProbe:       nlProbe,
		pathToNetNS:        make(map[string]*NetNs),
		netNsNetLinkProbes: make(map[string]*netNsNetLinkProbe),
		rootNs:             rootNs,
		watcher:            watcher,
		pending:            make(chan string, 10),
	}, nil
}
<|endoftext|>


<commit_before>package towerfall

import (
	"testing"

	"github.com/gin-gonic/gin"
)

func init() {
	gin.SetMode(gin.TestMode)
}

// MockServer returns a Server{} a with clean test Database{}
func MockServer(t *testing.T) (*Server, func()) {
	conf := ParseConfig()
	conf.DbName = "test_drunkenfall"
	conf.Port = 56513

	db, serverTeardown := testDatabase(t, conf)

	s := NewServer(conf, db)
	db.Server = s

	return s, func() {
		serverTeardown()
	}
}

// func testServer() *httptest.Server {
// 	// Server tests use the fake production data.
// 	s := MockServer(t)

// 	SetupFakeTournament(nil, s, &NewRequest{"a", "a", time.Now(), "cover", true})
// 	SetupFakeTournament(nil, s, &NewRequest{"b", "b", time.Now(), "cover", true})

// 	ws := melody.New()
// 	r := s.BuildRouter(ws)
// 	return httptest.NewServer(r)
// }

// func TestServeTournaments(t *testing.T) {
// 	assert := assert.New(t)
// 	s := testServer()
// 	defer s.Close()

// 	res, err := http.Get(s.URL + "/api/tournaments/")
// 	assert.Nil(err)
// 	assert.Equal(http.StatusOK, res.StatusCode)

// 	j, err := ioutil.ReadAll(res.Body)
// 	assert.Nil(err)

// 	lt := &TournamentList{}
// 	json.Unmarshal(j, lt)
// 	assert.Equal(2, len(lt.Tournaments))

// 	res.Body.Close()
// }
<commit_msg>Reset used players per test tournament<commit_after>package towerfall

import (
	"testing"

	"github.com/gin-gonic/gin"
)

func init() {
	gin.SetMode(gin.TestMode)
}

// MockServer returns a Server{} a with clean test Database{}
func MockServer(t *testing.T) (*Server, func()) {
	conf := ParseConfig()
	conf.DbName = "test_drunkenfall"
	conf.Port = 56513

	usedPeople = make([]string, 0)

	db, serverTeardown := testDatabase(t, conf)

	s := NewServer(conf, db)
	db.Server = s

	return s, func() {
		serverTeardown()
	}
}

// func testServer() *httptest.Server {
// 	// Server tests use the fake production data.
// 	s := MockServer(t)

// 	SetupFakeTournament(nil, s, &NewRequest{"a", "a", time.Now(), "cover", true})
// 	SetupFakeTournament(nil, s, &NewRequest{"b", "b", time.Now(), "cover", true})

// 	ws := melody.New()
// 	r := s.BuildRouter(ws)
// 	return httptest.NewServer(r)
// }

// func TestServeTournaments(t *testing.T) {
// 	assert := assert.New(t)
// 	s := testServer()
// 	defer s.Close()

// 	res, err := http.Get(s.URL + "/api/tournaments/")
// 	assert.Nil(err)
// 	assert.Equal(http.StatusOK, res.StatusCode)

// 	j, err := ioutil.ReadAll(res.Body)
// 	assert.Nil(err)

// 	lt := &TournamentList{}
// 	json.Unmarshal(j, lt)
// 	assert.Equal(2, len(lt.Tournaments))

// 	res.Body.Close()
// }
<|endoftext|>


<commit_before>package http

import (
	"github.com/geodan/gost/src/sensorthings/models"
	"github.com/stretchr/testify/assert"
	"sort"
	"testing"
)

func TestEndPointLength(t *testing.T) {
	// arrange
	ep1 := &Endpoint{}
	ep2 := &Endpoint{}
	eps := Endpoints{}
	eps = append(eps, ep1)
	eps = append(eps, ep2)

	// act
	l := eps.Len()

	// assert
	assert.True(t, l == 2, "Number of Endpoints should be 2")
}

func TestIsDynamic(t *testing.T) {
	// arrange
	urlDynamic := "http://www.{}.nl"
	urlNotDynamic := "http://www.nu.nl"

	// act
	resultNotDynamic := isDynamic(urlNotDynamic)
	resultDynamic := isDynamic(urlDynamic)

	// assert
	assert.False(t, resultNotDynamic)
	assert.True(t, resultDynamic)
}

func TestEndPointSort(t *testing.T) {
	// arrange
	ep1 := &Endpoint{}
	ep1.Operation.Path = "ep1"
	ep1.Operation.OperationType = models.HTTPOperationGet
	ep2 := &Endpoint{}
	ep2.Operation.Path = "ep2"
	ep2.Operation.OperationType = models.HTTPOperationPost

	eps := Endpoints{ep1,ep2}

	// act
	sort.Sort(eps)

	// assert
	assert.True(t, len(eps) == 2, "Number of Endpoints should be 2")
	// post becomes first after sorting
	assert.True(t, eps[0].Operation.Path=="ep2")
	assert.True(t, eps[1].Operation.Path=="ep1")
}

func TestEndPointSortDynamic(t *testing.T) {
	// arrange
	httpep1 := &Endpoint{}
	httpep1.Operation.Path = "ep1{}"
	httpep1.Operation.OperationType = models.HTTPOperationGet
	httpep2 := &Endpoint{}
	httpep2.Operation.Path = "ep2{}longer"
	httpep2.Operation.OperationType = models.HTTPOperationPost

	eps := Endpoints{httpep1,httpep2}

	// act
	sort.Sort(eps)

	// assert
	assert.True(t, len(eps) == 2, "Number of Endpoints should be 2")
	// when both urls are dynamic, the longer path comes first
	assert.True(t, eps[0].Operation.Path=="ep2{}longer")
	assert.True(t, eps[1].Operation.Path=="ep1{}")
}

func TestEndPointSortlength(t *testing.T) {
	// arrange
	httpep1 := &Endpoint{}
	httpep1.Operation.Path = "ep1"
	httpep1.Operation.OperationType = models.HTTPOperationGet
	httpep2 := &Endpoint{}
	httpep2.Operation.Path = "ep2longer"
	httpep2.Operation.OperationType = models.HTTPOperationPost

	eps := Endpoints{httpep1,httpep2}

	// act
	sort.Sort(eps)

	// assert
	assert.True(t, len(eps) == 2, "Number of Endpoints should be 2")
	// when both urls are dynamic, the longer path comes first
	assert.True(t, eps[0].Operation.Path=="ep2longer")
	assert.True(t, eps[1].Operation.Path=="ep1")
}
<commit_msg>small things<commit_after>package http

import (
	"github.com/geodan/gost/src/sensorthings/models"
	"github.com/stretchr/testify/assert"
	"sort"
	"testing"
)

func TestEndPointLength(t *testing.T) {
	// arrange
	ep1 := &Endpoint{}
	ep2 := &Endpoint{}
	eps := Endpoints{}
	eps = append(eps, ep1)
	eps = append(eps, ep2)

	// act
	l := eps.Len()

	// assert
	assert.True(t, l == 2, "Number of Endpoints should be 2")
}

func TestIsDynamic(t *testing.T) {
	// arrange
	urlDynamic := "http://www.{}.nl"
	urlNotDynamic := "http://www.nu.nl"

	// act
	resultNotDynamic := isDynamic(urlNotDynamic)
	resultDynamic := isDynamic(urlDynamic)

	// assert
	assert.False(t, resultNotDynamic)
	assert.True(t, resultDynamic)
}

func TestEndPointSort(t *testing.T) {
	// arrange
	ep1 := &Endpoint{}
	ep1.Operation.Path = "ep1"
	ep1.Operation.OperationType = models.HTTPOperationGet
	ep2 := &Endpoint{}
	ep2.Operation.Path = "ep2"
	ep2.Operation.OperationType = models.HTTPOperationPost

	eps := Endpoints{ep1, ep2}

	// act
	sort.Sort(eps)

	// assert
	assert.True(t, len(eps) == 2, "Number of Endpoints should be 2")
	// post becomes first after sorting
	assert.True(t, eps[0].Operation.Path == "ep2")
	assert.True(t, eps[1].Operation.Path == "ep1")
}

func TestEndPointSortDynamic(t *testing.T) {
	// arrange
	httpep1 := &Endpoint{}
	httpep1.Operation.Path = "ep1{}"
	httpep1.Operation.OperationType = models.HTTPOperationGet
	httpep2 := &Endpoint{}
	httpep2.Operation.Path = "ep2{}longer"
	httpep2.Operation.OperationType = models.HTTPOperationPost

	eps := Endpoints{httpep1, httpep2}

	// act
	sort.Sort(eps)

	// assert
	assert.True(t, len(eps) == 2, "Number of Endpoints should be 2")
	// when both urls are dynamic, the longer path comes first
	assert.True(t, eps[0].Operation.Path == "ep2{}longer")
	assert.True(t, eps[1].Operation.Path == "ep1{}")
}

func TestEndPointSortlength(t *testing.T) {
	// arrange
	httpep1 := &Endpoint{}
	httpep1.Operation.Path = "ep1"
	httpep1.Operation.OperationType = models.HTTPOperationGet
	httpep2 := &Endpoint{}
	httpep2.Operation.Path = "ep2longer"
	httpep2.Operation.OperationType = models.HTTPOperationPost

	eps := Endpoints{httpep1, httpep2}

	// act
	sort.Sort(eps)

	// assert
	assert.True(t, len(eps) == 2, "Number of Endpoints should be 2")
	// when both urls are dynamic, the longer path comes first
	assert.True(t, eps[0].Operation.Path == "ep2longer")
	assert.True(t, eps[1].Operation.Path == "ep1")
}

func TestEndPointNotDynamic(t *testing.T) {
	// arrange
	httpep1 := &Endpoint{}
	httpep1.Operation.Path = "ep1 {c:.*}"
	httpep1.Operation.OperationType = models.HTTPOperationGet
	httpep2 := &Endpoint{}
	httpep2.Operation.Path = "ep2longer"
	httpep2.Operation.OperationType = models.HTTPOperationGet
	eps := Endpoints{httpep1, httpep2}

	// act
	sort.Sort(eps)

	// assert
	assert.True(t, eps[0].Operation.Path == "ep2longer")
	assert.True(t, eps[1].Operation.Path == "ep1 {c:.*}")

}
<|endoftext|>


<commit_before><commit_msg>Fixed updating version<commit_after><|endoftext|>


<commit_before>package asana

import (
	"context"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"net/url"
	"reflect"
	"testing"
)

var (
	client *Client
	mux    *http.ServeMux
	server *httptest.Server
	ctx    = context.Background()
)

func setup() {
	client = NewClient(nil)
	mux = http.NewServeMux()
	server = httptest.NewServer(mux)
	url, _ := url.Parse(server.URL)
	client.BaseURL = url
}

func teardown() {
	server.Close()
}

func TestNewClient(t *testing.T) {
	c := NewClient(nil)

	if c.BaseURL.String() != defaultBaseURL {
		t.Errorf("NewClient BaseURL = %v, want %v", c.BaseURL.String(), defaultBaseURL)
	}
	if c.UserAgent != userAgent {
		t.Errorf("NewClient UserAgent = %v, want %v", c.UserAgent, userAgent)
	}
}

func TestNewError(t *testing.T) {
	err := Error{Phrase: "P", Message: "M"}
	if err.Error() != "M - P" {
		t.Errorf("Invalid Error message: %v", err.Error())
	}
}

func TestListWorkspaces(t *testing.T) {
	setup()
	defer teardown()

	mux.HandleFunc("/workspaces", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, `{"data":[
			{"id":1,"name":"Organization 1"},
			{"id":2,"name":"Organization 2"}
		]}`)
	})

	workspaces, err := client.ListWorkspaces(ctx)
	if err != nil {
		t.Errorf("ListWorkspaces returned error: %v", err)
	}

	want := []Workspace{
		{ID: 1, Name: "Organization 1"},
		{ID: 2, Name: "Organization 2"},
	}

	if !reflect.DeepEqual(workspaces, want) {
		t.Errorf("ListWorkspaces returned %+v, want %+v", workspaces, want)
	}
}

func TestListUsers(t *testing.T) {
	setup()
	defer teardown()

	mux.HandleFunc("/users", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, `{"data":[
			{"id":1,"email":"test1@asana.com"},
			{"id":2,"email":"test2@asana.com"}
		]}`)
	})

	users, err := client.ListUsers(ctx, nil)
	if err != nil {
		t.Errorf("ListUsers returned error: %v", err)
	}

	want := []User{
		{ID: 1, Email: "test1@asana.com"},
		{ID: 2, Email: "test2@asana.com"},
	}

	if !reflect.DeepEqual(users, want) {
		t.Errorf("ListUsers returned %+v, want %+v", users, want)
	}
}

func TestListProjects(t *testing.T) {
	setup()
	defer teardown()

	mux.HandleFunc("/projects", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, `{"data":[
			{"id":1,"name":"Project 1"},
			{"id":2,"name":"Project 2"}
		]}`)
	})

	projects, err := client.ListProjects(ctx, nil)
	if err != nil {
		t.Errorf("ListProjects returned error: %v", err)
	}

	want := []Project{
		{ID: 1, Name: "Project 1"},
		{ID: 2, Name: "Project 2"},
	}

	if !reflect.DeepEqual(projects, want) {
		t.Errorf("ListProjects returned %+v, want %+v", projects, want)
	}
}

func TestListTasks(t *testing.T) {
	setup()
	defer teardown()

	mux.HandleFunc("/tasks", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, `{"data":[
			{"id":1,"name":"Task 1"},
			{"id":2,"name":"Task 2"}
		]}`)
	})

	tasks, err := client.ListTasks(ctx, nil)
	if err != nil {
		t.Errorf("ListTasks returned error: %v", err)
	}

	want := []Task{
		{ID: 1, Name: "Task 1"},
		{ID: 2, Name: "Task 2"},
	}

	if !reflect.DeepEqual(tasks, want) {
		t.Errorf("ListTasks returned %+v, want %+v", tasks, want)
	}
}

func TestUpdateTask(t *testing.T) {
	setup()
	defer teardown()

	var called int
	defer func() { testCalled(t, called, 1) }()
	mux.HandleFunc("/tasks/1", func(w http.ResponseWriter, r *http.Request) {
		called++
		testMethod(t, r, "PUT")
		testHeader(t, r, "Content-Type", "application/json")
		b, err := ioutil.ReadAll(r.Body)
		if err != nil {
			t.Fatalf("error reading request body: %v", err)
		}
		want := `{"data":{"notes":"updated notes"}}`
		if !reflect.DeepEqual(string(b), want) {
			t.Errorf("handler received request body %+v, want %+v", string(b), want)
		}

		fmt.Fprint(w, `{"data":{"id":1,"notes":"updated notes"}}`)
	})

	// TODO: Add this to package API, like go-github, maybe? Think about it first.
	//
	// String is a helper routine that allocates a new string value
	// to store v and returns a pointer to it.
	String := func(v string) *string { return &v }

	task, err := client.UpdateTask(ctx, 1, TaskUpdate{Notes: String("updated notes")}, nil)
	if err != nil {
		t.Errorf("UpdateTask returned error: %v", err)
	}

	want := Task{ID: 1, Notes: "updated notes"}
	if !reflect.DeepEqual(task, want) {
		t.Errorf("UpdateTask returned %+v, want %+v", task, want)
	}
}

func TestListTags(t *testing.T) {
	setup()
	defer teardown()

	mux.HandleFunc("/tags", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, `{"data":[
			{"id":1,"name":"Tag 1"},
			{"id":2,"name":"Tag 2"}
		]}`)
	})

	tags, err := client.ListTags(ctx, nil)
	if err != nil {
		t.Errorf("ListTags returned error: %v", err)
	}

	want := []Tag{
		{ID: 1, Name: "Tag 1"},
		{ID: 2, Name: "Tag 2"},
	}

	if !reflect.DeepEqual(tags, want) {
		t.Errorf("ListTags returned %+v, want %+v", tags, want)
	}
}

func TestUnauthorized(t *testing.T) {
	setup()
	defer teardown()

	mux.HandleFunc("/tags", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusUnauthorized)
	})

	_, err := client.ListTags(ctx, nil)
	if err != ErrUnauthorized {
		t.Errorf("Unexpected err %v", err)
	}
}

func TestCreateTask(t *testing.T) {
	setup()
	defer teardown()

	var called int
	defer func() { testCalled(t, called, 1) }()

	mux.HandleFunc("/tasks", func(w http.ResponseWriter, r *http.Request) {
		called++
		testMethod(t, r, "POST")
		testHeader(t, r, "Content-Type", "application/x-www-form-urlencoded")
		b, err := ioutil.ReadAll(r.Body)
		if err != nil {
			t.Fatalf("error reading request body: %v", err)
		}
		values, err := url.ParseQuery(string(b))
		if err != nil {
			t.Fatalf("error parsing body: %v", err)
		}
		want := url.Values{
			"key1": []string{"value1"},
			"key2": []string{"value2"},
		}
		if !reflect.DeepEqual(values, want) {
			t.Errorf("invalid body received %v", values)
		}
		fmt.Fprint(w, `{"data":{"id":1,"notes":"updated notes"}}`)
	})

	task, err := client.CreateTask(ctx, map[string]string{
		"key1": "value1",
		"key2": "value2",
	}, nil)

	if err != nil {
		t.Errorf("CreateTask returned error: %v", err)
	}

	want := Task{ID: 1, Notes: "updated notes"}
	if !reflect.DeepEqual(task, want) {
		t.Errorf("CreateTask returned %+v, want %+v", task, want)
	}
}

func testMethod(t *testing.T, r *http.Request, want string) {
	if got := r.Method; got != want {
		t.Errorf("Request method: %v, want %v", got, want)
	}
}

func testHeader(t *testing.T, r *http.Request, header string, want string) {
	if got := r.Header.Get(header); got != want {
		t.Errorf("Header.Get(%q) returned %q, want %q", header, got, want)
	}
}

func testCalled(t *testing.T, called int, want int) {
	if got := called; got != want {
		t.Errorf("handler was called %v times, but expected to be called %v times", got, want)
	}
}
<commit_msg>Remove global context in tests<commit_after>package asana

import (
	"context"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"net/url"
	"reflect"
	"testing"
)

var (
	client *Client
	mux    *http.ServeMux
	server *httptest.Server
)

func setup() {
	client = NewClient(nil)
	mux = http.NewServeMux()
	server = httptest.NewServer(mux)
	url, _ := url.Parse(server.URL)
	client.BaseURL = url
}

func teardown() {
	server.Close()
}

func TestNewClient(t *testing.T) {
	c := NewClient(nil)

	if c.BaseURL.String() != defaultBaseURL {
		t.Errorf("NewClient BaseURL = %v, want %v", c.BaseURL.String(), defaultBaseURL)
	}
	if c.UserAgent != userAgent {
		t.Errorf("NewClient UserAgent = %v, want %v", c.UserAgent, userAgent)
	}
}

func TestNewError(t *testing.T) {
	err := Error{Phrase: "P", Message: "M"}
	if err.Error() != "M - P" {
		t.Errorf("Invalid Error message: %v", err.Error())
	}
}

func TestListWorkspaces(t *testing.T) {
	setup()
	defer teardown()

	mux.HandleFunc("/workspaces", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, `{"data":[
			{"id":1,"name":"Organization 1"},
			{"id":2,"name":"Organization 2"}
		]}`)
	})

	workspaces, err := client.ListWorkspaces(context.Background())
	if err != nil {
		t.Errorf("ListWorkspaces returned error: %v", err)
	}

	want := []Workspace{
		{ID: 1, Name: "Organization 1"},
		{ID: 2, Name: "Organization 2"},
	}

	if !reflect.DeepEqual(workspaces, want) {
		t.Errorf("ListWorkspaces returned %+v, want %+v", workspaces, want)
	}
}

func TestListUsers(t *testing.T) {
	setup()
	defer teardown()

	mux.HandleFunc("/users", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, `{"data":[
			{"id":1,"email":"test1@asana.com"},
			{"id":2,"email":"test2@asana.com"}
		]}`)
	})

	users, err := client.ListUsers(context.Background(), nil)
	if err != nil {
		t.Errorf("ListUsers returned error: %v", err)
	}

	want := []User{
		{ID: 1, Email: "test1@asana.com"},
		{ID: 2, Email: "test2@asana.com"},
	}

	if !reflect.DeepEqual(users, want) {
		t.Errorf("ListUsers returned %+v, want %+v", users, want)
	}
}

func TestListProjects(t *testing.T) {
	setup()
	defer teardown()

	mux.HandleFunc("/projects", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, `{"data":[
			{"id":1,"name":"Project 1"},
			{"id":2,"name":"Project 2"}
		]}`)
	})

	projects, err := client.ListProjects(context.Background(), nil)
	if err != nil {
		t.Errorf("ListProjects returned error: %v", err)
	}

	want := []Project{
		{ID: 1, Name: "Project 1"},
		{ID: 2, Name: "Project 2"},
	}

	if !reflect.DeepEqual(projects, want) {
		t.Errorf("ListProjects returned %+v, want %+v", projects, want)
	}
}

func TestListTasks(t *testing.T) {
	setup()
	defer teardown()

	mux.HandleFunc("/tasks", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, `{"data":[
			{"id":1,"name":"Task 1"},
			{"id":2,"name":"Task 2"}
		]}`)
	})

	tasks, err := client.ListTasks(context.Background(), nil)
	if err != nil {
		t.Errorf("ListTasks returned error: %v", err)
	}

	want := []Task{
		{ID: 1, Name: "Task 1"},
		{ID: 2, Name: "Task 2"},
	}

	if !reflect.DeepEqual(tasks, want) {
		t.Errorf("ListTasks returned %+v, want %+v", tasks, want)
	}
}

func TestUpdateTask(t *testing.T) {
	setup()
	defer teardown()

	var called int
	defer func() { testCalled(t, called, 1) }()
	mux.HandleFunc("/tasks/1", func(w http.ResponseWriter, r *http.Request) {
		called++
		testMethod(t, r, "PUT")
		testHeader(t, r, "Content-Type", "application/json")
		b, err := ioutil.ReadAll(r.Body)
		if err != nil {
			t.Fatalf("error reading request body: %v", err)
		}
		want := `{"data":{"notes":"updated notes"}}`
		if !reflect.DeepEqual(string(b), want) {
			t.Errorf("handler received request body %+v, want %+v", string(b), want)
		}

		fmt.Fprint(w, `{"data":{"id":1,"notes":"updated notes"}}`)
	})

	// TODO: Add this to package API, like go-github, maybe? Think about it first.
	//
	// String is a helper routine that allocates a new string value
	// to store v and returns a pointer to it.
	String := func(v string) *string { return &v }

	task, err := client.UpdateTask(context.Background(), 1, TaskUpdate{Notes: String("updated notes")}, nil)
	if err != nil {
		t.Errorf("UpdateTask returned error: %v", err)
	}

	want := Task{ID: 1, Notes: "updated notes"}
	if !reflect.DeepEqual(task, want) {
		t.Errorf("UpdateTask returned %+v, want %+v", task, want)
	}
}

func TestListTags(t *testing.T) {
	setup()
	defer teardown()

	mux.HandleFunc("/tags", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, `{"data":[
			{"id":1,"name":"Tag 1"},
			{"id":2,"name":"Tag 2"}
		]}`)
	})

	tags, err := client.ListTags(context.Background(), nil)
	if err != nil {
		t.Errorf("ListTags returned error: %v", err)
	}

	want := []Tag{
		{ID: 1, Name: "Tag 1"},
		{ID: 2, Name: "Tag 2"},
	}

	if !reflect.DeepEqual(tags, want) {
		t.Errorf("ListTags returned %+v, want %+v", tags, want)
	}
}

func TestUnauthorized(t *testing.T) {
	setup()
	defer teardown()

	mux.HandleFunc("/tags", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusUnauthorized)
	})

	_, err := client.ListTags(context.Background(), nil)
	if err != ErrUnauthorized {
		t.Errorf("Unexpected err %v", err)
	}
}

func TestCreateTask(t *testing.T) {
	setup()
	defer teardown()

	var called int
	defer func() { testCalled(t, called, 1) }()

	mux.HandleFunc("/tasks", func(w http.ResponseWriter, r *http.Request) {
		called++
		testMethod(t, r, "POST")
		testHeader(t, r, "Content-Type", "application/x-www-form-urlencoded")
		b, err := ioutil.ReadAll(r.Body)
		if err != nil {
			t.Fatalf("error reading request body: %v", err)
		}
		values, err := url.ParseQuery(string(b))
		if err != nil {
			t.Fatalf("error parsing body: %v", err)
		}
		want := url.Values{
			"key1": []string{"value1"},
			"key2": []string{"value2"},
		}
		if !reflect.DeepEqual(values, want) {
			t.Errorf("invalid body received %v", values)
		}
		fmt.Fprint(w, `{"data":{"id":1,"notes":"updated notes"}}`)
	})

	task, err := client.CreateTask(context.Background(), map[string]string{
		"key1": "value1",
		"key2": "value2",
	}, nil)

	if err != nil {
		t.Errorf("CreateTask returned error: %v", err)
	}

	want := Task{ID: 1, Notes: "updated notes"}
	if !reflect.DeepEqual(task, want) {
		t.Errorf("CreateTask returned %+v, want %+v", task, want)
	}
}

func testMethod(t *testing.T, r *http.Request, want string) {
	if got := r.Method; got != want {
		t.Errorf("Request method: %v, want %v", got, want)
	}
}

func testHeader(t *testing.T, r *http.Request, header string, want string) {
	if got := r.Header.Get(header); got != want {
		t.Errorf("Header.Get(%q) returned %q, want %q", header, got, want)
	}
}

func testCalled(t *testing.T, called int, want int) {
	if got := called; got != want {
		t.Errorf("handler was called %v times, but expected to be called %v times", got, want)
	}
}
<|endoftext|>


<commit_before>package fake

import (
	"math/rand"
	"strings"

	"strconv"
)

type creditCard struct {
	vendor   string
	length   int
	prefixes []int
}

var creditCards = map[string]creditCard{
	"visa":       {"VISA", 16, []int{4539, 4556, 4916, 4532, 4929, 40240071, 4485, 4716, 4}},
	"mastercard": {"MasterCard", 16, []int{51, 52, 53, 54, 55}},
	"amex":       {"American Express", 15, []int{34, 37}},
	"discover":   {"Discover", 16, []int{6011}},
}

// CreditCardType returns one of the following credit values:
// VISA, MasterCard, American Express and Discover
func CreditCardType() string {
	n := len(creditCards)
	var vendors []string
	for _, cc := range creditCards {
		vendors = append(vendors, cc.vendor)
	}

	return vendors[rand.Intn(n)]
}

// CreditCardNum generated credit card number according to the card number rules
func CreditCardNum(vendor string) string {
	if vendor != "" {
		vendor = strings.ToLower(vendor)
	} else {
		var vendors []string
		for v := range creditCards {
			vendors = append(vendors, v)
		}
		vendor = vendors[rand.Intn(len(vendors))]
	}
	card := creditCards[vendor]
	prefix := strconv.Itoa(card.prefixes[rand.Intn(len(card.prefixes))])
	num := []rune(prefix)
	for i := 0; i < card.length-len(prefix); i++ {
		num = append(num, genCCDigit(num))
	}
	return string(num)
}

func genCCDigit(num []rune) rune {
	sum := 0
	for i := len(num) - 1; i >= 0; i-- {
		n := int(num[i])
		if i%2 != 0 {
			sum += n
		} else {
			if n*2 > 9 {
				sum += n*2 - 9
			} else {
				sum += n * 2
			}
		}
	}
	return rune(((sum/10+1)*10 - sum) % 10)
}
<commit_msg>credit cards: improve vendor prefix mapping. document supported vendors for CreditCardNum().<commit_after>package fake

import (
	"math/rand"
	"strings"

	"strconv"
)

type creditCard struct {
	vendor   string
	length   int
	prefixes []int
}

// https://en.wikipedia.org/wiki/Payment_card_number#Issuer_identification_number_.28IIN.29
var creditCards = map[string]creditCard{
	"amex":       {"American Express", 15, []int{34, 37}},
	"discover":   {"Discover", 16, []int{6011, 622126, 622925, 644, 649, 65}},
	"mastercard": {"MasterCard", 16, []int{5}},
	"visa":       {"VISA", 16, []int{4}},
}

// CreditCardType returns one of the following credit values:
// VISA, MasterCard, American Express and Discover
func CreditCardType() string {
	n := len(creditCards)
	var vendors []string
	for _, cc := range creditCards {
		vendors = append(vendors, cc.vendor)
	}

	return vendors[rand.Intn(n)]
}

// CreditCardNum generated credit card number according to the vendor's card number rules.
// Currently supports amex, discover, mastercard, and visa.
func CreditCardNum(vendor string) string {
	if vendor != "" {
		vendor = strings.ToLower(vendor)
	} else {
		var vendors []string
		for v := range creditCards {
			vendors = append(vendors, v)
		}
		vendor = vendors[rand.Intn(len(vendors))]
	}
	card := creditCards[vendor]
	prefix := strconv.Itoa(card.prefixes[rand.Intn(len(card.prefixes))])
	num := []rune(prefix)
	for i := 0; i < card.length-len(prefix); i++ {
		num = append(num, genCCDigit(num))
	}
	return string(num)
}

func genCCDigit(num []rune) rune {
	sum := 0
	for i := len(num) - 1; i >= 0; i-- {
		n := int(num[i])
		if i%2 != 0 {
			sum += n
		} else {
			if n*2 > 9 {
				sum += n*2 - 9
			} else {
				sum += n * 2
			}
		}
	}
	return rune(((sum/10+1)*10 - sum) % 10)
}
<|endoftext|>