<commit_before>package chef

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

// chef.Cookbook defines the relevant parameters of a Chef cookbook. This
// includes the RESTful URL of a cookbook and a slice of all of the cookbooks
// versions. The versions each have two attributes: Url, which represents the
// RESTful URL of the cookbook version and Version, which represents the version
// number (identifier) of the cookbook version
type Cookbook struct {
	Url      string `json:"url"`
	Versions []struct {
		Url     string `json:"url"`
		Version string `json:"version"`
	} `json:"versions"`
}

// chef.CookbookVersion defines the relevant parameters of a specific Chef
// cookbook version. This includes, but is not limited to, information about
// recipes, files, etc, various pieces of metadata about the cookbook at that
// point in time, such as the name of the cookbook, the description, the
// license, etc.
type CookbookVersion struct {
	Recipes []struct {
		CookbookItem
	} `json:"recipes"`
	Files []struct {
		CookbookItem
	} `json:"files"`
	RootFiles []struct {
		CookbookItem
	} `json:"root_file"`
	Metadata struct {
		Name            string            `json:"name"`
		Description     string            `json:"description"`
		LongDescription string            `json:"long_description"`
		Maintainer      string            `json:"maintainer"`
		MaintainerEmail string            `json:"maintainer_email"`
		License         string            `json:"license"`
		Providing       map[string]string `json:"providing"`
		Dependencies    map[string]string `json:dependencies`
	} `json:"metadata"`
	Name      string `json:"cookbook_name"`
	Version   string `json:"version"`
	FullName  string `json:"name"`
	Frozen    bool   `json:"frozen?"`
	ChefType  string `json:"chef_type"`
	JSONClass string `json:"json_class"`
}

// chef.CookbookItem defines the relevant parameters of various items that are
// found in a chef Cookbook such as the name, checksum, etc. This type is
// embedded in the chef.CookVersion type to reduce code repetition.
type CookbookItem struct {
	Name        string `json:"name"`
	Path        string `json:"path"`
	Checksum    string `json:"checksum"`
	Specificity string `json:"specificity"`
	Url         string `json:"url"`
}

// chef.GetCookbooks returns a map of cookbook names to a pointer to the
// chef.Cookbook type as well as an error indicating if the request was
// successful or not.
//
// Usgae:
//
//     cookbooks, err := chef.GetCookbooks()
//     if err != nil {
//         fmt.Println(err)
//         os.Exit(1)
//     }
//     // do what you please with the "cookbooks" variable which is a map of
//     // cookbook names to chef.Cookbook types
//     for name, cookbook := range cookbooks {
//         fmt.Println(name, cookbook.Version[0])
//      }
func (chef *Chef) GetCookbooks() (map[string]*Cookbook, error) {
	resp, err := chef.Get("cookbooks")
	if err != nil {
		return nil, err
	}
	body, err := responseBody(resp)
	if err != nil {
		return nil, err
	}

	cookbooks := map[string]*Cookbook{}
	json.Unmarshal(body, &cookbooks)

	return cookbooks, nil
}

// chef.GetCookbook returns a pointer to the chef.Cookbook type for a given
// string that represents a cookbook name. It also returns a bool indicating
// whether or not the client was found and an error indicating if the request
// failed or not.
//
// Note that if the request is successful but no such client existed, the error
// return value will be nil but the bool will be false.
//
// Usage:
//
//     cookbook, ok, err := chef.GetCookbook("apache")
//     if err != nil {
//         fmt.Println(err)
//         os.Exit(1)
//     }
//     if !ok {
//         fmt.Println("Couldn't find that cookbook!")
//     } else {
//         // do what you please with the "cookbook" variable which is of the
//         // *Chef.Cookbook type
//         fmt.Printf("%#v\n", cookbook)
//     }
func (chef *Chef) GetCookbook(name string) (*Cookbook, bool, error) {
	resp, err := chef.Get(fmt.Sprintf("cookbooks/%s", name))
	if err != nil {
		return nil, false, err
	}
	body, err := responseBody(resp)
	if err != nil {
		if strings.Contains(err.Error(), "404") {
			return nil, false, nil
		}
		return nil, false, err
	}

	cookbook := map[string]*Cookbook{}
	json.Unmarshal(body, &cookbook)

	return cookbook[name], true, nil
}

// chef.GetCookbookVersion returns a pointer to the chef.CookbookVersion type
// for a given string that represents a cookbook version. It also returns a bool
// indicating whether or not the client was found and an error indicating if
// the request failed or not.
//
// Note that if the request is successful but no such client existed, the error
// return value will be nil but the bool will be false.
//
// Usage:
//
//     cookbook, ok, err := chef.GetCookbookVersion("apache", "1.0.0")
//     if err != nil {
//         fmt.Println(err)
//         os.Exit(1)
//     }
//     if !ok {
//         fmt.Println("Couldn't find that cookbook version!")
//     } else {
//         // do what you please with the "cookbook" variable which is of the
//         // *Chef.CookbookVersion type
//         fmt.Printf("%#v\n", cookbook)
//     }
func (chef *Chef) GetCookbookVersion(name, version string) (*CookbookVersion, bool, error) {
	resp, err := chef.Get(fmt.Sprintf("cookbooks/%s/%s", name, version))
	if err != nil {
		return nil, false, err
	}
	body, err := responseBody(resp)
	if err != nil {
		if strings.Contains(err.Error(), "404") {
			return nil, false, nil
		}
		return nil, false, err
	}
	cookbook := new(CookbookVersion)
	json.Unmarshal(body, &cookbook)
	return cookbook, true, nil
}
<commit_msg>add all cookbook items to CookbookVersion<commit_after>package chef

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

// chef.Cookbook defines the relevant parameters of a Chef cookbook. This
// includes the RESTful URL of a cookbook and a slice of all of the cookbooks
// versions. The versions each have two attributes: Url, which represents the
// RESTful URL of the cookbook version and Version, which represents the version
// number (identifier) of the cookbook version
type Cookbook struct {
	Url      string `json:"url"`
	Versions []struct {
		Url     string `json:"url"`
		Version string `json:"version"`
	} `json:"versions"`
}

// chef.CookbookVersion defines the relevant parameters of a specific Chef
// cookbook version. This includes, but is not limited to, information about
// recipes, files, etc, various pieces of metadata about the cookbook at that
// point in time, such as the name of the cookbook, the description, the
// license, etc.
type CookbookVersion struct {
	Files []struct {
		CookbookItem
	} `json:"files"`
	Definitions []struct {
		CookbookItem
	} `json: "definitions"`
	Libraries []struct {
		CookbookItem
	} `json: "libraries"`
	Attributes []struct {
		CookbookItem
	} `json:"attributes"`
	Recipes []struct {
		CookbookItem
	} `json:"recipes"`
	Providers []struct {
		CookbookItem
	} `json: "providers"`
	Resources []struct {
		CookbookItem
	} `json: "resources"`
	Templates []struct {
		CookbookItem
	} `json: "templates"`
	RootFiles []struct {
		CookbookItem
	} `json:"root_file"`
	Metadata struct {
		Name            string            `json:"name"`
		Description     string            `json:"description"`
		LongDescription string            `json:"long_description"`
		Maintainer      string            `json:"maintainer"`
		MaintainerEmail string            `json:"maintainer_email"`
		License         string            `json:"license"`
		Providing       map[string]string `json:"providing"`
		Dependencies    map[string]string `json:dependencies`
	} `json:"metadata"`
	Name      string `json:"cookbook_name"`
	Version   string `json:"version"`
	FullName  string `json:"name"`
	Frozen    bool   `json:"frozen?"`
	ChefType  string `json:"chef_type"`
	JSONClass string `json:"json_class"`
}

// chef.CookbookItem defines the relevant parameters of various items that are
// found in a chef Cookbook such as the name, checksum, etc. This type is
// embedded in the chef.CookVersion type to reduce code repetition.
type CookbookItem struct {
	Name        string `json:"name"`
	Path        string `json:"path"`
	Checksum    string `json:"checksum"`
	Specificity string `json:"specificity"`
	Url         string `json:"url"`
}

// chef.GetCookbooks returns a map of cookbook names to a pointer to the
// chef.Cookbook type as well as an error indicating if the request was
// successful or not.
//
// Usgae:
//
//     cookbooks, err := chef.GetCookbooks()
//     if err != nil {
//         fmt.Println(err)
//         os.Exit(1)
//     }
//     // do what you please with the "cookbooks" variable which is a map of
//     // cookbook names to chef.Cookbook types
//     for name, cookbook := range cookbooks {
//         fmt.Println(name, cookbook.Version[0])
//      }
func (chef *Chef) GetCookbooks() (map[string]*Cookbook, error) {
	resp, err := chef.Get("cookbooks")
	if err != nil {
		return nil, err
	}
	body, err := responseBody(resp)
	if err != nil {
		return nil, err
	}

	cookbooks := map[string]*Cookbook{}
	json.Unmarshal(body, &cookbooks)

	return cookbooks, nil
}

// chef.GetCookbook returns a pointer to the chef.Cookbook type for a given
// string that represents a cookbook name. It also returns a bool indicating
// whether or not the client was found and an error indicating if the request
// failed or not.
//
// Note that if the request is successful but no such client existed, the error
// return value will be nil but the bool will be false.
//
// Usage:
//
//     cookbook, ok, err := chef.GetCookbook("apache")
//     if err != nil {
//         fmt.Println(err)
//         os.Exit(1)
//     }
//     if !ok {
//         fmt.Println("Couldn't find that cookbook!")
//     } else {
//         // do what you please with the "cookbook" variable which is of the
//         // *Chef.Cookbook type
//         fmt.Printf("%#v\n", cookbook)
//     }
func (chef *Chef) GetCookbook(name string) (*Cookbook, bool, error) {
	resp, err := chef.Get(fmt.Sprintf("cookbooks/%s", name))
	if err != nil {
		return nil, false, err
	}
	body, err := responseBody(resp)
	if err != nil {
		if strings.Contains(err.Error(), "404") {
			return nil, false, nil
		}
		return nil, false, err
	}

	cookbook := map[string]*Cookbook{}
	json.Unmarshal(body, &cookbook)

	return cookbook[name], true, nil
}

// chef.GetCookbookVersion returns a pointer to the chef.CookbookVersion type
// for a given string that represents a cookbook version. It also returns a bool
// indicating whether or not the client was found and an error indicating if
// the request failed or not.
//
// Note that if the request is successful but no such client existed, the error
// return value will be nil but the bool will be false.
//
// Usage:
//
//     cookbook, ok, err := chef.GetCookbookVersion("apache", "1.0.0")
//     if err != nil {
//         fmt.Println(err)
//         os.Exit(1)
//     }
//     if !ok {
//         fmt.Println("Couldn't find that cookbook version!")
//     } else {
//         // do what you please with the "cookbook" variable which is of the
//         // *Chef.CookbookVersion type
//         fmt.Printf("%#v\n", cookbook)
//     }
func (chef *Chef) GetCookbookVersion(name, version string) (*CookbookVersion, bool, error) {
	resp, err := chef.Get(fmt.Sprintf("cookbooks/%s/%s", name, version))
	if err != nil {
		return nil, false, err
	}
	body, err := responseBody(resp)
	if err != nil {
		if strings.Contains(err.Error(), "404") {
			return nil, false, nil
		}
		return nil, false, err
	}
	cookbook := new(CookbookVersion)
	json.Unmarshal(body, &cookbook)
	return cookbook, true, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"

	"github.com/jung-kurt/gofpdf"
)

type KeyInformation struct {
	x      float64
	y      float64
	width  float64
	height float64

	use bool
}

type Scan struct {
	line        int
	lineHead    int
	inKeymaps   bool
	layerNumber int
	keys        [3][]string
	m           map[string]string
}

func (self *Scan) Init() {
	self.line = 1
	self.lineHead = 0
	self.inKeymaps = false
	self.layerNumber = 0
	self.m = map[string]string{"KC_EQL": "=",
		"KC_DELT": "Del", "KC_BSPC": "BkSp",
		"KC_TRNS": "", "KC_ENT": "Enter", "KC_1": "1",
		"KC_2": "2", "KC_3": "3", "KC_4": "4", "KC_5": "5", "KC_6": "7",
		"KC_7": "7", "KC_8": "8", "KC_9": "9", "KC_0": "0",
		"KC_A": "A", "KC_B": "B", "KC_C": "C", "KC_D": "D",
		"KC_E": "E", "KC_F": "F", "KC_G": "G", "KC_H": "H",
		"KC_I": "I", "KC_J": "J", "KC_K": "K", "KC_L": "L",
		"KC_M": "M", "KC_N": "N", "KC_O": "O", "KC_P": "P",
		"KC_Q": "Q", "KC_R": "R", "KC_S": "S", "KC_T": "T",
		"KC_U": "U", "KC_V": "V", "KC_W": "W", "KC_X": "X",
		"KC_Y": "Y", "KC_Z": "Z",
		"KC_EXLM": "!", "KC_AT": "@", "KC_LCBR": "{", "KC_RCBR": "}", "KC_PIPE": "|",
		"KC_HASH": "#", "KC_DLR": "$", "KC_LPRN": "(", "KC_RPRN": ")", "KC_GRV": "`",
		"KC_PERC": "%", "KC_CIRC": "^", "KC_LBRC": "[", "KC_RBRC": "]", "KC_TILD": "~",
		"KC_PLUS": "+", "KC_ASTR": "*", "KC_DOT": ".", "KC_AMPR": "&",
		"KC_MINS": "-", "KC_BSLS": "\\", "KC_RSFT": "RShift",
		"KC_MUTE": "Mute", "RGB_HUD": "Hue-", "RGB_HUI": "Hue+",
		"KC_F1": "F1", "KC_F2": "F2", "KC_F3": "F3", "KC_F4": "F4",
		"KC_F5": "F5", "KC_F6": "F6", "KC_F7": "F7", "KC_F8": "F8",
		"KC_F9": "F9", "KC_F10": "F10", "KC_F11": "F11", "KC_F12": "F12",
		"KC_UP": "UP", "KC_DOWN": "DOWN", "KC_LEFT": "LEFT", "KC_RGHT": "RIGHT",
		"KC_MS_U": "MsUp", "KC_MS_D": "MsDown", "KC_MS_L": "MsLeft", "KC_MS_R": "MsRght",
		"KC_BTN1": "Lclk", "KC_BTN2": "Rclk",
		"RGB_TOG": "Toggle", "RGB_SLD": "Solid",
		"RGB_VAD": "Brightness-", "RGB_VAI": "Brightness+", "RGB_MOD": "Animat",
		"KC_LSFT": "LShift", "KC_SPC": "SPC",
		"KC_VOLU": "VolUp", "KC_VOLD": "VolDn", "KC_MPRV": "Prev", "KC_MNXT": "Next",
		"KC_HOME": "Home", "KC_END": "End", "KC_PGUP": "PgUp", "KC_PGDN": "PgDn",
		"KC_MPLY": "Play", "KC_TAB": "Tab",
		"KC_WBAK": "BrowserBack"}
}

