<commit_before>package screenshot

// #cgo LDFLAGS: -framework CoreGraphics -framework CoreFoundation
// #include <CoreGraphics/CoreGraphics.h>
import "C"

import (
	"errors"
	"github.com/kbinani/screenshot/internal/util"
	"image"
	"unsafe"
)

func Capture(x, y, width, height int) (*image.RGBA, error) {
	if width <= 0 || height <= 0 {
		return nil, errors.New("width or height should be > 0")
	}

	rect := image.Rect(0, 0, width, height)
	img, err := util.CreateImage(rect)
	if err != nil {
		return nil, err
	}

	// cg: CoreGraphics coordinate (origin: lower-left corner of primary display, x-axis: rightward, y-axis: upward)
	// win: Windows coordinate (origin: upper-left corner of primary display, x-axis: rightward, y-axis: downward)
	// di: Display local coordinate (origin: upper-left corner of the display, x-axis: rightward, y-axis: downward)

	cgMainDisplayBounds := getCoreGraphicsCoordinateOfDisplay(C.CGMainDisplayID())

	winBottomLeft := C.CGPointMake(C.CGFloat(x), C.CGFloat(y+height))
	cgBottomLeft := getCoreGraphicsCoordinateFromWindowsCoordinate(winBottomLeft, cgMainDisplayBounds)
	cgCaptureBounds := C.CGRectMake(cgBottomLeft.x, cgBottomLeft.y, C.CGFloat(width), C.CGFloat(height))

	ids := activeDisplayList()

	ctx := createBitmapContext(width, height, (*C.uint32_t)(unsafe.Pointer(&img.Pix[0])), img.Stride)
	if ctx == nil {
		return nil, errors.New("cannot create bitmap context")
	}

	colorSpace := createColorspace()
	if colorSpace == nil {
		return nil, errors.New("cannot create colorspace")
	}
	defer C.CGColorSpaceRelease(colorSpace)

	for _, id := range ids {
		cgBounds := getCoreGraphicsCoordinateOfDisplay(id)
		cgIntersect := C.CGRectIntersection(cgBounds, cgCaptureBounds)
		if C.CGRectIsNull(cgIntersect) {
			continue
		}
		if cgIntersect.size.width <= 0 || cgIntersect.size.height <= 0 {
			continue
		}

		// CGDisplayCreateImageForRect potentially fail in case width/height is odd number.
		if int(cgIntersect.size.width)%2 != 0 {
			cgIntersect.size.width = C.CGFloat(int(cgIntersect.size.width) + 1)
		}
		if int(cgIntersect.size.height)%2 != 0 {
			cgIntersect.size.height = C.CGFloat(int(cgIntersect.size.height) + 1)
		}

		diIntersectDisplayLocal := C.CGRectMake(cgIntersect.origin.x-cgBounds.origin.x,
			cgBounds.origin.y+cgBounds.size.height-(cgIntersect.origin.y+cgIntersect.size.height),
			cgIntersect.size.width, cgIntersect.size.height)
		captured := C.CGDisplayCreateImageForRect(id, diIntersectDisplayLocal)
		if captured == nil {
			return nil, errors.New("cannot capture display")
		}
		defer C.CGImageRelease(captured)

		image := C.CGImageCreateCopyWithColorSpace(captured, colorSpace)
		if image == nil {
			return nil, errors.New("failed copying captured image")
		}
		defer C.CGImageRelease(image)

		cgDrawRect := C.CGRectMake(cgIntersect.origin.x-cgCaptureBounds.origin.x, cgIntersect.origin.y-cgCaptureBounds.origin.y,
			cgIntersect.size.width, cgIntersect.size.height)
		C.CGContextDrawImage(ctx, cgDrawRect, image)
	}

	i := 0
	for iy := 0; iy < height; iy++ {
		j := i
		for ix := 0; ix < width; ix++ {
			// ARGB => RGBA, and set A to 255
			img.Pix[j], img.Pix[j+1], img.Pix[j+2], img.Pix[j+3] = img.Pix[j+1], img.Pix[j+2], img.Pix[j+3], 255
			j += 4
		}
		i += img.Stride
	}

	return img, nil
}

func NumActiveDisplays() int {
	var count C.uint32_t = 0
	if C.CGGetActiveDisplayList(0, nil, &count) == C.kCGErrorSuccess {
		return int(count)
	} else {
		return 0
	}
}

func GetDisplayBounds(displayIndex int) image.Rectangle {
	id := getDisplayId(displayIndex)
	main := C.CGMainDisplayID()

	var rect image.Rectangle

	bounds := getCoreGraphicsCoordinateOfDisplay(id)
	rect.Min.X = int(bounds.origin.x)
	if main == id {
		rect.Min.Y = 0
	} else {
		mainBounds := getCoreGraphicsCoordinateOfDisplay(main)
		mainHeight := mainBounds.size.height
		rect.Min.Y = int(mainHeight - (bounds.origin.y + bounds.size.height))
	}
	rect.Max.X = rect.Min.X + int(bounds.size.width)
	rect.Max.Y = rect.Min.Y + int(bounds.size.height)

	return rect
}

func getDisplayId(displayIndex int) C.CGDirectDisplayID {
	main := C.CGMainDisplayID()
	if displayIndex == 0 {
		return main
	} else {
		n := NumActiveDisplays()
		ids := make([]C.CGDirectDisplayID, n)
		if C.CGGetActiveDisplayList(C.uint32_t(n), (*C.CGDirectDisplayID)(unsafe.Pointer(&ids[0])), nil) != C.kCGErrorSuccess {
			return 0
		}
		index := 0
		for i := 0; i < n; i++ {
			if ids[i] == main {
				continue
			}
			index++
			if index == displayIndex {
				return ids[i]
			}
		}
	}

	return 0
}

func getCoreGraphicsCoordinateOfDisplay(id C.CGDirectDisplayID) C.CGRect {
	main := C.CGDisplayBounds(C.CGMainDisplayID())
	r := C.CGDisplayBounds(id)
	return C.CGRectMake(r.origin.x, -r.origin.y-r.size.height+main.size.height,
		r.size.width, r.size.height)
}

func getCoreGraphicsCoordinateFromWindowsCoordinate(p C.CGPoint, mainDisplayBounds C.CGRect) C.CGPoint {
	return C.CGPointMake(p.x, mainDisplayBounds.size.height-p.y)
}

func createBitmapContext(width int, height int, data *C.uint32_t, bytesPerRow int) C.CGContextRef {
	colorSpace := createColorspace()
	if colorSpace == nil {
		return nil
	}
	defer C.CGColorSpaceRelease(colorSpace)

	return C.CGBitmapContextCreate(unsafe.Pointer(data),
		C.size_t(width),
		C.size_t(height),
		8, // bits per component
		C.size_t(bytesPerRow),
		colorSpace,
		C.kCGImageAlphaNoneSkipFirst)
}

func createColorspace() C.CGColorSpaceRef {
	return C.CGColorSpaceCreateWithName(C.kCGColorSpaceSRGB)
}

func activeDisplayList() []C.CGDirectDisplayID {
	count := C.uint32_t(NumActiveDisplays())
	ret := make([]C.CGDirectDisplayID, count)
	if C.CGGetActiveDisplayList(count, (*C.CGDirectDisplayID)(unsafe.Pointer(&ret[0])), nil) == C.kCGErrorSuccess {
		return ret
	} else {
		return make([]C.CGDirectDisplayID, 0)
	}
}
<commit_msg>support go1.10<commit_after>package screenshot

// #cgo LDFLAGS: -framework CoreGraphics -framework CoreFoundation
// #include <CoreGraphics/CoreGraphics.h>
import "C"

import (
	"errors"
	"image"
	"unsafe"

	"github.com/kbinani/screenshot/internal/util"
)

func Capture(x, y, width, height int) (*image.RGBA, error) {
	if width <= 0 || height <= 0 {
		return nil, errors.New("width or height should be > 0")
	}

	rect := image.Rect(0, 0, width, height)
	img, err := util.CreateImage(rect)
	if err != nil {
		return nil, err
	}

	// cg: CoreGraphics coordinate (origin: lower-left corner of primary display, x-axis: rightward, y-axis: upward)
	// win: Windows coordinate (origin: upper-left corner of primary display, x-axis: rightward, y-axis: downward)
	// di: Display local coordinate (origin: upper-left corner of the display, x-axis: rightward, y-axis: downward)

	cgMainDisplayBounds := getCoreGraphicsCoordinateOfDisplay(C.CGMainDisplayID())

	winBottomLeft := C.CGPointMake(C.CGFloat(x), C.CGFloat(y+height))
	cgBottomLeft := getCoreGraphicsCoordinateFromWindowsCoordinate(winBottomLeft, cgMainDisplayBounds)
	cgCaptureBounds := C.CGRectMake(cgBottomLeft.x, cgBottomLeft.y, C.CGFloat(width), C.CGFloat(height))

	ids := activeDisplayList()

	ctx := createBitmapContext(width, height, (*C.uint32_t)(unsafe.Pointer(&img.Pix[0])), img.Stride)
	if ctx == 0 {
		return nil, errors.New("cannot create bitmap context")
	}

	colorSpace := createColorspace()
	if colorSpace == 0 {
		return nil, errors.New("cannot create colorspace")
	}
	defer C.CGColorSpaceRelease(colorSpace)

	for _, id := range ids {
		cgBounds := getCoreGraphicsCoordinateOfDisplay(id)
		cgIntersect := C.CGRectIntersection(cgBounds, cgCaptureBounds)
		if C.CGRectIsNull(cgIntersect) {
			continue
		}
		if cgIntersect.size.width <= 0 || cgIntersect.size.height <= 0 {
			continue
		}

		// CGDisplayCreateImageForRect potentially fail in case width/height is odd number.
		if int(cgIntersect.size.width)%2 != 0 {
			cgIntersect.size.width = C.CGFloat(int(cgIntersect.size.width) + 1)
		}
		if int(cgIntersect.size.height)%2 != 0 {
			cgIntersect.size.height = C.CGFloat(int(cgIntersect.size.height) + 1)
		}

		diIntersectDisplayLocal := C.CGRectMake(cgIntersect.origin.x-cgBounds.origin.x,
			cgBounds.origin.y+cgBounds.size.height-(cgIntersect.origin.y+cgIntersect.size.height),
			cgIntersect.size.width, cgIntersect.size.height)
		captured := C.CGDisplayCreateImageForRect(id, diIntersectDisplayLocal)
		if captured == nil {
			return nil, errors.New("cannot capture display")
		}
		defer C.CGImageRelease(captured)

		image := C.CGImageCreateCopyWithColorSpace(captured, colorSpace)
		if image == nil {
			return nil, errors.New("failed copying captured image")
		}
		defer C.CGImageRelease(image)

		cgDrawRect := C.CGRectMake(cgIntersect.origin.x-cgCaptureBounds.origin.x, cgIntersect.origin.y-cgCaptureBounds.origin.y,
			cgIntersect.size.width, cgIntersect.size.height)
		C.CGContextDrawImage(ctx, cgDrawRect, image)
	}

	i := 0
	for iy := 0; iy < height; iy++ {
		j := i
		for ix := 0; ix < width; ix++ {
			// ARGB => RGBA, and set A to 255
			img.Pix[j], img.Pix[j+1], img.Pix[j+2], img.Pix[j+3] = img.Pix[j+1], img.Pix[j+2], img.Pix[j+3], 255
			j += 4
		}
		i += img.Stride
	}

	return img, nil
}

func NumActiveDisplays() int {
	var count C.uint32_t = 0
	if C.CGGetActiveDisplayList(0, nil, &count) == C.kCGErrorSuccess {
		return int(count)
	} else {
		return 0
	}
}

func GetDisplayBounds(displayIndex int) image.Rectangle {
	id := getDisplayId(displayIndex)
	main := C.CGMainDisplayID()

	var rect image.Rectangle

	bounds := getCoreGraphicsCoordinateOfDisplay(id)
	rect.Min.X = int(bounds.origin.x)
	if main == id {
		rect.Min.Y = 0
	} else {
		mainBounds := getCoreGraphicsCoordinateOfDisplay(main)
		mainHeight := mainBounds.size.height
		rect.Min.Y = int(mainHeight - (bounds.origin.y + bounds.size.height))
	}
	rect.Max.X = rect.Min.X + int(bounds.size.width)
	rect.Max.Y = rect.Min.Y + int(bounds.size.height)

	return rect
}

func getDisplayId(displayIndex int) C.CGDirectDisplayID {
	main := C.CGMainDisplayID()
	if displayIndex == 0 {
		return main
	} else {
		n := NumActiveDisplays()
		ids := make([]C.CGDirectDisplayID, n)
		if C.CGGetActiveDisplayList(C.uint32_t(n), (*C.CGDirectDisplayID)(unsafe.Pointer(&ids[0])), nil) != C.kCGErrorSuccess {
			return 0
		}
		index := 0
		for i := 0; i < n; i++ {
			if ids[i] == main {
				continue
			}
			index++
			if index == displayIndex {
				return ids[i]
			}
		}
	}

	return 0
}

