<commit_before>package traytor

import "image/color"
import "math"

//Colour is a representation of a float64 RGB colour
type Colour struct {
	R, G, B float64
}

//Colour32Bit is 32bit colour implementing the color.Color interface
type Colour32Bit struct {
	R, G, B uint32
}

//NewColour32Bit return a new 32bit colour
func NewColour32Bit(r, g, b uint32) *Colour32Bit {
	return &Colour32Bit{R: r, G: g, B: b}
}

//RGBA implements the color.Color interface converting the 32bit colour to 32bit colour with alpha
func (c *Colour32Bit) RGBA() (r, g, b, a uint32) {
	return c.R, c.G, c.B, 1
}

//NewColour returns a new RGB colour
func NewColour(r, g, b float64) *Colour {
	return &Colour{R: r, G: g, B: b}
}

//To32Bit returns each of the components of the given RGB color to  uint32
func (c *Colour) To32Bit() *Colour32Bit {
	return NewColour32Bit(linearTosRGB(c.R), linearTosRGB(c.G), linearTosRGB(c.B))
}

//linearTosRGBreturn an int between 0 and 1 constructed from a given float between 0 and 255
func linearTosRGB(x float64) uint32 {
	a := 0.055
	if x <= 0 {
		return 0
	}
	if x >= 1 {
		return 255
	}
	if x <= 0.00313008 {
		x = x * 12.02
	} else {
		x = (1.0+a)*math.Pow(x, 1.0/2.4) - a
	}
	return uint32(Round(x * 255.0))
}

//sRGBToLinear converts singel int number to float using special magic formula.
func sRGBToLinear(i uint32) float64 {
	if i > 255 {
		return 1
	}

	x := float64(i) / 255.0
	if x <= 0.04045 {
		return x / 12.92
	} else {
		return (math.Pow((1.055*x), (1/2.4)) - 0.055)
	}
}

//ToColour takes any colour that implements the color.Color interface and turns it into RGB colout(r, g, b are between 0 and 1)
func ToColour(c color.Color) *Colour {
	r, g, b, _ := c.RGBA()
	return NewColour(sRGBToLinear(r), sRGBToLinear(g), sRGBToLinear(b))
}

//MakeZero returns black RGB colour
func (c *Colour) MakeZero() {
	c.SetColour(0, 0, 0)
}

//SetColour sets the colour's components to the given r, g and b
func (c *Colour) SetColour(r, g, b float64) {
	c.R, c.G, c.B = r, g, b
}

//Intensity returns the intensity of the given colour
func (c *Colour) Intensity() float64 {
	return (c.R + c.G + c.B) / 3.0
}

func (c *Colour) Add(other *Colour) {
	c.R += other.R
	c.G += other.G
	c.B += other.B
}
<commit_msg>make colours use float32<commit_after>package traytor

import "image/color"
import "math"

//Colour is a representation of a float32 RGB colour
type Colour struct {
	R, G, B float32
}

//Colour32Bit is 32bit colour implementing the color.Color interface
type Colour32Bit struct {
	R, G, B uint32
}

//NewColour32Bit return a new 32bit colour
func NewColour32Bit(r, g, b uint32) *Colour32Bit {
	return &Colour32Bit{R: r, G: g, B: b}
}

//RGBA implements the color.Color interface converting the 32bit colour to 32bit colour with alpha
func (c *Colour32Bit) RGBA() (r, g, b, a uint32) {
	return c.R, c.G, c.B, 1
}

//NewColour returns a new RGB colour
func NewColour(r, g, b float32) *Colour {
	return &Colour{R: r, G: g, B: b}
}

//To32Bit returns each of the components of the given RGB color to  uint32
func (c *Colour) To32Bit() *Colour32Bit {
	return NewColour32Bit(linearTosRGB(c.R), linearTosRGB(c.G), linearTosRGB(c.B))
}

//linearTosRGBreturn an int between 0 and 1 constructed from a given float between 0 and 255
func linearTosRGB(x float32) uint32 {
	a := 0.055
	if x <= 0 {
		return 0
	}
	if x >= 1 {
		return 255
	}
	if x <= 0.00313008 {
		x = x * 12.02
	} else {
		x = (1.0+a)*math.Pow(x, 1.0/2.4) - a
	}
	return uint32(Round(x * 255.0))
}

//sRGBToLinear converts singel int number to float using special magic formula.
func sRGBToLinear(i uint32) float32 {
	if i > 255 {
		return 1
	}

	x := float32(i) / 255.0
	if x <= 0.04045 {
		return x / 12.92
	} else {
		return (math.Pow((1.055*x), (1/2.4)) - 0.055)
	}
}

//ToColour takes any colour that implements the color.Color interface and turns it into RGB colout(r, g, b are between 0 and 1)
func ToColour(c color.Color) *Colour {
	r, g, b, _ := c.RGBA()
	return NewColour(sRGBToLinear(r), sRGBToLinear(g), sRGBToLinear(b))
}

//MakeZero returns black RGB colour
func (c *Colour) MakeZero() {
	c.SetColour(0, 0, 0)
}

//SetColour sets the colour's components to the given r, g and b
func (c *Colour) SetColour(r, g, b float32) {
	c.R, c.G, c.B = r, g, b
}

//Intensity returns the intensity of the given colour
func (c *Colour) Intensity() float32 {
	return (c.R + c.G + c.B) / 3.0
}

func (c *Colour) Add(other *Colour) {
	c.R += other.R
	c.G += other.G
	c.B += other.B
}
<|endoftext|>


<commit_before>// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
// this source code is governed by a BSD-style license that can be found in
// the LICENSE file.
//
// Package excelize providing a set of functions that allow you to write to
// and read from XLSX files. Support reads and writes XLSX file generated by
// Microsoft Excel™ 2007 and later. Support save file without losing original
// charts of XLSX. This library needs Go version 1.8 or later.

package excelize

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

// parseFormatCommentsSet provides a function to parse the format settings of
// the comment with default value.
func parseFormatCommentsSet(formatSet string) (*formatComment, error) {
	format := formatComment{
		Author: "Author:",
		Text:   " ",
	}
	err := json.Unmarshal([]byte(formatSet), &format)
	return &format, err
}

// GetComments retrieves all comments and returns a map of worksheet name to
// the worksheet comments.
func (f *File) GetComments() (comments map[string][]Comment) {
	comments = map[string][]Comment{}
	for n := range f.sheetMap {
		if d := f.commentsReader("xl" + strings.TrimPrefix(f.getSheetComments(f.GetSheetIndex(n)), "..")); d != nil {
			sheetComments := []Comment{}
			for _, comment := range d.CommentList.Comment {
				sheetComment := Comment{}
				if comment.AuthorID < len(d.Authors) {
					sheetComment.Author = d.Authors[comment.AuthorID].Author
				}
				sheetComment.Ref = comment.Ref
				sheetComment.AuthorID = comment.AuthorID
				for _, text := range comment.Text.R {
					sheetComment.Text += text.T
				}
				sheetComments = append(sheetComments, sheetComment)
			}
			comments[n] = sheetComments
		}
	}
	return
}

// getSheetComments provides the method to get the target comment reference by
// given worksheet index.
func (f *File) getSheetComments(sheetID int) string {
	var rels = "xl/worksheets/_rels/sheet" + strconv.Itoa(sheetID) + ".xml.rels"
	if sheetRels := f.workSheetRelsReader(rels); sheetRels != nil {
		for _, v := range sheetRels.Relationships {
			if v.Type == SourceRelationshipComments {
				return v.Target
			}
		}
	}
	return ""
}

// AddComment provides the method to add comment in a sheet by given worksheet
// index, cell and format set (such as author and text). Note that the max
// author length is 255 and the max text length is 32512. For example, add a
// comment in Sheet1!$A$30:
//
//    err := f.AddComment("Sheet1", "A30", `{"author":"Excelize: ","text":"This is a comment."}`)
//
func (f *File) AddComment(sheet, cell, format string) error {
	formatSet, err := parseFormatCommentsSet(format)
	if err != nil {
		return err
	}
	// Read sheet data.
	xlsx, err := f.workSheetReader(sheet)
	if err != nil {
		return err
	}
	commentID := f.countComments() + 1
	drawingVML := "xl/drawings/vmlDrawing" + strconv.Itoa(commentID) + ".vml"
	sheetRelationshipsComments := "../comments" + strconv.Itoa(commentID) + ".xml"
	sheetRelationshipsDrawingVML := "../drawings/vmlDrawing" + strconv.Itoa(commentID) + ".vml"
	if xlsx.LegacyDrawing != nil {
		// The worksheet already has a comments relationships, use the relationships drawing ../drawings/vmlDrawing%d.vml.
		sheetRelationshipsDrawingVML = f.getSheetRelationshipsTargetByID(sheet, xlsx.LegacyDrawing.RID)
		commentID, _ = strconv.Atoi(strings.TrimSuffix(strings.TrimPrefix(sheetRelationshipsDrawingVML, "../drawings/vmlDrawing"), ".vml"))
		drawingVML = strings.Replace(sheetRelationshipsDrawingVML, "..", "xl", -1)
	} else {
		// Add first comment for given sheet.
		rID := f.addSheetRelationships(sheet, SourceRelationshipDrawingVML, sheetRelationshipsDrawingVML, "")
		f.addSheetRelationships(sheet, SourceRelationshipComments, sheetRelationshipsComments, "")
		f.addSheetLegacyDrawing(sheet, rID)
	}
	commentsXML := "xl/comments" + strconv.Itoa(commentID) + ".xml"
	f.addComment(commentsXML, cell, formatSet)
	var colCount int
	for i, l := range strings.Split(formatSet.Text, "\n") {
		if ll := len(l); ll > colCount {
			if i == 0 {
				ll += len(formatSet.Author)
			}
			colCount = ll
		}
	}
	err = f.addDrawingVML(commentID, drawingVML, cell, strings.Count(formatSet.Text, "\n")+1, colCount)
	if err != nil {
		return err
	}
	f.addContentTypePart(commentID, "comments")
	return err
}

// addDrawingVML provides a function to create comment as
// xl/drawings/vmlDrawing%d.vml by given commit ID and cell.
func (f *File) addDrawingVML(commentID int, drawingVML, cell string, lineCount, colCount int) error {
	col, row, err := CellNameToCoordinates(cell)
	if err != nil {
		return err
	}
	yAxis := col - 1
	xAxis := row - 1
	vml := f.VMLDrawing[drawingVML]
	if vml == nil {
		vml = &vmlDrawing{
			XMLNSv:  "urn:schemas-microsoft-com:vml",
			XMLNSo:  "urn:schemas-microsoft-com:office:office",
			XMLNSx:  "urn:schemas-microsoft-com:office:excel",
			XMLNSmv: "http://macVmlSchemaUri",
			Shapelayout: &xlsxShapelayout{
				Ext: "edit",
				IDmap: &xlsxIDmap{
					Ext:  "edit",
					Data: commentID,
				},
			},
			Shapetype: &xlsxShapetype{
				ID:        "_x0000_t202",
				Coordsize: "21600,21600",
				Spt:       202,
				Path:      "m0,0l0,21600,21600,21600,21600,0xe",
				Stroke: &xlsxStroke{
					Joinstyle: "miter",
				},
				VPath: &vPath{
					Gradientshapeok: "t",
					Connecttype:     "miter",
				},
			},
		}
	}
	sp := encodeShape{
		Fill: &vFill{
			Color2: "#fbfe82",
			Angle:  -180,
			Type:   "gradient",
			Fill: &oFill{
				Ext:  "view",
				Type: "gradientUnscaled",
			},
		},
		Shadow: &vShadow{
			On:       "t",
			Color:    "black",
			Obscured: "t",
		},
		Path: &vPath{
			Connecttype: "none",
		},
		Textbox: &vTextbox{
			Style: "mso-direction-alt:auto",
			Div: &xlsxDiv{
				Style: "text-align:left",
			},
		},
		ClientData: &xClientData{
			ObjectType: "Note",
			Anchor: fmt.Sprintf(
				"%d, 23, %d, 0, %d, %d, %d, 5",
				1+yAxis, 1+xAxis, 2+yAxis+lineCount, colCount+yAxis, 2+xAxis+lineCount),
			AutoFill: "True",
			Row:      xAxis,
			Column:   yAxis,
		},
	}
	s, _ := xml.Marshal(sp)
	shape := xlsxShape{
		ID:          "_x0000_s1025",
		Type:        "#_x0000_t202",
		Style:       "position:absolute;73.5pt;width:108pt;height:59.25pt;z-index:1;visibility:hidden",
		Fillcolor:   "#fbf6d6",
		Strokecolor: "#edeaa1",
		Val:         string(s[13 : len(s)-14]),
	}
	d := f.decodeVMLDrawingReader(drawingVML)
	if d != nil {
		for _, v := range d.Shape {
			s := xlsxShape{
				ID:          "_x0000_s1025",
				Type:        "#_x0000_t202",
				Style:       "position:absolute;73.5pt;width:108pt;height:59.25pt;z-index:1;visibility:hidden",
				Fillcolor:   "#fbf6d6",
				Strokecolor: "#edeaa1",
				Val:         v.Val,
			}
			vml.Shape = append(vml.Shape, s)
		}
	}
	vml.Shape = append(vml.Shape, shape)
	f.VMLDrawing[drawingVML] = vml
	return err
}