func (self *Scan) Err(s int) {
	fmt.Printf("\n!!Error!!%d\n", s)
}

func (self *Scan) GetDisplayName(key string) string {
	_, ok := self.m[key]
	if ok {
		return self.m[key]
	} else {
		return key
	}
}
func (self *Scan) Output() {
	pdf := gofpdf.New("P", "mm", "A4", "")
	pdf.SetFont("Arial", "", 10)
	pdf.AddPage()

	curx, cury := pdf.GetXY()
	x := curx
	y := cury
	_, lineHt := pdf.GetFontSize()

	//
	cols := [14]float64{0, 0, -0.25, -0.375, -0.25, 0, 0,
		0, 0, -0.25, -0.375, -0.25, 0, 0}
	var lkil []KeyInformation
	var rkil []KeyInformation
	for j := 0; j < 8; j++ {
		for i := 0; i < 7; i++ {
			var ltmp = KeyInformation{x: float64(i * 10), y: float64(j * 10), width: float64(10), height: float64(10), use: true}
			var rtmp = KeyInformation{x: float64((i + 13) * 10), y: float64(j * 10), width: float64(10), height: float64(10), use: true}
			if j < 6 {
				ltmp.y = ltmp.y + cols[i]*10
				rtmp.y = rtmp.y + cols[i+7]*10
			}
			if i == 0 {
				ltmp.x = ltmp.x - 5
				ltmp.width = 15
			}
			if i == 6 {
				rtmp.width = 15
			}
			lkil = append(lkil, ltmp)
			rkil = append(rkil, rtmp)
		}
	}
	//
	lkil[20].use = false
	rkil[14].use = false
	lkil[33].use = false
	rkil[29].use = false
	lkil[34].use = false
	rkil[28].use = false
	//
	for j := 5; j < 8; j++ {
		for i := 0; i < 4; i++ {
			lkil[j*7+i].use = false
			rkil[j*7+(6-i)].use = false
		}
	}
	//
	lkil[39].use = false
	rkil[37].use = false
	lkil[46].use = false
	rkil[44].use = false
	lkil[47].use = false
	rkil[43].use = false
	//
	lkil[53].height = float64(20)
	lkil[53].y = lkil[53].y - 10
	rkil[51].height = float64(20)
	rkil[51].y = lkil[51].y - 10
	lkil[54].height = float64(20)
	lkil[54].y = lkil[54].y - 10
	rkil[50].height = float64(20)
	rkil[50].y = lkil[50].y - 10
	//
	lkil[13].height = float64(15)
	rkil[7].height = float64(15)
	lkil[27].height = float64(15)
	rkil[21].height = float64(15)
	lkil[27].y = lkil[27].y - 5
	rkil[21].y = rkil[21].y - 5
	//
	lkil[28].x = lkil[28].x + 5
	lkil[28].width = 10
	rkil[34].width = 10
	// right

	for k := 0; k < 3; k++ {
		var keyindex int = 0
		for j := 0; j < 8; j++ {
			for i := 0; i < 7; i++ {
				var ki = lkil[j*7+i]
				if ki.use {
					if j > 4 {
						pdf.TransformBegin()
						pdf.TransformRotate(-30, 97, 97+90*float64(k))
					}
					pdf.Rect(curx+ki.x, cury+float64(k*90)+ki.y, ki.width, ki.height, "")
					pdf.SetXY(curx+ki.x, cury+float64(k*90)+ki.y)
					pdf.Cell(0, 0+lineHt, self.GetDisplayName(self.keys[k][keyindex]))
					keyindex = keyindex + 1
					if j > 4 {
						pdf.TransformEnd()
					}
				}
			}
		}
		for j := 0; j < 8; j++ {
			for i := 0; i < 7; i++ {
				var ki = rkil[j*7+i]
				if ki.use {
					if j > 4 {
						pdf.TransformBegin()
						pdf.TransformRotate(30, 113, 97+90*float64(k))
					}
					pdf.Rect(ki.x, cury+float64(k*90)+ki.y, ki.width, ki.height, "")
					pdf.SetXY(ki.x, cury+float64(k*90)+ki.y)
					pdf.Cell(0, 0+lineHt, self.GetDisplayName(self.keys[k][keyindex]))
					keyindex = keyindex + 1
					if j > 4 {
						pdf.TransformEnd()
					}
					x += 10
				}
			}
			y = y + 10
			x = curx
		}
		y = y + 20
	}
	pdf.Output(os.Stdout)
}

func main() {
	if len(os.Args) < 2 {
		fmt.Printf("%v FILE\n", os.Args[0])
		os.Exit(1)
	}
	file, err := os.Open(os.Args[1])
	if err != nil {
		log.Fatal(err)
	}

	buffer, err := ioutil.ReadAll(file)
	if err != nil {
		log.Fatal(err)
	}

	file.Close()

	parser := &Parser{Buffer: string(buffer)}
	parser.Init()
	parser.s.Init()
	err2 := parser.Parse()

	if err2 != nil {
		fmt.Println(err2)
	} else {
		parser.Execute()
		parser.s.Output()
	}
}
<commit_msg>Release 0.1.0<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"

	"github.com/jung-kurt/gofpdf"
)

const version = "0.1.0"

type KeyInformation struct {
	x      float64
	y      float64
	width  float64
	height float64

	use bool
}

type Scan struct {
	line        int
	lineHead    int
	inKeymaps   bool
	layerNumber int
	keys        [3][]string
	m           map[string]string
}

func (self *Scan) Init() {
	self.line = 1
	self.lineHead = 0
	self.inKeymaps = false
	self.layerNumber = 0
	self.m = map[string]string{"KC_EQL": "=",
		"KC_DELT": "Del", "KC_BSPC": "BkSp",
		"KC_TRNS": "", "KC_ENT": "Enter", "KC_1": "1",
		"KC_2": "2", "KC_3": "3", "KC_4": "4", "KC_5": "5", "KC_6": "7",
		"KC_7": "7", "KC_8": "8", "KC_9": "9", "KC_0": "0",
		"KC_A": "A", "KC_B": "B", "KC_C": "C", "KC_D": "D",
		"KC_E": "E", "KC_F": "F", "KC_G": "G", "KC_H": "H",
		"KC_I": "I", "KC_J": "J", "KC_K": "K", "KC_L": "L",
		"KC_M": "M", "KC_N": "N", "KC_O": "O", "KC_P": "P",
		"KC_Q": "Q", "KC_R": "R", "KC_S": "S", "KC_T": "T",
		"KC_U": "U", "KC_V": "V", "KC_W": "W", "KC_X": "X",
		"KC_Y": "Y", "KC_Z": "Z",
		"KC_EXLM": "!", "KC_AT": "@", "KC_LCBR": "{", "KC_RCBR": "}", "KC_PIPE": "|",
		"KC_HASH": "#", "KC_DLR": "$", "KC_LPRN": "(", "KC_RPRN": ")", "KC_GRV": "`",
		"KC_PERC": "%", "KC_CIRC": "^", "KC_LBRC": "[", "KC_RBRC": "]", "KC_TILD": "~",
		"KC_PLUS": "+", "KC_ASTR": "*", "KC_DOT": ".", "KC_AMPR": "&",
		"KC_MINS": "-", "KC_BSLS": "\\", "KC_RSFT": "RShift",
		"KC_MUTE": "Mute", "RGB_HUD": "Hue-", "RGB_HUI": "Hue+",
		"KC_F1": "F1", "KC_F2": "F2", "KC_F3": "F3", "KC_F4": "F4",
		"KC_F5": "F5", "KC_F6": "F6", "KC_F7": "F7", "KC_F8": "F8",
		"KC_F9": "F9", "KC_F10": "F10", "KC_F11": "F11", "KC_F12": "F12",
		"KC_UP": "UP", "KC_DOWN": "DOWN", "KC_LEFT": "LEFT", "KC_RGHT": "RIGHT",
		"KC_MS_U": "MsUp", "KC_MS_D": "MsDown", "KC_MS_L": "MsLeft", "KC_MS_R": "MsRght",
		"KC_BTN1": "Lclk", "KC_BTN2": "Rclk",
		"RGB_TOG": "Toggle", "RGB_SLD": "Solid",
		"RGB_VAD": "Brightness-", "RGB_VAI": "Brightness+", "RGB_MOD": "Animat",
		"KC_LSFT": "LShift", "KC_SPC": "SPC",
		"KC_VOLU": "VolUp", "KC_VOLD": "VolDn", "KC_MPRV": "Prev", "KC_MNXT": "Next",
		"KC_HOME": "Home", "KC_END": "End", "KC_PGUP": "PgUp", "KC_PGDN": "PgDn",
		"KC_MPLY": "Play", "KC_TAB": "Tab",
		"KC_WBAK": "BrowserBack"}
}

func (self *Scan) Err(s int) {
	fmt.Printf("\n!!Error!!%d\n", s)
}

func (self *Scan) GetDisplayName(key string) string {
	_, ok := self.m[key]
	if ok {
		return self.m[key]
	} else {
		return key
	}
}
func (self *Scan) Output() {
	pdf := gofpdf.New("P", "mm", "A4", "")
	pdf.SetFont("Arial", "", 10)
	pdf.AddPage()

	curx, cury := pdf.GetXY()
	x := curx
	y := cury
	_, lineHt := pdf.GetFontSize()

	//
	cols := [14]float64{0, 0, -0.25, -0.375, -0.25, 0, 0,
		0, 0, -0.25, -0.375, -0.25, 0, 0}
	var lkil []KeyInformation
	var rkil []KeyInformation
	for j := 0; j < 8; j++ {
		for i := 0; i < 7; i++ {
			var ltmp = KeyInformation{x: float64(i * 10), y: float64(j * 10), width: float64(10), height: float64(10), use: true}
			var rtmp = KeyInformation{x: float64((i + 13) * 10), y: float64(j * 10), width: float64(10), height: float64(10), use: true}
			if j < 6 {
				ltmp.y = ltmp.y + cols[i]*10
				rtmp.y = rtmp.y + cols[i+7]*10
			}
			if i == 0 {
				ltmp.x = ltmp.x - 5
				ltmp.width = 15
			}
			if i == 6 {
				rtmp.width = 15
			}
			lkil = append(lkil, ltmp)
			rkil = append(rkil, rtmp)
		}
	}
	//
	lkil[20].use = false
	rkil[14].use = false
	lkil[33].use = false
	rkil[29].use = false
	lkil[34].use = false
	rkil[28].use = false
	//
	for j := 5; j < 8; j++ {
		for i := 0; i < 4; i++ {
			lkil[j*7+i].use = false
			rkil[j*7+(6-i)].use = false
		}
	}
	//
	lkil[39].use = false
	rkil[37].use = false
	lkil[46].use = false
	rkil[44].use = false
	lkil[47].use = false
	rkil[43].use = false
	//
	lkil[53].height = float64(20)
	lkil[53].y = lkil[53].y - 10
	rkil[51].height = float64(20)
	rkil[51].y = lkil[51].y - 10
	lkil[54].height = float64(20)
	lkil[54].y = lkil[54].y - 10
	rkil[50].height = float64(20)
	rkil[50].y = lkil[50].y - 10
	//
	lkil[13].height = float64(15)
	rkil[7].height = float64(15)
	lkil[27].height = float64(15)
	rkil[21].height = float64(15)
	lkil[27].y = lkil[27].y - 5
	rkil[21].y = rkil[21].y - 5
	//
	lkil[28].x = lkil[28].x + 5
	lkil[28].width = 10
	rkil[34].width = 10
	// right

	for k := 0; k < 3; k++ {
		var keyindex int = 0
		for j := 0; j < 8; j++ {
			for i := 0; i < 7; i++ {
				var ki = lkil[j*7+i]
				if ki.use {
					if j > 4 {
						pdf.TransformBegin()
						pdf.TransformRotate(-30, 97, 97+90*float64(k))
					}
					pdf.Rect(curx+ki.x, cury+float64(k*90)+ki.y, ki.width, ki.height, "")
					pdf.SetXY(curx+ki.x, cury+float64(k*90)+ki.y)
					pdf.Cell(0, 0+lineHt, self.GetDisplayName(self.keys[k][keyindex]))
					keyindex = keyindex + 1
					if j > 4 {
						pdf.TransformEnd()
					}
				}
			}
		}
		for j := 0; j < 8; j++ {
			for i := 0; i < 7; i++ {
				var ki = rkil[j*7+i]
				if ki.use {
					if j > 4 {
						pdf.TransformBegin()
						pdf.TransformRotate(30, 113, 97+90*float64(k))
					}
					pdf.Rect(ki.x, cury+float64(k*90)+ki.y, ki.width, ki.height, "")
					pdf.SetXY(ki.x, cury+float64(k*90)+ki.y)
					pdf.Cell(0, 0+lineHt, self.GetDisplayName(self.keys[k][keyindex]))
					keyindex = keyindex + 1
					if j > 4 {
						pdf.TransformEnd()
					}
					x += 10
				}
			}
			y = y + 10
			x = curx
		}
		y = y + 20
	}
	pdf.Output(os.Stdout)
}