func getCoreGraphicsCoordinateOfDisplay(id C.CGDirectDisplayID) C.CGRect {
	main := C.CGDisplayBounds(C.CGMainDisplayID())
	r := C.CGDisplayBounds(id)
	return C.CGRectMake(r.origin.x, -r.origin.y-r.size.height+main.size.height,
		r.size.width, r.size.height)
}

func getCoreGraphicsCoordinateFromWindowsCoordinate(p C.CGPoint, mainDisplayBounds C.CGRect) C.CGPoint {
	return C.CGPointMake(p.x, mainDisplayBounds.size.height-p.y)
}

func createBitmapContext(width int, height int, data *C.uint32_t, bytesPerRow int) C.CGContextRef {
	colorSpace := createColorspace()
	if colorSpace == 0 {
		return 0
	}
	defer C.CGColorSpaceRelease(colorSpace)

	return C.CGBitmapContextCreate(unsafe.Pointer(data),
		C.size_t(width),
		C.size_t(height),
		8, // bits per component
		C.size_t(bytesPerRow),
		colorSpace,
		C.kCGImageAlphaNoneSkipFirst)
}

func createColorspace() C.CGColorSpaceRef {
	return C.CGColorSpaceCreateWithName(C.kCGColorSpaceSRGB)
}

func activeDisplayList() []C.CGDirectDisplayID {
	count := C.uint32_t(NumActiveDisplays())
	ret := make([]C.CGDirectDisplayID, count)
	if C.CGGetActiveDisplayList(count, (*C.CGDirectDisplayID)(unsafe.Pointer(&ret[0])), nil) == C.kCGErrorSuccess {
		return ret
	} else {
		return make([]C.CGDirectDisplayID, 0)
	}
}
<|endoftext|>


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

//go:build openbsd && !mips64
// +build openbsd,!mips64

package runtime

import "unsafe"

//go:nosplit
//go:cgo_unsafe_args
func thrsleep(ident uintptr, clock_id int32, tsp *timespec, lock uintptr, abort *uint32) int32 {
	return libcCall(unsafe.Pointer(funcPC(thrsleep_trampoline)), unsafe.Pointer(&ident))
}
func thrsleep_trampoline()

//go:nosplit
//go:cgo_unsafe_args
func thrwakeup(ident uintptr, n int32) int32 {
	return libcCall(unsafe.Pointer(funcPC(thrwakeup_trampoline)), unsafe.Pointer(&ident))
}
func thrwakeup_trampoline()

func osyield() {
	libcCall(unsafe.Pointer(funcPC(sched_yield_trampoline)), unsafe.Pointer(nil))
}
func sched_yield_trampoline()

//go:nosplit
func osyield_no_g() {
	asmcgocall_no_g(unsafe.Pointer(funcPC(sched_yield_trampoline)), unsafe.Pointer(nil))
}

//go:cgo_import_dynamic libc_thrsleep __thrsleep "libc.so"
//go:cgo_import_dynamic libc_thrwakeup __thrwakeup "libc.so"
//go:cgo_import_dynamic libc_sched_yield sched_yield "libc.so"

//go:cgo_import_dynamic _ _ "libc.so"
<commit_msg>runtime: mark osyield nosplit on OpenBSD<commit_after>// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build openbsd && !mips64
// +build openbsd,!mips64

package runtime

import "unsafe"

//go:nosplit
//go:cgo_unsafe_args
func thrsleep(ident uintptr, clock_id int32, tsp *timespec, lock uintptr, abort *uint32) int32 {
	return libcCall(unsafe.Pointer(funcPC(thrsleep_trampoline)), unsafe.Pointer(&ident))
}
func thrsleep_trampoline()

//go:nosplit
//go:cgo_unsafe_args
func thrwakeup(ident uintptr, n int32) int32 {
	return libcCall(unsafe.Pointer(funcPC(thrwakeup_trampoline)), unsafe.Pointer(&ident))
}
func thrwakeup_trampoline()

//go:nosplit
func osyield() {
	libcCall(unsafe.Pointer(funcPC(sched_yield_trampoline)), unsafe.Pointer(nil))
}
func sched_yield_trampoline()

//go:nosplit
func osyield_no_g() {
	asmcgocall_no_g(unsafe.Pointer(funcPC(sched_yield_trampoline)), unsafe.Pointer(nil))
}

//go:cgo_import_dynamic libc_thrsleep __thrsleep "libc.so"
//go:cgo_import_dynamic libc_thrwakeup __thrwakeup "libc.so"
//go:cgo_import_dynamic libc_sched_yield sched_yield "libc.so"

//go:cgo_import_dynamic _ _ "libc.so"
<|endoftext|>


<commit_before>package respond_test

import (
	"encoding/json"
	"errors"
	"io"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/matryer/respond"

	"github.com/cheekybits/is"
)

var testdata = map[string]interface{}{"test": true}

type testHandler struct {
	status int
	data   interface{}
}

func (t *testHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	respond.With(w, r, t.status, t.data)
}

type testStatusHandler struct {
	status int
}

func (t *testStatusHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	respond.WithStatus(w, r, t.status)
}

func newTestRequest() *http.Request {
	r, err := http.NewRequest("GET", "Something", nil)
	if err != nil {
		panic("bad request: " + err.Error())
	}
	return r
}

func TestWith(t *testing.T) {
	is := is.New(t)

	w := httptest.NewRecorder()
	r := newTestRequest()

	respond.With(w, r, http.StatusOK, testdata)

	is.Equal(http.StatusOK, w.Code)
	var data map[string]interface{}
	is.NoErr(json.Unmarshal(w.Body.Bytes(), &data))
	is.Equal(data, testdata)
	is.Equal(w.HeaderMap.Get("Content-Type"), "application/json; charset=utf-8")
}

func TestWithStatusDefault(t *testing.T) {
	is := is.New(t)

	w := httptest.NewRecorder()
	r := newTestRequest()

	respond.WithStatus(w, r, http.StatusTeapot)

	is.Equal(http.StatusTeapot, w.Code)
	var data map[string]interface{}
	is.NoErr(json.Unmarshal(w.Body.Bytes(), &data))
	is.Equal(data["status"], "I'm a teapot")
	is.Equal(data["code"], http.StatusTeapot)
	is.Equal(w.HeaderMap.Get("Content-Type"), "application/json; charset=utf-8")
}

func TestWithStatusOptions(t *testing.T) {
	is := is.New(t)

	options := &respond.Options{
		StatusData: func(w http.ResponseWriter, r *http.Request, status int) interface{} {
			return map[string]interface{}{"s": status}
		},
	}
	testHandler := &testStatusHandler{
		status: http.StatusTeapot,
	}
	handler := options.Handler(testHandler)

	w := httptest.NewRecorder()
	r := newTestRequest()

	handler.ServeHTTP(w, r)

	is.Equal(http.StatusTeapot, w.Code)
	is.Equal(w.Body.String(), `{"s":418}`+"\n")
	is.Equal(w.HeaderMap.Get("Content-Type"), "application/json; charset=utf-8")
}

func TestBefore(t *testing.T) {
	is := is.New(t)

	options := &respond.Options{}
	var beforecall map[string]interface{}
	options.Before = func(w http.ResponseWriter, r *http.Request, status int, data interface{}) (int, interface{}) {
		beforecall = map[string]interface{}{
			"w": w, "r": r, "status": status, "data": data,
		}
		return status, data
	}

	testHandler := &testHandler{
		status: http.StatusOK, data: testdata,
	}
	handler := options.Handler(testHandler)

	w := httptest.NewRecorder()
	r := newTestRequest()

	handler.ServeHTTP(w, r)

	is.OK(beforecall)
	is.Equal(beforecall["w"], w)
	is.Equal(beforecall["r"], r)
	is.Equal(beforecall["status"], testHandler.status)
	is.Equal(beforecall["data"], testHandler.data)

	is.Equal(http.StatusOK, w.Code)
	var data map[string]interface{}
	is.NoErr(json.Unmarshal(w.Body.Bytes(), &data))
	is.Equal(data, testdata)
	is.Equal(w.HeaderMap.Get("Content-Type"), "application/json; charset=utf-8")

}

func TestAfter(t *testing.T) {
	is := is.New(t)

	options := &respond.Options{}
	var aftercall map[string]interface{}
	options.After = func(w http.ResponseWriter, r *http.Request, status int, data interface{}) {
		aftercall = map[string]interface{}{
			"w": w, "r": r, "status": status, "data": data,
		}
	}

	testHandler := &testHandler{
		status: http.StatusOK, data: testdata,
	}
	handler := options.Handler(testHandler)

	w := httptest.NewRecorder()
	r := newTestRequest()

	handler.ServeHTTP(w, r)

	is.OK(aftercall)
	is.Equal(aftercall["w"], w)
	is.Equal(aftercall["r"], r)
	is.Equal(aftercall["status"], testHandler.status)
	is.Equal(aftercall["data"], testHandler.data)

	is.Equal(http.StatusOK, w.Code)
	var data map[string]interface{}
	is.NoErr(json.Unmarshal(w.Body.Bytes(), &data))
	is.Equal(data, testdata)
	is.Equal(w.HeaderMap.Get("Content-Type"), "application/json; charset=utf-8")

}

type testEncoder struct {
	err error
}

func (e *testEncoder) Encode(w http.ResponseWriter, r *http.Request, v interface{}) error {
	io.WriteString(w, "testEncoder")
	return e.err
}

func (e *testEncoder) ContentType(w http.ResponseWriter, r *http.Request) string {
	return "test/encoder"
}

func TestEncoder(t *testing.T) {
	is := is.New(t)

	options := &respond.Options{}
	var encodercall map[string]interface{}
	options.Encoder = func(w http.ResponseWriter, r *http.Request) respond.Encoder {
		encodercall = map[string]interface{}{
			"w": w, "r": r,
		}
		return &testEncoder{}
	}

	testHandler := &testHandler{
		status: http.StatusOK, data: testdata,
	}
	handler := options.Handler(testHandler)

	w := httptest.NewRecorder()
	r := newTestRequest()

	handler.ServeHTTP(w, r)

	is.OK(encodercall)
	is.Equal(encodercall["w"], w)
	is.Equal(encodercall["r"], r)

	is.Equal(http.StatusOK, w.Code)
	is.Equal(w.Body.String(), "testEncoder")
	is.Equal(w.HeaderMap.Get("Content-Type"), "test/encoder")

}

func TestEncoderOnErr(t *testing.T) {
	is := is.New(t)

	var onErrCall map[string]interface{}
	options := &respond.Options{
		OnErr: func(err error) {
			onErrCall = map[string]interface{}{"err": err}
		},
	}
	encoderErr := errors.New("something went wrong while encoding")
	options.Encoder = func(w http.ResponseWriter, r *http.Request) respond.Encoder {
		return &testEncoder{
			err: encoderErr,
		}
	}

	testHandler := &testHandler{
		status: http.StatusOK, data: testdata,
	}
	handler := options.Handler(testHandler)

	w := httptest.NewRecorder()
	r := newTestRequest()

	handler.ServeHTTP(w, r)

	is.OK(onErrCall)
	is.Equal(onErrCall["err"], encoderErr)

}

func TestOnErrPanic(t *testing.T) {
	is := is.New(t)

	o := respond.Options{}

	err := errors.New("something went wrong")
	is.PanicWith("respond: "+err.Error(), func() { o.OnErrPanic(err) })

}

func TestMultipleWith(t *testing.T) {
	is := is.New(t)

	options := &respond.Options{}
	handler := options.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		respond.With(w, r, http.StatusInternalServerError, errors.New("borked"))
		respond.With(w, r, http.StatusOK, nil)
	}))

	w := httptest.NewRecorder()
	r := newTestRequest()

	is.PanicWith("respond: multiple responses", func() {
		handler.ServeHTTP(w, r)
	})

	options = &respond.Options{
		AllowMultiple: true,
	}
	handler = options.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		respond.With(w, r, http.StatusInternalServerError, errors.New("borked"))
		respond.With(w, r, http.StatusOK, nil)
	}))

	w = httptest.NewRecorder()
	r = newTestRequest()

	handler.ServeHTTP(w, r)

}
<commit_msg>added error response test<commit_after>package respond_test

import (
	"encoding/json"
	"errors"
	"io"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/matryer/respond"

	"github.com/cheekybits/is"
)

var testdata = map[string]interface{}{"test": true}

type testHandler struct {
	status int
	data   interface{}
}

func (t *testHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	respond.With(w, r, t.status, t.data)
}

type testStatusHandler struct {
	status int
}

func (t *testStatusHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	respond.WithStatus(w, r, t.status)
}

func newTestRequest() *http.Request {
	r, err := http.NewRequest("GET", "Something", nil)
	if err != nil {
		panic("bad request: " + err.Error())
	}
	return r
}

func TestWith(t *testing.T) {
	is := is.New(t)

	w := httptest.NewRecorder()
	r := newTestRequest()

	respond.With(w, r, http.StatusOK, testdata)

	is.Equal(http.StatusOK, w.Code)
	var data map[string]interface{}
	is.NoErr(json.Unmarshal(w.Body.Bytes(), &data))
	is.Equal(data, testdata)
	is.Equal(w.HeaderMap.Get("Content-Type"), "application/json; charset=utf-8")
}