// addComment provides a function to create chart as xl/comments%d.xml by
// given cell and format sets.
func (f *File) addComment(commentsXML, cell string, formatSet *formatComment) {
	a := formatSet.Author
	t := formatSet.Text
	if len(a) > 255 {
		a = a[0:255]
	}
	if len(t) > 32512 {
		t = t[0:32512]
	}
	comments := f.commentsReader(commentsXML)
	if comments == nil {
		comments = &xlsxComments{
			Authors: []xlsxAuthor{
				{
					Author: formatSet.Author,
				},
			},
		}
	}
	cmt := xlsxComment{
		Ref:      cell,
		AuthorID: 0,
		Text: xlsxText{
			R: []xlsxR{
				{
					RPr: &xlsxRPr{
						B:  " ",
						Sz: &attrValFloat{Val: 9},
						Color: &xlsxColor{
							Indexed: 81,
						},
						RFont:  &attrValString{Val: "Calibri"},
						Family: &attrValInt{Val: 2},
					},
					T: a,
				},
				{
					RPr: &xlsxRPr{
						Sz: &attrValFloat{Val: 9},
						Color: &xlsxColor{
							Indexed: 81,
						},
						RFont:  &attrValString{Val: "Calibri"},
						Family: &attrValInt{Val: 2},
					},
					T: t,
				},
			},
		},
	}
	comments.CommentList.Comment = append(comments.CommentList.Comment, cmt)
	f.Comments[commentsXML] = comments
}

// countComments provides a function to get comments files count storage in
// the folder xl.
func (f *File) countComments() int {
	count := 0
	for k := range f.XLSX {
		if strings.Contains(k, "xl/comments") {
			count++
		}
	}
	return count
}

// decodeVMLDrawingReader provides a function to get the pointer to the
// structure after deserialization of xl/drawings/vmlDrawing%d.xml.
func (f *File) decodeVMLDrawingReader(path string) *decodeVmlDrawing {
	if f.DecodeVMLDrawing[path] == nil {
		c, ok := f.XLSX[path]
		if ok {
			d := decodeVmlDrawing{}
			_ = xml.Unmarshal(namespaceStrictToTransitional(c), &d)
			f.DecodeVMLDrawing[path] = &d
		}
	}
	return f.DecodeVMLDrawing[path]
}

// vmlDrawingWriter provides a function to save xl/drawings/vmlDrawing%d.xml
// after serialize structure.
func (f *File) vmlDrawingWriter() {
	for path, vml := range f.VMLDrawing {
		if vml != nil {
			v, _ := xml.Marshal(vml)
			f.XLSX[path] = v
		}
	}
}

// commentsReader provides a function to get the pointer to the structure
// after deserialization of xl/comments%d.xml.
func (f *File) commentsReader(path string) *xlsxComments {
	if f.Comments[path] == nil {
		content, ok := f.XLSX[path]
		if ok {
			c := xlsxComments{}
			_ = xml.Unmarshal(namespaceStrictToTransitional(content), &c)
			f.Comments[path] = &c
		}
	}
	return f.Comments[path]
}

// commentsWriter provides a function to save xl/comments%d.xml after
// serialize structure.
func (f *File) commentsWriter() {
	for path, c := range f.Comments {
		if c != nil {
			v, _ := xml.Marshal(c)
			f.saveFileList(path, v)
		}
	}
}
<commit_msg>fixed #373, comments duplicate caused by inner counting errors<commit_after>// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
// this source code is governed by a BSD-style license that can be found in
// the LICENSE file.
//
// Package excelize providing a set of functions that allow you to write to
// and read from XLSX files. Support reads and writes XLSX file generated by
// Microsoft Excel™ 2007 and later. Support save file without losing original
// charts of XLSX. This library needs Go version 1.8 or later.

package excelize

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

// parseFormatCommentsSet provides a function to parse the format settings of
// the comment with default value.
func parseFormatCommentsSet(formatSet string) (*formatComment, error) {
	format := formatComment{
		Author: "Author:",
		Text:   " ",
	}
	err := json.Unmarshal([]byte(formatSet), &format)
	return &format, err
}

// GetComments retrieves all comments and returns a map of worksheet name to
// the worksheet comments.
func (f *File) GetComments() (comments map[string][]Comment) {
	comments = map[string][]Comment{}
	for n := range f.sheetMap {
		if d := f.commentsReader("xl" + strings.TrimPrefix(f.getSheetComments(f.GetSheetIndex(n)), "..")); d != nil {
			sheetComments := []Comment{}
			for _, comment := range d.CommentList.Comment {
				sheetComment := Comment{}
				if comment.AuthorID < len(d.Authors) {
					sheetComment.Author = d.Authors[comment.AuthorID].Author
				}
				sheetComment.Ref = comment.Ref
				sheetComment.AuthorID = comment.AuthorID
				for _, text := range comment.Text.R {
					sheetComment.Text += text.T
				}
				sheetComments = append(sheetComments, sheetComment)
			}
			comments[n] = sheetComments
		}
	}
	return
}

// getSheetComments provides the method to get the target comment reference by
// given worksheet index.
func (f *File) getSheetComments(sheetID int) string {
	var rels = "xl/worksheets/_rels/sheet" + strconv.Itoa(sheetID) + ".xml.rels"
	if sheetRels := f.workSheetRelsReader(rels); sheetRels != nil {
		for _, v := range sheetRels.Relationships {
			if v.Type == SourceRelationshipComments {
				return v.Target
			}
		}
	}
	return ""
}

// AddComment provides the method to add comment in a sheet by given worksheet
// index, cell and format set (such as author and text). Note that the max
// author length is 255 and the max text length is 32512. For example, add a
// comment in Sheet1!$A$30:
//
//    err := f.AddComment("Sheet1", "A30", `{"author":"Excelize: ","text":"This is a comment."}`)
//
func (f *File) AddComment(sheet, cell, format string) error {
	formatSet, err := parseFormatCommentsSet(format)
	if err != nil {
		return err
	}
	// Read sheet data.
	xlsx, err := f.workSheetReader(sheet)
	if err != nil {
		return err
	}
	commentID := f.countComments() + 1
	drawingVML := "xl/drawings/vmlDrawing" + strconv.Itoa(commentID) + ".vml"
	sheetRelationshipsComments := "../comments" + strconv.Itoa(commentID) + ".xml"
	sheetRelationshipsDrawingVML := "../drawings/vmlDrawing" + strconv.Itoa(commentID) + ".vml"
	if xlsx.LegacyDrawing != nil {
		// The worksheet already has a comments relationships, use the relationships drawing ../drawings/vmlDrawing%d.vml.
		sheetRelationshipsDrawingVML = f.getSheetRelationshipsTargetByID(sheet, xlsx.LegacyDrawing.RID)
		commentID, _ = strconv.Atoi(strings.TrimSuffix(strings.TrimPrefix(sheetRelationshipsDrawingVML, "../drawings/vmlDrawing"), ".vml"))
		drawingVML = strings.Replace(sheetRelationshipsDrawingVML, "..", "xl", -1)
	} else {
		// Add first comment for given sheet.
		rID := f.addSheetRelationships(sheet, SourceRelationshipDrawingVML, sheetRelationshipsDrawingVML, "")
		f.addSheetRelationships(sheet, SourceRelationshipComments, sheetRelationshipsComments, "")
		f.addSheetLegacyDrawing(sheet, rID)
	}
	commentsXML := "xl/comments" + strconv.Itoa(commentID) + ".xml"
	f.addComment(commentsXML, cell, formatSet)
	var colCount int
	for i, l := range strings.Split(formatSet.Text, "\n") {
		if ll := len(l); ll > colCount {
			if i == 0 {
				ll += len(formatSet.Author)
			}
			colCount = ll
		}
	}
	err = f.addDrawingVML(commentID, drawingVML, cell, strings.Count(formatSet.Text, "\n")+1, colCount)
	if err != nil {
		return err
	}
	f.addContentTypePart(commentID, "comments")
	return err
}

// addDrawingVML provides a function to create comment as
// xl/drawings/vmlDrawing%d.vml by given commit ID and cell.
func (f *File) addDrawingVML(commentID int, drawingVML, cell string, lineCount, colCount int) error {
	col, row, err := CellNameToCoordinates(cell)
	if err != nil {
		return err
	}
	yAxis := col - 1
	xAxis := row - 1
	vml := f.VMLDrawing[drawingVML]
	if vml == nil {
		vml = &vmlDrawing{
			XMLNSv:  "urn:schemas-microsoft-com:vml",
			XMLNSo:  "urn:schemas-microsoft-com:office:office",
			XMLNSx:  "urn:schemas-microsoft-com:office:excel",
			XMLNSmv: "http://macVmlSchemaUri",
			Shapelayout: &xlsxShapelayout{
				Ext: "edit",
				IDmap: &xlsxIDmap{
					Ext:  "edit",
					Data: commentID,
				},
			},
			Shapetype: &xlsxShapetype{
				ID:        "_x0000_t202",
				Coordsize: "21600,21600",
				Spt:       202,
				Path:      "m0,0l0,21600,21600,21600,21600,0xe",
				Stroke: &xlsxStroke{
					Joinstyle: "miter",
				},
				VPath: &vPath{
					Gradientshapeok: "t",
					Connecttype:     "miter",
				},
			},
		}
	}
	sp := encodeShape{
		Fill: &vFill{
			Color2: "#fbfe82",
			Angle:  -180,
			Type:   "gradient",
			Fill: &oFill{
				Ext:  "view",
				Type: "gradientUnscaled",
			},
		},
		Shadow: &vShadow{
			On:       "t",
			Color:    "black",
			Obscured: "t",
		},
		Path: &vPath{
			Connecttype: "none",
		},
		Textbox: &vTextbox{
			Style: "mso-direction-alt:auto",
			Div: &xlsxDiv{
				Style: "text-align:left",
			},
		},
		ClientData: &xClientData{
			ObjectType: "Note",
			Anchor: fmt.Sprintf(
				"%d, 23, %d, 0, %d, %d, %d, 5",
				1+yAxis, 1+xAxis, 2+yAxis+lineCount, colCount+yAxis, 2+xAxis+lineCount),
			AutoFill: "True",
			Row:      xAxis,
			Column:   yAxis,
		},
	}
	s, _ := xml.Marshal(sp)
	shape := xlsxShape{
		ID:          "_x0000_s1025",
		Type:        "#_x0000_t202",
		Style:       "position:absolute;73.5pt;width:108pt;height:59.25pt;z-index:1;visibility:hidden",
		Fillcolor:   "#fbf6d6",
		Strokecolor: "#edeaa1",
		Val:         string(s[13 : len(s)-14]),
	}
	d := f.decodeVMLDrawingReader(drawingVML)
	if d != nil {
		for _, v := range d.Shape {
			s := xlsxShape{
				ID:          "_x0000_s1025",
				Type:        "#_x0000_t202",
				Style:       "position:absolute;73.5pt;width:108pt;height:59.25pt;z-index:1;visibility:hidden",
				Fillcolor:   "#fbf6d6",
				Strokecolor: "#edeaa1",
				Val:         v.Val,
			}
			vml.Shape = append(vml.Shape, s)
		}
	}
	vml.Shape = append(vml.Shape, shape)
	f.VMLDrawing[drawingVML] = vml
	return err
}

// addComment provides a function to create chart as xl/comments%d.xml by
// given cell and format sets.
func (f *File) addComment(commentsXML, cell string, formatSet *formatComment) {
	a := formatSet.Author
	t := formatSet.Text
	if len(a) > 255 {
		a = a[0:255]
	}
	if len(t) > 32512 {
		t = t[0:32512]
	}
	comments := f.commentsReader(commentsXML)
	if comments == nil {
		comments = &xlsxComments{
			Authors: []xlsxAuthor{
				{
					Author: formatSet.Author,
				},
			},
		}
	}
	cmt := xlsxComment{
		Ref:      cell,
		AuthorID: 0,
		Text: xlsxText{
			R: []xlsxR{
				{
					RPr: &xlsxRPr{
						B:  " ",
						Sz: &attrValFloat{Val: 9},
						Color: &xlsxColor{
							Indexed: 81,
						},
						RFont:  &attrValString{Val: "Calibri"},
						Family: &attrValInt{Val: 2},
					},
					T: a,
				},
				{
					RPr: &xlsxRPr{
						Sz: &attrValFloat{Val: 9},
						Color: &xlsxColor{
							Indexed: 81,
						},
						RFont:  &attrValString{Val: "Calibri"},
						Family: &attrValInt{Val: 2},
					},
					T: t,
				},
			},
		},
	}
	comments.CommentList.Comment = append(comments.CommentList.Comment, cmt)
	f.Comments[commentsXML] = comments
}

// countComments provides a function to get comments files count storage in
// the folder xl.
func (f *File) countComments() int {
	c1, c2 := 0, 0
	for k := range f.XLSX {
		if strings.Contains(k, "xl/comments") {
			c1++
		}
	}
	for rel := range f.Comments {
		if strings.Contains(rel, "xl/comments") {
			c2++
		}
	}
	if c1 < c2 {
		return c2
	}
	return c1
}

// decodeVMLDrawingReader provides a function to get the pointer to the
// structure after deserialization of xl/drawings/vmlDrawing%d.xml.
func (f *File) decodeVMLDrawingReader(path string) *decodeVmlDrawing {
	if f.DecodeVMLDrawing[path] == nil {
		c, ok := f.XLSX[path]
		if ok {
			d := decodeVmlDrawing{}
			_ = xml.Unmarshal(namespaceStrictToTransitional(c), &d)
			f.DecodeVMLDrawing[path] = &d
		}
	}
	return f.DecodeVMLDrawing[path]
}

// vmlDrawingWriter provides a function to save xl/drawings/vmlDrawing%d.xml
// after serialize structure.
func (f *File) vmlDrawingWriter() {
	for path, vml := range f.VMLDrawing {
		if vml != nil {
			v, _ := xml.Marshal(vml)
			f.XLSX[path] = v
		}
	}
}

// commentsReader provides a function to get the pointer to the structure
// after deserialization of xl/comments%d.xml.
func (f *File) commentsReader(path string) *xlsxComments {
	if f.Comments[path] == nil {
		content, ok := f.XLSX[path]
		if ok {
			c := xlsxComments{}
			_ = xml.Unmarshal(namespaceStrictToTransitional(content), &c)
			f.Comments[path] = &c
		}
	}
	return f.Comments[path]
}