func main() {
	if len(os.Args) < 2 {
		fmt.Printf("%v FILE\n", os.Args[0])
		os.Exit(1)
	}
	file, err := os.Open(os.Args[1])
	if err != nil {
		log.Fatal(err)
	}

	buffer, err := ioutil.ReadAll(file)
	if err != nil {
		log.Fatal(err)
	}

	file.Close()

	parser := &Parser{Buffer: string(buffer)}
	parser.Init()
	parser.s.Init()
	err2 := parser.Parse()

	if err2 != nil {
		fmt.Println(err2)
	} else {
		parser.Execute()
		parser.s.Output()
	}
}
<|endoftext|>


<commit_before>// Package wsdlgen generates Go source code from wsdl documents.
//
// The wsdlgen package generates Go source for calling the various
// methods defined in a WSDL (Web Service Definition Language) document.
// The generated Go source is self-contained, with no dependencies on
// non-standard packages.
//
// Code generation for the wsdlgen package can be configured by using
// the provided Option functions.
package wsdlgen

import (
	"encoding/xml"
	"errors"
	"fmt"
	"go/ast"
	"io/ioutil"
	"strings"

	"aqwari.net/xml/internal/gen"
	"aqwari.net/xml/wsdl"
	"aqwari.net/xml/xsd"
	"aqwari.net/xml/xsdgen"
)

// Types conforming to the Logger interface can receive information about
// the code generation process.
type Logger interface {
	Printf(format string, v ...interface{})
}

type printer struct {
	*Config
	code *xsdgen.Code
	wsdl *wsdl.Definition
	file *ast.File
}

// Provides aspects about an RPC call to the template for the function
// bodies.
type opArgs struct {
	// formatted with appropriate variable names
	input, output []string

	// URL to send request to
	Address string

	// POST or GET
	Method string

	SOAPAction string

	// Name of the method to call
	MsgName xml.Name

	// if we're returning individual values, these slices
	// are in an order matching the input/output slices.
	InputName, OutputName xml.Name
	InputFields           []field
	OutputFields          []field

	// If not "", inputs come in a wrapper struct
	InputType string

	// If not "", we return values in a wrapper struct
	ReturnType   string
	ReturnFields []field
}

// struct members. Need to export the fields for our template
type field struct {
	Name, Type string
	XMLName    xml.Name

	// If this is a wrapper struct for >InputThreshold arguments,
	// PublicType holds the type that we want to expose to the
	// user. For example, if the web service expects an xsdDate
	// to be sent to it, PublicType will be time.Time and a conversion
	// will take place before sending the request to the server.
	PublicType string

	// This refers to the name of the value to assign to this field
	// in the argument list. Empty for return values.
	InputArg string
}

// GenAST creates a Go source file containing type and method declarations
// that can be used to access the service described in the provided set of wsdl
// files.
func (cfg *Config) GenAST(files ...string) (*ast.File, error) {
	if len(files) == 0 {
		return nil, errors.New("must provide at least one file name")
	}
	if cfg.pkgName == "" {
		cfg.pkgName = "ws"
	}
	if cfg.pkgHeader == "" {
		cfg.pkgHeader = fmt.Sprintf("Package %s", cfg.pkgName)
	}
	docs := make([][]byte, 0, len(files))
	for _, filename := range files {
		if data, err := ioutil.ReadFile(filename); err != nil {
			return nil, err
		} else {
			cfg.debugf("read %s", filename)
			docs = append(docs, data)
		}
	}

	cfg.debugf("parsing WSDL file %s", files[0])
	def, err := wsdl.Parse(docs[0])
	if err != nil {
		return nil, err
	}
	cfg.verbosef("building xsd type whitelist from WSDL")
	cfg.registerXSDTypes(def)

	cfg.verbosef("generating type declarations from xml schema")
	code, err := cfg.xsdgen.GenCode(docs...)
	if err != nil {
		return nil, err
	}

	cfg.verbosef("generating function definitions from WSDL")
	return cfg.genAST(def, code)
}

func (cfg *Config) genAST(def *wsdl.Definition, code *xsdgen.Code) (*ast.File, error) {
	file, err := code.GenAST()
	if err != nil {
		return nil, err
	}
	file.Name = ast.NewIdent(cfg.pkgName)
	file = gen.PackageDoc(file, cfg.pkgHeader, "\n", def.Doc)
	p := &printer{
		Config: cfg,
		wsdl:   def,
		file:   file,
		code:   code,
	}
	return p.genAST()
}

func (p *printer) genAST() (*ast.File, error) {
	p.addHelpers()
	for _, port := range p.wsdl.Ports {
		if err := p.port(port); err != nil {
			return nil, err
		}
	}
	return p.file, nil
}

func (p *printer) port(port wsdl.Port) error {
	for _, operation := range port.Operations {
		if err := p.operation(port, operation); err != nil {
			return err
		}
	}
	return nil
}

func (p *printer) operation(port wsdl.Port, op wsdl.Operation) error {
	input, ok := p.wsdl.Message[op.Input]
	if !ok {
		return fmt.Errorf("unknown input message type %s", op.Input.Local)
	}
	output, ok := p.wsdl.Message[op.Output]
	if !ok {
		return fmt.Errorf("unknown output message type %s", op.Output.Local)
	}
	params, err := p.opArgs(port.Address, port.Method, op, input, output)
	if err != nil {
		return err
	}

	if params.InputType != "" {
		decls, err := gen.Snippets(params, `
			type {{.InputType}} struct {
			{{ range .InputFields -}}
				{{.Name}} {{.PublicType}}
			{{ end -}}
			}`,
		)
		if err != nil {
			return err
		}
		p.file.Decls = append(p.file.Decls, decls...)
	}
	if params.ReturnType != "" {
		decls, err := gen.Snippets(params, `
			type {{.ReturnType}} struct {
			{{ range .ReturnFields -}}
				{{.Name}} {{.Type}}
			{{ end -}}
			}`,
		)
		if err != nil {
			return err
		}
		p.file.Decls = append(p.file.Decls, decls...)
	}
	fn := gen.Func(p.xsdgen.NameOf(op.Name)).
		Comment(op.Doc).
		Receiver("c *Client").
		Args(params.input...).
		BodyTmpl(`
			var input struct {
				XMLName struct{} `+"`"+`xml:"{{.MsgName.Space}} {{.MsgName.Local}}"`+"`"+`
				Args struct {
					{{ range .InputFields -}}
					{{.Name}} {{.Type}} `+"`"+`xml:"{{.XMLName.Space}} {{.XMLName.Local}}"`+"`"+`
					{{ end -}}
				}`+"`xml:\"{{.InputName.Space}} {{.InputName.Local}}\"`"+`
			}

			{{- range .InputFields }}
			input.Args.{{.Name}} = {{.Type}}({{.InputArg}})
			{{ end }}

			var output struct {
				XMLName struct{} `+"`"+`xml:"{{.MsgName.Space}} {{.MsgName.Local}}"`+"`"+`
				Args struct {
					{{ range .OutputFields -}}
					{{.Name}} {{.Type}} `+"`"+`xml:"{{.XMLName.Space}} {{.XMLName.Local}}"`+"`"+`
					{{ end -}}
				}`+"`xml:\"{{.OutputName.Space}} {{.OutputName.Local}}\"`"+`
			}

			err := c.do({{.Method|printf "%q"}}, {{.Address|printf "%q"}}, {{.SOAPAction|printf "%q"}}, &input, &output)

			{{ if .OutputFields -}}
			return {{ range .OutputFields }}{{.Type}}(output.Args.{{.Name}}), {{ end }} err
			{{- else if .ReturnType -}}
			var result {{ .ReturnType }}
			{{ range .ReturnFields -}}
			result.{{.Name}} = {{.Type}}(output.Args.{{.InputArg}})
			{{ end -}}
			return result, err
			{{- else -}}
			return err
			{{- end -}}
		`, params).
		Returns(params.output...)
	if decl, err := fn.Decl(); err != nil {
		return err
	} else {
		p.file.Decls = append(p.file.Decls, decl)
	}
	return nil
}

// The xsdgen package generates private types for some builtin
// types. These types should be hidden from the user and converted
// on the fly.
func exposeType(typ string) string {
	switch typ {
	case "xsdDate", "xsdTime", "xsdDateTime", "gDay",
		"gMonth", "gMonthDay", "gYear", "gYearMonth":
		return "time.Time"
	case "hexBinary", "base64Binary":
		return "[]byte"
	case "idrefs", "nmtokens", "notation", "entities":
		return "[]string"
	}
	return typ
}

func (p *printer) getPartType(part wsdl.Part) (string, error) {
	if part.Type != (xml.Name{}) {
		return p.code.NameOf(part.Type), nil
	}
	if part.Element != (xml.Name{}) {
		doc, ok := p.code.DocType(part.Element.Space)
		if !ok {
			return "", fmt.Errorf("part %s: could not lookup element %v",
				part.Name, part.Element)
		}
		for _, el := range doc.Elements {
			if el.Name == part.Element {
				return p.code.NameOf(xsd.XMLName(el.Type)), nil
			}
		}
	}
	return "", fmt.Errorf("part %s has no element or type", part.Name)
}

func (p *printer) opArgs(addr, method string, op wsdl.Operation, input, output wsdl.Message) (opArgs, error) {
	var args opArgs
	args.Address = addr
	args.Method = method
	args.SOAPAction = op.SOAPAction
	args.MsgName = op.Name
	args.InputName = input.Name
	for _, part := range input.Parts {
		typ, err := p.getPartType(part)
		if err != nil {
			return args, err
		}
		inputType := exposeType(typ)
		vname := gen.Sanitize(part.Name)
		if vname == typ {
			vname += "_"
		}
		args.input = append(args.input, vname+" "+inputType)
		args.InputFields = append(args.InputFields, field{
			Name:       strings.Title(part.Name),
			Type:       typ,
			PublicType: exposeType(typ),
			XMLName:    xml.Name{p.wsdl.TargetNS, part.Name},
			InputArg:   vname,
		})
	}
	if len(args.input) > p.maxArgs {
		args.InputType = strings.Title(args.InputName.Local)
		args.input = []string{"v " + args.InputName.Local}
		for i, v := range input.Parts {
			args.InputFields[i].InputArg = "v." + strings.Title(v.Name)
		}
	}
	args.OutputName = output.Name
	for _, part := range output.Parts {
		typ, err := p.getPartType(part)
		if err != nil {
			return args, err
		}
		outputType := exposeType(typ)
		args.output = append(args.output, outputType)
		args.OutputFields = append(args.OutputFields, field{
			Name:    strings.Title(part.Name),
			Type:    typ,
			XMLName: xml.Name{p.wsdl.TargetNS, part.Name},
		})
	}
	if len(args.output) > p.maxReturns {
		args.ReturnType = strings.Title(args.OutputName.Local)
		args.ReturnFields = make([]field, len(args.OutputFields))
		for i, v := range args.OutputFields {
			args.ReturnFields[i] = field{
				Name:     v.Name,
				Type:     exposeType(v.Type),
				InputArg: v.Name,
			}
		}
		args.output = []string{args.ReturnType}
	}
	// NOTE(droyo) if we decide to name our return values,
	// we have to change this too.
	args.output = append(args.output, "error")

	return args, nil
}

// To keep our output small (as possible), we only generate type
// declarations for the types that are named in the WSDL definition.
func (cfg *Config) registerXSDTypes(def *wsdl.Definition) {
	xmlns := make(map[string]struct{})
	// Some schema may list messages that are not used by any
	// ports, so we have to be thorough.
	for _, port := range def.Ports {
		for _, op := range port.Operations {
			for _, name := range []xml.Name{op.Input, op.Output} {
				if msg, ok := def.Message[name]; !ok {
					cfg.logf("ERROR: No message def found for %s", name.Local)
				} else {
					for _, part := range msg.Parts {
						if part.Type.Space != "" {
							xmlns[part.Type.Space] = struct{}{}
						}
						if part.Element.Space != "" {
							xmlns[part.Element.Space] = struct{}{}
						}
						cfg.xsdgen.Option(xsdgen.AllowType(part.Type))
					}
				}
			}
		}
	}
	namespaces := make([]string, 0, len(xmlns))
	for ns := range xmlns {
		namespaces = append(namespaces, ns)
	}
	cfg.xsdgen.Option(xsdgen.Namespaces(namespaces...))
}
<commit_msg>Small bug in wsdlgen<commit_after>// Package wsdlgen generates Go source code from wsdl documents.
//
// The wsdlgen package generates Go source for calling the various
// methods defined in a WSDL (Web Service Definition Language) document.
// The generated Go source is self-contained, with no dependencies on
// non-standard packages.
//
// Code generation for the wsdlgen package can be configured by using
// the provided Option functions.
package wsdlgen

import (
	"encoding/xml"
	"errors"
	"fmt"
	"go/ast"
	"io/ioutil"
	"strings"

	"aqwari.net/xml/internal/gen"
	"aqwari.net/xml/wsdl"
	"aqwari.net/xml/xsd"
	"aqwari.net/xml/xsdgen"
)

// Types conforming to the Logger interface can receive information about
// the code generation process.
type Logger interface {
	Printf(format string, v ...interface{})
}

type printer struct {
	*Config
	code *xsdgen.Code
	wsdl *wsdl.Definition
	file *ast.File
}

// Provides aspects about an RPC call to the template for the function
// bodies.
type opArgs struct {
	// formatted with appropriate variable names
	input, output []string

	// URL to send request to
	Address string

	// POST or GET
	Method string

	SOAPAction string

	// Name of the method to call
	MsgName xml.Name

	// if we're returning individual values, these slices
	// are in an order matching the input/output slices.
	InputName, OutputName xml.Name
	InputFields           []field
	OutputFields          []field

	// If not "", inputs come in a wrapper struct
	InputType string

	// If not "", we return values in a wrapper struct
	ReturnType   string
	ReturnFields []field
}

// struct members. Need to export the fields for our template
type field struct {
	Name, Type string
	XMLName    xml.Name

	// If this is a wrapper struct for >InputThreshold arguments,
	// PublicType holds the type that we want to expose to the
	// user. For example, if the web service expects an xsdDate
	// to be sent to it, PublicType will be time.Time and a conversion
	// will take place before sending the request to the server.
	PublicType string

	// This refers to the name of the value to assign to this field
	// in the argument list. Empty for return values.
	InputArg string
}