func TestWithStatusDefault(t *testing.T) {
	is := is.New(t)

	w := httptest.NewRecorder()
	r := newTestRequest()

	respond.WithStatus(w, r, http.StatusTeapot)

	is.Equal(http.StatusTeapot, w.Code)
	var data map[string]interface{}
	is.NoErr(json.Unmarshal(w.Body.Bytes(), &data))
	is.Equal(data["status"], "I'm a teapot")
	is.Equal(data["code"], http.StatusTeapot)
	is.Equal(w.HeaderMap.Get("Content-Type"), "application/json; charset=utf-8")
}

func TestWithStatusOptions(t *testing.T) {
	is := is.New(t)

	options := &respond.Options{
		StatusData: func(w http.ResponseWriter, r *http.Request, status int) interface{} {
			return map[string]interface{}{"s": status}
		},
	}
	testHandler := &testStatusHandler{
		status: http.StatusTeapot,
	}
	handler := options.Handler(testHandler)

	w := httptest.NewRecorder()
	r := newTestRequest()

	handler.ServeHTTP(w, r)

	is.Equal(http.StatusTeapot, w.Code)
	is.Equal(w.Body.String(), `{"s":418}`+"\n")
	is.Equal(w.HeaderMap.Get("Content-Type"), "application/json; charset=utf-8")
}

func TestWithError(t *testing.T) {
	is := is.New(t)

	w := httptest.NewRecorder()
	r := newTestRequest()

	err := errors.New("something went wrong")

	options := &respond.Options{
		Before: func(w http.ResponseWriter, r *http.Request, status int, data interface{}) (int, interface{}) {
			if err, ok := data.(error); ok {
				return status, map[string]interface{}{"error": err.Error()}
			}
			return status, data
		},
	}
	testHandler := &testHandler{
		status: http.StatusInternalServerError,
		data:   err,
	}
	handler := options.Handler(testHandler)

	handler.ServeHTTP(w, r)

	is.Equal(http.StatusInternalServerError, w.Code)
	var data map[string]interface{}
	is.NoErr(json.Unmarshal(w.Body.Bytes(), &data))
	is.Equal(data, map[string]interface{}{"error": err.Error()})
	is.Equal(w.HeaderMap.Get("Content-Type"), "application/json; charset=utf-8")
}

func TestBefore(t *testing.T) {
	is := is.New(t)

	options := &respond.Options{}
	var beforecall map[string]interface{}
	options.Before = func(w http.ResponseWriter, r *http.Request, status int, data interface{}) (int, interface{}) {
		beforecall = map[string]interface{}{
			"w": w, "r": r, "status": status, "data": data,
		}
		return status, data
	}

	testHandler := &testHandler{
		status: http.StatusOK, data: testdata,
	}
	handler := options.Handler(testHandler)

	w := httptest.NewRecorder()
	r := newTestRequest()

	handler.ServeHTTP(w, r)

	is.OK(beforecall)
	is.Equal(beforecall["w"], w)
	is.Equal(beforecall["r"], r)
	is.Equal(beforecall["status"], testHandler.status)
	is.Equal(beforecall["data"], testHandler.data)

	is.Equal(http.StatusOK, w.Code)
	var data map[string]interface{}
	is.NoErr(json.Unmarshal(w.Body.Bytes(), &data))
	is.Equal(data, testdata)
	is.Equal(w.HeaderMap.Get("Content-Type"), "application/json; charset=utf-8")

}

func TestAfter(t *testing.T) {
	is := is.New(t)

	options := &respond.Options{}
	var aftercall map[string]interface{}
	options.After = func(w http.ResponseWriter, r *http.Request, status int, data interface{}) {
		aftercall = map[string]interface{}{
			"w": w, "r": r, "status": status, "data": data,
		}
	}

	testHandler := &testHandler{
		status: http.StatusOK, data: testdata,
	}
	handler := options.Handler(testHandler)

	w := httptest.NewRecorder()
	r := newTestRequest()

	handler.ServeHTTP(w, r)

	is.OK(aftercall)
	is.Equal(aftercall["w"], w)
	is.Equal(aftercall["r"], r)
	is.Equal(aftercall["status"], testHandler.status)
	is.Equal(aftercall["data"], testHandler.data)

	is.Equal(http.StatusOK, w.Code)
	var data map[string]interface{}
	is.NoErr(json.Unmarshal(w.Body.Bytes(), &data))
	is.Equal(data, testdata)
	is.Equal(w.HeaderMap.Get("Content-Type"), "application/json; charset=utf-8")

}

type testEncoder struct {
	err error
}

func (e *testEncoder) Encode(w http.ResponseWriter, r *http.Request, v interface{}) error {
	io.WriteString(w, "testEncoder")
	return e.err
}

func (e *testEncoder) ContentType(w http.ResponseWriter, r *http.Request) string {
	return "test/encoder"
}

func TestEncoder(t *testing.T) {
	is := is.New(t)

	options := &respond.Options{}
	var encodercall map[string]interface{}
	options.Encoder = func(w http.ResponseWriter, r *http.Request) respond.Encoder {
		encodercall = map[string]interface{}{
			"w": w, "r": r,
		}
		return &testEncoder{}
	}

	testHandler := &testHandler{
		status: http.StatusOK, data: testdata,
	}
	handler := options.Handler(testHandler)

	w := httptest.NewRecorder()
	r := newTestRequest()

	handler.ServeHTTP(w, r)

	is.OK(encodercall)
	is.Equal(encodercall["w"], w)
	is.Equal(encodercall["r"], r)

	is.Equal(http.StatusOK, w.Code)
	is.Equal(w.Body.String(), "testEncoder")
	is.Equal(w.HeaderMap.Get("Content-Type"), "test/encoder")

}

func TestEncoderOnErr(t *testing.T) {
	is := is.New(t)

	var onErrCall map[string]interface{}
	options := &respond.Options{
		OnErr: func(err error) {
			onErrCall = map[string]interface{}{"err": err}
		},
	}
	encoderErr := errors.New("something went wrong while encoding")
	options.Encoder = func(w http.ResponseWriter, r *http.Request) respond.Encoder {
		return &testEncoder{
			err: encoderErr,
		}
	}

	testHandler := &testHandler{
		status: http.StatusOK, data: testdata,
	}
	handler := options.Handler(testHandler)

	w := httptest.NewRecorder()
	r := newTestRequest()

	handler.ServeHTTP(w, r)

	is.OK(onErrCall)
	is.Equal(onErrCall["err"], encoderErr)

}

func TestOnErrPanic(t *testing.T) {
	is := is.New(t)

	o := respond.Options{}

	err := errors.New("something went wrong")
	is.PanicWith("respond: "+err.Error(), func() { o.OnErrPanic(err) })

}

func TestMultipleWith(t *testing.T) {
	is := is.New(t)

	options := &respond.Options{}
	handler := options.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		respond.With(w, r, http.StatusInternalServerError, errors.New("borked"))
		respond.With(w, r, http.StatusOK, nil)
	}))

	w := httptest.NewRecorder()
	r := newTestRequest()

	is.PanicWith("respond: multiple responses", func() {
		handler.ServeHTTP(w, r)
	})

	options = &respond.Options{
		AllowMultiple: true,
	}
	handler = options.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		respond.With(w, r, http.StatusInternalServerError, errors.New("borked"))
		respond.With(w, r, http.StatusOK, nil)
	}))

	w = httptest.NewRecorder()
	r = newTestRequest()

	handler.ServeHTTP(w, r)

}
<|endoftext|>


<commit_before>/*
Copyright 2014 The Kubernetes Authors.

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

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

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

package apimachinery

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

	"k8s.io/api/core/v1"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/intstr"
	"k8s.io/apimachinery/pkg/util/uuid"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/kubernetes/test/e2e/framework"
	e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
	imageutils "k8s.io/kubernetes/test/utils/image"

	"github.com/onsi/ginkgo"
	"k8s.io/apimachinery/pkg/types"
)

func extinguish(f *framework.Framework, totalNS int, maxAllowedAfterDel int, maxSeconds int) {
	var err error

	ginkgo.By("Creating testing namespaces")
	wg := &sync.WaitGroup{}
	wg.Add(totalNS)
	for n := 0; n < totalNS; n++ {
		go func(n int) {
			defer wg.Done()
			defer ginkgo.GinkgoRecover()
			ns := fmt.Sprintf("nslifetest-%v", n)
			_, err = f.CreateNamespace(ns, nil)
			framework.ExpectNoError(err, "failed to create namespace: %s", ns)
		}(n)
	}
	wg.Wait()

	//Wait 10 seconds, then SEND delete requests for all the namespaces.
	ginkgo.By("Waiting 10 seconds")
	time.Sleep(time.Duration(10 * time.Second))
	deleteFilter := []string{"nslifetest"}
	deleted, err := framework.DeleteNamespaces(f.ClientSet, deleteFilter, nil /* skipFilter */)
	framework.ExpectNoError(err, "failed to delete namespace(s) containing: %s", deleteFilter)
	framework.ExpectEqual(len(deleted), totalNS)

	ginkgo.By("Waiting for namespaces to vanish")
	//Now POLL until all namespaces have been eradicated.
	framework.ExpectNoError(wait.Poll(2*time.Second, time.Duration(maxSeconds)*time.Second,
		func() (bool, error) {
			var cnt = 0
			nsList, err := f.ClientSet.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{})
			if err != nil {
				return false, err
			}
			for _, item := range nsList.Items {
				if strings.Contains(item.Name, "nslifetest") {
					cnt++
				}
			}
			if cnt > maxAllowedAfterDel {
				framework.Logf("Remaining namespaces : %v", cnt)
				return false, nil
			}
			return true, nil
		}))
}

func ensurePodsAreRemovedWhenNamespaceIsDeleted(f *framework.Framework) {
	ginkgo.By("Creating a test namespace")
	namespaceName := "nsdeletetest"
	namespace, err := f.CreateNamespace(namespaceName, nil)
	framework.ExpectNoError(err, "failed to create namespace: %s", namespaceName)

	ginkgo.By("Waiting for a default service account to be provisioned in namespace")
	err = framework.WaitForDefaultServiceAccountInNamespace(f.ClientSet, namespace.Name)
	framework.ExpectNoError(err, "failure while waiting for a default service account to be provisioned in namespace: %s", namespace.Name)

	ginkgo.By("Creating a pod in the namespace")
	podName := "test-pod"
	pod := &v1.Pod{
		ObjectMeta: metav1.ObjectMeta{
			Name: podName,
		},
		Spec: v1.PodSpec{
			Containers: []v1.Container{
				{
					Name:  "nginx",
					Image: imageutils.GetPauseImageName(),
				},
			},
		},
	}
	pod, err = f.ClientSet.CoreV1().Pods(namespace.Name).Create(context.TODO(), pod, metav1.CreateOptions{})
	framework.ExpectNoError(err, "failed to create pod %s in namespace: %s", podName, namespace.Name)

	ginkgo.By("Waiting for the pod to have running status")
	framework.ExpectNoError(e2epod.WaitForPodRunningInNamespace(f.ClientSet, pod))

	ginkgo.By("Deleting the namespace")
	err = f.ClientSet.CoreV1().Namespaces().Delete(context.TODO(), namespace.Name, metav1.DeleteOptions{})
	framework.ExpectNoError(err, "failed to delete namespace: %s", namespace.Name)

	ginkgo.By("Waiting for the namespace to be removed.")
	maxWaitSeconds := int64(60) + *pod.Spec.TerminationGracePeriodSeconds
	framework.ExpectNoError(wait.Poll(1*time.Second, time.Duration(maxWaitSeconds)*time.Second,
		func() (bool, error) {
			_, err = f.ClientSet.CoreV1().Namespaces().Get(context.TODO(), namespace.Name, metav1.GetOptions{})
			if err != nil && apierrors.IsNotFound(err) {
				return true, nil
			}
			return false, nil
		}))

	ginkgo.By("Recreating the namespace")
	namespace, err = f.CreateNamespace(namespaceName, nil)
	framework.ExpectNoError(err, "failed to create namespace: %s", namespaceName)

	ginkgo.By("Verifying there are no pods in the namespace")
	_, err = f.ClientSet.CoreV1().Pods(namespace.Name).Get(context.TODO(), pod.Name, metav1.GetOptions{})
	framework.ExpectError(err, "failed to get pod %s in namespace: %s", pod.Name, namespace.Name)
}