// commentsWriter provides a function to save xl/comments%d.xml after
// serialize structure.
func (f *File) commentsWriter() {
	for path, c := range f.Comments {
		if c != nil {
			v, _ := xml.Marshal(c)
			f.saveFileList(path, v)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright (C) 2015  Arista Networks, Inc.
// Use of this source code is governed by the Apache License 2.0
// that can be found in the COPYING file.

package test

import (
	"io/ioutil"
	"os"
	"testing"
)

// CopyFile copies a file
func CopyFile(t *testing.T, srcPath, dstPath string) {
	src, err := os.Open(srcPath)
	if err != nil {
		t.Fatal(err)
	}
	defer src.Close()
	// This loads the entire file in memory, which is fine for small-ish files.
	input, err := ioutil.ReadAll(src)
	if err != nil {
		t.Fatal(err)
	}
	err = ioutil.WriteFile(dstPath, input, os.FileMode(0600))
	if err != nil {
		t.Fatal(err)
	}
}
<commit_msg>test: Don't load the file in memory when copying it.<commit_after>// Copyright (C) 2015  Arista Networks, Inc.
// Use of this source code is governed by the Apache License 2.0
// that can be found in the COPYING file.

package test

import (
	"io"
	"os"
	"testing"
)

// CopyFile copies a file
func CopyFile(t *testing.T, srcPath, dstPath string) {
	src, err := os.Open(srcPath)
	if err != nil {
		t.Fatal(err)
	}
	defer src.Close()
	dst, err := os.Create(dstPath)
	if err != nil {
		t.Fatal(err)
	}
	defer dst.Close()
	_, err = io.Copy(dst, src)
	if err != nil {
		t.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package jsoncodec_test

import (
	"encoding/json"
	"errors"
	"io"
	. "launchpad.net/gocheck"
	"launchpad.net/juju-core/rpc"
	"launchpad.net/juju-core/rpc/jsoncodec"
	"launchpad.net/juju-core/testing"
	"reflect"
	"regexp"
	stdtesting "testing"
)

type suite struct {
	testing.LoggingSuite
}

var _ = Suite(&suite{})

func TestPackage(t *stdtesting.T) {
	TestingT(t)
}

type value struct {
	X string
}

var readTests = []struct {
	msg        string
	expectHdr  rpc.Header
	expectBody interface{}
}{{
	msg: `{"RequestId": 1, "Type": "foo", "Id": "id", "Request": "frob", "Params": {"X": "param"}}`,
	expectHdr: rpc.Header{
		RequestId: 1,
		Type:      "foo",
		Id:        "id",
		Request:   "frob",
	},
	expectBody: &value{X: "param"},
}, {
	msg: `{"RequestId": 2, "Error": "an error", "ErrorCode": "a code"}`,
	expectHdr: rpc.Header{
		RequestId: 2,
		Error:     "an error",
		ErrorCode: "a code",
	},
	expectBody: new(map[string]interface{}),
}, {
	msg: `{"RequestId": 3, "Response": {"X": "result"}}`,
	expectHdr: rpc.Header{
		RequestId: 3,
	},
	expectBody: &value{X: "result"},
}}

func (*suite) TestRead(c *C) {
	for i, test := range readTests {
		c.Logf("test %d", i)
		codec := jsoncodec.New(&testConn{
			readMsgs: []string{test.msg},
		})
		var hdr rpc.Header
		err := codec.ReadHeader(&hdr)
		c.Assert(err, IsNil)
		c.Assert(hdr, DeepEquals, test.expectHdr)

		c.Assert(hdr.IsRequest(), Equals, test.expectHdr.IsRequest())

		body := reflect.New(reflect.ValueOf(test.expectBody).Type().Elem()).Interface()
		err = codec.ReadBody(body, test.expectHdr.IsRequest())
		c.Assert(err, IsNil)
		c.Assert(body, DeepEquals, test.expectBody)

		err = codec.ReadHeader(&hdr)
		c.Assert(err, Equals, io.EOF)
	}
}

func (*suite) TestReadHeaderLogsRequests(c *C) {
	msg := `{"RequestId":1,"Type": "foo","Id": "id","Request":"frob","Params":{"X":"param"}}`
	codec := jsoncodec.New(&testConn{
		readMsgs: []string{msg, msg, msg},
	})
	// Check that logging is off by default
	var h rpc.Header
	err := codec.ReadHeader(&h)
	c.Assert(err, IsNil)
	c.Assert(c.GetTestLog(), Matches, "")

	// Check that we see a log message when we switch logging on.
	codec.SetLogging(true)
	err = codec.ReadHeader(&h)
	c.Assert(err, IsNil)
	c.Assert(c.GetTestLog(), Matches, ".*DEBUG rpc/jsoncodec: <- "+regexp.QuoteMeta(msg)+`\n`)

	// Check that we can switch it off again
	codec.SetLogging(false)
	err = codec.ReadHeader(&h)
	c.Assert(err, IsNil)
	c.Assert(c.GetTestLog(), Matches, ".*DEBUG rpc/jsoncodec: <- "+regexp.QuoteMeta(msg)+`\n`)
}

func (*suite) TestWriteMessageLogsRequests(c *C) {
	codec := jsoncodec.New(&testConn{})
	h := rpc.Header{
		RequestId: 1,
		Type:      "foo",
		Id:        "id",
		Request:   "frob",
	}

	// Check that logging is off by default
	err := codec.WriteMessage(&h, value{X: "param"})
	c.Assert(err, IsNil)
	c.Assert(c.GetTestLog(), Matches, "")

	// Check that we see a log message when we switch logging on.
	codec.SetLogging(true)
	err = codec.WriteMessage(&h, value{X: "param"})
	c.Assert(err, IsNil)
	msg := `{"RequestId":1,"Type":"foo","Id":"id","Request":"frob","Params":{"X":"param"}}`
	c.Assert(c.GetTestLog(), Matches, `.*DEBUG rpc/jsoncodec: -> `+regexp.QuoteMeta(msg)+`\n`)

	// Check that we can switch it off again
	codec.SetLogging(false)
	err = codec.WriteMessage(&h, value{X: "param"})
	c.Assert(err, IsNil)
	c.Assert(c.GetTestLog(), Matches, `.*DEBUG rpc/jsoncodec: -> `+regexp.QuoteMeta(msg)+`\n`)
}

func (*suite) TestConcurrentSetLoggingAndWrite(c *C) {
	// If log messages are not set atomically, this
	// test will fail when run under the race detector.
	codec := jsoncodec.New(&testConn{})
	done := make(chan struct{})
	go func() {
		codec.SetLogging(true)
		done <- struct{}{}
	}()
	h := rpc.Header{
		RequestId: 1,
		Type:      "foo",
		Id:        "id",
		Request:   "frob",
	}
	err := codec.WriteMessage(&h, value{X: "param"})
	c.Assert(err, IsNil)
	<-done
}

func (*suite) TestConcurrentSetLoggingAndRead(c *C) {
	// If log messages are not set atomically, this
	// test will fail when run under the race detector.
	msg := `{"RequestId":1,"Type": "foo","Id": "id","Request":"frob","Params":{"X":"param"}}`
	codec := jsoncodec.New(&testConn{
		readMsgs: []string{msg, msg, msg},
	})
	done := make(chan struct{})
	go func() {
		codec.SetLogging(true)
		done <- struct{}{}
	}()
	var h rpc.Header
	err := codec.ReadHeader(&h)
	c.Assert(err, IsNil)
	<-done
}

func (*suite) TestErrorAfterClose(c *C) {
	conn := &testConn{
		err: errors.New("some error"),
	}
	codec := jsoncodec.New(conn)
	var hdr rpc.Header
	err := codec.ReadHeader(&hdr)
	c.Assert(err, ErrorMatches, "error receiving message: some error")

	err = codec.Close()
	c.Assert(err, IsNil)
	c.Assert(conn.closed, Equals, true)

	err = codec.ReadHeader(&hdr)
	c.Assert(err, Equals, io.EOF)
}

var writeTests = []struct {
	hdr       *rpc.Header
	body      interface{}
	isRequest bool
	expect    string
}{{
	hdr: &rpc.Header{
		RequestId: 1,
		Type:      "foo",
		Id:        "id",
		Request:   "frob",
	},
	body:   &value{X: "param"},
	expect: `{"RequestId": 1, "Type": "foo","Id":"id", "Request": "frob", "Params": {"X": "param"}}`,
}, {
	hdr: &rpc.Header{
		RequestId: 2,
		Error:     "an error",
		ErrorCode: "a code",
	},
	expect: `{"RequestId": 2, "Error": "an error", "ErrorCode": "a code"}`,
}, {
	hdr: &rpc.Header{
		RequestId: 3,
	},
	body:   &value{X: "result"},
	expect: `{"RequestId": 3, "Response": {"X": "result"}}`,
}}

func (*suite) TestWrite(c *C) {
	for i, test := range writeTests {
		c.Logf("test %d", i)
		var conn testConn
		codec := jsoncodec.New(&conn)
		err := codec.WriteMessage(test.hdr, test.body)
		c.Assert(err, IsNil)
		c.Assert(conn.writeMsgs, HasLen, 1)

		assertJSONEqual(c, conn.writeMsgs[0], test.expect)
	}
}

// assertJSONEqual compares the json strings v0
// and v1 ignoring white space.
func assertJSONEqual(c *C, v0, v1 string) {
	var m0, m1 interface{}
	err := json.Unmarshal([]byte(v0), &m0)
	c.Assert(err, IsNil)
	err = json.Unmarshal([]byte(v1), &m1)
	c.Assert(err, IsNil)
	data0, err := json.Marshal(m0)
	c.Assert(err, IsNil)
	data1, err := json.Marshal(m1)
	c.Assert(err, IsNil)
	c.Assert(string(data0), Equals, string(data1))
}

type testConn struct {
	readMsgs  []string
	err       error
	writeMsgs []string
	closed    bool
}

func (c *testConn) Receive(msg interface{}) error {
	if len(c.readMsgs) > 0 {
		s := c.readMsgs[0]
		c.readMsgs = c.readMsgs[1:]
		return json.Unmarshal([]byte(s), msg)
	}
	if c.err != nil {
		return c.err
	}
	return io.EOF
}

func (c *testConn) Send(msg interface{}) error {
	data, err := json.Marshal(msg)
	if err != nil {
		return err
	}
	c.writeMsgs = append(c.writeMsgs, string(data))
	return nil
}

func (c *testConn) Close() error {
	c.closed = true
	return nil
}
<commit_msg>rpc/jsoncodec: fix tests<commit_after>package jsoncodec_test

import (
	"encoding/json"
	"errors"
	"io"
	. "launchpad.net/gocheck"
	"launchpad.net/juju-core/rpc"
	"launchpad.net/juju-core/rpc/jsoncodec"
	"launchpad.net/juju-core/testing"
	"reflect"
	"regexp"
	stdtesting "testing"
)

type suite struct {
	testing.LoggingSuite
}

var _ = Suite(&suite{})

func TestPackage(t *stdtesting.T) {
	TestingT(t)
}

type value struct {
	X string
}

var readTests = []struct {
	msg        string
	expectHdr  rpc.Header
	expectBody interface{}
}{{
	msg: `{"RequestId": 1, "Type": "foo", "Id": "id", "Request": "frob", "Params": {"X": "param"}}`,
	expectHdr: rpc.Header{
		RequestId: 1,
		Type:      "foo",
		Id:        "id",
		Request:   "frob",
	},
	expectBody: &value{X: "param"},
}, {
	msg: `{"RequestId": 2, "Error": "an error", "ErrorCode": "a code"}`,
	expectHdr: rpc.Header{
		RequestId: 2,
		Error:     "an error",
		ErrorCode: "a code",
	},
	expectBody: new(map[string]interface{}),
}, {
	msg: `{"RequestId": 3, "Response": {"X": "result"}}`,
	expectHdr: rpc.Header{
		RequestId: 3,
	},
	expectBody: &value{X: "result"},
}}

func (*suite) TestRead(c *C) {
	for i, test := range readTests {
		c.Logf("test %d", i)
		codec := jsoncodec.New(&testConn{
			readMsgs: []string{test.msg},
		})
		var hdr rpc.Header
		err := codec.ReadHeader(&hdr)
		c.Assert(err, IsNil)
		c.Assert(hdr, DeepEquals, test.expectHdr)

		c.Assert(hdr.IsRequest(), Equals, test.expectHdr.IsRequest())

		body := reflect.New(reflect.ValueOf(test.expectBody).Type().Elem()).Interface()
		err = codec.ReadBody(body, test.expectHdr.IsRequest())
		c.Assert(err, IsNil)
		c.Assert(body, DeepEquals, test.expectBody)

		err = codec.ReadHeader(&hdr)
		c.Assert(err, Equals, io.EOF)
	}
}

func (*suite) TestReadHeaderLogsRequests(c *C) {
	msg := `{"RequestId":1,"Type": "foo","Id": "id","Request":"frob","Params":{"X":"param"}}`
	codec := jsoncodec.New(&testConn{
		readMsgs: []string{msg, msg, msg},
	})
	// Check that logging is off by default
	var h rpc.Header
	err := codec.ReadHeader(&h)
	c.Assert(err, IsNil)
	c.Assert(c.GetTestLog(), Matches, "")

	// Check that we see a log message when we switch logging on.
	codec.SetLogging(true)
	err = codec.ReadHeader(&h)
	c.Assert(err, IsNil)
	c.Assert(c.GetTestLog(), Matches, ".*DEBUG juju rpc/jsoncodec: <- "+regexp.QuoteMeta(msg)+`\n`)

	// Check that we can switch it off again
	codec.SetLogging(false)
	err = codec.ReadHeader(&h)
	c.Assert(err, IsNil)
	c.Assert(c.GetTestLog(), Matches, ".*DEBUG juju rpc/jsoncodec: <- "+regexp.QuoteMeta(msg)+`\n`)
}

func (*suite) TestWriteMessageLogsRequests(c *C) {
	codec := jsoncodec.New(&testConn{})
	h := rpc.Header{
		RequestId: 1,
		Type:      "foo",
		Id:        "id",
		Request:   "frob",
	}

	// Check that logging is off by default
	err := codec.WriteMessage(&h, value{X: "param"})
	c.Assert(err, IsNil)
	c.Assert(c.GetTestLog(), Matches, "")

	// Check that we see a log message when we switch logging on.
	codec.SetLogging(true)
	err = codec.WriteMessage(&h, value{X: "param"})
	c.Assert(err, IsNil)
	msg := `{"RequestId":1,"Type":"foo","Id":"id","Request":"frob","Params":{"X":"param"}}`
	c.Assert(c.GetTestLog(), Matches, `.*DEBUG juju rpc/jsoncodec: -> `+regexp.QuoteMeta(msg)+`\n`)

	// Check that we can switch it off again
	codec.SetLogging(false)
	err = codec.WriteMessage(&h, value{X: "param"})
	c.Assert(err, IsNil)
	c.Assert(c.GetTestLog(), Matches, `.*DEBUG juju rpc/jsoncodec: -> `+regexp.QuoteMeta(msg)+`\n`)
}

func (*suite) TestConcurrentSetLoggingAndWrite(c *C) {
	// If log messages are not set atomically, this
	// test will fail when run under the race detector.
	codec := jsoncodec.New(&testConn{})
	done := make(chan struct{})
	go func() {
		codec.SetLogging(true)
		done <- struct{}{}
	}()
	h := rpc.Header{
		RequestId: 1,
		Type:      "foo",
		Id:        "id",
		Request:   "frob",
	}
	err := codec.WriteMessage(&h, value{X: "param"})
	c.Assert(err, IsNil)
	<-done
}

func (*suite) TestConcurrentSetLoggingAndRead(c *C) {
	// If log messages are not set atomically, this
	// test will fail when run under the race detector.
	msg := `{"RequestId":1,"Type": "foo","Id": "id","Request":"frob","Params":{"X":"param"}}`
	codec := jsoncodec.New(&testConn{
		readMsgs: []string{msg, msg, msg},
	})
	done := make(chan struct{})
	go func() {
		codec.SetLogging(true)
		done <- struct{}{}
	}()
	var h rpc.Header
	err := codec.ReadHeader(&h)
	c.Assert(err, IsNil)
	<-done
}

func (*suite) TestErrorAfterClose(c *C) {
	conn := &testConn{
		err: errors.New("some error"),
	}
	codec := jsoncodec.New(conn)
	var hdr rpc.Header
	err := codec.ReadHeader(&hdr)
	c.Assert(err, ErrorMatches, "error receiving message: some error")

	err = codec.Close()
	c.Assert(err, IsNil)
	c.Assert(conn.closed, Equals, true)

	err = codec.ReadHeader(&hdr)
	c.Assert(err, Equals, io.EOF)
}

var writeTests = []struct {
	hdr       *rpc.Header
	body      interface{}
	isRequest bool
	expect    string
}{{
	hdr: &rpc.Header{
		RequestId: 1,
		Type:      "foo",
		Id:        "id",
		Request:   "frob",
	},
	body:   &value{X: "param"},
	expect: `{"RequestId": 1, "Type": "foo","Id":"id", "Request": "frob", "Params": {"X": "param"}}`,
}, {
	hdr: &rpc.Header{
		RequestId: 2,
		Error:     "an error",
		ErrorCode: "a code",
	},
	expect: `{"RequestId": 2, "Error": "an error", "ErrorCode": "a code"}`,
}, {
	hdr: &rpc.Header{
		RequestId: 3,
	},
	body:   &value{X: "result"},
	expect: `{"RequestId": 3, "Response": {"X": "result"}}`,
}}

func (*suite) TestWrite(c *C) {
	for i, test := range writeTests {
		c.Logf("test %d", i)
		var conn testConn
		codec := jsoncodec.New(&conn)
		err := codec.WriteMessage(test.hdr, test.body)
		c.Assert(err, IsNil)
		c.Assert(conn.writeMsgs, HasLen, 1)

		assertJSONEqual(c, conn.writeMsgs[0], test.expect)
	}
}

// assertJSONEqual compares the json strings v0
// and v1 ignoring white space.
func assertJSONEqual(c *C, v0, v1 string) {
	var m0, m1 interface{}
	err := json.Unmarshal([]byte(v0), &m0)
	c.Assert(err, IsNil)
	err = json.Unmarshal([]byte(v1), &m1)
	c.Assert(err, IsNil)
	data0, err := json.Marshal(m0)
	c.Assert(err, IsNil)
	data1, err := json.Marshal(m1)
	c.Assert(err, IsNil)
	c.Assert(string(data0), Equals, string(data1))
}

type testConn struct {
	readMsgs  []string
	err       error
	writeMsgs []string
	closed    bool
}

func (c *testConn) Receive(msg interface{}) error {
	if len(c.readMsgs) > 0 {
		s := c.readMsgs[0]
		c.readMsgs = c.readMsgs[1:]
		return json.Unmarshal([]byte(s), msg)
	}
	if c.err != nil {
		return c.err
	}
	return io.EOF
}

func (c *testConn) Send(msg interface{}) error {
	data, err := json.Marshal(msg)
	if err != nil {
		return err
	}
	c.writeMsgs = append(c.writeMsgs, string(data))
	return nil
}

func (c *testConn) Close() error {
	c.closed = true
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2020 Authors of Cilium
//
// 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 k8sTest

import (
	"fmt"
	"strings"

	. "github.com/cilium/cilium/test/ginkgo-ext"
	"github.com/cilium/cilium/test/helpers"

	. "github.com/onsi/gomega"
)

const (
	script      = "bpf/verifier-test.sh"
	podName     = "test-verifier"
	podManifest = "test-verifier.yaml"
)

// This test tries to compile BPF programs with a set of options that maximize
// size & complexity (as defined in bpf/Makefile). Programs are then loaded in
// the kernel by test-verifier.sh to detect complexity & other verifier-related
// regressions.
//
// In our K8s test pipelines, we can only access VMs through kubeconfig. Thus,
// to be able to compile and load the BPF programs on the VM, we define a new
// privileged Pod (test-verifier) which mounts the bpffs and the Cilium source
// directory. All test commands are executed in this privileged Pod after
// uninstalling Cilium from the cluster.
var _ = Describe("K8sVerifier", func() {

	SkipContextIf(func() bool {
		// Skip K8s versions for which the test is currently flaky.
		return helpers.SkipK8sVersions(">=1.14.0 <1.20.0") && helpers.SkipQuarantined()
	}, "Dummy context for quarantine", func() {
		var kubectl *helpers.Kubectl

		collectObjectFiles := func() {
			testPath, err := helpers.CreateReportDirectory()
			if err != nil {
				GinkgoPrint(fmt.Sprintf("Cannot create test results directory %s", testPath))
				return
			}
			res := kubectl.Exec("kubectl exec test-verifier -- ls bpf/")
			for _, file := range strings.Split(strings.TrimSuffix(res.Stdout(), "\n"), "\n") {
				if strings.HasSuffix(file, ".o") {
					cmd := fmt.Sprintf("kubectl cp %s:bpf/%s \"%s/%s\"", podName, file, testPath, file)
					res = kubectl.Exec(cmd)
					if !res.WasSuccessful() {
						GinkgoPrint(fmt.Sprintf("Failed to cp BPF object file: %s\n%s", cmd, res.Stderr()))
					}
				}
			}
		}
		BeforeAll(func() {
			SkipIfIntegration(helpers.CIIntegrationGKE)

			kubectl = helpers.CreateKubectl(helpers.K8s1VMName(), logger)
			// We don't check the returned error because Cilium could
			// already be removed (e.g., first test to run).
			kubectl.DeleteResource("ds", fmt.Sprintf("-n %s cilium", helpers.CiliumNamespace))
			ExpectCiliumNotRunning(kubectl)

			testVerifierManifest := helpers.ManifestGet(kubectl.BasePath(), podManifest)
			res := kubectl.ApplyDefault(testVerifierManifest)
			res.ExpectSuccess("Unable to apply %s", testVerifierManifest)
			err := kubectl.WaitForSinglePod(helpers.DefaultNamespace, podName, helpers.HelperTimeout)
			Expect(err).Should(BeNil(), fmt.Sprintf("%s pod not ready after timeout", podName))

			res = kubectl.ExecPodCmd(helpers.DefaultNamespace, podName, "make -C bpf clean V=0")
			res.ExpectSuccess("Failed to clean up bpf/ tree")
		})

		AfterFailed(func() {
			res := kubectl.Exec("kubectl describe nodes")
			GinkgoPrint(res.CombineOutput().String())
			res = kubectl.Exec("kubectl describe pods")
			GinkgoPrint(res.CombineOutput().String())

			By("Collecting bpf_*.o artifacts")
			collectObjectFiles()
		})

		AfterAll(func() {
			kubectl.DeleteResource("pod", podName)
		})

		It("Runs the kernel verifier against Cilium's BPF datapath", func() {
			By("Building BPF objects from the tree")
			kernel := "49"
			switch {
			case helpers.RunsOnNetNextKernel():
				kernel = "netnext"
			case helpers.RunsOn419Kernel():
				kernel = "419"
			}
			cmd := fmt.Sprintf("make -C bpf KERNEL=%s", kernel)
			res := kubectl.ExecPodCmd(helpers.DefaultNamespace, podName, cmd)
			res.ExpectSuccess("Expected compilation of the BPF objects to succeed")
			res = kubectl.ExecPodCmd(helpers.DefaultNamespace, podName, "make -C tools/maptool/")
			res.ExpectSuccess("Expected compilation of maptool to succeed")

			if helpers.RunsOn419Kernel() {
				// On 4.19, we need to remove global data sections before loading
				// those programs. The libbpf version used in our bpftool (which
				// loads these two programs), rejects global data.
				By("Remove global data section")
				for _, prog := range []string{"bpf/sockops/bpf_sockops.o", "bpf/sockops/bpf_redir.o"} {
					cmd := "llvm-objcopy --remove-section=.debug_info --remove-section=.BTF --remove-section=.data /cilium/%s /cilium/%s"
					res := kubectl.ExecPodCmd(helpers.DefaultNamespace, podName,
						fmt.Sprintf(cmd, prog, prog))
					res.ExpectSuccess(fmt.Sprintf("Expected deletion of object file sections from %s to succeed.", prog))
				}
			}

			By("Running the verifier test script")
			cmd = fmt.Sprintf("test/%s", script)
			res = kubectl.ExecPodCmd(helpers.DefaultNamespace, podName, cmd)
			res.ExpectSuccess("Expected the kernel verifier to pass for BPF programs")
		})
	})
})
<commit_msg>test: Unquarantine K8sVerifier on k8s-all<commit_after>// Copyright 2020 Authors of Cilium
//
// 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 k8sTest

import (
	"fmt"
	"strings"

	. "github.com/cilium/cilium/test/ginkgo-ext"
	"github.com/cilium/cilium/test/helpers"

	. "github.com/onsi/gomega"
)

const (
	script      = "bpf/verifier-test.sh"
	podName     = "test-verifier"
	podManifest = "test-verifier.yaml"
)

// This test tries to compile BPF programs with a set of options that maximize
// size & complexity (as defined in bpf/Makefile). Programs are then loaded in
// the kernel by test-verifier.sh to detect complexity & other verifier-related
// regressions.
//
// In our K8s test pipelines, we can only access VMs through kubeconfig. Thus,
// to be able to compile and load the BPF programs on the VM, we define a new
// privileged Pod (test-verifier) which mounts the bpffs and the Cilium source
// directory. All test commands are executed in this privileged Pod after
// uninstalling Cilium from the cluster.
var _ = Describe("K8sVerifier", func() {
	var kubectl *helpers.Kubectl

	collectObjectFiles := func() {
		testPath, err := helpers.CreateReportDirectory()
		if err != nil {
			GinkgoPrint(fmt.Sprintf("Cannot create test results directory %s", testPath))
			return
		}
		res := kubectl.Exec("kubectl exec test-verifier -- ls bpf/")
		for _, file := range strings.Split(strings.TrimSuffix(res.Stdout(), "\n"), "\n") {
			if strings.HasSuffix(file, ".o") {
				cmd := fmt.Sprintf("kubectl cp %s:bpf/%s \"%s/%s\"", podName, file, testPath, file)
				res = kubectl.Exec(cmd)
				if !res.WasSuccessful() {
					GinkgoPrint(fmt.Sprintf("Failed to cp BPF object file: %s\n%s", cmd, res.Stderr()))
				}
			}
		}
	}
	BeforeAll(func() {
		SkipIfIntegration(helpers.CIIntegrationGKE)

		kubectl = helpers.CreateKubectl(helpers.K8s1VMName(), logger)
		// We don't check the returned error because Cilium could
		// already be removed (e.g., first test to run).
		kubectl.DeleteResource("ds", fmt.Sprintf("-n %s cilium", helpers.CiliumNamespace))
		ExpectCiliumNotRunning(kubectl)

		testVerifierManifest := helpers.ManifestGet(kubectl.BasePath(), podManifest)
		res := kubectl.ApplyDefault(testVerifierManifest)
		res.ExpectSuccess("Unable to apply %s", testVerifierManifest)
		err := kubectl.WaitForSinglePod(helpers.DefaultNamespace, podName, helpers.HelperTimeout)
		Expect(err).Should(BeNil(), fmt.Sprintf("%s pod not ready after timeout", podName))

		res = kubectl.ExecPodCmd(helpers.DefaultNamespace, podName, "make -C bpf clean V=0")
		res.ExpectSuccess("Failed to clean up bpf/ tree")
	})

	AfterFailed(func() {
		res := kubectl.Exec("kubectl describe nodes")
		GinkgoPrint(res.CombineOutput().String())
		res = kubectl.Exec("kubectl describe pods")
		GinkgoPrint(res.CombineOutput().String())

		By("Collecting bpf_*.o artifacts")
		collectObjectFiles()
	})

	AfterAll(func() {
		kubectl.DeleteResource("pod", podName)
	})

	It("Runs the kernel verifier against Cilium's BPF datapath", func() {
		By("Building BPF objects from the tree")
		kernel := "49"
		switch {
		case helpers.RunsOnNetNextKernel():
			kernel = "netnext"
		case helpers.RunsOn419Kernel():
			kernel = "419"
		}
		cmd := fmt.Sprintf("make -C bpf KERNEL=%s", kernel)
		res := kubectl.ExecPodCmd(helpers.DefaultNamespace, podName, cmd)
		res.ExpectSuccess("Expected compilation of the BPF objects to succeed")
		res = kubectl.ExecPodCmd(helpers.DefaultNamespace, podName, "make -C tools/maptool/")
		res.ExpectSuccess("Expected compilation of maptool to succeed")

		if helpers.RunsOn419Kernel() {
			// On 4.19, we need to remove global data sections before loading
			// those programs. The libbpf version used in our bpftool (which
			// loads these two programs), rejects global data.
			By("Remove global data section")
			for _, prog := range []string{"bpf/sockops/bpf_sockops.o", "bpf/sockops/bpf_redir.o"} {
				cmd := "llvm-objcopy --remove-section=.debug_info --remove-section=.BTF --remove-section=.data /cilium/%s /cilium/%s"
				res := kubectl.ExecPodCmd(helpers.DefaultNamespace, podName,
					fmt.Sprintf(cmd, prog, prog))
				res.ExpectSuccess(fmt.Sprintf("Expected deletion of object file sections from %s to succeed.", prog))
			}
		}

		By("Running the verifier test script")
		cmd = fmt.Sprintf("test/%s", script)
		res = kubectl.ExecPodCmd(helpers.DefaultNamespace, podName, cmd)
		res.ExpectSuccess("Expected the kernel verifier to pass for BPF programs")
	})
})
<|endoftext|>


<commit_before>package convert

import (
	"testing"
	"time"
)

//功能测试

func Test_String2Bytes_1(t *testing.T) {
	str := "0123456789"
	b := String2Bytes(str)
	t.Log(str, " String to Byte: ", b)
}

func Test_String2Int_1(t *testing.T) {
	str := "1234567890"
	b, e := String2Int(str)
	if e == nil {
		t.Log(str, " String to Int: ", b)
	} else {
		t.Error(e)
	}
}

func Test_String2Int_2(t *testing.T) {
	str := "1234567890ssss"
	b, e := String2Int(str)
	if e == nil {
		t.Log(str, " String to Int: ", b)
	} else {
		t.Error(e)
	}
}

func Test_Int2String_1(t *testing.T) {
	vint := 9876543210
	s := Int2String(vint)
	t.Log(vint, "Int to String: ", s)
}

//String2Int64
func Test_String2Int64_1(t *testing.T) {
	str := "0200000010"
	b, e := String2Int64(str)
	if e != nil {
		t.Error(e)
	} else {
		t.Log(str, "String to Int64: ", b)
	}
}

//String2Int64
func Test_String2Int64_2(t *testing.T) {
	str := "a0200000010"
	b, e := String2Int64(str)
	if e != nil {
		t.Error(e)
	} else {
		t.Log(str, "String to Int64: ", b)
	}
}

//Int642String
func Test_Int642String_1(t *testing.T) {
	var vint int64 = 1 << 62
	s := Int642String(vint)
	t.Log(vint, "Int64 to String: ", s)
}

func Test_Int642String_2(t *testing.T) {
	var vint int64 = 1 << 62 >> 4
	s := Int642String(vint)
	t.Log(vint, "Int64 to String: ", s)
}

//NSToTime
func Test_NSToTime_1(t *testing.T) {
	now := time.Now().UnixNano()
	b, e := NSToTime(now)
	if e != nil {
		t.Error(e)
	}
	t.Log(now, "NSToTime: ", b)
}

//NSToTime
func Test_NSToTime_2(t *testing.T) {
	now := time.Now().Unix()
	b, e := NSToTime(now)
	if e != nil {
		t.Error(e)
	}
	t.Log(now, "NSToTime: ", b)
}
<commit_msg>Finish TestCase<commit_after>package convert

import (
	"testing"
	"time"
	"github.com/devfeel/dotweb/test"
)

//功能测试

func Test_String2Bytes_1(t *testing.T) {
	str := "0123456789"
	b := String2Bytes(str)
	t.Log(str, " String to Byte: ", b)
	excepted:=[]byte{48,49,50,51,52,53,54,55,56,57}
	test.Equal(t,excepted,b)
}

func Test_String2Int_1(t *testing.T) {
	str := "1234567890"
	b, e := String2Int(str)

	t.Log(str, " String to Int: ", b)
	test.Nil(t,e)
	test.Equal(t,1234567890,b)
}

func Test_String2Int_2(t *testing.T) {
	str := "1234567890ssss"
	b, e := String2Int(str)

	t.Log(str, " String to Int: ", b)
	test.NotNil(t,e)
	test.Equal(t,0,b)
}

func Test_Int2String_1(t *testing.T) {
	vint := 9876543210
	s := Int2String(vint)
	t.Log(vint, "Int to String: ", s)
	test.Equal(t,"9876543210",s)
}

//String2Int64
func Test_String2Int64_1(t *testing.T) {
	str := "0200000010"
	b, e := String2Int64(str)

	t.Log(str, "String to Int64: ", b)
	test.Nil(t,e)
	test.Equal(t,int64(200000010),b)
}

//String2Int64
func Test_String2Int64_2(t *testing.T) {
	str := "a0200000010"
	b, e := String2Int64(str)

	t.Log(str, "String to Int64: ", b)
	test.NotNil(t,e)
	test.Equal(t,int64(0),b)
}

//Int642String
func Test_Int642String_1(t *testing.T) {
	var vint int64 = 1 << 62
	s := Int642String(vint)
	t.Log(vint, "Int64 to String: ", s)
	test.Equal(t,"4611686018427387904",s)
}

func Test_Int642String_2(t *testing.T) {
	var vint int64 = 1 << 62 >> 4
	s := Int642String(vint)
	t.Log(vint, "Int64 to String: ", s)

	test.Equal(t,"288230376151711744",s)
}

//NSToTime
func Test_NSToTime_1(t *testing.T) {
	now := time.Now().UnixNano()
	b, e := NSToTime(now)
	test.Nil(t,e)
	t.Log(now, "NSToTime: ", b)
}

//NSToTime
func Test_NSToTime_2(t *testing.T) {
	now := time.Now().Unix()
	b, e := NSToTime(now)
	test.Nil(t,e)
	t.Log(now, "NSToTime: ", b)
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2014 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package wire

import (
	"bytes"
	"encoding/binary"
	"github.com/FactomProject/FactomCode/common"
	"github.com/agl/ed25519"
	"io"
)

// MsgCommitEntry implements the Message interface and represents a factom
// Commit-Entry message.  It is used by client to commit the entry before
// revealing it.
type MsgCommitEntry struct {
	Version   int8
	MilliTime *[6]byte
	EntryHash *common.Hash
	Credits   uint8
	ECPubKey  *[32]byte
	Sig       *[64]byte
}

// BtcEncode encodes the receiver to w using the bitcoin protocol encoding.
// This is part of the Message interface implementation.
func (msg *MsgCommitEntry) BtcEncode(w io.Writer, pver uint32) error {
	// Version
	if err := writeElement(w, &msg.Version); err != nil {
		return err
	}

	//MilliTime
	if err := writeVarBytes(w, pver, msg.MilliTime[:]); err != nil {
		return err
	}

	//EntryHash
	if err := writeVarBytes(w, uint32(common.HASH_LENGTH), msg.EntryHash.Bytes);
		err != nil {
		return err
	}

	//Credits
	if err := writeElement(w, &msg.Credits); err != nil {
		return err
	}

	//ECPubKey
	if err := writeVarBytes(w, uint32(ed25519.PublicKeySize), msg.ECPubKey[:]);
		err != nil {
		return err
	}

	//Signature
	if err := writeVarBytes(w, uint32(ed25519.SignatureSize), msg.Sig[:]);
		err != nil {
		return err
	}

	return nil
}

// BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
// This is part of the Message interface implementation.
func (msg *MsgCommitEntry) BtcDecode(r io.Reader, pver uint32) error {
	// Version
	if err := readElement(r, &msg.Version); err != nil {
		return err
	}

	// MilliTime
	if bytes, err := readVarBytes(r, pver, uint32(6), CmdCommitEntry);
		err != nil {
		return err
	} else {
		copy(msg.MilliTime[:], bytes)
	}

	// EntryHash
	if bytes, err := readVarBytes(r, pver, uint32(common.HASH_LENGTH),
		CmdCommitEntry); err != nil {
		return err
	} else {
		copy(msg.EntryHash.Bytes, bytes[:32])
	}

	// Credits
	if err := readElement(r, &msg.Credits); err != nil {
		return err
	}

	// ECPubKey
	if bytes, err := readVarBytes(r, pver, uint32(ed25519.PublicKeySize),
		CmdCommitEntry); err != nil {
		return err
	} else {
		msg.ECPubKey = new([32]byte)
		copy(msg.ECPubKey[:], bytes)
	}

	// Signature
	if bytes, err := readVarBytes(r, pver, uint32(ed25519.SignatureSize),
		CmdCommitEntry); err != nil {
		return err
	} else {
		msg.Sig = new([64]byte)
		copy(msg.Sig[:], bytes)
	}

	return nil
}

// Command returns the protocol command string for the message.  This is part
// of the Message interface implementation.
func (msg *MsgCommitEntry) Command() string {
	return CmdCommitEntry
}

// MaxPayloadLength returns the maximum length the payload can be for the
// receiver.  This is part of the Message interface implementation.
func (msg *MsgCommitEntry) MaxPayloadLength(pver uint32) uint32 {
	return MaxAppMsgPayload
}

// NewMsgCommitEntry returns a new bitcoin Commit Entry message that conforms to
// the Message interface.
func NewMsgCommitEntry() *MsgCommitEntry {
	m := new(MsgCommitEntry)
	m.MilliTime = new([6]byte)
	m.EntryHash = new(common.Hash)
	m.EntryHash.Bytes = make([]byte, 32)
	m.ECPubKey = new([32]byte)
	m.Sig = new([64]byte)

	return m
}

// Check whether the msg can pass the message level validations
// such as timestamp, signiture and etc
func (msg *MsgCommitEntry) IsValid() bool {
	// Verify signature (Version + MilliTime + EntryHash + Credits)
	buf := new(bytes.Buffer)
	binary.Write(buf, binary.BigEndian, msg.Version)
	buf.Write(msg.MilliTime[:])
	buf.Write(msg.EntryHash.Bytes)
	binary.Write(buf, binary.BigEndian, msg.Credits)

	return ed25519.Verify(msg.ECPubKey, buf.Bytes(), msg.Sig)
}

// Create a sha hash from the message binary (output of BtcEncode)
func (msg *MsgCommitEntry) Sha() (ShaHash, error) {

	buf := bytes.NewBuffer(nil)
	msg.BtcEncode(buf, ProtocolVersion)
	var sha ShaHash
	_ = sha.SetBytes(Sha256(buf.Bytes()))

	return sha, nil
}
<commit_msg>msgcommitentry<commit_after>// Copyright (c) 2013-2014 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package wire

import (
	"bytes"
	"encoding/binary"
	"io"

	"github.com/FactomProject/FactomCode/common"
	"github.com/agl/ed25519"
)

// MsgCommitEntry implements the Message interface and represents a factom
// Commit-Entry message.  It is used by client to commit the entry before
// revealing it.
type MsgCommitEntry struct {
	Version   int8
	MilliTime *[6]byte
	EntryHash *common.Hash
	Credits   uint8
	ECPubKey  *[32]byte
	Sig       *[64]byte
}

// BtcEncode encodes the receiver to w using the bitcoin protocol encoding.
// This is part of the Message interface implementation.
func (msg *MsgCommitEntry) BtcEncode(w io.Writer, pver uint32) error {
	// Version
	if err := writeElement(w, &msg.Version); err != nil {
		return err
	}

	//MilliTime
	if err := writeVarBytes(w, pver, msg.MilliTime[:]); err != nil {
		return err
	}

	//EntryHash
	if err := writeVarBytes(w, uint32(common.HASH_LENGTH), msg.EntryHash.Bytes); err != nil {
		return err
	}

	//Credits
	if err := writeElement(w, &msg.Credits); err != nil {
		return err
	}

	//ECPubKey
	if err := writeVarBytes(w, uint32(ed25519.PublicKeySize), msg.ECPubKey[:]); err != nil {
		return err
	}

	//Signature
	if err := writeVarBytes(w, uint32(ed25519.SignatureSize), msg.Sig[:]); err != nil {
		return err
	}

	return nil
}

// BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
// This is part of the Message interface implementation.
func (msg *MsgCommitEntry) BtcDecode(r io.Reader, pver uint32) error {
	// Version
	if err := readElement(r, &msg.Version); err != nil {
		return err
	}

	// MilliTime
	if bytes, err := readVarBytes(r, pver, uint32(6), CmdCommitEntry); err != nil {
		return err
	} else {
		copy(msg.MilliTime[:], bytes)
	}

	// EntryHash
	if bytes, err := readVarBytes(r, pver, uint32(common.HASH_LENGTH),
		CmdCommitEntry); err != nil {
		return err
	} else {
		copy(msg.EntryHash.Bytes, bytes[:32])
	}

	// Credits
	if err := readElement(r, &msg.Credits); err != nil {
		return err
	}

	// ECPubKey
	if bytes, err := readVarBytes(r, pver, uint32(ed25519.PublicKeySize),
		CmdCommitEntry); err != nil {
		return err
	} else {
		msg.ECPubKey = new([32]byte)
		copy(msg.ECPubKey[:], bytes)
	}

	// Signature
	if bytes, err := readVarBytes(r, pver, uint32(ed25519.SignatureSize),
		CmdCommitEntry); err != nil {
		return err
	} else {
		msg.Sig = new([64]byte)
		copy(msg.Sig[:], bytes)
	}

	return nil
}

// Command returns the protocol command string for the message.  This is part
// of the Message interface implementation.
func (msg *MsgCommitEntry) Command() string {
	return CmdCommitEntry
}

// MaxPayloadLength returns the maximum length the payload can be for the
// receiver.  This is part of the Message interface implementation.
func (msg *MsgCommitEntry) MaxPayloadLength(pver uint32) uint32 {
	return MaxAppMsgPayload
}

// NewMsgCommitEntry returns a new bitcoin Commit Entry message that conforms to
// the Message interface.
func NewMsgCommitEntry() *MsgCommitEntry {
	m := new(MsgCommitEntry)
	m.MilliTime = new([6]byte)
	m.EntryHash = new(common.Hash)
	m.EntryHash.Bytes = make([]byte, 32)
	m.ECPubKey = new([32]byte)
	m.Sig = new([64]byte)

	return m
}

// Check whether the msg can pass the message level validations
// such as timestamp, signiture and etc
func (msg *MsgCommitEntry) IsValid() bool {
	// Verify signature (Version + MilliTime + EntryHash + Credits)
	buf := new(bytes.Buffer)
	binary.Write(buf, binary.BigEndian, msg.Version)
	buf.Write(msg.MilliTime[:])
	buf.Write(msg.EntryHash.Bytes)
	binary.Write(buf, binary.BigEndian, msg.Credits)

	return ed25519.Verify(msg.ECPubKey, buf.Bytes(), msg.Sig)
}

// Create a sha hash from the message binary (output of BtcEncode)
func (msg *MsgCommitEntry) Sha() (ShaHash, error) {

	buf := bytes.NewBuffer(nil)
	msg.BtcEncode(buf, ProtocolVersion)
	var sha ShaHash
	_ = sha.SetBytes(Sha256(buf.Bytes()))

	return sha, nil
}
<|endoftext|>


<commit_before>package ipc

import (
	"fmt"
	"io"
	"os"
	"strings"
	"testing"
	"time"

	"veyron.io/veyron/veyron2/naming"

	"veyron.io/veyron/veyron/lib/expect"
	"veyron.io/veyron/veyron/runtimes/google/ipc/stream/vc"

	"veyron.io/veyron/veyron/lib/modules"
	imanager "veyron.io/veyron/veyron/runtimes/google/ipc/stream/manager"
	"veyron.io/veyron/veyron/runtimes/google/ipc/stream/proxy"
	"veyron.io/veyron/veyron/runtimes/google/ipc/stream/sectest"
	inaming "veyron.io/veyron/veyron/runtimes/google/naming"
	tnaming "veyron.io/veyron/veyron/runtimes/google/testing/mocks/naming"
)

// TestReconnect verifies that the client transparently re-establishes the
// connection to the server if the server dies and comes back (on the same
// endpoint).
func TestReconnect(t *testing.T) {
	b := createBundle(t, sectest.NewPrincipal("client"), nil, nil) // We only need the client from the bundle.
	defer b.cleanup(t)
	sh := modules.NewShell()
	defer sh.Cleanup(os.Stderr, os.Stderr)
	server, err := sh.Start("runServer", "127.0.0.1:0")
	if err != nil {
		t.Fatalf("unexpected error: %s", err)
	}
	session := expect.NewSession(t, server.Stdout(), time.Minute)
	addr := session.ReadLine()
	ep, err := inaming.NewEndpoint(addr)
	if err != nil {
		t.Fatalf("inaming.NewEndpoint(%q): %v", addr, err)
	}
	serverName := naming.JoinAddressName(ep.String(), "suffix")
	makeCall := func() (string, error) {
		ctx, _ := testContext().WithDeadline(time.Now().Add(5 * time.Second))
		call, err := b.client.StartCall(ctx, serverName, "Echo", []interface{}{"bratman"})
		if err != nil {
			return "", fmt.Errorf("START: %s", err)
		}
		var result string
		if err = call.Finish(&result); err != nil {
			return "", err
		}
		return result, nil
	}
	expected := `method:"Echo",suffix:"suffix",arg:"bratman"`
	if result, err := makeCall(); err != nil || result != expected {
		t.Errorf("Got (%q, %v) want (%q, nil)", result, err, expected)
	}
	// Kill the server, verify client can't talk to it anymore.
	server.Shutdown(nil, nil)
	if _, err := makeCall(); err == nil || !strings.HasPrefix(err.Error(), "START") {
		t.Fatalf(`Got (%v) want ("START: <err>") as server is down`, err)
	}

	// Resurrect the server with the same address, verify client
	// re-establishes the connection.
	server, err = sh.Start("runServer", addr)
	if err != nil {
		t.Fatalf("unexpected error: %s", err)
	}
	session = expect.NewSession(t, server.Stdout(), time.Minute)
	defer server.Shutdown(nil, nil)
	session.Expect(addr)
	if result, err := makeCall(); err != nil || result != expected {
		t.Errorf("Got (%q, %v) want (%q, nil)", result, err, expected)
	}
}

type proxyHandle struct {
	ns      naming.Namespace
	process modules.Handle
	session *expect.Session
	mount   string
}

func (h *proxyHandle) Start(t *testing.T) error {
	sh := modules.NewShell()
	server, err := sh.Start("runProxy")
	if err != nil {
		t.Fatalf("unexpected error: %s", err)
	}
	h.process = server
	h.session = expect.NewSession(t, server.Stdout(), time.Minute)
	h.mount = h.session.ReadLine()
	if err := h.session.Error(); err != nil {
		return err
	}
	if err := h.ns.Mount(testContext(), "proxy", h.mount, time.Hour); err != nil {
		return err
	}
	return nil
}

func (h *proxyHandle) Stop() error {
	if h.process == nil {
		return nil
	}
	h.process.Shutdown(os.Stderr, os.Stderr)
	h.process = nil
	if len(h.mount) == 0 {
		return nil
	}
	return h.ns.Unmount(testContext(), "proxy", h.mount)
}

func TestProxy(t *testing.T) {
	sm := imanager.InternalNew(naming.FixedRoutingID(0x555555555))
	ns := tnaming.NewSimpleNamespace()
	client, err := InternalNewClient(sm, ns, vc.LocalPrincipal{sectest.NewPrincipal("client")})
	if err != nil {
		t.Fatal(err)
	}
	defer client.Close()
	server, err := InternalNewServer(testContext(), sm, ns, vc.LocalPrincipal{sectest.NewPrincipal("server")})
	if err != nil {
		t.Fatal(err)
	}
	defer server.Stop()

	name := "mountpoint/server/suffix"
	makeCall := func() (string, error) {
		ctx, _ := testContext().WithDeadline(time.Now().Add(5 * time.Second))
		// Let's fail fast so that the tests don't take as long to run.
		call, err := client.StartCall(ctx, name, "Echo", []interface{}{"batman"})
		if err != nil {
			// proxy is down, we should return here/.... prepend
			// the error with a well known string so that we can test for that.
			return "", fmt.Errorf("RESOLVE: %s", err)
		}
		var result string
		if err = call.Finish(&result); err != nil {
			return "", err
		}
		return result, nil
	}
	proxy := &proxyHandle{ns: ns}
	if err := proxy.Start(t); err != nil {
		t.Fatal(err)
	}
	defer proxy.Stop()
	spec := listenSpec
	spec.Proxy = "proxy"
	if _, err := server.ListenX(&spec); err != nil {
		t.Fatal(err)
	}
	if err := server.Serve("mountpoint/server", testServerDisp{&testServer{}}); err != nil {
		t.Fatal(err)
	}
	verifyMount(t, ns, name)
	// Proxied endpoint should be published and RPC should succeed (through proxy)
	const expected = `method:"Echo",suffix:"suffix",arg:"batman"`
	if result, err := makeCall(); result != expected || err != nil {
		t.Fatalf("Got (%v, %v) want (%v, nil)", result, err, expected)
	}
	// Proxy dies, calls should fail and the name should be unmounted.
	if err := proxy.Stop(); err != nil {
		t.Fatal(err)
	}
	for {
		if _, err := ns.Resolve(testContext(), name); err != nil {
			break
		}
	}
	if result, err := makeCall(); err == nil || !strings.HasPrefix(err.Error(), "RESOLVE") {
		t.Fatalf(`Got (%v, %v) want ("", "RESOLVE: <err>") as proxy is down`, result, err)
	}
	verifyMountMissing(t, ns, name)

	// Proxy restarts, calls should eventually start succeeding.
	if err := proxy.Start(t); err != nil {
		t.Fatal(err)
	}

	for {
		if result, err := makeCall(); err == nil {
			if result != expected {
				t.Errorf("Got (%v, %v) want (%v, nil)", result, err, expected)
			}
			break
		}
	}
}

func runServer(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
	mgr := imanager.InternalNew(naming.FixedRoutingID(0x1111111))
	ns := tnaming.NewSimpleNamespace()
	server, err := InternalNewServer(testContext(), mgr, ns, vc.LocalPrincipal{sectest.NewPrincipal("server")})
	if err != nil {
		return fmt.Errorf("InternalNewServer failed: %v", err)
	}
	disp := testServerDisp{new(testServer)}
	if err := server.Serve("server", disp); err != nil {
		return fmt.Errorf("server.Register failed: %v", err)
	}
	spec := listenSpec
	spec.Address = args[1]
	ep, err := server.ListenX(&spec)
	if err != nil {
		return fmt.Errorf("server.Listen failed: %v", err)
	}
	fmt.Fprintf(stdout, "%s\n", ep.Addr())
	// parent process should explicitly shut us down by closing stdin.
	modules.WaitForEOF(stdin)
	return nil
}

func runProxy(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
	rid, err := naming.NewRoutingID()
	if err != nil {
		return err
	}
	proxy, err := proxy.New(rid, sectest.NewPrincipal("proxy"), "tcp", "127.0.0.1:0", "")
	if err != nil {
		return err
	}
	fmt.Fprintf(stdout, "/%s\n", proxy.Endpoint().String())
	// parent process should explicitly shut us down by closing stdin.
	modules.WaitForEOF(stdin)
	return nil
}

// Required by modules framework.
func TestHelperProcess(t *testing.T) {
	modules.DispatchInTest()
}

func init() {
	modules.RegisterChild("runServer", "[address]", runServer)
	modules.RegisterChild("runProxy", "", runProxy)
}
<commit_msg>veyron/runtimes/google/ipc: Fix flaky TestReconnect<commit_after>package ipc

import (
	"fmt"
	"io"
	"os"
	"strings"
	"testing"
	"time"

	"veyron.io/veyron/veyron2/naming"

	"veyron.io/veyron/veyron/lib/expect"
	"veyron.io/veyron/veyron/runtimes/google/ipc/stream/vc"

	"veyron.io/veyron/veyron/lib/modules"
	imanager "veyron.io/veyron/veyron/runtimes/google/ipc/stream/manager"
	"veyron.io/veyron/veyron/runtimes/google/ipc/stream/proxy"
	"veyron.io/veyron/veyron/runtimes/google/ipc/stream/sectest"
	inaming "veyron.io/veyron/veyron/runtimes/google/naming"
	tnaming "veyron.io/veyron/veyron/runtimes/google/testing/mocks/naming"
)

// TestReconnect verifies that the client transparently re-establishes the
// connection to the server if the server dies and comes back (on the same
// endpoint).
func TestReconnect(t *testing.T) {
	b := createBundle(t, sectest.NewPrincipal("client"), nil, nil) // We only need the client from the bundle.
	defer b.cleanup(t)
	sh := modules.NewShell()
	defer sh.Cleanup(os.Stderr, os.Stderr)
	server, err := sh.Start("runServer", "127.0.0.1:0")
	if err != nil {
		t.Fatalf("unexpected error: %s", err)
	}
	session := expect.NewSession(t, server.Stdout(), time.Minute)
	addr := session.ReadLine()
	ep, err := inaming.NewEndpoint(addr)
	if err != nil {
		t.Fatalf("inaming.NewEndpoint(%q): %v", addr, err)
	}
	serverName := naming.JoinAddressName(ep.String(), "suffix")
	makeCall := func() (string, error) {
		ctx, _ := testContext().WithDeadline(time.Now().Add(5 * time.Second))
		call, err := b.client.StartCall(ctx, serverName, "Echo", []interface{}{"bratman"})
		if err != nil {
			return "", fmt.Errorf("START: %s", err)
		}
		var result string
		if err = call.Finish(&result); err != nil {
			return "", err
		}
		return result, nil
	}
	expected := `method:"Echo",suffix:"suffix",arg:"bratman"`
	if result, err := makeCall(); err != nil || result != expected {
		t.Errorf("Got (%q, %v) want (%q, nil)", result, err, expected)
	}
	// Kill the server, verify client can't talk to it anymore.
	server.Shutdown(nil, nil)
	if _, err := makeCall(); err == nil || (!strings.HasPrefix(err.Error(), "START") && !strings.Contains(err.Error(), "EOF")) {
		t.Fatalf(`Got (%v) want ("START: <err>" or "EOF") as server is down`, err)
	}

	// Resurrect the server with the same address, verify client
	// re-establishes the connection.
	server, err = sh.Start("runServer", addr)
	if err != nil {
		t.Fatalf("unexpected error: %s", err)
	}
	session = expect.NewSession(t, server.Stdout(), time.Minute)
	defer server.Shutdown(nil, nil)
	session.Expect(addr)
	if result, err := makeCall(); err != nil || result != expected {
		t.Errorf("Got (%q, %v) want (%q, nil)", result, err, expected)
	}
}

type proxyHandle struct {
	ns      naming.Namespace
	process modules.Handle
	session *expect.Session
	mount   string
}

func (h *proxyHandle) Start(t *testing.T) error {
	sh := modules.NewShell()
	server, err := sh.Start("runProxy")
	if err != nil {
		t.Fatalf("unexpected error: %s", err)
	}
	h.process = server
	h.session = expect.NewSession(t, server.Stdout(), time.Minute)
	h.mount = h.session.ReadLine()
	if err := h.session.Error(); err != nil {
		return err
	}
	if err := h.ns.Mount(testContext(), "proxy", h.mount, time.Hour); err != nil {
		return err
	}
	return nil
}

func (h *proxyHandle) Stop() error {
	if h.process == nil {
		return nil
	}
	h.process.Shutdown(os.Stderr, os.Stderr)
	h.process = nil
	if len(h.mount) == 0 {
		return nil
	}
	return h.ns.Unmount(testContext(), "proxy", h.mount)
}

func TestProxy(t *testing.T) {
	sm := imanager.InternalNew(naming.FixedRoutingID(0x555555555))
	ns := tnaming.NewSimpleNamespace()
	client, err := InternalNewClient(sm, ns, vc.LocalPrincipal{sectest.NewPrincipal("client")})
	if err != nil {
		t.Fatal(err)
	}
	defer client.Close()
	server, err := InternalNewServer(testContext(), sm, ns, vc.LocalPrincipal{sectest.NewPrincipal("server")})
	if err != nil {
		t.Fatal(err)
	}
	defer server.Stop()

	name := "mountpoint/server/suffix"
	makeCall := func() (string, error) {
		ctx, _ := testContext().WithDeadline(time.Now().Add(5 * time.Second))
		// Let's fail fast so that the tests don't take as long to run.
		call, err := client.StartCall(ctx, name, "Echo", []interface{}{"batman"})
		if err != nil {
			// proxy is down, we should return here/.... prepend
			// the error with a well known string so that we can test for that.
			return "", fmt.Errorf("RESOLVE: %s", err)
		}
		var result string
		if err = call.Finish(&result); err != nil {
			return "", err
		}
		return result, nil
	}
	proxy := &proxyHandle{ns: ns}
	if err := proxy.Start(t); err != nil {
		t.Fatal(err)
	}
	defer proxy.Stop()
	spec := listenSpec
	spec.Proxy = "proxy"
	if _, err := server.ListenX(&spec); err != nil {
		t.Fatal(err)
	}
	if err := server.Serve("mountpoint/server", testServerDisp{&testServer{}}); err != nil {
		t.Fatal(err)
	}
	verifyMount(t, ns, name)
	// Proxied endpoint should be published and RPC should succeed (through proxy)
	const expected = `method:"Echo",suffix:"suffix",arg:"batman"`
	if result, err := makeCall(); result != expected || err != nil {
		t.Fatalf("Got (%v, %v) want (%v, nil)", result, err, expected)
	}
	// Proxy dies, calls should fail and the name should be unmounted.
	if err := proxy.Stop(); err != nil {
		t.Fatal(err)
	}
	if result, err := makeCall(); err == nil || (!strings.HasPrefix(err.Error(), "RESOLVE") && !strings.Contains(err.Error(), "EOF")) {
		t.Fatalf(`Got (%v, %v) want ("", "RESOLVE: <err>" or "EOF") as proxy is down`, result, err)
	}
	for {
		if _, err := ns.Resolve(testContext(), name); err != nil {
			break
		}
		time.Sleep(10 * time.Millisecond)
	}
	verifyMountMissing(t, ns, name)

	// Proxy restarts, calls should eventually start succeeding.
	if err := proxy.Start(t); err != nil {
		t.Fatal(err)
	}

	for {
		if result, err := makeCall(); err == nil {
			if result != expected {
				t.Errorf("Got (%v, %v) want (%v, nil)", result, err, expected)
			}
			break
		}
	}
}

func runServer(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
	mgr := imanager.InternalNew(naming.FixedRoutingID(0x1111111))
	ns := tnaming.NewSimpleNamespace()
	server, err := InternalNewServer(testContext(), mgr, ns, vc.LocalPrincipal{sectest.NewPrincipal("server")})
	if err != nil {
		return fmt.Errorf("InternalNewServer failed: %v", err)
	}
	disp := testServerDisp{new(testServer)}
	if err := server.Serve("server", disp); err != nil {
		return fmt.Errorf("server.Register failed: %v", err)
	}
	spec := listenSpec
	spec.Address = args[1]
	ep, err := server.ListenX(&spec)
	if err != nil {
		return fmt.Errorf("server.Listen failed: %v", err)
	}
	fmt.Fprintf(stdout, "%s\n", ep.Addr())
	// parent process should explicitly shut us down by closing stdin.
	modules.WaitForEOF(stdin)
	return nil
}

func runProxy(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
	rid, err := naming.NewRoutingID()
	if err != nil {
		return err
	}
	proxy, err := proxy.New(rid, sectest.NewPrincipal("proxy"), "tcp", "127.0.0.1:0", "")
	if err != nil {
		return err
	}
	fmt.Fprintf(stdout, "/%s\n", proxy.Endpoint().String())
	// parent process should explicitly shut us down by closing stdin.
	modules.WaitForEOF(stdin)
	return nil
}

// Required by modules framework.
func TestHelperProcess(t *testing.T) {
	modules.DispatchInTest()
}

func init() {
	modules.RegisterChild("runServer", "[address]", runServer)
	modules.RegisterChild("runProxy", "", runProxy)
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// 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
//
// 	https://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 csp

import (
	"context"
	"crypto/rand"
	"encoding/base64"
	"strings"

	"github.com/google/go-safeweb/safehttp"
)

// Directive is the name of a single CSP directive.
type Directive string

const (
	DirectiveScriptSrc Directive = "script-src"
	DirectiveStyleSrc            = "style-src"
	DirectiveObjectSrc           = "object-src"
	DirectiveBaseURI             = "base-uri"
	DirectiveReportURI           = "report-uri"
)

const (
	ValueHTTPS         = "https:"
	ValueHTTP          = "http:"
	ValueUnsafeEval    = "'unsafe-eval'"
	ValueUnsafeInline  = "'unsafe-inline'"
	ValueNone          = "'none'"
	ValueStrictDynamic = "'strict-dynamic'"
)

// PolicyDirective contains a single CSP directive.
type PolicyDirective struct {
	Directive Directive
	Values    []string
	AddNonce  bool
}

// nonceSize is the size of the nonces in bytes.
const nonceSize = 8

func generateNonce(readRand func([]byte) (int, error)) string {
	if readRand == nil {
		readRand = rand.Read
	}
	b := make([]byte, nonceSize)
	_, err := readRand(b)
	if err != nil {
		// TODO: handle this better, what should happen here?
		panic(err)
	}
	return base64.StdEncoding.EncodeToString(b)
}

// Policy defines a CSP policy, containing many directives.
type Policy struct {
	Directives []*PolicyDirective
	// readRand is used for dependency injection in tests.
	readRand func([]byte) (int, error)
}

// NewPolicy creates a new strict, nonce-based CSP.
// See https://csp.withgoogle.com/docs/strict-csp.html for more info.
//
// TODO: maybe reportURI should be safehttp.URL?
func NewPolicy(reportURI string) *Policy {
	return &Policy{
		Directives: []*PolicyDirective{
			{Directive: DirectiveObjectSrc, Values: []string{ValueNone}, AddNonce: false},
			{
				Directive: DirectiveScriptSrc,
				Values: []string{
					ValueUnsafeInline,
					ValueUnsafeEval,
					ValueStrictDynamic,
					ValueHTTPS,
					ValueHTTP,
				},
				AddNonce: true,
			},
			{Directive: DirectiveBaseURI, Values: []string{ValueNone}, AddNonce: false},
			{Directive: DirectiveReportURI, Values: []string{reportURI}, AddNonce: false},
		},
	}
}

// Serialize serializes this policy for use in a Content-Security-Policy header
// or in a Content-Security-Policy-Report-Only header. The nonces generated for
// each directive is also returned.
func (p Policy) Serialize() (csp string, nonces map[Directive]string) {
	nonces = make(map[Directive]string)
	b := strings.Builder{}

	for i, d := range p.Directives {
		if i != 0 {
			b.WriteString("; ")
		}
		b.WriteString(string(d.Directive))

		if d.AddNonce {
			n := generateNonce(p.readRand)
			b.WriteString(" 'nonce-")
			b.WriteString(n)
			b.WriteString("'")
			nonces[d.Directive] = n
		}

		for _, v := range d.Values {
			b.WriteString(" ")
			b.WriteString(v)
		}
	}
	return b.String(), nonces
}

// Interceptor intercepts requests and applies CSP policies.
type Interceptor struct {
	// EnforcementPolicy will be applied as the Content-Security-Policy header.
	EnforcementPolicy *Policy

	// ReportOnlyPolicy will be applied as the
	// Content-Security-Policy-Report-Only header.
	ReportOnlyPolicy *Policy
}

// Default creates a new CSP interceptor with a strict nonce-based policy in
// enforcement mode.
func Default(reportURI string) Interceptor {
	return Interceptor{EnforcementPolicy: NewPolicy(reportURI)}
}

type ctxKey string

// Before claims and sets the Content-Security-Policy header and the
// Content-Security-Policy-Report-Only header.
func (it Interceptor) Before(w safehttp.ResponseWriter, r *safehttp.IncomingRequest) safehttp.Result {
	h := w.Header()
	setCSP, err := h.Claim("Content-Security-Policy")
	if err != nil {
		return w.ServerError(safehttp.StatusInternalServerError)
	}
	if it.EnforcementPolicy != nil {
		s, nonces := it.EnforcementPolicy.Serialize()
		setCSP([]string{s})
		if len(nonces) != 0 {
			r.SetContext(context.WithValue(r.Context(), ctxKey("enforce"), nonces))
		}
	}

	setCSPReportOnly, err := h.Claim("Content-Security-Policy-Report-Only")
	if err != nil {
		return w.ServerError(safehttp.StatusInternalServerError)
	}
	if it.ReportOnlyPolicy != nil {
		s, nonces := it.ReportOnlyPolicy.Serialize()
		setCSPReportOnly([]string{s})
		if len(nonces) != 0 {
			r.SetContext(context.WithValue(r.Context(), ctxKey("report"), nonces))
		}
	}

	return safehttp.Result{}
}
<commit_msg>Nits in comments fixed.<commit_after>// Copyright 2020 Google LLC
//
// 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
//
// 	https://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 csp

import (
	"context"
	"crypto/rand"
	"encoding/base64"
	"strings"

	"github.com/google/go-safeweb/safehttp"
)

// Directive is the name of a single CSP directive.
type Directive string

const (
	DirectiveScriptSrc Directive = "script-src"
	DirectiveStyleSrc            = "style-src"
	DirectiveObjectSrc           = "object-src"
	DirectiveBaseURI             = "base-uri"
	DirectiveReportURI           = "report-uri"
)

const (
	ValueHTTPS         = "https:"
	ValueHTTP          = "http:"
	ValueUnsafeEval    = "'unsafe-eval'"
	ValueUnsafeInline  = "'unsafe-inline'"
	ValueNone          = "'none'"
	ValueStrictDynamic = "'strict-dynamic'"
)

// PolicyDirective contains a single CSP directive.
type PolicyDirective struct {
	Directive Directive
	Values    []string
	AddNonce  bool
}

// nonceSize is the size of the nonces in bytes.
const nonceSize = 8

func generateNonce(readRand func([]byte) (int, error)) string {
	if readRand == nil {
		readRand = rand.Read
	}
	b := make([]byte, nonceSize)
	_, err := readRand(b)
	if err != nil {
		// TODO: handle this better, what should happen here?
		panic(err)
	}
	return base64.StdEncoding.EncodeToString(b)
}

// Policy defines a CSP policy, containing many directives.
type Policy struct {
	Directives []*PolicyDirective
	// readRand is used for dependency injection in tests.
	readRand func([]byte) (int, error)
}

// NewPolicy creates a new strict, nonce-based CSP.
// See https://csp.withgoogle.com/docs/strict-csp.html for more info.
//
// TODO: maybe reportURI should be safehttp.URL?
func NewPolicy(reportURI string) *Policy {
	return &Policy{
		Directives: []*PolicyDirective{
			{Directive: DirectiveObjectSrc, Values: []string{ValueNone}, AddNonce: false},
			{
				Directive: DirectiveScriptSrc,
				Values: []string{
					ValueUnsafeInline,
					ValueUnsafeEval,
					ValueStrictDynamic,
					ValueHTTPS,
					ValueHTTP,
				},
				AddNonce: true,
			},
			{Directive: DirectiveBaseURI, Values: []string{ValueNone}, AddNonce: false},
			{Directive: DirectiveReportURI, Values: []string{reportURI}, AddNonce: false},
		},
	}
}

// Serialize serializes this policy for use in a Content-Security-Policy header
// or in a Content-Security-Policy-Report-Only header. The nonces generated for
// each directive are also returned.
func (p Policy) Serialize() (csp string, nonces map[Directive]string) {
	nonces = make(map[Directive]string)
	b := strings.Builder{}

	for i, d := range p.Directives {
		if i != 0 {
			b.WriteString("; ")
		}
		b.WriteString(string(d.Directive))

		if d.AddNonce {
			n := generateNonce(p.readRand)
			b.WriteString(" 'nonce-")
			b.WriteString(n)
			b.WriteString("'")
			nonces[d.Directive] = n
		}

		for _, v := range d.Values {
			b.WriteString(" ")
			b.WriteString(v)
		}
	}
	return b.String(), nonces
}

// Interceptor intercepts requests and applies CSP policies.
type Interceptor struct {
	// EnforcementPolicy will be applied as the Content-Security-Policy header.
	EnforcementPolicy *Policy

	// ReportOnlyPolicy will be applied as the Content-Security-Policy-Report-Only
	// header.
	ReportOnlyPolicy *Policy
}

// Default creates a new CSP interceptor with a strict nonce-based policy in
// enforcement mode.
func Default(reportURI string) Interceptor {
	return Interceptor{EnforcementPolicy: NewPolicy(reportURI)}
}

type ctxKey string

// Before claims and sets the Content-Security-Policy header and the
// Content-Security-Policy-Report-Only header.
func (it Interceptor) Before(w safehttp.ResponseWriter, r *safehttp.IncomingRequest) safehttp.Result {
	h := w.Header()
	setCSP, err := h.Claim("Content-Security-Policy")
	if err != nil {
		return w.ServerError(safehttp.StatusInternalServerError)
	}
	if it.EnforcementPolicy != nil {
		s, nonces := it.EnforcementPolicy.Serialize()
		setCSP([]string{s})
		if len(nonces) != 0 {
			r.SetContext(context.WithValue(r.Context(), ctxKey("enforce"), nonces))
		}
	}

	setCSPReportOnly, err := h.Claim("Content-Security-Policy-Report-Only")
	if err != nil {
		return w.ServerError(safehttp.StatusInternalServerError)
	}
	if it.ReportOnlyPolicy != nil {
		s, nonces := it.ReportOnlyPolicy.Serialize()
		setCSPReportOnly([]string{s})
		if len(nonces) != 0 {
			r.SetContext(context.WithValue(r.Context(), ctxKey("report"), nonces))
		}
	}

	return safehttp.Result{}
}
<|endoftext|>


<commit_before>package framework

import (
	"bytes"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"text/template"
	"time"
)

type AppData struct {
	AppName    string
	Author     string
	Date       string
	TplPath    string
	OutputPath string
}

func New(appName string, author string, tplPath string, outputPath string) (error, AppData) {
	t := time.Now()
	app := AppData{appName, author, fmt.Sprintf("%d-%.2d-%.2d", t.Year(), t.Month(), t.Day()), tplPath, outputPath}

	return nil, app
}

func (app *AppData) Generate() error {
	fmt.Println("Processing...")

	//walk file list
	fileList, err := walkFileList(app.TplPath)
	if err != nil {
		//log err
		return err
	}

	//create file
	err = app.createAppFiles(fileList)
	if err != nil {
		return err
	}

	fmt.Println("Success.")

	return nil
}

func walkFileList(path string) ([]string, error) {
	var fileList = make([]string, 0)
	i := 0
	err := filepath.Walk(path, func(path string, f os.FileInfo, err error) error {
		if f == nil {
			return err
		}
		if f.IsDir() {
			return nil
		}
		fileList = append(fileList, path)
		i++
		return nil
	})
	return fileList, err
}

func (app *AppData) createAppFiles(fileList []string) error {
	//remove if exist
	err := os.RemoveAll(app.OutputPath + "/" + app.AppName)
	if err != nil {
		return err
	}

	//create file
	for i := 0; i < len(fileList); i++ {
		app.createFile(fileList[i])
	}

	return nil
}

func (app *AppData) createFile(filePath string) error {
	// rename file
	replacedFileName := strings.Replace(filePath, app.TplPath, app.OutputPath+"/"+app.AppName, -1)
	tplFileName := strings.Replace(replacedFileName, ".tpl", "", -1)
	fileNameTpl, err := template.New("file").Parse(tplFileName)
	if err != nil {
		return err
	}

	// create buffer
	buffer := new(bytes.Buffer)
	err = fileNameTpl.Execute(buffer, app)
	if err != nil {
		return err
	}

	realFileName := buffer.String()

	dir, _ := filepath.Split(realFileName)

	// create dir
	err = os.MkdirAll(dir, 0777)
	if err != nil {
		return err
	}

	// create file
	fout, err := os.Create(realFileName)
	defer fout.Close()
	if err != nil {
		return err
	}

	// build template
	// content := make([]byte, 10240)
	fin, err := os.Open(filePath)
	defer fin.Close()
	if err != nil {
		return err
	}
	// _, _ = fin.Read(content)
	contentTpl, err := template.ParseFiles(filePath)
	if err != nil {
		return err
	}
	buffer.Reset()
	err = contentTpl.Execute(buffer, app)
	// _, _ = fout.Write(buffer)
	buffer.WriteTo(fout)

	return nil
}
<commit_msg>Remove useless comments<commit_after>package framework

import (
	"bytes"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"text/template"
	"time"
)

type AppData struct {
	AppName    string
	Author     string
	Date       string
	TplPath    string
	OutputPath string
}

func New(appName string, author string, tplPath string, outputPath string) (error, AppData) {
	t := time.Now()
	app := AppData{appName, author, fmt.Sprintf("%d-%.2d-%.2d", t.Year(), t.Month(), t.Day()), tplPath, outputPath}

	return nil, app
}

func (app *AppData) Generate() error {
	fmt.Println("Processing...")

	//walk file list
	fileList, err := walkFileList(app.TplPath)
	if err != nil {
		//log err
		return err
	}

	//create file
	err = app.createAppFiles(fileList)
	if err != nil {
		return err
	}

	fmt.Println("Success.")

	return nil
}

func walkFileList(path string) ([]string, error) {
	var fileList = make([]string, 0)
	i := 0
	err := filepath.Walk(path, func(path string, f os.FileInfo, err error) error {
		if f == nil {
			return err
		}
		if f.IsDir() {
			return nil
		}
		fileList = append(fileList, path)
		i++
		return nil
	})
	return fileList, err
}

func (app *AppData) createAppFiles(fileList []string) error {
	//remove if exist
	err := os.RemoveAll(app.OutputPath + "/" + app.AppName)
	if err != nil {
		return err
	}

	//create file
	for i := 0; i < len(fileList); i++ {
		app.createFile(fileList[i])
	}

	return nil
}

func (app *AppData) createFile(filePath string) error {
	// rename file
	replacedFileName := strings.Replace(filePath, app.TplPath, app.OutputPath+"/"+app.AppName, -1)
	tplFileName := strings.Replace(replacedFileName, ".tpl", "", -1)
	fileNameTpl, err := template.New("file").Parse(tplFileName)
	if err != nil {
		return err
	}

	// create buffer
	buffer := new(bytes.Buffer)
	err = fileNameTpl.Execute(buffer, app)
	if err != nil {
		return err
	}

	realFileName := buffer.String()

	dir, _ := filepath.Split(realFileName)

	// create dir
	err = os.MkdirAll(dir, 0777)
	if err != nil {
		return err
	}

	// create file
	fout, err := os.Create(realFileName)
	defer fout.Close()
	if err != nil {
		return err
	}

	// build template
	contentTpl, err := template.ParseFiles(filePath)
	if err != nil {
		return err
	}
	buffer.Reset()
	err = contentTpl.Execute(buffer, app)
	_, err = buffer.WriteTo(fout)

	return nil
}
<|endoftext|>


<commit_before>package main

import "net/http"
import "fmt"
import "encoding/json"
import "bytes"
import "os/exec"
import "path"
import "os"

type StoredObjectRecord struct {
	S3 struct {
		Bucket struct {
			Name string
		}
		Object struct {
			Key string
		}
	}
}

type WebhookPayload struct {
	EventType string
	Records   []StoredObjectRecord
}

type Object struct {
	Bucket string
	Key    string
}

func (p *WebhookPayload) Object() Object {
	s3 := p.Records[0].S3

	return Object{
		Bucket: s3.Bucket.Name,
		Key:    s3.Object.Key,
	}
}

func publishHandler(w http.ResponseWriter, r *http.Request) {
	buf := new(bytes.Buffer)
	buf.ReadFrom(r.Body)

	var payload WebhookPayload
	json.Unmarshal(buf.Bytes(), &payload)

	obj := payload.Object()

	fmt.Printf("Bucket:\t%s\n", obj.Bucket)
	fmt.Printf("Key:\t%s\n", obj.Key)

	// start transaction
	var out bytes.Buffer
	cmd_transaction := exec.Command("cvmfs_server", "transaction")
	cmd_transaction.Stdout = &out
	err := cmd_transaction.Run()
	if err != nil {
		fmt.Println("ERROR: failed to open transaction!")
	}
	fmt.Println("Started transaction...")
	fmt.Println(out.String())

	// unpack the layer
	repo := "docker2cvmfs-ci.cern.ch"
	src := path.Join("/home/ubuntu/minio/export/", obj.Bucket, obj.Key)
	dst := path.Join("/cvmfs", repo, "layers", obj.Key)

	os.Mkdir(dst, os.ModePerm)
	tarCmd := fmt.Sprintf("tar xf %s -C %s", src, dst)

	fmt.Printf("Command is: %s\n", tarCmd)

	cmd_extract := exec.Command("bash", "-c", tarCmd)
	cmd_extract.Stdout = &out
	err = cmd_extract.Run()
	if err != nil {
		fmt.Println("ERROR: failed to extract!")
	}
	fmt.Println("Extracted")
	fmt.Println(out.String())

	cmd_publish := exec.Command("cvmfs_server", "publish")
	cmd_publish.Stdout = &out
	err = cmd_publish.Run()
	if err != nil {
		fmt.Println("ERROR: failed to publish!")
	}
	fmt.Println("Published transaction!")
	fmt.Println(out.String())
}

func main() {
	http.HandleFunc("/", publishHandler)
	http.ListenAndServe("0.0.0.0:3000", nil)

}
<commit_msg>Support for publisher configuration file<commit_after>package main

import "net/http"
import "fmt"
import "encoding/json"
import "bytes"
import "os/exec"
import "path"
import "io/ioutil"
import "os"

type StoredObjectRecord struct {
	S3 struct {
		Bucket struct {
			Name string
		}
		Object struct {
			Key string
		}
	}
}

type WebhookPayload struct {
	EventType string
	Records   []StoredObjectRecord
}

type Object struct {
	Bucket string
	Key    string
}

func (p *WebhookPayload) Object() Object {
	s3 := p.Records[0].S3

	return Object{
		Bucket: s3.Bucket.Name,
		Key:    s3.Object.Key,
	}
}

type PublisherConfig struct {
	CvmfsRepo        string
	MinioStoragePath string
}

var publisherConfig PublisherConfig

func LoadConfig(configPath string) (config PublisherConfig, err error) {
	var f []byte

	f, err = ioutil.ReadFile(configPath)
	if err != nil {
		return config, err
	}

	err = json.Unmarshal(f, &config)
	if err != nil {
		return config, err
	}

	return config, nil
}

type CvmfsManager struct {
	CvmfsRepo string
}

func (cm CvmfsManager) StartTransaction() error {
	cmd := exec.Command("cvmfs_server", "transaction", publisherConfig.CvmfsRepo)
	if out, err := cmd.CombinedOutput(); err != nil {
		fmt.Println("ERROR: failed to open transaction!")
		fmt.Println(err)
		fmt.Println(out)
		return err
	}
	fmt.Println("Started transaction...")
	return nil
}

func (cm CvmfsManager) ImportTarball(src, digest string) error {
	dst := path.Join("/cvmfs", cm.CvmfsRepo, "layers", digest)

	os.Mkdir(dst, os.ModePerm)
	tarCmd := fmt.Sprintf("tar xf %s -C %s", src, dst)

	cmd := exec.Command("bash", "-c", tarCmd)

	if out, err := cmd.CombinedOutput(); err != nil {
		fmt.Println("ERROR: failed to extract!")
		fmt.Printf("Command was: %s\n", tarCmd)
		fmt.Println(err)
		fmt.Println(out)
		return err
	}
	fmt.Println("Extracted")
	return nil
}

func (cm CvmfsManager) PublishTransaction() error {
	cmd := exec.Command("cvmfs_server", "publish")
	if out, err := cmd.CombinedOutput(); err != nil {
		fmt.Println("ERROR: failed to publish!")
		fmt.Println(err)
		fmt.Println(out)
		return err
	} else {
		fmt.Println("Published transaction!")
		fmt.Println(out)
		return nil
	}
}

func decodePayload(r *http.Request) (obj Object, err error) {
	buf := new(bytes.Buffer)
	buf.ReadFrom(r.Body)

	var payload WebhookPayload
	if err := json.Unmarshal(buf.Bytes(), &payload); err != nil {
		fmt.Println(buf.String())
		return obj, err
	}

	obj = payload.Object()
	return obj, nil
}

func publishHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Println("Got a request!")

	var obj Object
	var err error
	if obj, err = decodePayload(r); err != nil {
		fmt.Println("Failed to parse request.")
		return
	}

	fmt.Printf("Bucket:\t%s\n", obj.Bucket)
	fmt.Printf("Key:\t%s\n", obj.Key)

	cm := CvmfsManager{CvmfsRepo: publisherConfig.CvmfsRepo}
	if err := cm.StartTransaction(); err != nil {
		fmt.Println(err)
		w.WriteHeader(400)
		return
	}

	filepath := path.Join(publisherConfig.MinioStoragePath, obj.Bucket, obj.Key)
	if err := cm.ImportTarball(filepath, obj.Key); err != nil {
		fmt.Println(err)
		w.WriteHeader(400)
		return
	}

	if err := cm.PublishTransaction(); err != nil {
		fmt.Println(err)
		w.WriteHeader(400)
		return
	}
}

func main() {
	if len(os.Args) < 2 {
		fmt.Println("Specify path to config file as first argument.")
		os.Exit(-1)
	}

	var err error
	if publisherConfig, err = LoadConfig(os.Args[1]); err != nil {
		fmt.Println("Invalid config.")
		fmt.Println(err)
		os.Exit(-2)
	}

	fmt.Println("Config finished!")

	http.HandleFunc("/", publishHandler)
	http.ListenAndServe("0.0.0.0:3000", nil)

}
<|endoftext|>