// GenAST creates a Go source file containing type and method declarations
// that can be used to access the service described in the provided set of wsdl
// files.
func (cfg *Config) GenAST(files ...string) (*ast.File, error) {
	if len(files) == 0 {
		return nil, errors.New("must provide at least one file name")
	}
	if cfg.pkgName == "" {
		cfg.pkgName = "ws"
	}
	if cfg.pkgHeader == "" {
		cfg.pkgHeader = fmt.Sprintf("Package %s", cfg.pkgName)
	}
	docs := make([][]byte, 0, len(files))
	for _, filename := range files {
		if data, err := ioutil.ReadFile(filename); err != nil {
			return nil, err
		} else {
			cfg.debugf("read %s", filename)
			docs = append(docs, data)
		}
	}

	cfg.debugf("parsing WSDL file %s", files[0])
	def, err := wsdl.Parse(docs[0])
	if err != nil {
		return nil, err
	}
	cfg.verbosef("building xsd type whitelist from WSDL")
	cfg.registerXSDTypes(def)

	cfg.verbosef("generating type declarations from xml schema")
	code, err := cfg.xsdgen.GenCode(docs...)
	if err != nil {
		return nil, err
	}

	cfg.verbosef("generating function definitions from WSDL")
	return cfg.genAST(def, code)
}

func (cfg *Config) genAST(def *wsdl.Definition, code *xsdgen.Code) (*ast.File, error) {
	file, err := code.GenAST()
	if err != nil {
		return nil, err
	}
	file.Name = ast.NewIdent(cfg.pkgName)
	file = gen.PackageDoc(file, cfg.pkgHeader, "\n", def.Doc)
	p := &printer{
		Config: cfg,
		wsdl:   def,
		file:   file,
		code:   code,
	}
	return p.genAST()
}

func (p *printer) genAST() (*ast.File, error) {
	p.addHelpers()
	for _, port := range p.wsdl.Ports {
		if err := p.port(port); err != nil {
			return nil, err
		}
	}
	return p.file, nil
}

func (p *printer) port(port wsdl.Port) error {
	for _, operation := range port.Operations {
		if err := p.operation(port, operation); err != nil {
			return err
		}
	}
	return nil
}

func (p *printer) operation(port wsdl.Port, op wsdl.Operation) error {
	input, ok := p.wsdl.Message[op.Input]
	if !ok {
		return fmt.Errorf("unknown input message type %s", op.Input.Local)
	}
	output, ok := p.wsdl.Message[op.Output]
	if !ok {
		return fmt.Errorf("unknown output message type %s", op.Output.Local)
	}
	params, err := p.opArgs(port.Address, port.Method, op, input, output)
	if err != nil {
		return err
	}

	if params.InputType != "" {
		decls, err := gen.Snippets(params, `
			type {{.InputType}} struct {
			{{ range .InputFields -}}
				{{.Name}} {{.PublicType}}
			{{ end -}}
			}`,
		)
		if err != nil {
			return err
		}
		p.file.Decls = append(p.file.Decls, decls...)
	}
	if params.ReturnType != "" {
		decls, err := gen.Snippets(params, `
			type {{.ReturnType}} struct {
			{{ range .ReturnFields -}}
				{{.Name}} {{.Type}}
			{{ end -}}
			}`,
		)
		if err != nil {
			return err
		}
		p.file.Decls = append(p.file.Decls, decls...)
	}
	fn := gen.Func(p.xsdgen.NameOf(op.Name)).
		Comment(op.Doc).
		Receiver("c *Client").
		Args(params.input...).
		BodyTmpl(`
			var input struct {
				XMLName struct{} `+"`"+`xml:"{{.MsgName.Space}} {{.MsgName.Local}}"`+"`"+`
				Args struct {
					{{ range .InputFields -}}
					{{.Name}} {{.Type}} `+"`"+`xml:"{{.XMLName.Space}} {{.XMLName.Local}}"`+"`"+`
					{{ end -}}
				}`+"`xml:\"{{.InputName.Space}} {{.InputName.Local}}\"`"+`
			}

			{{- range .InputFields }}
			input.Args.{{.Name}} = {{.Type}}({{.InputArg}})
			{{ end }}

			var output struct {
				XMLName struct{} `+"`"+`xml:"{{.MsgName.Space}} {{.MsgName.Local}}"`+"`"+`
				Args struct {
					{{ range .OutputFields -}}
					{{.Name}} {{.Type}} `+"`"+`xml:"{{.XMLName.Space}} {{.XMLName.Local}}"`+"`"+`
					{{ end -}}
				}`+"`xml:\"{{.OutputName.Space}} {{.OutputName.Local}}\"`"+`
			}

			err := c.do({{.Method|printf "%q"}}, {{.Address|printf "%q"}}, {{.SOAPAction|printf "%q"}}, &input, &output)

			{{ if .OutputFields -}}
			return {{ range .OutputFields }}{{.Type}}(output.Args.{{.Name}}), {{ end }} err
			{{- else if .ReturnType -}}
			var result {{ .ReturnType }}
			{{ range .ReturnFields -}}
			result.{{.Name}} = {{.Type}}(output.Args.{{.InputArg}})
			{{ end -}}
			return result, err
			{{- else -}}
			return err
			{{- end -}}
		`, params).
		Returns(params.output...)
	if decl, err := fn.Decl(); err != nil {
		return err
	} else {
		p.file.Decls = append(p.file.Decls, decl)
	}
	return nil
}

// The xsdgen package generates private types for some builtin
// types. These types should be hidden from the user and converted
// on the fly.
func exposeType(typ string) string {
	switch typ {
	case "xsdDate", "xsdTime", "xsdDateTime", "gDay",
		"gMonth", "gMonthDay", "gYear", "gYearMonth":
		return "time.Time"
	case "hexBinary", "base64Binary":
		return "[]byte"
	case "idrefs", "nmtokens", "notation", "entities":
		return "[]string"
	}
	return typ
}

func (p *printer) getPartType(part wsdl.Part) (string, error) {
	if part.Type.Local != "" {
		return p.code.NameOf(part.Type), nil
	}
	if part.Element.Local != "" {
		doc, ok := p.code.DocType(part.Element.Space)
		if !ok {
			return "", fmt.Errorf("part %s: could not lookup element %v",
				part.Name, part.Element)
		}
		for _, el := range doc.Elements {
			if el.Name == part.Element {
				return p.code.NameOf(xsd.XMLName(el.Type)), nil
			}
		}
	}
	return "", fmt.Errorf("part %s has no element or type", part.Name)
}

func (p *printer) opArgs(addr, method string, op wsdl.Operation, input, output wsdl.Message) (opArgs, error) {
	var args opArgs
	args.Address = addr
	args.Method = method
	args.SOAPAction = op.SOAPAction
	args.MsgName = op.Name
	args.InputName = input.Name
	for _, part := range input.Parts {
		typ, err := p.getPartType(part)
		if err != nil {
			return args, err
		}
		inputType := exposeType(typ)
		vname := gen.Sanitize(part.Name)
		if vname == typ {
			vname += "_"
		}
		args.input = append(args.input, vname+" "+inputType)
		args.InputFields = append(args.InputFields, field{
			Name:       strings.Title(part.Name),
			Type:       typ,
			PublicType: exposeType(typ),
			XMLName:    xml.Name{p.wsdl.TargetNS, part.Name},
			InputArg:   vname,
		})
	}
	if len(args.input) > p.maxArgs {
		args.InputType = strings.Title(args.InputName.Local)
		args.input = []string{"v " + args.InputName.Local}
		for i, v := range input.Parts {
			args.InputFields[i].InputArg = "v." + strings.Title(v.Name)
		}
	}
	args.OutputName = output.Name
	for _, part := range output.Parts {
		typ, err := p.getPartType(part)
		if err != nil {
			return args, err
		}
		outputType := exposeType(typ)
		args.output = append(args.output, outputType)
		args.OutputFields = append(args.OutputFields, field{
			Name:    strings.Title(part.Name),
			Type:    typ,
			XMLName: xml.Name{p.wsdl.TargetNS, part.Name},
		})
	}
	if len(args.output) > p.maxReturns {
		args.ReturnType = strings.Title(args.OutputName.Local)
		args.ReturnFields = make([]field, len(args.OutputFields))
		for i, v := range args.OutputFields {
			args.ReturnFields[i] = field{
				Name:     v.Name,
				Type:     exposeType(v.Type),
				InputArg: v.Name,
			}
		}
		args.output = []string{args.ReturnType}
	}
	// NOTE(droyo) if we decide to name our return values,
	// we have to change this too.
	args.output = append(args.output, "error")

	return args, nil
}

// To keep our output small (as possible), we only generate type
// declarations for the types that are named in the WSDL definition.
func (cfg *Config) registerXSDTypes(def *wsdl.Definition) {
	xmlns := make(map[string]struct{})
	// Some schema may list messages that are not used by any
	// ports, so we have to be thorough.
	for _, port := range def.Ports {
		for _, op := range port.Operations {
			for _, name := range []xml.Name{op.Input, op.Output} {
				if msg, ok := def.Message[name]; !ok {
					cfg.logf("ERROR: No message def found for %s", name.Local)
				} else {
					for _, part := range msg.Parts {
						if part.Type.Space != "" {
							xmlns[part.Type.Space] = struct{}{}
						}
						if part.Element.Space != "" {
							xmlns[part.Element.Space] = struct{}{}
						}
						cfg.xsdgen.Option(xsdgen.AllowType(part.Type))
					}
				}
			}
		}
	}
	namespaces := make([]string, 0, len(xmlns))
	for ns := range xmlns {
		namespaces = append(namespaces, ns)
	}
	cfg.xsdgen.Option(xsdgen.Namespaces(namespaces...))
}
<|endoftext|>


<commit_before>package core

import (
	"encoding/base64"
	"fmt"
	simplejson "github.com/bitly/go-simplejson"
	"net/http"
	"strconv"
	"strings"
)

const (
	DefaultAPIBaseURL = "http://demo6970933.mockable.io"
	DefaultAPIVersion = 1
)

type APIClient struct {
	Server    string
	UUID      string
	AuthToken string
	Client    *http.Client
}

func NewAPIClient(server string, uuid string, authToken string) *APIClient {
	return &APIClient{
		Client:    &http.Client{},
		UUID:      uuid,
		AuthToken: authToken,
		Server:    server,
	}
}

type ConfigResponse struct {
	Signed string
	Raw    string
}

func NewConfigResponse(json *simplejson.Json) (*ConfigResponse, error) {
	raw, err := json.Get("raw").String()
	if err != nil {
		return nil, err
	}

	signed, err := json.Get("signed").String()
	if err != nil {
		return nil, err
	}

	return &ConfigResponse{
		Raw:    raw,
		Signed: signed,
	}, nil
}

func (c *ConfigResponse) GetRawDecoded() string {
	rawDecoded, _ := base64.StdEncoding.DecodeString(c.Raw)
	return string(rawDecoded)
}

func (c *ConfigResponse) GetSignedDecoded() string {
	signedDecoded, _ := base64.StdEncoding.DecodeString(c.Signed)
	return string(signedDecoded)
}

func (api *APIClient) GetFormattedURL(prefix ...string) string {
	return fmt.Sprintf("%s/%s/%s", api.Server, strconv.Itoa(DefaultAPIVersion),
		strings.Join(prefix, "/"))
}

func (api *APIClient) NewRequest(method string, url string) (*simplejson.Json, error) {
	request, err := http.NewRequest(method, url, nil)
	if err != nil {
		return nil, err
	}

	if api.AuthToken != "" {
		request.Header.Add("Auth-Token", api.AuthToken)
	}

	response, err := api.Client.Do(request)
	if err != nil {
		return nil, err
	}

	if response.StatusCode != 200 {
		return nil, fmt.Errorf("Invalid server response: %s", response.Status)
	}

	defer response.Body.Close()
	reader, err := simplejson.NewFromReader(response.Body)

	if err != nil {
		return nil, err
	}

	return reader, nil
}

func (api *APIClient) GetConfig() (*ConfigResponse, error) {
	response, err := api.NewRequest("GET", api.GetFormattedURL(api.UUID))

	if err != nil {
		return nil, err
	}

	config, err := NewConfigResponse(response)
	if err != nil {
		return nil, err
	}

	return config, nil
}
<commit_msg>[core/api] CreateConfig, UpdateConfig mapped to POST/PUT<commit_after>package core

import (
	"encoding/base64"
	"fmt"
	simplejson "github.com/bitly/go-simplejson"
	"net/http"
	"strconv"
	"strings"
)

const (
	DefaultAPIBaseURL = "http://demo6970933.mockable.io"
	DefaultAPIVersion = 1
)

type APIClient struct {
	Server    string
	UUID      string
	AuthToken string
	Client    *http.Client
}

func NewAPIClient(server string, uuid string, authToken string) *APIClient {
	return &APIClient{
		Client:    &http.Client{},
		UUID:      uuid,
		AuthToken: authToken,
		Server:    server,
	}
}

type ConfigResponse struct {
	Signed string
	Raw    string
}

func NewConfigResponse(json *simplejson.Json) (*ConfigResponse, error) {
	raw, err := json.Get("raw").String()
	if err != nil {
		return nil, err
	}

	signed, err := json.Get("signed").String()
	if err != nil {
		return nil, err
	}

	return &ConfigResponse{
		Raw:    raw,
		Signed: signed,
	}, nil
}

func (c *ConfigResponse) GetRawDecoded() string {
	rawDecoded, _ := base64.StdEncoding.DecodeString(c.Raw)
	return string(rawDecoded)
}

func (c *ConfigResponse) GetSignedDecoded() string {
	signedDecoded, _ := base64.StdEncoding.DecodeString(c.Signed)
	return string(signedDecoded)
}

func (api *APIClient) GetFormattedURL(prefix ...string) string {
	return fmt.Sprintf("%s/%s/%s", api.Server, strconv.Itoa(DefaultAPIVersion),
		strings.Join(prefix, "/"))
}