func ensureServicesAreRemovedWhenNamespaceIsDeleted(f *framework.Framework) {
	var err error

	ginkgo.By("Creating a test namespace")
	namespaceName := "nsdeletetest"
	namespace, err := f.CreateNamespace(namespaceName, nil)
	framework.ExpectNoError(err, "failed to create namespace: %s", namespaceName)

	ginkgo.By("Waiting for a default service account to be provisioned in namespace")
	err = framework.WaitForDefaultServiceAccountInNamespace(f.ClientSet, namespace.Name)
	framework.ExpectNoError(err, "failure while waiting for a default service account to be provisioned in namespace: %s", namespace.Name)

	ginkgo.By("Creating a service in the namespace")
	serviceName := "test-service"
	labels := map[string]string{
		"foo": "bar",
		"baz": "blah",
	}
	service := &v1.Service{
		ObjectMeta: metav1.ObjectMeta{
			Name: serviceName,
		},
		Spec: v1.ServiceSpec{
			Selector: labels,
			Ports: []v1.ServicePort{{
				Port:       80,
				TargetPort: intstr.FromInt(80),
			}},
		},
	}
	service, err = f.ClientSet.CoreV1().Services(namespace.Name).Create(context.TODO(), service, metav1.CreateOptions{})
	framework.ExpectNoError(err, "failed to create service %s in namespace %s", serviceName, namespace.Name)

	ginkgo.By("Deleting the namespace")
	err = f.ClientSet.CoreV1().Namespaces().Delete(context.TODO(), namespace.Name, metav1.DeleteOptions{})
	framework.ExpectNoError(err, "failed to delete namespace: %s", namespace.Name)

	ginkgo.By("Waiting for the namespace to be removed.")
	maxWaitSeconds := int64(60)
	framework.ExpectNoError(wait.Poll(1*time.Second, time.Duration(maxWaitSeconds)*time.Second,
		func() (bool, error) {
			_, err = f.ClientSet.CoreV1().Namespaces().Get(context.TODO(), namespace.Name, metav1.GetOptions{})
			if err != nil && apierrors.IsNotFound(err) {
				return true, nil
			}
			return false, nil
		}))

	ginkgo.By("Recreating the namespace")
	namespace, err = f.CreateNamespace(namespaceName, nil)
	framework.ExpectNoError(err, "failed to create namespace: %s", namespaceName)

	ginkgo.By("Verifying there is no service in the namespace")
	_, err = f.ClientSet.CoreV1().Services(namespace.Name).Get(context.TODO(), service.Name, metav1.GetOptions{})
	framework.ExpectError(err, "failed to get service %s in namespace: %s", service.Name, namespace.Name)
}

// This test must run [Serial] due to the impact of running other parallel
// tests can have on its performance.  Each test that follows the common
// test framework follows this pattern:
//   1. Create a Namespace
//   2. Do work that generates content in that namespace
//   3. Delete a Namespace
// Creation of a Namespace is non-trivial since it requires waiting for a
// ServiceAccount to be generated.
// Deletion of a Namespace is non-trivial and performance intensive since
// its an orchestrated process.  The controller that handles deletion must
// query the namespace for all existing content, and then delete each piece
// of content in turn.  As the API surface grows to add more KIND objects
// that could exist in a Namespace, the number of calls that the namespace
// controller must orchestrate grows since it must LIST, DELETE (1x1) each
// KIND.
// There is work underway to improve this, but it's
// most likely not going to get significantly better until etcd v3.
// Going back to this test, this test generates 100 Namespace objects, and then
// rapidly deletes all of them.  This causes the NamespaceController to observe
// and attempt to process a large number of deletes concurrently.  In effect,
// it's like running 100 traditional e2e tests in parallel.  If the namespace
// controller orchestrating deletes is slowed down deleting another test's
// content then this test may fail.  Since the goal of this test is to soak
// Namespace creation, and soak Namespace deletion, its not appropriate to
// further soak the cluster with other parallel Namespace deletion activities
// that each have a variable amount of content in the associated Namespace.
// When run in [Serial] this test appears to delete Namespace objects at a
// rate of approximately 1 per second.
var _ = SIGDescribe("Namespaces [Serial]", func() {

	f := framework.NewDefaultFramework("namespaces")

	/*
		Testname: namespace-deletion-removes-pods
		Description: Ensure that if a namespace is deleted then all pods are removed from that namespace.
	*/
	framework.ConformanceIt("should ensure that all pods are removed when a namespace is deleted",
		func() { ensurePodsAreRemovedWhenNamespaceIsDeleted(f) })

	/*
		Testname: namespace-deletion-removes-services
		Description: Ensure that if a namespace is deleted then all services are removed from that namespace.
	*/
	framework.ConformanceIt("should ensure that all services are removed when a namespace is deleted",
		func() { ensureServicesAreRemovedWhenNamespaceIsDeleted(f) })

	ginkgo.It("should delete fast enough (90 percent of 100 namespaces in 150 seconds)",
		func() { extinguish(f, 100, 10, 150) })

	// On hold until etcd3; see #7372
	ginkgo.It("should always delete fast (ALL of 100 namespaces in 150 seconds) [Feature:ComprehensiveNamespaceDraining]",
		func() { extinguish(f, 100, 0, 150) })

	/*
	   Release : v1.18
	   Testname: Namespace patching
	   Description: A Namespace is created.
	   The Namespace is patched.
	   The Namespace and MUST now include the new Label.
	*/
	framework.ConformanceIt("should patch a Namespace", func() {
		ginkgo.By("creating a Namespace")
		namespaceName := "nspatchtest-" + string(uuid.NewUUID())
		ns, err := f.CreateNamespace(namespaceName, nil)
		framework.ExpectNoError(err, "failed creating Namespace")
		namespaceName = ns.ObjectMeta.Name

		ginkgo.By("patching the Namespace")
		nspatch, err := json.Marshal(map[string]interface{}{
			"metadata": map[string]interface{}{
				"labels": map[string]string{"testLabel": "testValue"},
			},
		})
		framework.ExpectNoError(err, "failed to marshal JSON patch data")
		_, err = f.ClientSet.CoreV1().Namespaces().Patch(context.TODO(), namespaceName, types.StrategicMergePatchType, []byte(nspatch), metav1.PatchOptions{})
		framework.ExpectNoError(err, "failed to patch Namespace")

		ginkgo.By("get the Namespace and ensuring it has the label")
		namespace, err := f.ClientSet.CoreV1().Namespaces().Get(context.TODO(), namespaceName, metav1.GetOptions{})
		framework.ExpectNoError(err, "failed to get Namespace")
		framework.ExpectEqual(namespace.ObjectMeta.Labels["testLabel"], "testValue", "namespace not patched")
	})

})
<commit_msg>Apimachinery test: Fix date race<commit_after>/*
Copyright 2014 The Kubernetes Authors.

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

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

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

package apimachinery

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

	"k8s.io/api/core/v1"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/intstr"
	"k8s.io/apimachinery/pkg/util/uuid"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/kubernetes/test/e2e/framework"
	e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
	imageutils "k8s.io/kubernetes/test/utils/image"

	"github.com/onsi/ginkgo"
	"k8s.io/apimachinery/pkg/types"
)

func extinguish(f *framework.Framework, totalNS int, maxAllowedAfterDel int, maxSeconds int) {
	var err error

	ginkgo.By("Creating testing namespaces")
	wg := &sync.WaitGroup{}
	wg.Add(totalNS)
	for n := 0; n < totalNS; n++ {
		go func(n int) {
			defer wg.Done()
			defer ginkgo.GinkgoRecover()
			ns := fmt.Sprintf("nslifetest-%v", n)
			_, err := f.CreateNamespace(ns, nil)
			framework.ExpectNoError(err, "failed to create namespace: %s", ns)
		}(n)
	}
	wg.Wait()

	//Wait 10 seconds, then SEND delete requests for all the namespaces.
	ginkgo.By("Waiting 10 seconds")
	time.Sleep(time.Duration(10 * time.Second))
	deleteFilter := []string{"nslifetest"}
	deleted, err := framework.DeleteNamespaces(f.ClientSet, deleteFilter, nil /* skipFilter */)
	framework.ExpectNoError(err, "failed to delete namespace(s) containing: %s", deleteFilter)
	framework.ExpectEqual(len(deleted), totalNS)

	ginkgo.By("Waiting for namespaces to vanish")
	//Now POLL until all namespaces have been eradicated.
	framework.ExpectNoError(wait.Poll(2*time.Second, time.Duration(maxSeconds)*time.Second,
		func() (bool, error) {
			var cnt = 0
			nsList, err := f.ClientSet.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{})
			if err != nil {
				return false, err
			}
			for _, item := range nsList.Items {
				if strings.Contains(item.Name, "nslifetest") {
					cnt++
				}
			}
			if cnt > maxAllowedAfterDel {
				framework.Logf("Remaining namespaces : %v", cnt)
				return false, nil
			}
			return true, nil
		}))
}

func ensurePodsAreRemovedWhenNamespaceIsDeleted(f *framework.Framework) {
	ginkgo.By("Creating a test namespace")
	namespaceName := "nsdeletetest"
	namespace, err := f.CreateNamespace(namespaceName, nil)
	framework.ExpectNoError(err, "failed to create namespace: %s", namespaceName)

	ginkgo.By("Waiting for a default service account to be provisioned in namespace")
	err = framework.WaitForDefaultServiceAccountInNamespace(f.ClientSet, namespace.Name)
	framework.ExpectNoError(err, "failure while waiting for a default service account to be provisioned in namespace: %s", namespace.Name)

	ginkgo.By("Creating a pod in the namespace")
	podName := "test-pod"
	pod := &v1.Pod{
		ObjectMeta: metav1.ObjectMeta{
			Name: podName,
		},
		Spec: v1.PodSpec{
			Containers: []v1.Container{
				{
					Name:  "nginx",
					Image: imageutils.GetPauseImageName(),
				},
			},
		},
	}
	pod, err = f.ClientSet.CoreV1().Pods(namespace.Name).Create(context.TODO(), pod, metav1.CreateOptions{})
	framework.ExpectNoError(err, "failed to create pod %s in namespace: %s", podName, namespace.Name)

	ginkgo.By("Waiting for the pod to have running status")
	framework.ExpectNoError(e2epod.WaitForPodRunningInNamespace(f.ClientSet, pod))

	ginkgo.By("Deleting the namespace")
	err = f.ClientSet.CoreV1().Namespaces().Delete(context.TODO(), namespace.Name, metav1.DeleteOptions{})
	framework.ExpectNoError(err, "failed to delete namespace: %s", namespace.Name)

	ginkgo.By("Waiting for the namespace to be removed.")
	maxWaitSeconds := int64(60) + *pod.Spec.TerminationGracePeriodSeconds
	framework.ExpectNoError(wait.Poll(1*time.Second, time.Duration(maxWaitSeconds)*time.Second,
		func() (bool, error) {
			_, err = f.ClientSet.CoreV1().Namespaces().Get(context.TODO(), namespace.Name, metav1.GetOptions{})
			if err != nil && apierrors.IsNotFound(err) {
				return true, nil
			}
			return false, nil
		}))

	ginkgo.By("Recreating the namespace")
	namespace, err = f.CreateNamespace(namespaceName, nil)
	framework.ExpectNoError(err, "failed to create namespace: %s", namespaceName)

	ginkgo.By("Verifying there are no pods in the namespace")
	_, err = f.ClientSet.CoreV1().Pods(namespace.Name).Get(context.TODO(), pod.Name, metav1.GetOptions{})
	framework.ExpectError(err, "failed to get pod %s in namespace: %s", pod.Name, namespace.Name)
}

func ensureServicesAreRemovedWhenNamespaceIsDeleted(f *framework.Framework) {
	var err error

	ginkgo.By("Creating a test namespace")
	namespaceName := "nsdeletetest"
	namespace, err := f.CreateNamespace(namespaceName, nil)
	framework.ExpectNoError(err, "failed to create namespace: %s", namespaceName)

	ginkgo.By("Waiting for a default service account to be provisioned in namespace")
	err = framework.WaitForDefaultServiceAccountInNamespace(f.ClientSet, namespace.Name)
	framework.ExpectNoError(err, "failure while waiting for a default service account to be provisioned in namespace: %s", namespace.Name)

	ginkgo.By("Creating a service in the namespace")
	serviceName := "test-service"
	labels := map[string]string{
		"foo": "bar",
		"baz": "blah",
	}
	service := &v1.Service{
		ObjectMeta: metav1.ObjectMeta{
			Name: serviceName,
		},
		Spec: v1.ServiceSpec{
			Selector: labels,
			Ports: []v1.ServicePort{{
				Port:       80,
				TargetPort: intstr.FromInt(80),
			}},
		},
	}
	service, err = f.ClientSet.CoreV1().Services(namespace.Name).Create(context.TODO(), service, metav1.CreateOptions{})
	framework.ExpectNoError(err, "failed to create service %s in namespace %s", serviceName, namespace.Name)

	ginkgo.By("Deleting the namespace")
	err = f.ClientSet.CoreV1().Namespaces().Delete(context.TODO(), namespace.Name, metav1.DeleteOptions{})
	framework.ExpectNoError(err, "failed to delete namespace: %s", namespace.Name)

	ginkgo.By("Waiting for the namespace to be removed.")
	maxWaitSeconds := int64(60)
	framework.ExpectNoError(wait.Poll(1*time.Second, time.Duration(maxWaitSeconds)*time.Second,
		func() (bool, error) {
			_, err = f.ClientSet.CoreV1().Namespaces().Get(context.TODO(), namespace.Name, metav1.GetOptions{})
			if err != nil && apierrors.IsNotFound(err) {
				return true, nil
			}
			return false, nil
		}))

	ginkgo.By("Recreating the namespace")
	namespace, err = f.CreateNamespace(namespaceName, nil)
	framework.ExpectNoError(err, "failed to create namespace: %s", namespaceName)

	ginkgo.By("Verifying there is no service in the namespace")
	_, err = f.ClientSet.CoreV1().Services(namespace.Name).Get(context.TODO(), service.Name, metav1.GetOptions{})
	framework.ExpectError(err, "failed to get service %s in namespace: %s", service.Name, namespace.Name)
}