func (api *APIClient) NewRequest(method string, url string) (*simplejson.Json, error) {
	request, err := http.NewRequest(method, url, nil)
	if err != nil {
		return nil, err
	}

	if api.AuthToken != "" {
		request.Header.Add("Auth-Token", api.AuthToken)
	}

	response, err := api.Client.Do(request)
	if err != nil {
		return nil, err
	}

	if response.StatusCode != 200 {
		return nil, fmt.Errorf("Invalid server response: %s", response.Status)
	}

	defer response.Body.Close()
	reader, err := simplejson.NewFromReader(response.Body)

	if err != nil {
		return nil, err
	}

	return reader, nil
}

func (api *APIClient) GetConfig() (*ConfigResponse, error) {
	response, err := api.NewRequest("GET", api.GetFormattedURL(api.UUID))

	if err != nil {
		return nil, err
	}

	config, err := NewConfigResponse(response)
	if err != nil {
		return nil, err
	}

	return config, nil
}

func (api *APIClient) UpdateConfig() (*ConfigResponse, error) {
	response, err := api.NewRequest("UPDATE", api.GetFormattedURL(api.UUID))

	if err != nil {
		return nil, err
	}

	config, err := NewConfigResponse(response)
	if err != nil {
		return nil, err
	}

	return config, nil
}

func (api *APIClient) CreateConfig() (*ConfigResponse, error) {
	response, err := api.NewRequest("POST", api.GetFormattedURL(api.UUID))

	if err != nil {
		return nil, err
	}

	config, err := NewConfigResponse(response)
	if err != nil {
		return nil, err
	}

	return config, nil
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/gin-gonic/gin"
	"github.com/justinas/nosurf"
	"net/http"
	"sync"

	"github.com/eirka/eirka-libs/config"
	"github.com/eirka/eirka-libs/db"
)

var (
	sitemap    = make(map[string]*SiteData)
	mu         = new(sync.RWMutex)
	csrfcookie = &http.Cookie{
		Name:  "session_csrf",
		Value: nosurf.Token(c.Request),
		Path:  "/",
	}
)

type SiteData struct {
	Ib          uint
	Api         string
	Img         string
	Title       string
	Desc        string
	Nsfw        bool
	Style       string
	Logo        string
	Imageboards []Imageboard
}

type Imageboard struct {
	Title   string
	Address string
}

// generates a nosurf cookie for angularjs
func CSRFCookie() gin.HandlerFunc {
	return func(c *gin.Context) {

		http.SetCookie(c.Writer, csrfcookie)

		c.Next()

	}
}

// gets the details from the request for the page handler variables
func Details() gin.HandlerFunc {
	return func(c *gin.Context) {

		host := c.Request.Host

		mu.RLock()
		site := sitemap[host]
		mu.RUnlock()

		if site == nil {

			sitedata := &SiteData{}

			// Get Database handle
			dbase, err := db.GetDb()
			if err != nil {
				c.Error(err)
				c.Abort()
				return
			}

			err = dbase.QueryRow(`SELECT ib_id,ib_title,ib_description,ib_nsfw,ib_api,ib_img,ib_style,ib_logo FROM imageboards WHERE ib_domain = ?`, host).Scan(&sitedata.Ib, &sitedata.Title, &sitedata.Desc, &sitedata.Nsfw, &sitedata.Api, &sitedata.Img, &sitedata.Style, &sitedata.Logo)
			if err != nil {
				c.Error(err)
				c.Abort()
				return
			}

			rows, err := dbase.Query(`SELECT ib_title,ib_domain FROM imageboards WHERE ib_id != ?`, sitedata.Ib)
			if err != nil {
				c.Error(err)
				c.Abort()
				return
			}
			defer rows.Close()

			for rows.Next() {

				ib := Imageboard{}

				err := rows.Scan(&ib.Title, &ib.Address)
				if err != nil {
					return
				}

				sitedata.Imageboards = append(sitedata.Imageboards, ib)
			}
			err = rows.Err()
			if err != nil {
				c.Error(err)
				c.Abort()
				return
			}

			mu.Lock()
			sitemap[host] = sitedata
			mu.Unlock()

		}

		c.Next()

	}
}

// Handles index page generation
func IndexController(c *gin.Context) {

	host := c.Request.Host

	mu.RLock()
	site := sitemap[host]
	mu.RUnlock()

	c.HTML(http.StatusOK, "index", gin.H{
		"primjs":      config.Settings.Prim.Js,
		"primcss":     config.Settings.Prim.Css,
		"ib":          site.Ib,
		"apisrv":      site.Api,
		"imgsrv":      site.Img,
		"title":       site.Title,
		"desc":        site.Desc,
		"nsfw":        site.Nsfw,
		"style":       site.Style,
		"logo":        site.Logo,
		"imageboards": site.Imageboards,
		"csrf":        nosurf.Token(c.Request),
	})

	return

}

// Handles error messages for wrong routes
func ErrorController(c *gin.Context) {

	c.String(http.StatusNotFound, "Not Found")

	return

}
<commit_msg>add csrf<commit_after>package main

import (
	"github.com/gin-gonic/gin"
	"github.com/justinas/nosurf"
	"net/http"
	"sync"

	"github.com/eirka/eirka-libs/config"
	"github.com/eirka/eirka-libs/db"
)

var (
	sitemap = make(map[string]*SiteData)
	mu      = new(sync.RWMutex)
)

type SiteData struct {
	Ib          uint
	Api         string
	Img         string
	Title       string
	Desc        string
	Nsfw        bool
	Style       string
	Logo        string
	Imageboards []Imageboard
}

type Imageboard struct {
	Title   string
	Address string
}

// generates a nosurf cookie for angularjs
func CSRFCookie() gin.HandlerFunc {
	return func(c *gin.Context) {

		csrfcookie := &http.Cookie{
			Name:  "session_csrf",
			Value: nosurf.Token(c.Request),
			Path:  "/",
		}

		http.SetCookie(c.Writer, csrfcookie)

		c.Next()

	}
}

// gets the details from the request for the page handler variables
func Details() gin.HandlerFunc {
	return func(c *gin.Context) {

		host := c.Request.Host

		mu.RLock()
		site := sitemap[host]
		mu.RUnlock()

		if site == nil {

			sitedata := &SiteData{}

			// Get Database handle
			dbase, err := db.GetDb()
			if err != nil {
				c.Error(err)
				c.Abort()
				return
			}

			err = dbase.QueryRow(`SELECT ib_id,ib_title,ib_description,ib_nsfw,ib_api,ib_img,ib_style,ib_logo FROM imageboards WHERE ib_domain = ?`, host).Scan(&sitedata.Ib, &sitedata.Title, &sitedata.Desc, &sitedata.Nsfw, &sitedata.Api, &sitedata.Img, &sitedata.Style, &sitedata.Logo)
			if err != nil {
				c.Error(err)
				c.Abort()
				return
			}

			rows, err := dbase.Query(`SELECT ib_title,ib_domain FROM imageboards WHERE ib_id != ?`, sitedata.Ib)
			if err != nil {
				c.Error(err)
				c.Abort()
				return
			}
			defer rows.Close()

			for rows.Next() {

				ib := Imageboard{}

				err := rows.Scan(&ib.Title, &ib.Address)
				if err != nil {
					return
				}

				sitedata.Imageboards = append(sitedata.Imageboards, ib)
			}
			err = rows.Err()
			if err != nil {
				c.Error(err)
				c.Abort()
				return
			}

			mu.Lock()
			sitemap[host] = sitedata
			mu.Unlock()

		}

		c.Next()

	}
}

// Handles index page generation
func IndexController(c *gin.Context) {

	host := c.Request.Host

	mu.RLock()
	site := sitemap[host]
	mu.RUnlock()

	c.HTML(http.StatusOK, "index", gin.H{
		"primjs":      config.Settings.Prim.Js,
		"primcss":     config.Settings.Prim.Css,
		"ib":          site.Ib,
		"apisrv":      site.Api,
		"imgsrv":      site.Img,
		"title":       site.Title,
		"desc":        site.Desc,
		"nsfw":        site.Nsfw,
		"style":       site.Style,
		"logo":        site.Logo,
		"imageboards": site.Imageboards,
		"csrf":        nosurf.Token(c.Request),
	})

	return

}

// Handles error messages for wrong routes
func ErrorController(c *gin.Context) {

	c.String(http.StatusNotFound, "Not Found")

	return

}
<|endoftext|>


<commit_before>package bild

import (
	"fmt"
	"image"
	"math"
)

// ConvolutionMatrix interface.
// At returns the matrix value at position x, y.
// Normalized returns a new matrix with normalized values.
// SideLength returns the matrix side length.
type ConvolutionMatrix interface {
	At(x, y int) float64
	Normalized() ConvolutionMatrix
	SideLength() int
}

// NewKernel returns a kernel of the provided length.
func NewKernel(length int) *Kernel {
	return &Kernel{make([]float64, length*length), length}
}

// Kernel to be used as a convolution matrix.
type Kernel struct {
	Matrix []float64
	Stride int
}

// Normalized returns a new Kernel with normalized values.
func (k *Kernel) Normalized() ConvolutionMatrix {
	sum := absum(k)
	stride := k.Stride
	nk := NewKernel(stride)

	// avoid division by 0
	if sum == 0 {
		sum = 1
	}

	for i := 0; i < stride*stride; i++ {
		nk.Matrix[i] = k.Matrix[i] / sum
	}

	return nk
}

// SideLength returns the matrix side length.
func (k *Kernel) SideLength() int {
	return k.Stride
}

// At returns the matrix value at position x, y.
func (k *Kernel) At(x, y int) float64 {
	return k.Matrix[y*k.Stride+x]
}

// String returns the string representation of the matrix.
func (k *Kernel) String() string {
	result := ""
	stride := k.Stride
	for x := 0; x < stride; x++ {
		result += fmt.Sprintf("\n")
		for y := 0; y < stride; y++ {
			result += fmt.Sprintf("%-8.4f", k.At(x, y))
		}
	}
	return result
}

// ConvolutionOptions are the Convolve function parameters.
// Bias is added to each RGB channel after convoluting. Range is -255 to 255.
// Wrap sets if indices outside of image dimensions should be taken from the opposite side.
// CarryAlpha sets if the alpha should be taken from the source image without convoluting
type ConvolutionOptions struct {
	Bias       float64
	Wrap       bool
	CarryAlpha bool
}

// Convolve applies a convolution matrix (kernel) to an image with the supplied options.
func Convolve(img image.Image, k ConvolutionMatrix, o *ConvolutionOptions) *image.RGBA {
	bounds := img.Bounds()
	src := CloneAsRGBA(img)
	dst := image.NewRGBA(bounds)

	w, h := bounds.Max.X, bounds.Max.Y
	kernelLength := k.SideLength()

	bias := 0.0
	wrap := false
	carryAlpha := true
	if o != nil {
		bias = o.Bias
		wrap = o.Wrap
		carryAlpha = o.CarryAlpha
	}

	parallelize(h, func(start, end int) {
		for x := 0; x < w; x++ {
			for y := start; y < end; y++ {

				var r, g, b, a float64
				for kx := 0; kx < kernelLength; kx++ {
					for ky := 0; ky < kernelLength; ky++ {

						var ix, iy int
						if wrap {
							ix = (x - kernelLength/2 + kx + w) % w
							iy = (y - kernelLength/2 + ky + h) % h
						} else {
							ix = x - kernelLength/2 + kx
							iy = y - kernelLength/2 + ky

							if ix < 0 || ix >= w || iy < 0 || iy >= h {
								continue
							}
						}

						ipos := iy*dst.Stride + ix*4
						kvalue := k.At(kx, ky)

						r += float64(src.Pix[ipos+0]) * kvalue
						g += float64(src.Pix[ipos+1]) * kvalue
						b += float64(src.Pix[ipos+2]) * kvalue
						if !carryAlpha {
							a += float64(src.Pix[ipos+3]) * kvalue
						}
					}
				}

				pos := y*dst.Stride + x*4
				dst.Pix[pos+0] = uint8(math.Max(math.Min(r+bias, 255), 0))
				dst.Pix[pos+1] = uint8(math.Max(math.Min(g+bias, 255), 0))
				dst.Pix[pos+2] = uint8(math.Max(math.Min(b+bias, 255), 0))
				if !carryAlpha {
					dst.Pix[pos+3] = uint8(math.Max(math.Min(a, 255), 0))
				} else {
					dst.Pix[pos+3] = src.Pix[pos+3]
				}
			}
		}
	})

	return dst
}

// absum returns the absolute cumulative value of the matrix.
func absum(k *Kernel) float64 {
	var sum float64
	for _, v := range k.Matrix {
		sum += math.Abs(v)
	}
	return sum
}
<commit_msg>improved speed of convolve operation by running sequentially first.<commit_after>package bild

import (
	"fmt"
	"image"
	"math"
)

// ConvolutionMatrix interface.
// At returns the matrix value at position x, y.
// Normalized returns a new matrix with normalized values.
// SideLength returns the matrix side length.
type ConvolutionMatrix interface {
	At(x, y int) float64
	Normalized() ConvolutionMatrix
	SideLength() int
}

// NewKernel returns a kernel of the provided length.
func NewKernel(length int) *Kernel {
	return &Kernel{make([]float64, length*length), length}
}

// Kernel to be used as a convolution matrix.
type Kernel struct {
	Matrix []float64
	Stride int
}

// Normalized returns a new Kernel with normalized values.
func (k *Kernel) Normalized() ConvolutionMatrix {
	sum := absum(k)
	stride := k.Stride
	nk := NewKernel(stride)

	// avoid division by 0
	if sum == 0 {
		sum = 1
	}

	for i := 0; i < stride*stride; i++ {
		nk.Matrix[i] = k.Matrix[i] / sum
	}

	return nk
}

// SideLength returns the matrix side length.
func (k *Kernel) SideLength() int {
	return k.Stride
}

// At returns the matrix value at position x, y.
func (k *Kernel) At(x, y int) float64 {
	return k.Matrix[y*k.Stride+x]
}

// String returns the string representation of the matrix.
func (k *Kernel) String() string {
	result := ""
	stride := k.Stride
	for x := 0; x < stride; x++ {
		result += fmt.Sprintf("\n")
		for y := 0; y < stride; y++ {
			result += fmt.Sprintf("%-8.4f", k.At(x, y))
		}
	}
	return result
}

// ConvolutionOptions are the Convolve function parameters.
// Bias is added to each RGB channel after convoluting. Range is -255 to 255.
// Wrap sets if indices outside of image dimensions should be taken from the opposite side.
// CarryAlpha sets if the alpha should be taken from the source image without convoluting
type ConvolutionOptions struct {
	Bias       float64
	Wrap       bool
	CarryAlpha bool
}

// Convolve applies a convolution matrix (kernel) to an image with the supplied options.
//
// Usage example:
//
//		Convolve(img, kernel, &ConvolutionOptions{Bias: 0, Wrap: false, CarryAlpha: false})
//
func Convolve(img image.Image, k ConvolutionMatrix, o *ConvolutionOptions) *image.RGBA {
	bounds := img.Bounds()
	src := CloneAsRGBA(img)
	dst := image.NewRGBA(bounds)

	w, h := bounds.Max.X, bounds.Max.Y
	kernelLength := k.SideLength()

	bias := 0.0
	wrap := false
	carryAlpha := true
	if o != nil {
		bias = o.Bias
		wrap = o.Wrap
		carryAlpha = o.CarryAlpha
	}

	parallelize(h, func(start, end int) {
		for y := start; y < end; y++ {
			for x := 0; x < w; x++ {

				var r, g, b, a float64
				for ky := 0; ky < kernelLength; ky++ {
					for kx := 0; kx < kernelLength; kx++ {

						var ix, iy int
						if wrap {
							ix = (x - kernelLength/2 + kx + w) % w
							iy = (y - kernelLength/2 + ky + h) % h
						} else {
							ix = x - kernelLength/2 + kx
							iy = y - kernelLength/2 + ky

							if ix < 0 || ix >= w || iy < 0 || iy >= h {
								continue
							}
						}

						ipos := iy*dst.Stride + ix*4
						kvalue := k.At(kx, ky)

						r += float64(src.Pix[ipos+0]) * kvalue
						g += float64(src.Pix[ipos+1]) * kvalue
						b += float64(src.Pix[ipos+2]) * kvalue
						if !carryAlpha {
							a += float64(src.Pix[ipos+3]) * kvalue
						}
					}
				}

				pos := y*dst.Stride + x*4
				dst.Pix[pos+0] = uint8(math.Max(math.Min(r+bias, 255), 0))
				dst.Pix[pos+1] = uint8(math.Max(math.Min(g+bias, 255), 0))
				dst.Pix[pos+2] = uint8(math.Max(math.Min(b+bias, 255), 0))
				if !carryAlpha {
					dst.Pix[pos+3] = uint8(math.Max(math.Min(a, 255), 0))
				} else {
					dst.Pix[pos+3] = src.Pix[pos+3]
				}
			}
		}
	})

	return dst
}

// absum returns the absolute cumulative value of the matrix.
func absum(k *Kernel) float64 {
	var sum float64
	for _, v := range k.Matrix {
		sum += math.Abs(v)
	}
	return sum
}
<|endoftext|>


<commit_before>// Copyright 2018 Istio 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 bootstrap

import (
	"encoding/json"
	"io/ioutil"
	"os"
	"path"
	"reflect"
	"regexp"
	"testing"

	"github.com/envoyproxy/go-control-plane/envoy/config/bootstrap/v2"
	"github.com/ghodss/yaml"
	"github.com/gogo/protobuf/jsonpb"
	"github.com/gogo/protobuf/proto"
	diff "gopkg.in/d4l3k/messagediff.v1"

	meshconfig "istio.io/api/mesh/v1alpha1"
	"istio.io/istio/pkg/test/env"
)

// Generate configs for the default configs used by istio.
// If the template is updated, copy the new golden files from out:
// cp $TOP/out/linux_amd64/release/bootstrap/all/envoy-rev0.json pkg/bootstrap/testdata/all_golden.json
// cp $TOP/out/linux_amd64/release/bootstrap/auth/envoy-rev0.json pkg/bootstrap/testdata/auth_golden.json
// cp $TOP/out/linux_amd64/release/bootstrap/default/envoy-rev0.json pkg/bootstrap/testdata/default_golden.json
// cp $TOP/out/linux_amd64/release/bootstrap/tracing_lightstep/envoy-rev0.json pkg/bootstrap/testdata/tracing_lightstep_golden.json
// cp $TOP/out/linux_amd64/release/bootstrap/tracing_zipkin/envoy-rev0.json pkg/bootstrap/testdata/tracing_zipkin_golden.json
func TestGolden(t *testing.T) {
	cases := []struct {
		base                       string
		labels                     map[string]string
		annotations                map[string]string
		expectLightstepAccessToken bool
	}{
		{
			base: "auth",
		},
		{
			base: "default",
		},
		{
			base: "running",
			labels: map[string]string{
				"ISTIO_PROXY_SHA":     "istio-proxy:sha",
				"INTERCEPTION_MODE":   "REDIRECT",
				"ISTIO_PROXY_VERSION": "istio-proxy:version",
				"ISTIO_VERSION":       "release-3.1",
				"POD_NAME":            "svc-0-0-0-6944fb884d-4pgx8",
			},
			annotations: map[string]string{
				"istio.io/insecurepath": "{\"paths\":[\"/metrics\",\"/live\"]}",
			},
		},
		{
			// nolint: goimports
			base: "tracing_lightstep",
			expectLightstepAccessToken: true,
		},
		{
			base: "tracing_zipkin",
		},
		{
			// Specify zipkin/statsd address, similar with the default config in v1 tests
			base: "all",
		},
	}

	out := env.ISTIO_OUT.Value() // defined in the makefile
	if out == "" {
		out = "/tmp"
	}

	for _, c := range cases {
		t.Run("Bootstrap-"+c.base, func(t *testing.T) {
			cfg, err := loadProxyConfig(c.base, out, t)
			if err != nil {
				t.Fatal(err)
			}

			_, localEnv := createEnv(t, c.labels, c.annotations)
			fn, err := WriteBootstrap(cfg, "sidecar~1.2.3.4~foo~bar", 0, []string{
				"spiffe://cluster.local/ns/istio-system/sa/istio-pilot-service-account"}, nil, localEnv)
			if err != nil {
				t.Fatal(err)
			}

			real, err := ioutil.ReadFile(fn)
			if err != nil {
				t.Error("Error reading generated file ", err)
				return
			}

			// apply minor modifications for the generated file so that tests are consistent
			// across different env setups
			err = ioutil.WriteFile(fn, correctForEnvDifference(real), 0700)
			if err != nil {
				t.Error("Error modifying generated file ", err)
				return
			}

			// re-read generated file with the changes having been made
			real, err = ioutil.ReadFile(fn)
			if err != nil {
				t.Error("Error reading generated file ", err)
				return
			}

			golden, err := ioutil.ReadFile("testdata/" + c.base + "_golden.json")
			if err != nil {
				golden = []byte{}
			}

			realM := v2.Bootstrap{}
			goldenM := v2.Bootstrap{}

			jgolden, err := yaml.YAMLToJSON(golden)

			if err != nil {
				t.Fatalf("unable to convert: %s %v", c.base, err)
			}

			if err = jsonpb.UnmarshalString(string(jgolden), &goldenM); err != nil {
				t.Fatalf("invalid json %s %s\n%v", c.base, err, string(jgolden))
			}

			if err = goldenM.Validate(); err != nil {
				t.Fatalf("invalid golder: %v", err)
			}

			jreal, err := yaml.YAMLToJSON(real)

			if err != nil {
				t.Fatalf("unable to convert: %v", err)
			}

			if err = jsonpb.UnmarshalString(string(jreal), &realM); err != nil {
				t.Fatalf("invalid json %v\n%s", err, string(real))
			}

			if !reflect.DeepEqual(realM, goldenM) {
				s, _ := diff.PrettyDiff(realM, goldenM)
				t.Logf("difference: %s", s)
				t.Fatalf("\n got: %v\nwant: %v", realM, goldenM)
			}

			// Check if the LightStep access token file exists
			_, err = os.Stat(lightstepAccessTokenFile(path.Dir(fn)))
			if c.expectLightstepAccessToken {
				if os.IsNotExist(err) {
					t.Error("expected to find a LightStep access token file but none found")
				} else if err != nil {
					t.Error("error running Stat on file: ", err)
				}
			} else {
				if err == nil {
					t.Error("found a LightStep access token file but none was expected")
				} else if !os.IsNotExist(err) {
					t.Error("error running Stat on file: ", err)
				}
			}
		})
	}

}

type regexReplacement struct {
	pattern     *regexp.Regexp
	replacement []byte
}

// correctForEnvDifference corrects the portions of a generated bootstrap config that vary depending on the environment
// so that they match the golden file's expected value.
func correctForEnvDifference(in []byte) []byte {
	replacements := []regexReplacement{
		// Lightstep access tokens are written to a file and that path is dependent upon the environment variables that
		// are set. Standardize the path so that golden files can be properly checked.
		{
			pattern:     regexp.MustCompile(`("access_token_file": ").*(lightstep_access_token.txt")`),
			replacement: []byte("$1/test-path/$2"),
		},
	}

	out := in
	for _, r := range replacements {
		out = r.pattern.ReplaceAll(out, r.replacement)
	}
	return out
}

func loadProxyConfig(base, out string, _ *testing.T) (*meshconfig.ProxyConfig, error) {
	content, err := ioutil.ReadFile("testdata/" + base + ".proto")
	if err != nil {
		return nil, err
	}
	cfg := &meshconfig.ProxyConfig{}
	err = proto.UnmarshalText(string(content), cfg)
	if err != nil {
		return nil, err
	}

	// Exported from makefile or env
	cfg.ConfigPath = out + "/bootstrap/" + base
	gobase := os.Getenv("ISTIO_GO")
	if gobase == "" {
		gobase = "../.."
	}
	cfg.CustomConfigFile = gobase + "/tools/deb/envoy_bootstrap_v2.json"
	return cfg, nil
}

func TestGetHostPort(t *testing.T) {
	var testCases = []struct {
		name         string
		addr         string
		expectedHost string
		expectedPort string
		errStr       string
	}{
		{
			name:         "Valid IPv4 host/port",
			addr:         "127.0.0.1:5000",
			expectedHost: "127.0.0.1",
			expectedPort: "5000",
			errStr:       "",
		},
		{
			name:         "Valid IPv6 host/port",
			addr:         "[2001:db8::100]:5000",
			expectedHost: "2001:db8::100",
			expectedPort: "5000",
			errStr:       "",
		},
		{
			name:         "Valid host/port",
			addr:         "istio-pilot:15005",
			expectedHost: "istio-pilot",
			expectedPort: "15005",
			errStr:       "",
		},
		{
			name:         "No port specified",
			addr:         "127.0.0.1:",
			expectedHost: "127.0.0.1",
			expectedPort: "",
			errStr:       "",
		},
		{
			name:         "Missing port",
			addr:         "127.0.0.1",
			expectedHost: "",
			expectedPort: "",
			errStr:       "unable to parse test address \"127.0.0.1\": address 127.0.0.1: missing port in address",
		},
		{
			name:         "Missing brackets for IPv6",
			addr:         "2001:db8::100:5000",
			expectedHost: "",
			expectedPort: "",
			errStr:       "unable to parse test address \"2001:db8::100:5000\": address 2001:db8::100:5000: too many colons in address",
		},
		{
			name:         "No address provided",
			addr:         "",
			expectedHost: "",
			expectedPort: "",
			errStr:       "unable to parse test address \"\": missing port in address",
		},
	}
	for _, tc := range testCases {
		h, p, err := GetHostPort("test", tc.addr)
		if err == nil {
			if tc.errStr != "" {
				t.Errorf("[%s] expected error %q, but no error seen", tc.name, tc.errStr)
			} else if h != tc.expectedHost || p != tc.expectedPort {
				t.Errorf("[%s] expected %s:%s, got %s:%s", tc.name, tc.expectedHost, tc.expectedPort, h, p)
			}
		} else {
			if tc.errStr == "" {
				t.Errorf("[%s] expected no error but got %q", tc.name, err.Error())
			} else if err.Error() != tc.errStr {
				t.Errorf("[%s] expected error message %q, got %v", tc.name, tc.errStr, err)
			}
		}
	}
}

func TestStoreHostPort(t *testing.T) {
	opts := map[string]interface{}{}
	StoreHostPort("istio-pilot", "15005", "foo", opts)
	actual, ok := opts["foo"]
	if !ok {
		t.Fatalf("expected to have map entry foo populated")
	}
	expected := "{\"address\": \"istio-pilot\", \"port_value\": 15005}"
	if actual != expected {
		t.Errorf("expected value %q, got %q", expected, actual)
	}
}

type encodeFn func(string) string

func envEncode(m map[string]string, prefix string, encode encodeFn, out []string) []string {
	for k, v := range m {
		out = append(out, prefix+encode(k)+"="+encode(v))
	}
	return out
}

// createEnv takes labels and annotations are returns environment in go format.
func createEnv(t *testing.T, labels map[string]string, anno map[string]string) (map[string]string, []string) {
	merged := map[string]string{}
	mergeMap(merged, labels)
	mergeMap(merged, anno)

	envs := make([]string, 0)

	if labels != nil {
		envs = append(envs, encodeAsJSON(t, labels, "LABELS"))
	}

	if anno != nil {
		envs = append(envs, encodeAsJSON(t, anno, "ANNOTATIONS"))
	}
	return merged, envs
}

func encodeAsJSON(t *testing.T, data map[string]string, name string) string {
	jsonStr, err := json.Marshal(data)
	if err != nil {
		t.Fatalf("failed to marshal %s %v: %v", name, data, err)
	}
	return IstioMetaJSONPrefix + name + "=" + string(jsonStr)
}