// This test must run [Serial] due to the impact of running other parallel
// tests can have on its performance.  Each test that follows the common
// test framework follows this pattern:
//   1. Create a Namespace
//   2. Do work that generates content in that namespace
//   3. Delete a Namespace
// Creation of a Namespace is non-trivial since it requires waiting for a
// ServiceAccount to be generated.
// Deletion of a Namespace is non-trivial and performance intensive since
// its an orchestrated process.  The controller that handles deletion must
// query the namespace for all existing content, and then delete each piece
// of content in turn.  As the API surface grows to add more KIND objects
// that could exist in a Namespace, the number of calls that the namespace
// controller must orchestrate grows since it must LIST, DELETE (1x1) each
// KIND.
// There is work underway to improve this, but it's
// most likely not going to get significantly better until etcd v3.
// Going back to this test, this test generates 100 Namespace objects, and then
// rapidly deletes all of them.  This causes the NamespaceController to observe
// and attempt to process a large number of deletes concurrently.  In effect,
// it's like running 100 traditional e2e tests in parallel.  If the namespace
// controller orchestrating deletes is slowed down deleting another test's
// content then this test may fail.  Since the goal of this test is to soak
// Namespace creation, and soak Namespace deletion, its not appropriate to
// further soak the cluster with other parallel Namespace deletion activities
// that each have a variable amount of content in the associated Namespace.
// When run in [Serial] this test appears to delete Namespace objects at a
// rate of approximately 1 per second.
var _ = SIGDescribe("Namespaces [Serial]", func() {

	f := framework.NewDefaultFramework("namespaces")

	/*
		Testname: namespace-deletion-removes-pods
		Description: Ensure that if a namespace is deleted then all pods are removed from that namespace.
	*/
	framework.ConformanceIt("should ensure that all pods are removed when a namespace is deleted",
		func() { ensurePodsAreRemovedWhenNamespaceIsDeleted(f) })

	/*
		Testname: namespace-deletion-removes-services
		Description: Ensure that if a namespace is deleted then all services are removed from that namespace.
	*/
	framework.ConformanceIt("should ensure that all services are removed when a namespace is deleted",
		func() { ensureServicesAreRemovedWhenNamespaceIsDeleted(f) })

	ginkgo.It("should delete fast enough (90 percent of 100 namespaces in 150 seconds)",
		func() { extinguish(f, 100, 10, 150) })

	// On hold until etcd3; see #7372
	ginkgo.It("should always delete fast (ALL of 100 namespaces in 150 seconds) [Feature:ComprehensiveNamespaceDraining]",
		func() { extinguish(f, 100, 0, 150) })

	/*
	   Release : v1.18
	   Testname: Namespace patching
	   Description: A Namespace is created.
	   The Namespace is patched.
	   The Namespace and MUST now include the new Label.
	*/
	framework.ConformanceIt("should patch a Namespace", func() {
		ginkgo.By("creating a Namespace")
		namespaceName := "nspatchtest-" + string(uuid.NewUUID())
		ns, err := f.CreateNamespace(namespaceName, nil)
		framework.ExpectNoError(err, "failed creating Namespace")
		namespaceName = ns.ObjectMeta.Name

		ginkgo.By("patching the Namespace")
		nspatch, err := json.Marshal(map[string]interface{}{
			"metadata": map[string]interface{}{
				"labels": map[string]string{"testLabel": "testValue"},
			},
		})
		framework.ExpectNoError(err, "failed to marshal JSON patch data")
		_, err = f.ClientSet.CoreV1().Namespaces().Patch(context.TODO(), namespaceName, types.StrategicMergePatchType, []byte(nspatch), metav1.PatchOptions{})
		framework.ExpectNoError(err, "failed to patch Namespace")

		ginkgo.By("get the Namespace and ensuring it has the label")
		namespace, err := f.ClientSet.CoreV1().Namespaces().Get(context.TODO(), namespaceName, metav1.GetOptions{})
		framework.ExpectNoError(err, "failed to get Namespace")
		framework.ExpectEqual(namespace.ObjectMeta.Labels["testLabel"], "testValue", "namespace not patched")
	})

})
<|endoftext|>


<commit_before>package operators

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

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

	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/wait"
	e2e "k8s.io/kubernetes/test/e2e/framework"
)

var _ = g.Describe("[Feature:Platform] Managed cluster should", func() {
	defer g.GinkgoRecover()

	g.It("have no crashlooping pods in core namespaces over two minutes", func() {
		c, err := e2e.LoadClientset()
		o.Expect(err).NotTo(o.HaveOccurred())

		var lastPodsWithProblems []*corev1.Pod
		var lastPending map[string]*corev1.Pod
		wait.PollImmediate(5*time.Second, 2*time.Minute, func() (bool, error) {
			allPods, err := c.CoreV1().Pods("").List(metav1.ListOptions{})
			o.Expect(err).NotTo(o.HaveOccurred())

			var pods []*corev1.Pod
			for i := range allPods.Items {
				pod := &allPods.Items[i]
				if !strings.HasPrefix(pod.Namespace, "openshift-") && !strings.HasPrefix(pod.Namespace, "kube-") {
					continue
				}
				pods = append(pods, pod)
			}

			pending := make(map[string]*corev1.Pod)
			for _, pod := range pods {
				if pod.Status.Phase == corev1.PodPending {
					hasInitContainerRunning := false
					for _, initContainerStatus := range pod.Status.InitContainerStatuses {
						if initContainerStatus.State.Running != nil {
							hasInitContainerRunning = true
							break
						}
					}
					if !hasInitContainerRunning {
						pending[fmt.Sprintf("%s/%s", pod.Namespace, pod.Name)] = pod
					}
				}
			}
			lastPending = pending

			var podsWithProblems []*corev1.Pod
			var names []string
			for _, pod := range pods {
				if pod.Status.Phase == corev1.PodSucceeded {
					continue
				}
				switch {
				case hasCreateContainerError(pod):
				case hasImagePullError(pod):
				case isCrashLooping(pod):
				case hasExcessiveRestarts(pod):
				case hasFailingContainer(pod):
				default:
					continue
				}
				names = append(names, fmt.Sprintf("%s/%s", pod.Namespace, pod.Name))
				podsWithProblems = append(podsWithProblems, pod)
			}
			if len(names) > 0 {
				e2e.Logf("Some pods in error: %s", strings.Join(names, ", "))
			}
			lastPodsWithProblems = podsWithProblems
			return false, nil
		})
		var msg []string
		ns := make(map[string]struct{})
		for _, pod := range lastPodsWithProblems {
			delete(lastPending, fmt.Sprintf("%s/%s", pod.Namespace, pod.Name))
			if _, ok := ns[pod.Namespace]; !ok {
				e2e.DumpEventsInNamespace(func(opts metav1.ListOptions, ns string) (*corev1.EventList, error) {
					return c.CoreV1().Events(ns).List(opts)
				}, pod.Namespace)
				ns[pod.Namespace] = struct{}{}
			}
			status, _ := json.MarshalIndent(pod.Status, "", "  ")
			e2e.Logf("Pod status %s/%s:\n%s", pod.Namespace, pod.Name, string(status))
			msg = append(msg, fmt.Sprintf("Pod %s/%s is not healthy: %v", pod.Namespace, pod.Name, pod.Status.Message))
		}

		for _, pod := range lastPending {
			if strings.HasPrefix(pod.Name, "must-gather-") {
				e2e.Logf("Pod status %s/%s ignored for being pending", pod.Namespace, pod.Name)
				continue
			}
			if _, ok := ns[pod.Namespace]; !ok {
				e2e.DumpEventsInNamespace(func(opts metav1.ListOptions, ns string) (*corev1.EventList, error) {
					return c.CoreV1().Events(ns).List(opts)
				}, pod.Namespace)
				ns[pod.Namespace] = struct{}{}
			}
			status, _ := json.MarshalIndent(pod.Status, "", "  ")
			e2e.Logf("Pod status %s/%s:\n%s", pod.Namespace, pod.Name, string(status))
			if len(pod.Status.Message) == 0 {
				pod.Status.Message = "unknown error"
			}
			msg = append(msg, fmt.Sprintf("Pod %s/%s was pending entire time: %v", pod.Namespace, pod.Name, pod.Status.Message))
		}

		o.Expect(msg).To(o.BeEmpty())
	})
})

func hasCreateContainerError(pod *corev1.Pod) bool {
	for _, status := range append(append([]corev1.ContainerStatus{}, pod.Status.InitContainerStatuses...), pod.Status.ContainerStatuses...) {
		if status.State.Waiting != nil {
			if status.State.Waiting.Reason == "CreateContainerError" {
				pod.Status.Message = status.State.Waiting.Message
				if len(pod.Status.Message) == 0 {
					pod.Status.Message = fmt.Sprintf("container %s can't be created", status.Name)
				}
				return true
			}
		}
	}
	return false
}

func hasImagePullError(pod *corev1.Pod) bool {
	for _, status := range append(append([]corev1.ContainerStatus{}, pod.Status.InitContainerStatuses...), pod.Status.ContainerStatuses...) {
		if status.State.Waiting != nil {
			if reason := status.State.Waiting.Reason; reason == "ErrImagePull" || reason == "ImagePullBackOff" {
				pod.Status.Message = status.State.Waiting.Message
				if len(pod.Status.Message) == 0 {
					pod.Status.Message = fmt.Sprintf("container %s can't pull image", status.Name)
				}
				return true
			}
		}
	}
	return false
}

func hasFailingContainer(pod *corev1.Pod) bool {
	for _, status := range append(append([]corev1.ContainerStatus{}, pod.Status.InitContainerStatuses...), pod.Status.ContainerStatuses...) {
		if status.State.Terminated != nil && status.State.Terminated.ExitCode != 0 {
			pod.Status.Message = status.State.Terminated.Message
			if len(pod.Status.Message) == 0 {
				pod.Status.Message = fmt.Sprintf("container %s exited with non-zero exit code", status.Name)
			}
			return true
		}
	}
	return pod.Status.Phase == corev1.PodFailed
}

func isCrashLooping(pod *corev1.Pod) bool {
	for _, status := range append(append([]corev1.ContainerStatus{}, pod.Status.InitContainerStatuses...), pod.Status.ContainerStatuses...) {
		if status.State.Waiting != nil {
			if reason := status.State.Waiting.Reason; reason == "CrashLoopBackOff" {
				pod.Status.Message = status.State.Waiting.Message
				if len(pod.Status.Message) == 0 {
					pod.Status.Message = fmt.Sprintf("container %s is crashlooping", status.Name)
				}
				return true
			}
		}
	}
	return false
}

func hasExcessiveRestarts(pod *corev1.Pod) bool {
	for _, status := range append(append([]corev1.ContainerStatus{}, pod.Status.InitContainerStatuses...), pod.Status.ContainerStatuses...) {
		if status.RestartCount > 5 {
			pod.Status.Message = fmt.Sprintf("container %s has restarted more than 5 times", status.Name)
			return true
		}
	}
	return false
}
<commit_msg>lookout for crash looping pods in every iteration<commit_after>package operators

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

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

	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/wait"
	e2e "k8s.io/kubernetes/test/e2e/framework"
)