func TestNodeMetadata(t *testing.T) {
	labels := map[string]string{
		"l1":    "v1",
		"l2":    "v2",
		"istio": "sidecar",
	}
	anno := map[string]string{
		"istio.io/enable": "{\"abc\": 20}",
	}

	_, envs := createEnv(t, labels, nil)
	nm := getNodeMetaData(envs)

	if !reflect.DeepEqual(nm, labels) {
		t.Fatalf("Maps are not equal.\ngot: %v\nwant: %v", nm, labels)
	}

	merged, envs := createEnv(t, labels, anno)

	nm = getNodeMetaData(envs)
	if !reflect.DeepEqual(nm, merged) {
		t.Fatalf("Maps are not equal.\ngot: %v\nwant: %v", nm, merged)
	}

	t.Logf("envs => %v\nnm=> %v", envs, nm)

	// encode string incorrectly,
	// a warning is logged, but everything else works.
	envs = envEncode(anno, IstioMetaJSONPrefix, func(s string) string {
		return s
	}, envs)

	nm = getNodeMetaData(envs)
	if !reflect.DeepEqual(nm, merged) {
		t.Fatalf("Maps are not equal.\ngot: %v\nwant: %v", nm, merged)
	}

}

func mergeMap(to map[string]string, from map[string]string) {
	for k, v := range from {
		to[k] = v
	}
}
<commit_msg>fix TestNodeMetadata (#10002)<commit_after>// Copyright 2018 Istio 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 bootstrap

import (
	"encoding/json"
	"io/ioutil"
	"os"
	"path"
	"reflect"
	"regexp"
	"testing"

	"github.com/envoyproxy/go-control-plane/envoy/config/bootstrap/v2"
	"github.com/ghodss/yaml"
	"github.com/gogo/protobuf/jsonpb"
	"github.com/gogo/protobuf/proto"
	diff "gopkg.in/d4l3k/messagediff.v1"

	meshconfig "istio.io/api/mesh/v1alpha1"
	"istio.io/istio/pkg/test/env"
)

// Generate configs for the default configs used by istio.
// If the template is updated, copy the new golden files from out:
// cp $TOP/out/linux_amd64/release/bootstrap/all/envoy-rev0.json pkg/bootstrap/testdata/all_golden.json
// cp $TOP/out/linux_amd64/release/bootstrap/auth/envoy-rev0.json pkg/bootstrap/testdata/auth_golden.json
// cp $TOP/out/linux_amd64/release/bootstrap/default/envoy-rev0.json pkg/bootstrap/testdata/default_golden.json
// cp $TOP/out/linux_amd64/release/bootstrap/tracing_lightstep/envoy-rev0.json pkg/bootstrap/testdata/tracing_lightstep_golden.json
// cp $TOP/out/linux_amd64/release/bootstrap/tracing_zipkin/envoy-rev0.json pkg/bootstrap/testdata/tracing_zipkin_golden.json
func TestGolden(t *testing.T) {
	cases := []struct {
		base                       string
		labels                     map[string]string
		annotations                map[string]string
		expectLightstepAccessToken bool
	}{
		{
			base: "auth",
		},
		{
			base: "default",
		},
		{
			base: "running",
			labels: map[string]string{
				"ISTIO_PROXY_SHA":     "istio-proxy:sha",
				"INTERCEPTION_MODE":   "REDIRECT",
				"ISTIO_PROXY_VERSION": "istio-proxy:version",
				"ISTIO_VERSION":       "release-3.1",
				"POD_NAME":            "svc-0-0-0-6944fb884d-4pgx8",
			},
			annotations: map[string]string{
				"istio.io/insecurepath": "{\"paths\":[\"/metrics\",\"/live\"]}",
			},
		},
		{
			// nolint: goimports
			base: "tracing_lightstep",
			expectLightstepAccessToken: true,
		},
		{
			base: "tracing_zipkin",
		},
		{
			// Specify zipkin/statsd address, similar with the default config in v1 tests
			base: "all",
		},
	}

	out := env.ISTIO_OUT.Value() // defined in the makefile
	if out == "" {
		out = "/tmp"
	}

	for _, c := range cases {
		t.Run("Bootstrap-"+c.base, func(t *testing.T) {
			cfg, err := loadProxyConfig(c.base, out, t)
			if err != nil {
				t.Fatal(err)
			}

			_, localEnv := createEnv(t, c.labels, c.annotations)
			fn, err := WriteBootstrap(cfg, "sidecar~1.2.3.4~foo~bar", 0, []string{
				"spiffe://cluster.local/ns/istio-system/sa/istio-pilot-service-account"}, nil, localEnv)
			if err != nil {
				t.Fatal(err)
			}

			real, err := ioutil.ReadFile(fn)
			if err != nil {
				t.Error("Error reading generated file ", err)
				return
			}

			// apply minor modifications for the generated file so that tests are consistent
			// across different env setups
			err = ioutil.WriteFile(fn, correctForEnvDifference(real), 0700)
			if err != nil {
				t.Error("Error modifying generated file ", err)
				return
			}

			// re-read generated file with the changes having been made
			real, err = ioutil.ReadFile(fn)
			if err != nil {
				t.Error("Error reading generated file ", err)
				return
			}

			golden, err := ioutil.ReadFile("testdata/" + c.base + "_golden.json")
			if err != nil {
				golden = []byte{}
			}

			realM := v2.Bootstrap{}
			goldenM := v2.Bootstrap{}

			jgolden, err := yaml.YAMLToJSON(golden)

			if err != nil {
				t.Fatalf("unable to convert: %s %v", c.base, err)
			}

			if err = jsonpb.UnmarshalString(string(jgolden), &goldenM); err != nil {
				t.Fatalf("invalid json %s %s\n%v", c.base, err, string(jgolden))
			}

			if err = goldenM.Validate(); err != nil {
				t.Fatalf("invalid golder: %v", err)
			}

			jreal, err := yaml.YAMLToJSON(real)

			if err != nil {
				t.Fatalf("unable to convert: %v", err)
			}

			if err = jsonpb.UnmarshalString(string(jreal), &realM); err != nil {
				t.Fatalf("invalid json %v\n%s", err, string(real))
			}

			if !reflect.DeepEqual(realM, goldenM) {
				s, _ := diff.PrettyDiff(realM, goldenM)
				t.Logf("difference: %s", s)
				t.Fatalf("\n got: %v\nwant: %v", realM, goldenM)
			}

			// Check if the LightStep access token file exists
			_, err = os.Stat(lightstepAccessTokenFile(path.Dir(fn)))
			if c.expectLightstepAccessToken {
				if os.IsNotExist(err) {
					t.Error("expected to find a LightStep access token file but none found")
				} else if err != nil {
					t.Error("error running Stat on file: ", err)
				}
			} else {
				if err == nil {
					t.Error("found a LightStep access token file but none was expected")
				} else if !os.IsNotExist(err) {
					t.Error("error running Stat on file: ", err)
				}
			}
		})
	}

}

type regexReplacement struct {
	pattern     *regexp.Regexp
	replacement []byte
}

// correctForEnvDifference corrects the portions of a generated bootstrap config that vary depending on the environment
// so that they match the golden file's expected value.
func correctForEnvDifference(in []byte) []byte {
	replacements := []regexReplacement{
		// Lightstep access tokens are written to a file and that path is dependent upon the environment variables that
		// are set. Standardize the path so that golden files can be properly checked.
		{
			pattern:     regexp.MustCompile(`("access_token_file": ").*(lightstep_access_token.txt")`),
			replacement: []byte("$1/test-path/$2"),
		},
	}

	out := in
	for _, r := range replacements {
		out = r.pattern.ReplaceAll(out, r.replacement)
	}
	return out
}

func loadProxyConfig(base, out string, _ *testing.T) (*meshconfig.ProxyConfig, error) {
	content, err := ioutil.ReadFile("testdata/" + base + ".proto")
	if err != nil {
		return nil, err
	}
	cfg := &meshconfig.ProxyConfig{}
	err = proto.UnmarshalText(string(content), cfg)
	if err != nil {
		return nil, err
	}

	// Exported from makefile or env
	cfg.ConfigPath = out + "/bootstrap/" + base
	gobase := os.Getenv("ISTIO_GO")
	if gobase == "" {
		gobase = "../.."
	}
	cfg.CustomConfigFile = gobase + "/tools/deb/envoy_bootstrap_v2.json"
	return cfg, nil
}

func TestGetHostPort(t *testing.T) {
	var testCases = []struct {
		name         string
		addr         string
		expectedHost string
		expectedPort string
		errStr       string
	}{
		{
			name:         "Valid IPv4 host/port",
			addr:         "127.0.0.1:5000",
			expectedHost: "127.0.0.1",
			expectedPort: "5000",
			errStr:       "",
		},
		{
			name:         "Valid IPv6 host/port",
			addr:         "[2001:db8::100]:5000",
			expectedHost: "2001:db8::100",
			expectedPort: "5000",
			errStr:       "",
		},
		{
			name:         "Valid host/port",
			addr:         "istio-pilot:15005",
			expectedHost: "istio-pilot",
			expectedPort: "15005",
			errStr:       "",
		},
		{
			name:         "No port specified",
			addr:         "127.0.0.1:",
			expectedHost: "127.0.0.1",
			expectedPort: "",
			errStr:       "",
		},
		{
			name:         "Missing port",
			addr:         "127.0.0.1",
			expectedHost: "",
			expectedPort: "",
			errStr:       "unable to parse test address \"127.0.0.1\": address 127.0.0.1: missing port in address",
		},
		{
			name:         "Missing brackets for IPv6",
			addr:         "2001:db8::100:5000",
			expectedHost: "",
			expectedPort: "",
			errStr:       "unable to parse test address \"2001:db8::100:5000\": address 2001:db8::100:5000: too many colons in address",
		},
		{
			name:         "No address provided",
			addr:         "",
			expectedHost: "",
			expectedPort: "",
			errStr:       "unable to parse test address \"\": missing port in address",
		},
	}
	for _, tc := range testCases {
		h, p, err := GetHostPort("test", tc.addr)
		if err == nil {
			if tc.errStr != "" {
				t.Errorf("[%s] expected error %q, but no error seen", tc.name, tc.errStr)
			} else if h != tc.expectedHost || p != tc.expectedPort {
				t.Errorf("[%s] expected %s:%s, got %s:%s", tc.name, tc.expectedHost, tc.expectedPort, h, p)
			}
		} else {
			if tc.errStr == "" {
				t.Errorf("[%s] expected no error but got %q", tc.name, err.Error())
			} else if err.Error() != tc.errStr {
				t.Errorf("[%s] expected error message %q, got %v", tc.name, tc.errStr, err)
			}
		}
	}
}

func TestStoreHostPort(t *testing.T) {
	opts := map[string]interface{}{}
	StoreHostPort("istio-pilot", "15005", "foo", opts)
	actual, ok := opts["foo"]
	if !ok {
		t.Fatalf("expected to have map entry foo populated")
	}
	expected := "{\"address\": \"istio-pilot\", \"port_value\": 15005}"
	if actual != expected {
		t.Errorf("expected value %q, got %q", expected, actual)
	}
}

type encodeFn func(string) string

func envEncode(m map[string]string, prefix string, encode encodeFn, out []string) []string {
	for k, v := range m {
		out = append(out, prefix+encode(k)+"="+encode(v))
	}
	return out
}

// createEnv takes labels and annotations are returns environment in go format.
func createEnv(t *testing.T, labels map[string]string, anno map[string]string) (map[string]string, []string) {
	merged := map[string]string{}
	mergeMap(merged, labels)
	mergeMap(merged, anno)

	envs := make([]string, 0)

	if labels != nil {
		envs = append(envs, encodeAsJSON(t, labels, "LABELS"))
	}

	if anno != nil {
		envs = append(envs, encodeAsJSON(t, anno, "ANNOTATIONS"))
	}
	return merged, envs
}

func encodeAsJSON(t *testing.T, data map[string]string, name string) string {
	jsonStr, err := json.Marshal(data)
	if err != nil {
		t.Fatalf("failed to marshal %s %v: %v", name, data, err)
	}
	return IstioMetaJSONPrefix + name + "=" + string(jsonStr)
}

func TestNodeMetadata(t *testing.T) {
	labels := map[string]string{
		"l1":    "v1",
		"l2":    "v2",
		"istio": "sidecar",
	}
	anno := map[string]string{
		"istio.io/enable": "{20: 20}",
	}

	_, envs := createEnv(t, labels, nil)
	nm := getNodeMetaData(envs)

	if !reflect.DeepEqual(nm, labels) {
		t.Fatalf("Maps are not equal.\ngot: %v\nwant: %v", nm, labels)
	}

	merged, envs := createEnv(t, labels, anno)

	nm = getNodeMetaData(envs)
	if !reflect.DeepEqual(nm, merged) {
		t.Fatalf("Maps are not equal.\ngot: %v\nwant: %v", nm, merged)
	}

	t.Logf("envs => %v\nnm=> %v", envs, nm)

	// encode string incorrectly,
	// a warning is logged, but everything else works.
	envs = envEncode(anno, IstioMetaJSONPrefix, func(s string) string {
		return s
	}, envs)

	nm = getNodeMetaData(envs)
	if !reflect.DeepEqual(nm, merged) {
		t.Fatalf("Maps are not equal.\ngot: %v\nwant: %v", nm, merged)
	}

}

func mergeMap(to map[string]string, from map[string]string) {
	for k, v := range from {
		to[k] = v
	}
}
<|endoftext|>


<commit_before>// Copyright 2019 Google LLC 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 gameservers

import (
	"testing"

	agonesv1 "agones.dev/agones/pkg/apis/agones/v1"
	agtesting "agones.dev/agones/pkg/testing"
	"github.com/stretchr/testify/assert"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/watch"
	k8stesting "k8s.io/client-go/testing"
	"k8s.io/client-go/tools/cache"
)

const (
	defaultNs = "default"
	name1     = "node1"
	name2     = "node2"
)

func TestPerNodeCounterGameServerEvents(t *testing.T) {
	t.Parallel()

	pnc, m := newFakePerNodeCounter()

	fakeWatch := watch.NewFake()
	m.AgonesClient.AddWatchReactor("gameservers", k8stesting.DefaultWatchReactor(fakeWatch, nil))

	hasSynced := m.AgonesInformerFactory.Agones().V1().GameServers().Informer().HasSynced
	stop, cancel := agtesting.StartInformers(m)
	defer cancel()

	assert.Empty(t, pnc.Counts())

	gs := &agonesv1.GameServer{
		ObjectMeta: metav1.ObjectMeta{Name: "gs1", Namespace: defaultNs},
		Status: agonesv1.GameServerStatus{
			State: agonesv1.GameServerStateStarting, NodeName: name1,
		},
	}

	fakeWatch.Add(gs.DeepCopy())
	cache.WaitForCacheSync(stop, hasSynced)

	assert.Empty(t, pnc.Counts())

	gs.Status.State = agonesv1.GameServerStateReady
	fakeWatch.Add(gs.DeepCopy())
	cache.WaitForCacheSync(stop, hasSynced)

	counts := pnc.Counts()
	assert.Len(t, counts, 1)
	assert.Equal(t, int64(1), counts[name1].Ready)
	assert.Equal(t, int64(0), counts[name1].Allocated)

	gs.Status.State = agonesv1.GameServerStateAllocated
	fakeWatch.Add(gs.DeepCopy())
	cache.WaitForCacheSync(stop, hasSynced)

	counts = pnc.Counts()
	assert.Len(t, counts, 1)
	assert.Equal(t, int64(0), counts[name1].Ready)
	assert.Equal(t, int64(1), counts[name1].Allocated)

	gs.Status.State = agonesv1.GameServerStateShutdown
	fakeWatch.Add(gs.DeepCopy())
	cache.WaitForCacheSync(stop, hasSynced)

	counts = pnc.Counts()
	assert.Len(t, counts, 1)
	assert.Equal(t, int64(0), counts[name1].Ready)
	assert.Equal(t, int64(0), counts[name1].Allocated)

	gs.ObjectMeta.Name = "gs2"
	gs.Status.State = agonesv1.GameServerStateReady
	gs.Status.NodeName = name2

	fakeWatch.Add(gs.DeepCopy())
	cache.WaitForCacheSync(stop, hasSynced)

	counts = pnc.Counts()
	assert.Len(t, counts, 2)
	assert.Equal(t, int64(0), counts[name1].Ready)
	assert.Equal(t, int64(0), counts[name1].Allocated)
	assert.Equal(t, int64(1), counts[name2].Ready)
	assert.Equal(t, int64(0), counts[name2].Allocated)

	gs.ObjectMeta.Name = "gs3"
	// not likely, but to test the flow
	gs.Status.State = agonesv1.GameServerStateAllocated
	gs.Status.NodeName = name2

	fakeWatch.Add(gs.DeepCopy())
	cache.WaitForCacheSync(stop, hasSynced)

	counts = pnc.Counts()
	assert.Len(t, counts, 2)
	assert.Equal(t, int64(0), counts[name1].Ready)
	assert.Equal(t, int64(0), counts[name1].Allocated)
	assert.Equal(t, int64(1), counts[name2].Ready)
	assert.Equal(t, int64(1), counts[name2].Allocated)
}

func TestPerNodeCounterNodeEvents(t *testing.T) {
	t.Parallel()

	pnc, m := newFakePerNodeCounter()

	gsWatch := watch.NewFake()
	nodeWatch := watch.NewFake()
	m.AgonesClient.AddWatchReactor("gameservers", k8stesting.DefaultWatchReactor(gsWatch, nil))
	m.KubeClient.AddWatchReactor("nodes", k8stesting.DefaultWatchReactor(nodeWatch, nil))

	gsSynced := m.AgonesInformerFactory.Agones().V1().GameServers().Informer().HasSynced
	nodeSynced := m.KubeInformerFactory.Core().V1().Nodes().Informer().HasSynced

	stop, cancel := agtesting.StartInformers(m)
	defer cancel()

	assert.Empty(t, pnc.Counts())

	gs := &agonesv1.GameServer{
		ObjectMeta: metav1.ObjectMeta{Name: "gs1", Namespace: defaultNs},
		Status: agonesv1.GameServerStatus{
			State: agonesv1.GameServerStateReady, NodeName: name1}}
	node := &corev1.Node{ObjectMeta: metav1.ObjectMeta{Namespace: defaultNs, Name: name1}}

	gsWatch.Add(gs.DeepCopy())
	nodeWatch.Add(node.DeepCopy())
	cache.WaitForCacheSync(stop, gsSynced, nodeSynced)
	assert.Len(t, pnc.Counts(), 1)

	nodeWatch.Delete(node.DeepCopy())
	cache.WaitForCacheSync(stop, nodeSynced)
	assert.Empty(t, pnc.Counts())
}

func TestPerNodeCounterRun(t *testing.T) {
	t.Parallel()
	pnc, m := newFakePerNodeCounter()

	gs1 := &agonesv1.GameServer{
		ObjectMeta: metav1.ObjectMeta{Name: "gs1", Namespace: defaultNs},
		Status: agonesv1.GameServerStatus{
			State: agonesv1.GameServerStateReady, NodeName: name1}}

	gs2 := gs1.DeepCopy()
	gs2.ObjectMeta.Name = "gs2"
	gs2.Status.State = agonesv1.GameServerStateAllocated

	gs3 := gs1.DeepCopy()
	gs3.ObjectMeta.Name = "gs3"
	gs3.Status.State = agonesv1.GameServerStateStarting
	gs3.Status.NodeName = name2

	gs4 := gs1.DeepCopy()
	gs4.ObjectMeta.Name = "gs4"
	gs4.Status.State = agonesv1.GameServerStateAllocated

	m.AgonesClient.AddReactor("list", "gameservers", func(action k8stesting.Action) (bool, runtime.Object, error) {
		return true, &agonesv1.GameServerList{Items: []agonesv1.GameServer{*gs1, *gs2, *gs3, *gs4}}, nil
	})

	stop, cancel := agtesting.StartInformers(m)
	defer cancel()

	err := pnc.Run(0, stop)
	assert.Nil(t, err)

	counts := pnc.Counts()

	assert.Len(t, counts, 2)
	assert.Equal(t, int64(1), counts[name1].Ready)
	assert.Equal(t, int64(2), counts[name1].Allocated)
	assert.Equal(t, int64(0), counts[name2].Ready)
	assert.Equal(t, int64(0), counts[name2].Allocated)
}

// newFakeController returns a controller, backed by the fake Clientset
func newFakePerNodeCounter() (*PerNodeCounter, agtesting.Mocks) {
	m := agtesting.NewMocks()
	c := NewPerNodeCounter(m.KubeInformerFactory, m.AgonesInformerFactory)
	return c, m
}
<commit_msg>Flaky: TestPerNodeCounterRun (#1669)<commit_after>// Copyright 2019 Google LLC 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 gameservers

import (
	"testing"

	agonesv1 "agones.dev/agones/pkg/apis/agones/v1"
	agtesting "agones.dev/agones/pkg/testing"
	"github.com/stretchr/testify/assert"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/watch"
	k8stesting "k8s.io/client-go/testing"
	"k8s.io/client-go/tools/cache"
)

const (
	defaultNs = "default"
	name1     = "node1"
	name2     = "node2"
)

func TestPerNodeCounterGameServerEvents(t *testing.T) {
	t.Parallel()

	pnc, m := newFakePerNodeCounter()

	fakeWatch := watch.NewFake()
	m.AgonesClient.AddWatchReactor("gameservers", k8stesting.DefaultWatchReactor(fakeWatch, nil))

	hasSynced := m.AgonesInformerFactory.Agones().V1().GameServers().Informer().HasSynced
	stop, cancel := agtesting.StartInformers(m)
	defer cancel()

	assert.Empty(t, pnc.Counts())

	gs := &agonesv1.GameServer{
		ObjectMeta: metav1.ObjectMeta{Name: "gs1", Namespace: defaultNs},
		Status: agonesv1.GameServerStatus{
			State: agonesv1.GameServerStateStarting, NodeName: name1,
		},
	}

	fakeWatch.Add(gs.DeepCopy())
	cache.WaitForCacheSync(stop, hasSynced)

	assert.Empty(t, pnc.Counts())

	gs.Status.State = agonesv1.GameServerStateReady
	fakeWatch.Add(gs.DeepCopy())
	cache.WaitForCacheSync(stop, hasSynced)

	counts := pnc.Counts()
	assert.Len(t, counts, 1)
	assert.Equal(t, int64(1), counts[name1].Ready)
	assert.Equal(t, int64(0), counts[name1].Allocated)

	gs.Status.State = agonesv1.GameServerStateAllocated
	fakeWatch.Add(gs.DeepCopy())
	cache.WaitForCacheSync(stop, hasSynced)

	counts = pnc.Counts()
	assert.Len(t, counts, 1)
	assert.Equal(t, int64(0), counts[name1].Ready)
	assert.Equal(t, int64(1), counts[name1].Allocated)

	gs.Status.State = agonesv1.GameServerStateShutdown
	fakeWatch.Add(gs.DeepCopy())
	cache.WaitForCacheSync(stop, hasSynced)

	counts = pnc.Counts()
	assert.Len(t, counts, 1)
	assert.Equal(t, int64(0), counts[name1].Ready)
	assert.Equal(t, int64(0), counts[name1].Allocated)

	gs.ObjectMeta.Name = "gs2"
	gs.Status.State = agonesv1.GameServerStateReady
	gs.Status.NodeName = name2

	fakeWatch.Add(gs.DeepCopy())
	cache.WaitForCacheSync(stop, hasSynced)

	counts = pnc.Counts()
	assert.Len(t, counts, 2)
	assert.Equal(t, int64(0), counts[name1].Ready)
	assert.Equal(t, int64(0), counts[name1].Allocated)
	assert.Equal(t, int64(1), counts[name2].Ready)
	assert.Equal(t, int64(0), counts[name2].Allocated)

	gs.ObjectMeta.Name = "gs3"
	// not likely, but to test the flow
	gs.Status.State = agonesv1.GameServerStateAllocated
	gs.Status.NodeName = name2

	fakeWatch.Add(gs.DeepCopy())
	cache.WaitForCacheSync(stop, hasSynced)

	counts = pnc.Counts()
	assert.Len(t, counts, 2)
	assert.Equal(t, int64(0), counts[name1].Ready)
	assert.Equal(t, int64(0), counts[name1].Allocated)
	assert.Equal(t, int64(1), counts[name2].Ready)
	assert.Equal(t, int64(1), counts[name2].Allocated)
}

func TestPerNodeCounterNodeEvents(t *testing.T) {
	t.Parallel()

	pnc, m := newFakePerNodeCounter()

	gsWatch := watch.NewFake()
	nodeWatch := watch.NewFake()
	m.AgonesClient.AddWatchReactor("gameservers", k8stesting.DefaultWatchReactor(gsWatch, nil))
	m.KubeClient.AddWatchReactor("nodes", k8stesting.DefaultWatchReactor(nodeWatch, nil))

	gsSynced := m.AgonesInformerFactory.Agones().V1().GameServers().Informer().HasSynced
	nodeSynced := m.KubeInformerFactory.Core().V1().Nodes().Informer().HasSynced

	stop, cancel := agtesting.StartInformers(m)
	defer cancel()

	assert.Empty(t, pnc.Counts())

	gs := &agonesv1.GameServer{
		ObjectMeta: metav1.ObjectMeta{Name: "gs1", Namespace: defaultNs},
		Status: agonesv1.GameServerStatus{
			State: agonesv1.GameServerStateReady, NodeName: name1}}
	node := &corev1.Node{ObjectMeta: metav1.ObjectMeta{Namespace: defaultNs, Name: name1}}

	gsWatch.Add(gs.DeepCopy())
	nodeWatch.Add(node.DeepCopy())
	cache.WaitForCacheSync(stop, gsSynced, nodeSynced)
	assert.Len(t, pnc.Counts(), 1)

	nodeWatch.Delete(node.DeepCopy())
	cache.WaitForCacheSync(stop, nodeSynced)
	assert.Empty(t, pnc.Counts())
}

func TestPerNodeCounterRun(t *testing.T) {
	t.Parallel()
	pnc, m := newFakePerNodeCounter()

	gs1 := &agonesv1.GameServer{
		ObjectMeta: metav1.ObjectMeta{Name: "gs1", Namespace: defaultNs},
		Status: agonesv1.GameServerStatus{
			State: agonesv1.GameServerStateReady, NodeName: name1}}

	gs2 := gs1.DeepCopy()
	gs2.ObjectMeta.Name = "gs2"
	gs2.Status.State = agonesv1.GameServerStateAllocated

	gs3 := gs1.DeepCopy()
	gs3.ObjectMeta.Name = "gs3"
	gs3.Status.State = agonesv1.GameServerStateStarting
	gs3.Status.NodeName = name2

	gs4 := gs1.DeepCopy()
	gs4.ObjectMeta.Name = "gs4"
	gs4.Status.State = agonesv1.GameServerStateAllocated

	m.AgonesClient.AddReactor("list", "gameservers", func(action k8stesting.Action) (bool, runtime.Object, error) {
		return true, &agonesv1.GameServerList{Items: []agonesv1.GameServer{*gs1, *gs2, *gs3, *gs4}}, nil
	})

	stop, cancel := agtesting.StartInformers(m, pnc.gameServerSynced)
	defer cancel()

	err := pnc.Run(0, stop)
	assert.Nil(t, err)

	counts := pnc.Counts()

	assert.Len(t, counts, 2)
	assert.Equal(t, int64(1), counts[name1].Ready)
	assert.Equal(t, int64(2), counts[name1].Allocated)
	assert.Equal(t, int64(0), counts[name2].Ready)
	assert.Equal(t, int64(0), counts[name2].Allocated)
}

// newFakeController returns a controller, backed by the fake Clientset
func newFakePerNodeCounter() (*PerNodeCounter, agtesting.Mocks) {
	m := agtesting.NewMocks()
	c := NewPerNodeCounter(m.KubeInformerFactory, m.AgonesInformerFactory)
	return c, m
}
<|endoftext|>