var _ = g.Describe("[Feature:Platform] Managed cluster should", func() {
	defer g.GinkgoRecover()

	g.It("have no crashlooping pods in core namespaces over two minutes", func() {
		c, err := e2e.LoadClientset()
		o.Expect(err).NotTo(o.HaveOccurred())

		podsWithProblems := make(map[string]*corev1.Pod)
		var lastPending map[string]*corev1.Pod
		wait.PollImmediate(5*time.Second, 2*time.Minute, func() (bool, error) {
			allPods, err := c.CoreV1().Pods("").List(metav1.ListOptions{})
			o.Expect(err).NotTo(o.HaveOccurred())

			var pods []*corev1.Pod
			for i := range allPods.Items {
				pod := &allPods.Items[i]
				if !strings.HasPrefix(pod.Namespace, "openshift-") && !strings.HasPrefix(pod.Namespace, "kube-") {
					continue
				}
				pods = append(pods, pod)
			}

			pending := make(map[string]*corev1.Pod)
			for _, pod := range pods {
				if pod.Status.Phase == corev1.PodPending {
					hasInitContainerRunning := false
					for _, initContainerStatus := range pod.Status.InitContainerStatuses {
						if initContainerStatus.State.Running != nil {
							hasInitContainerRunning = true
							break
						}
					}
					if !hasInitContainerRunning {
						pending[fmt.Sprintf("%s/%s", pod.Namespace, pod.Name)] = pod
					}
				}
			}
			lastPending = pending

			var names []string
			for _, pod := range pods {
				if pod.Status.Phase == corev1.PodSucceeded {
					continue
				}
				switch {
				case hasCreateContainerError(pod):
				case hasImagePullError(pod):
				case isCrashLooping(pod):
				case hasExcessiveRestarts(pod):
				case hasFailingContainer(pod):
				default:
					continue
				}
				key := fmt.Sprintf("%s/%s", pod.Namespace, pod.Name)
				names = append(names, key)
				podsWithProblems[key] = pod
			}
			if len(names) > 0 {
				e2e.Logf("Some pods in error: %s", strings.Join(names, ", "))
			}
			return false, nil
		})
		var msg []string
		ns := make(map[string]struct{})
		for _, pod := range podsWithProblems {
			delete(lastPending, fmt.Sprintf("%s/%s", pod.Namespace, pod.Name))
			if _, ok := ns[pod.Namespace]; !ok {
				e2e.DumpEventsInNamespace(func(opts metav1.ListOptions, ns string) (*corev1.EventList, error) {
					return c.CoreV1().Events(ns).List(opts)
				}, pod.Namespace)
				ns[pod.Namespace] = struct{}{}
			}
			status, _ := json.MarshalIndent(pod.Status, "", "  ")
			e2e.Logf("Pod status %s/%s:\n%s", pod.Namespace, pod.Name, string(status))
			msg = append(msg, fmt.Sprintf("Pod %s/%s is not healthy: %v", pod.Namespace, pod.Name, pod.Status.Message))
		}

		for _, pod := range lastPending {
			if strings.HasPrefix(pod.Name, "must-gather-") {
				e2e.Logf("Pod status %s/%s ignored for being pending", pod.Namespace, pod.Name)
				continue
			}
			if _, ok := ns[pod.Namespace]; !ok {
				e2e.DumpEventsInNamespace(func(opts metav1.ListOptions, ns string) (*corev1.EventList, error) {
					return c.CoreV1().Events(ns).List(opts)
				}, pod.Namespace)
				ns[pod.Namespace] = struct{}{}
			}
			status, _ := json.MarshalIndent(pod.Status, "", "  ")
			e2e.Logf("Pod status %s/%s:\n%s", pod.Namespace, pod.Name, string(status))
			if len(pod.Status.Message) == 0 {
				pod.Status.Message = "unknown error"
			}
			msg = append(msg, fmt.Sprintf("Pod %s/%s was pending entire time: %v", pod.Namespace, pod.Name, pod.Status.Message))
		}

		o.Expect(msg).To(o.BeEmpty())
	})
})

func hasCreateContainerError(pod *corev1.Pod) bool {
	for _, status := range append(append([]corev1.ContainerStatus{}, pod.Status.InitContainerStatuses...), pod.Status.ContainerStatuses...) {
		if status.State.Waiting != nil {
			if status.State.Waiting.Reason == "CreateContainerError" {
				pod.Status.Message = status.State.Waiting.Message
				if len(pod.Status.Message) == 0 {
					pod.Status.Message = fmt.Sprintf("container %s can't be created", status.Name)
				}
				return true
			}
		}
	}
	return false
}

func hasImagePullError(pod *corev1.Pod) bool {
	for _, status := range append(append([]corev1.ContainerStatus{}, pod.Status.InitContainerStatuses...), pod.Status.ContainerStatuses...) {
		if status.State.Waiting != nil {
			if reason := status.State.Waiting.Reason; reason == "ErrImagePull" || reason == "ImagePullBackOff" {
				pod.Status.Message = status.State.Waiting.Message
				if len(pod.Status.Message) == 0 {
					pod.Status.Message = fmt.Sprintf("container %s can't pull image", status.Name)
				}
				return true
			}
		}
	}
	return false
}

func hasFailingContainer(pod *corev1.Pod) bool {
	for _, status := range append(append([]corev1.ContainerStatus{}, pod.Status.InitContainerStatuses...), pod.Status.ContainerStatuses...) {
		if status.State.Terminated != nil && status.State.Terminated.ExitCode != 0 {
			pod.Status.Message = status.State.Terminated.Message
			if len(pod.Status.Message) == 0 {
				pod.Status.Message = fmt.Sprintf("container %s exited with non-zero exit code", status.Name)
			}
			return true
		}
	}
	return pod.Status.Phase == corev1.PodFailed
}

func isCrashLooping(pod *corev1.Pod) bool {
	for _, status := range append(append([]corev1.ContainerStatus{}, pod.Status.InitContainerStatuses...), pod.Status.ContainerStatuses...) {
		if status.State.Waiting != nil {
			if reason := status.State.Waiting.Reason; reason == "CrashLoopBackOff" {
				pod.Status.Message = status.State.Waiting.Message
				if len(pod.Status.Message) == 0 {
					pod.Status.Message = fmt.Sprintf("container %s is crashlooping", status.Name)
				}
				return true
			}
		}
	}
	return false
}

func hasExcessiveRestarts(pod *corev1.Pod) bool {
	for _, status := range append(append([]corev1.ContainerStatus{}, pod.Status.InitContainerStatuses...), pod.Status.ContainerStatuses...) {
		if status.RestartCount > 5 {
			pod.Status.Message = fmt.Sprintf("container %s has restarted more than 5 times", status.Name)
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package builder

import (
	. "atlantis/common"
	"errors"
	"github.com/ooyala/go-jenkins-cli"
	"io"
)

type JenkinsBuilder struct {
	URL string
}

func NewJenkinsBuilder(url string) *JenkinsBuilder {
	return &JenkinsBuilder{URL: url}
}

func (b *JenkinsBuilder) Build(t *Task, repo, root, sha string) (io.ReadCloser, error) {
	jenkins.JENKINS_SERVER = b.URL
	t.LogStatus("Triggering Jenkins Build")
	info, err := jenkins.DoBuild("atlantis-build", "app_repo="+repo+"&app_root="+root+"&app_commit="+sha, true)
	if err != nil {
		return nil, errors.New("Jenkins Error: " + err.Error())
	}
	if info.Result != "SUCCESS" {
		return nil, errors.New("Jenkins Build " + info.Url + " " + info.Result)
	}
	return jenkins.GetArtifactReader("atlantis-build", info.Id, ManifestFile)
}
<commit_msg>make job name configurable<commit_after>package builder

import (
	. "atlantis/common"
	"errors"
	"github.com/ooyala/go-jenkins-cli"
	"io"
)

type JenkinsBuilder struct {
	URL string
	Job string
}

func NewJenkinsBuilder(url, job string) *JenkinsBuilder {
	return &JenkinsBuilder{URL: url, Job: job}
}

func (b *JenkinsBuilder) Build(t *Task, repo, root, sha string) (io.ReadCloser, error) {
	jenkins.JENKINS_SERVER = b.URL
	t.LogStatus("Triggering Jenkins Build")
	info, err := jenkins.DoBuild(b.Job, "app_repo="+repo+"&app_root="+root+"&app_commit="+sha, true)
	if err != nil {
		return nil, errors.New("Jenkins Error: " + err.Error())
	}
	if info.Result != "SUCCESS" {
		return nil, errors.New("Jenkins Build " + info.Url + " " + info.Result)
	}
	return jenkins.GetArtifactReader(b.Job, info.Id, ManifestFile)
}
<|endoftext|>


<commit_before>package stripe

import (
	"encoding/json"
	"fmt"
	"net/url"
	"strconv"
)

type LegalEntityType string

type IdentityVerificationStatus string

type Interval string

const (
	Individual  LegalEntityType = "individual"
	SoleProp    LegalEntityType = "sole_prop"
	LLC         LegalEntityType = "llc"
	Partnership LegalEntityType = "partnership"
	Corp        LegalEntityType = "corporation"

	IdentityVerificationWaiting  IdentityVerificationStatus = "waiting"
	IdentityVerificationPending  IdentityVerificationStatus = "pending"
	IdentityVerificationVerified IdentityVerificationStatus = "verified"
	IdentityVerificationFailed   IdentityVerificationStatus = "failed"

	Manual Interval = "manual"
	Day    Interval = "daily"
	Week   Interval = "weekly"
	Month  Interval = "monthly"
)

type AccountParams struct {
	Params
	Country, Email, DefaultCurrency, Statement, BusinessName, SupportPhone string
	LegalEntity                                                            *LegalEntity
	Managed                                                                bool
}

type AccountListParams struct {
	ListParams
}

// Account is the resource representing youe Stripe account.
// For more details see https://stripe.com/docs/api/#account.
type Account struct {
	ID             string `json:"id"`
	ChargesEnabled bool   `json:"charges_enabled"`
	Country        string `json:"country"`
	// Currencies is the list of supported currencies.
	Currencies       []string `json:"currencies_supported"`
	DefaultCurrency  string   `json:"default_currency"`
	DetailsSubmitted bool     `json:"details_submitted"`
	TransfersEnabled bool     `json:"transfers_enabled"`
	Name             string   `json:"display_name"`
	Email            string   `json:"email"`
	Statement        string   `json:"statement_descriptor"`
	Timezone         string   `json:"timezone"`
	BusinessName     string   `json:"business_name"`
	SupportPhone     string   `json:"support_phone"`
	ProductDesc      string   `json:"product_description"`
	Managed          bool     `json:"managed"`
	Keys             *struct {
		Secret  string `json:"secret"`
		Publish string `json:"publishable"`
	} `json:"keys"`
	Verification *struct {
		Fields    []string `json:"fields_needed"`
		Due       *int64   `json:"due_by"`
		Contacted bool     `json:"contacted"`
	} `json:"verification"`
	LegalEntity      *LegalEntity      `json:"legal_entity"`
	TransferSchedule *TransferSchedule `json:"transfer_schedule"`
}

type LegalEntity struct {
	Type             LegalEntityType      `json:"type"`
	BusinessName     string               `json:"business_name"`
	Address          Address              `json:"address"`
	First            string               `json:"first_name"`
	Last             string               `json:"last_name"`
	PersonalAddress  Address              `json:"personal_address"`
	DOB              DOB                  `json:"dob"`
	AdditionalOwners []Owner              `json:"additional_owners"`
	Verification     IdentityVerification `json:"verification"`
	SSN              string               `json:"ssn_last_4"`
	PersonalID       string               `json:"personal_id_number"`
	BusinessTaxID    string               `json:"business_tax_id"`
	BusinessVatID    string               `json:"business_vat_id"`
}

type Address struct {
	Line1   string `json:"line1"`
	Line2   string `json:"line2"`
	City    string `json:"city"`
	State   string `json:"state"`
	Zip     string `json:"postal_code"`
	Country string `json:"country"`
}

type DOB struct {
	Day   int `json:"day"`
	Month int `json:"month"`
	Year  int `json:"year"`
}

type Owner struct {
	First        string               `json:"first_name"`
	Last         string               `json:"last_name"`
	DOB          DOB                  `json:"dob"`
	Address      Address              `json:"address"`
	Verification IdentityVerification `json:"verification"`
}

type IdentityVerification struct {
	Status   IdentityVerificationStatus `json:"status"`
	Document *struct {
		ID      string `json:"id"`
		Created int64  `json:"created"`
		Size    int64  `json:"size"`
	} `json:"document"`
	Details *string `json:"details"`
}

type TransferSchedule struct {
	Delay    int      `json:"delay_days"`
	Interval Interval `json:"interval"`
}

type AccountList struct {
	ListMeta
	Values []*Account `json:"data"`
}

func (a *AccountParams) AppendDetails(values *url.Values) {
	if a.LegalEntity != nil {
		values.Add("legal_entity[type]", string(a.LegalEntity.Type))

		if len(a.LegalEntity.BusinessName) > 0 {
			values.Add("legal_entity[business_name]", a.LegalEntity.BusinessName)
		}

		if len(a.LegalEntity.First) > 0 {
			values.Add("legal_entity[first_name]", a.LegalEntity.First)
		}

		if len(a.LegalEntity.Last) > 0 {
			values.Add("legal_entity[last_name]", a.LegalEntity.Last)
		}

		values.Add("legal_entity[dob][day]", strconv.Itoa(a.LegalEntity.DOB.Day))
		values.Add("legal_entity[dob][month]", strconv.Itoa(a.LegalEntity.DOB.Month))
		values.Add("legal_entity[dob][year]", strconv.Itoa(a.LegalEntity.DOB.Year))

		if len(a.LegalEntity.SSN) > 0 {
			values.Add("legal_entity[ssn_last_4]", a.LegalEntity.SSN)
		}

		if len(a.LegalEntity.PersonalID) > 0 {
			values.Add("legal_entity[personal_id_number]", a.LegalEntity.PersonalID)
		}

		if len(a.LegalEntity.BusinessTaxID) > 0 {
			values.Add("legal_entity[business_tax_id]", a.LegalEntity.BusinessTaxID)
		}

		if len(a.LegalEntity.BusinessVatID) > 0 {
			values.Add("legal_entity[business_vat_id]", a.LegalEntity.BusinessVatID)
		}

		if len(a.LegalEntity.Address.Line1) > 0 {
			values.Add("legal_entity[address][line1]", a.LegalEntity.Address.Line1)
		}

		if len(a.LegalEntity.Address.Line2) > 0 {
			values.Add("legal_entity[address][line2]", a.LegalEntity.Address.Line2)
		}

		if len(a.LegalEntity.Address.City) > 0 {
			values.Add("legal_entity[address][city]", a.LegalEntity.Address.City)
		}

		if len(a.LegalEntity.Address.State) > 0 {
			values.Add("legal_entity[address][state]", a.LegalEntity.Address.State)
		}

		if len(a.LegalEntity.Address.Zip) > 0 {
			values.Add("legal_entity[address][postal_code]", a.LegalEntity.Address.Zip)
		}

		if len(a.LegalEntity.Address.Country) > 0 {
			values.Add("legal_entity[address][country]", a.LegalEntity.Address.Country)
		}

		if len(a.LegalEntity.PersonalAddress.Line1) > 0 {
			values.Add("legal_entity[personal_address][line1]", a.LegalEntity.PersonalAddress.Line1)
		}

		if len(a.LegalEntity.PersonalAddress.Line2) > 0 {
			values.Add("legal_entity[personal_address][line2]", a.LegalEntity.PersonalAddress.Line2)
		}

		if len(a.LegalEntity.PersonalAddress.City) > 0 {
			values.Add("legal_entity[personal_address][city]", a.LegalEntity.PersonalAddress.City)
		}

		if len(a.LegalEntity.PersonalAddress.State) > 0 {
			values.Add("legal_entity[personal_address][state]", a.LegalEntity.PersonalAddress.State)
		}

		if len(a.LegalEntity.PersonalAddress.Zip) > 0 {
			values.Add("legal_entity[personal_address][postal_code]", a.LegalEntity.PersonalAddress.Zip)
		}

		if len(a.LegalEntity.PersonalAddress.Country) > 0 {
			values.Add("legal_entity[personal_address][country]", a.LegalEntity.PersonalAddress.Country)
		}

		for i, owner := range a.LegalEntity.AdditionalOwners {
			if len(owner.First) > 0 {
				values.Add(fmt.Sprintf("legal_entity[additional_owners][%v][first_name]", i), owner.First)
			}

			if len(owner.Last) > 0 {
				values.Add(fmt.Sprintf("legal_entity[additional_owners][%v][last_name]", i), owner.Last)
			}

			values.Add(fmt.Sprintf("legal_entity[additional_owners][%v][dob][day]", i), strconv.Itoa(owner.DOB.Day))
			values.Add(fmt.Sprintf("legal_entity[additional_owners][%v][dob][month]", i), strconv.Itoa(owner.DOB.Month))
			values.Add(fmt.Sprintf("legal_entity[additional_owners][%v][dob][year]", i), strconv.Itoa(owner.DOB.Year))

			if len(owner.Address.Line1) > 0 {
				values.Add(fmt.Sprintf("legal_entity[additional_owners][%v][address][line1]", i), owner.Address.Line1)
			}

			if len(owner.Address.Line2) > 0 {
				values.Add(fmt.Sprintf("legal_entity[additional_owners][%v][address][line2]", i), owner.Address.Line2)
			}

			if len(owner.Address.City) > 0 {
				values.Add(fmt.Sprintf("legal_entity[additional_owners][%v][address][city]", i), owner.Address.City)
			}

			if len(owner.Address.State) > 0 {
				values.Add(fmt.Sprintf("legal_entity[additional_owners][%v][address][state]", i), owner.Address.State)
			}

			if len(owner.Address.Zip) > 0 {
				values.Add(fmt.Sprintf("legal_entity[additional_owners][%v][address][postal_code]", i), owner.Address.Zip)
			}

			if len(owner.Address.Country) > 0 {
				values.Add(fmt.Sprintf("legal_entity[additional_owners][%v][address][country]", i), owner.Address.Country)
			}
		}
	}
}

// UnmarshalJSON handles deserialization of an Account.
// This custom unmarshaling is needed because the resulting
// property may be an id or the full struct if it was expanded.
func (a *Account) UnmarshalJSON(data []byte) error {
	type account Account
	var aa account
	err := json.Unmarshal(data, &aa)

	if err == nil {
		*a = Account(aa)
	} else {
		// the id is surrounded by "\" characters, so strip them
		a.ID = string(data[1 : len(data)-1])
	}

	return nil
}
<commit_msg>address feedback<commit_after>package stripe

import (
	"encoding/json"
	"fmt"
	"net/url"
	"strconv"
)

type LegalEntityType string

type IdentityVerificationStatus string

type Interval string

const (
	Individual LegalEntityType = "individual"
	Corp       LegalEntityType = "corporation"

	IdentityVerificationPending    IdentityVerificationStatus = "pending"
	IdentityVerificationVerified   IdentityVerificationStatus = "verified"
	IdentityVerificationUnverified IdentityVerificationStatus = "unverified"

	Manual Interval = "manual"
	Day    Interval = "daily"
	Week   Interval = "weekly"
	Month  Interval = "monthly"
)

type AccountParams struct {
	Params
	Country, Email, DefaultCurrency, Statement, BusinessName, SupportPhone string
	LegalEntity                                                            *LegalEntity
	Managed                                                                bool
}

type AccountListParams struct {
	ListParams
}

// Account is the resource representing youe Stripe account.
// For more details see https://stripe.com/docs/api/#account.
type Account struct {
	ID             string `json:"id"`
	ChargesEnabled bool   `json:"charges_enabled"`
	Country        string `json:"country"`
	// Currencies is the list of supported currencies.
	Currencies       []string `json:"currencies_supported"`
	DefaultCurrency  string   `json:"default_currency"`
	DetailsSubmitted bool     `json:"details_submitted"`
	TransfersEnabled bool     `json:"transfers_enabled"`
	Name             string   `json:"display_name"`
	Email            string   `json:"email"`
	Statement        string   `json:"statement_descriptor"`
	Timezone         string   `json:"timezone"`
	BusinessName     string   `json:"business_name"`
	SupportPhone     string   `json:"support_phone"`
	ProductDesc      string   `json:"product_description"`
	Managed          bool     `json:"managed"`
	DebitNegativeBal bool     `json:"debit_negative_balances"`
	Keys             *struct {
		Secret  string `json:"secret"`
		Publish string `json:"publishable"`
	} `json:"keys"`
	Verification *struct {
		Fields    []string `json:"fields_needed"`
		Due       *int64   `json:"due_by"`
		Contacted bool     `json:"contacted"`
	} `json:"verification"`
	LegalEntity      *LegalEntity      `json:"legal_entity"`
	TransferSchedule *TransferSchedule `json:"transfer_schedule"`
}

type LegalEntity struct {
	Type             LegalEntityType      `json:"type"`
	BusinessName     string               `json:"business_name"`
	Address          Address              `json:"address"`
	First            string               `json:"first_name"`
	Last             string               `json:"last_name"`
	PersonalAddress  Address              `json:"personal_address"`
	DOB              DOB                  `json:"dob"`
	AdditionalOwners []Owner              `json:"additional_owners"`
	Verification     IdentityVerification `json:"verification"`
	SSN              string               `json:"ssn_last_4"`
	PersonalID       string               `json:"personal_id_number"`
	BusinessTaxID    string               `json:"business_tax_id"`
	BusinessVatID    string               `json:"business_vat_id"`
}

type Address struct {
	Line1   string `json:"line1"`
	Line2   string `json:"line2"`
	City    string `json:"city"`
	State   string `json:"state"`
	Zip     string `json:"postal_code"`
	Country string `json:"country"`
}

type DOB struct {
	Day   int `json:"day"`
	Month int `json:"month"`
	Year  int `json:"year"`
}

type Owner struct {
	First        string               `json:"first_name"`
	Last         string               `json:"last_name"`
	DOB          DOB                  `json:"dob"`
	Address      Address              `json:"address"`
	Verification IdentityVerification `json:"verification"`
}

type IdentityVerification struct {
	Status   IdentityVerificationStatus `json:"status"`
	Document *struct {
		ID      string `json:"id"`
		Created int64  `json:"created"`
		Size    int64  `json:"size"`
	} `json:"document"`
	Details *string `json:"details"`
}

type TransferSchedule struct {
	Delay    int      `json:"delay_days"`
	Interval Interval `json:"interval"`
}

type AccountList struct {
	ListMeta
	Values []*Account `json:"data"`
}

func (a *AccountParams) AppendDetails(values *url.Values) {
	if a.LegalEntity != nil {
		values.Add("legal_entity[type]", string(a.LegalEntity.Type))

		if len(a.LegalEntity.BusinessName) > 0 {
			values.Add("legal_entity[business_name]", a.LegalEntity.BusinessName)
		}

		if len(a.LegalEntity.First) > 0 {
			values.Add("legal_entity[first_name]", a.LegalEntity.First)
		}

		if len(a.LegalEntity.Last) > 0 {
			values.Add("legal_entity[last_name]", a.LegalEntity.Last)
		}

		values.Add("legal_entity[dob][day]", strconv.Itoa(a.LegalEntity.DOB.Day))
		values.Add("legal_entity[dob][month]", strconv.Itoa(a.LegalEntity.DOB.Month))
		values.Add("legal_entity[dob][year]", strconv.Itoa(a.LegalEntity.DOB.Year))

		if len(a.LegalEntity.SSN) > 0 {
			values.Add("legal_entity[ssn_last_4]", a.LegalEntity.SSN)
		}

		if len(a.LegalEntity.PersonalID) > 0 {
			values.Add("legal_entity[personal_id_number]", a.LegalEntity.PersonalID)
		}

		if len(a.LegalEntity.BusinessTaxID) > 0 {
			values.Add("legal_entity[business_tax_id]", a.LegalEntity.BusinessTaxID)
		}

		if len(a.LegalEntity.BusinessVatID) > 0 {
			values.Add("legal_entity[business_vat_id]", a.LegalEntity.BusinessVatID)
		}

		if len(a.LegalEntity.Address.Line1) > 0 {
			values.Add("legal_entity[address][line1]", a.LegalEntity.Address.Line1)
		}

		if len(a.LegalEntity.Address.Line2) > 0 {
			values.Add("legal_entity[address][line2]", a.LegalEntity.Address.Line2)
		}

		if len(a.LegalEntity.Address.City) > 0 {
			values.Add("legal_entity[address][city]", a.LegalEntity.Address.City)
		}

		if len(a.LegalEntity.Address.State) > 0 {
			values.Add("legal_entity[address][state]", a.LegalEntity.Address.State)
		}

		if len(a.LegalEntity.Address.Zip) > 0 {
			values.Add("legal_entity[address][postal_code]", a.LegalEntity.Address.Zip)
		}

		if len(a.LegalEntity.Address.Country) > 0 {
			values.Add("legal_entity[address][country]", a.LegalEntity.Address.Country)
		}

		if len(a.LegalEntity.PersonalAddress.Line1) > 0 {
			values.Add("legal_entity[personal_address][line1]", a.LegalEntity.PersonalAddress.Line1)
		}

		if len(a.LegalEntity.PersonalAddress.Line2) > 0 {
			values.Add("legal_entity[personal_address][line2]", a.LegalEntity.PersonalAddress.Line2)
		}

		if len(a.LegalEntity.PersonalAddress.City) > 0 {
			values.Add("legal_entity[personal_address][city]", a.LegalEntity.PersonalAddress.City)
		}

		if len(a.LegalEntity.PersonalAddress.State) > 0 {
			values.Add("legal_entity[personal_address][state]", a.LegalEntity.PersonalAddress.State)
		}

		if len(a.LegalEntity.PersonalAddress.Zip) > 0 {
			values.Add("legal_entity[personal_address][postal_code]", a.LegalEntity.PersonalAddress.Zip)
		}

		if len(a.LegalEntity.PersonalAddress.Country) > 0 {
			values.Add("legal_entity[personal_address][country]", a.LegalEntity.PersonalAddress.Country)
		}

		for i, owner := range a.LegalEntity.AdditionalOwners {
			if len(owner.First) > 0 {
				values.Add(fmt.Sprintf("legal_entity[additional_owners][%v][first_name]", i), owner.First)
			}

			if len(owner.Last) > 0 {
				values.Add(fmt.Sprintf("legal_entity[additional_owners][%v][last_name]", i), owner.Last)
			}

			values.Add(fmt.Sprintf("legal_entity[additional_owners][%v][dob][day]", i), strconv.Itoa(owner.DOB.Day))
			values.Add(fmt.Sprintf("legal_entity[additional_owners][%v][dob][month]", i), strconv.Itoa(owner.DOB.Month))
			values.Add(fmt.Sprintf("legal_entity[additional_owners][%v][dob][year]", i), strconv.Itoa(owner.DOB.Year))

			if len(owner.Address.Line1) > 0 {
				values.Add(fmt.Sprintf("legal_entity[additional_owners][%v][address][line1]", i), owner.Address.Line1)
			}

			if len(owner.Address.Line2) > 0 {
				values.Add(fmt.Sprintf("legal_entity[additional_owners][%v][address][line2]", i), owner.Address.Line2)
			}

			if len(owner.Address.City) > 0 {
				values.Add(fmt.Sprintf("legal_entity[additional_owners][%v][address][city]", i), owner.Address.City)
			}

			if len(owner.Address.State) > 0 {
				values.Add(fmt.Sprintf("legal_entity[additional_owners][%v][address][state]", i), owner.Address.State)
			}

			if len(owner.Address.Zip) > 0 {
				values.Add(fmt.Sprintf("legal_entity[additional_owners][%v][address][postal_code]", i), owner.Address.Zip)
			}

			if len(owner.Address.Country) > 0 {
				values.Add(fmt.Sprintf("legal_entity[additional_owners][%v][address][country]", i), owner.Address.Country)
			}
		}
	}
}

// UnmarshalJSON handles deserialization of an Account.
// This custom unmarshaling is needed because the resulting
// property may be an id or the full struct if it was expanded.
func (a *Account) UnmarshalJSON(data []byte) error {
	type account Account
	var aa account
	err := json.Unmarshal(data, &aa)

	if err == nil {
		*a = Account(aa)
	} else {
		// the id is surrounded by "\" characters, so strip them
		a.ID = string(data[1 : len(data)-1])
	}

	return nil
}
<|endoftext|>


<commit_before>package generation

import (
	"os"

	"chunkymonkey/chunkstore"
	"chunkymonkey/generation/perlin"
	"chunkymonkey/nbt"
	. "chunkymonkey/types"
)

const SeaLevel = 64

// ChunkData implements chunkstore.IChunkReader.
type ChunkData struct {
	loc        ChunkXz
	blocks     []byte
	blockData  []byte
	blockLight []byte
	skyLight   []byte
	heightMap  []byte
}

func newChunkData(loc ChunkXz) *ChunkData {
	return &ChunkData{
		loc:        loc,
		blocks:     make([]byte, ChunkSizeH*ChunkSizeH*ChunkSizeY),
		blockData:  make([]byte, (ChunkSizeH*ChunkSizeH*ChunkSizeY)>>1),
		skyLight:   make([]byte, (ChunkSizeH*ChunkSizeH*ChunkSizeY)>>1),
		blockLight: make([]byte, (ChunkSizeH*ChunkSizeH*ChunkSizeY)>>1),
		heightMap:  make([]byte, ChunkSizeH*ChunkSizeH),
	}
}

func (data *ChunkData) ChunkLoc() ChunkXz {
	return data.loc
}

func (data *ChunkData) Blocks() []byte {
	return data.blocks
}

func (data *ChunkData) BlockData() []byte {
	return data.blockData
}

func (data *ChunkData) BlockLight() []byte {
	return data.blockLight
}

func (data *ChunkData) SkyLight() []byte {
	return data.skyLight
}

func (data *ChunkData) HeightMap() []byte {
	return data.heightMap
}

func (data *ChunkData) GetRootTag() *nbt.NamedTag {
	return nil
}

// TestGenerator implements chunkstore.IChunkStore.
type TestGenerator struct {
	heightSource ISource
}

func NewTestGenerator(seed int64) *TestGenerator {
	perlin := perlin.NewPerlinNoise(seed)

	return &TestGenerator{
		heightSource: &Sum{
			Inputs: []ISource{
				&Turbulence{
					Dx:     &Scale{50, 1, &Offset{20.1, 0, perlin}},
					Dy:     &Scale{50, 1, &Offset{10.1, 0, perlin}},
					Factor: 50,
					Source: &Scale{
						Wavelength: 200,
						Amplitude:  50,
						Source:     perlin,
					},
				},
				&Turbulence{
					Dx:     &Scale{40, 1, &Offset{20.1, 0, perlin}},
					Dy:     &Scale{40, 1, &Offset{10.1, 0, perlin}},
					Factor: 10,
					Source: &Mult{
						A: &Scale{
							Wavelength: 40,
							Amplitude:  20,
							Source:     perlin,
						},
						// Local steepness.
						B: &Scale{
							Wavelength: 200,
							Amplitude:  1,
							Source:     &Add{perlin, 0.6},
						},
					},
				},
				&Scale{
					Wavelength: 5,
					Amplitude:  2,
					Source:     perlin,
				},
			},
		},
	}
}

func (gen *TestGenerator) LoadChunk(chunkLoc ChunkXz) (reader chunkstore.IChunkReader, err os.Error) {
	baseBlockXyz := chunkLoc.GetChunkCornerBlockXY()

	baseX, baseZ := baseBlockXyz.X, baseBlockXyz.Z

	data := newChunkData(chunkLoc)

	baseIndex := BlockIndex(0)
	heightMapIndex := 0
	for x := 0; x < ChunkSizeH; x++ {
		for z := 0; z < ChunkSizeH; z++ {
			xf, zf := float64(x)+float64(baseX), float64(z)+float64(baseZ)
			height := int(SeaLevel + gen.heightSource.At2d(xf, zf))

			if height < 0 {
				height = 0
			} else if height >= ChunkSizeY {
				height = ChunkSizeY - 1
			}

			skyLightHeight := gen.setBlockStack(
				height,
				data.blocks[baseIndex:baseIndex+ChunkSizeY])

			lightBase := baseIndex >> 1

			gen.setSkyLightStack(
				skyLightHeight,
				data.blocks[baseIndex:baseIndex+ChunkSizeY],
				data.skyLight[lightBase:lightBase+ChunkSizeY/2])

			data.heightMap[heightMapIndex] = byte(skyLightHeight)

			heightMapIndex++
			baseIndex += ChunkSizeY
		}
	}

	return data, nil
}

func (gen *TestGenerator) setBlockStack(height int, blocks []byte) (skyLightHeight int) {
	var topBlockType byte
	if height < SeaLevel+1 {
		skyLightHeight = SeaLevel + 1

		for y := SeaLevel; y > height; y-- {
			blocks[y] = 9 // stationary water
		}
		blocks[height] = 12 // sand
		topBlockType = 12
	} else {

		if height <= SeaLevel+1 {
			blocks[height] = 12 // sand
			topBlockType = 12
		} else {
			blocks[height] = 2 // grass
			topBlockType = 3   // dirt
		}
	}

	for y := height - 1; y > height-3 && y > 0; y-- {
		blocks[y] = topBlockType // dirt
	}
	for y := height - 3; y > 0; y-- {
		blocks[y] = 1 // stone
	}

	if skyLightHeight < 0 {
		skyLightHeight = 0
	}

	return
}

func (gen *TestGenerator) setSkyLightStack(skyLightHeight int, blocks []byte, skyLight []byte) {
	for y := ChunkSizeY - 1; y >= skyLightHeight; y-- {
		BlockIndex(y).SetBlockData(skyLight, 15)
	}

	lightLevel := 15

	for y := skyLightHeight; y >= 0 && lightLevel > 0; y-- {
		// TODO Use real block data in here.
		if blocks[y] == 9 {
			lightLevel -= 3
		} else if blocks[y] == 0 {
			// air
		} else {
			lightLevel -= 15
		}
		if lightLevel < 0 {
			lightLevel = 0
		}

		BlockIndex(y).SetBlockData(skyLight, byte(lightLevel))
	}
}
<commit_msg>Remove an incorrect comment.<commit_after>package generation

import (
	"os"

	"chunkymonkey/chunkstore"
	"chunkymonkey/generation/perlin"
	"chunkymonkey/nbt"
	. "chunkymonkey/types"
)

const SeaLevel = 64

// ChunkData implements chunkstore.IChunkReader.
type ChunkData struct {
	loc        ChunkXz
	blocks     []byte
	blockData  []byte
	blockLight []byte
	skyLight   []byte
	heightMap  []byte
}

func newChunkData(loc ChunkXz) *ChunkData {
	return &ChunkData{
		loc:        loc,
		blocks:     make([]byte, ChunkSizeH*ChunkSizeH*ChunkSizeY),
		blockData:  make([]byte, (ChunkSizeH*ChunkSizeH*ChunkSizeY)>>1),
		skyLight:   make([]byte, (ChunkSizeH*ChunkSizeH*ChunkSizeY)>>1),
		blockLight: make([]byte, (ChunkSizeH*ChunkSizeH*ChunkSizeY)>>1),
		heightMap:  make([]byte, ChunkSizeH*ChunkSizeH),
	}
}

func (data *ChunkData) ChunkLoc() ChunkXz {
	return data.loc
}

func (data *ChunkData) Blocks() []byte {
	return data.blocks
}

func (data *ChunkData) BlockData() []byte {
	return data.blockData
}

func (data *ChunkData) BlockLight() []byte {
	return data.blockLight
}

func (data *ChunkData) SkyLight() []byte {
	return data.skyLight
}

func (data *ChunkData) HeightMap() []byte {
	return data.heightMap
}

func (data *ChunkData) GetRootTag() *nbt.NamedTag {
	return nil
}

// TestGenerator implements chunkstore.IChunkStore.
type TestGenerator struct {
	heightSource ISource
}

func NewTestGenerator(seed int64) *TestGenerator {
	perlin := perlin.NewPerlinNoise(seed)

	return &TestGenerator{
		heightSource: &Sum{
			Inputs: []ISource{
				&Turbulence{
					Dx:     &Scale{50, 1, &Offset{20.1, 0, perlin}},
					Dy:     &Scale{50, 1, &Offset{10.1, 0, perlin}},
					Factor: 50,
					Source: &Scale{
						Wavelength: 200,
						Amplitude:  50,
						Source:     perlin,
					},
				},
				&Turbulence{
					Dx:     &Scale{40, 1, &Offset{20.1, 0, perlin}},
					Dy:     &Scale{40, 1, &Offset{10.1, 0, perlin}},
					Factor: 10,
					Source: &Mult{
						A: &Scale{
							Wavelength: 40,
							Amplitude:  20,
							Source:     perlin,
						},
						// Local steepness.
						B: &Scale{
							Wavelength: 200,
							Amplitude:  1,
							Source:     &Add{perlin, 0.6},
						},
					},
				},
				&Scale{
					Wavelength: 5,
					Amplitude:  2,
					Source:     perlin,
				},
			},
		},
	}
}

func (gen *TestGenerator) LoadChunk(chunkLoc ChunkXz) (reader chunkstore.IChunkReader, err os.Error) {
	baseBlockXyz := chunkLoc.GetChunkCornerBlockXY()

	baseX, baseZ := baseBlockXyz.X, baseBlockXyz.Z

	data := newChunkData(chunkLoc)

	baseIndex := BlockIndex(0)
	heightMapIndex := 0
	for x := 0; x < ChunkSizeH; x++ {
		for z := 0; z < ChunkSizeH; z++ {
			xf, zf := float64(x)+float64(baseX), float64(z)+float64(baseZ)
			height := int(SeaLevel + gen.heightSource.At2d(xf, zf))

			if height < 0 {
				height = 0
			} else if height >= ChunkSizeY {
				height = ChunkSizeY - 1
			}

			skyLightHeight := gen.setBlockStack(
				height,
				data.blocks[baseIndex:baseIndex+ChunkSizeY])

			lightBase := baseIndex >> 1

			gen.setSkyLightStack(
				skyLightHeight,
				data.blocks[baseIndex:baseIndex+ChunkSizeY],
				data.skyLight[lightBase:lightBase+ChunkSizeY/2])

			data.heightMap[heightMapIndex] = byte(skyLightHeight)

			heightMapIndex++
			baseIndex += ChunkSizeY
		}
	}

	return data, nil
}

func (gen *TestGenerator) setBlockStack(height int, blocks []byte) (skyLightHeight int) {
	var topBlockType byte
	if height < SeaLevel+1 {
		skyLightHeight = SeaLevel + 1

		for y := SeaLevel; y > height; y-- {
			blocks[y] = 9 // stationary water
		}
		blocks[height] = 12 // sand
		topBlockType = 12
	} else {

		if height <= SeaLevel+1 {
			blocks[height] = 12 // sand
			topBlockType = 12
		} else {
			blocks[height] = 2 // grass
			topBlockType = 3   // dirt
		}
	}

	for y := height - 1; y > height-3 && y > 0; y-- {
		blocks[y] = topBlockType
	}
	for y := height - 3; y > 0; y-- {
		blocks[y] = 1 // stone
	}

	if skyLightHeight < 0 {
		skyLightHeight = 0
	}

	return
}

func (gen *TestGenerator) setSkyLightStack(skyLightHeight int, blocks []byte, skyLight []byte) {
	for y := ChunkSizeY - 1; y >= skyLightHeight; y-- {
		BlockIndex(y).SetBlockData(skyLight, 15)
	}

	lightLevel := 15

	for y := skyLightHeight; y >= 0 && lightLevel > 0; y-- {
		// TODO Use real block data in here.
		if blocks[y] == 9 {
			lightLevel -= 3
		} else if blocks[y] == 0 {
			// air
		} else {
			lightLevel -= 15
		}
		if lightLevel < 0 {
			lightLevel = 0
		}

		BlockIndex(y).SetBlockData(skyLight, byte(lightLevel))
	}
}
<|endoftext|>