<commit_before>package hwio

// A driver for BeagleBone's running Linux kernel 3.8 or higher, which use device trees instead
// of the old driver.
//
// Notable differences between this driver and the other BeagleBone driver:
// - this uses the file system for everything.
// - will only work on linux kernel 3.8 and higher, irrespective of the board version.
// - memory mapping is no longer used, as it was unsupported anyway.
// - this will probably not have the raw performance of the memory map technique (this is yet to be measured)
// - this driver will likely support alot more functions, as it's leveraging drivers that already exist.
//
// This driver shares some information from the other driver, since the pin configuration information is essentially the same.
//
// Articles used in building this driver:
// GPIO:
// - http://www.avrfreaks.net/wiki/index.php/Documentation:Linux/GPIO#Example_of_GPIO_access_from_within_a_C_program
// Analog:
// - http://hipstercircuits.com/reading-analog-adc-values-on-beaglebone-black/
// Background on changes in linux kernal 3.8:
// - https://docs.google.com/document/d/17P54kZkZO_-JtTjrFuVz-Cp_RMMg7GB_8W9JK9sLKfA/edit?hl=en&forcehl=1#heading=h.mfjmczsbv38r

import (
	"errors"
	"fmt"
	"os"
	"strconv"
)

type BeagleBoneFSOpenPin struct {
	pin          Pin
	gpioLogical  int
	gpioBaseName string
	valueFile    *os.File
}

// Write a string to a file and close it again.
func writeStringToFile(filename string, value string) error {
	//	fmt.Printf("writing %s to file %s\n", value, filename)
	f, e := os.OpenFile(filename, os.O_WRONLY|os.O_TRUNC, 0666)
	if e != nil {
		return e
	}
	defer f.Close()

	f.WriteString(value)
	return nil
}

// Needs to be called to allocate the GPIO pin
func (op *BeagleBoneFSOpenPin) gpioExport() error {
	s := strconv.FormatInt(int64(op.gpioLogical), 10)
	e := writeStringToFile("/sys/class/gpio/export", s)
	if e != nil {
		return e
	}

	// calculate the base name for the gpio pin
	op.gpioBaseName = "/sys/class/gpio/gpio" + strconv.Itoa(op.gpioLogical)
	return nil
}

// Once exported, the direction of a GPIO can be set
func (op *BeagleBoneFSOpenPin) gpioDirection(dir string) error {
	if dir != "in" && dir != "out" {
		return errors.New("direction must be in or out")
	}
	f := op.gpioBaseName + "/direction"
	e := writeStringToFile(f, dir)

	mode := os.O_WRONLY | os.O_TRUNC
	if dir == "in" {
		mode = os.O_RDONLY
	}

	// open the value file with the correct mode. Put that file in 'op'. Note that we keep this file open
	// continuously for performance.
	// Preliminary tests on 200,000 DigitalWrites indicate an order of magnitude improvement when we don't have
	// to re-open the file each time. Re-seeking and writing a new value suffices.
	op.valueFile, e = os.OpenFile(op.gpioBaseName+"/value", mode, 0666)

	return e
}

// Get the value. Will return HIGH or LOW
func (op *BeagleBoneFSOpenPin) gpioGetValue() (int, error) {
	var b []byte
	b = make([]byte, 1)
	n, e := op.valueFile.ReadAt(b, 0)
	value := 0
	if n > 0 {
		if b[0] == '1' {
			value = HIGH
		} else {
			value = LOW
		}
	}
	return value, e
}

// Set the value, Expects HIGH or LOW
func (op *BeagleBoneFSOpenPin) gpioSetValue(value int) error {
	if op.valueFile == nil {
		fmt.Printf("value file no set\n")
		return errors.New("value file is not defined")
	}

	// Seek the start of the value file before writing. This is sufficient for the driver to accept a new value.
	_, e := op.valueFile.Seek(0, 0)
	if e != nil {
		return e
	}

	// Write a 1 or 0.
	// @todo investigate if we'd get better performance if we have precalculated []byte values with 0 and 1, and
	// use write directly instead of WriteString. Probably only marginal.
	if value == 0 {
		op.valueFile.WriteString("0")
	} else {
		op.valueFile.WriteString("1")
	}

	return nil
}

type BeagleBoneFSDriver struct {
	openPins map[Pin]*BeagleBoneFSOpenPin
}

func (d *BeagleBoneFSDriver) Init() error {
	d.openPins = make(map[Pin]*BeagleBoneFSOpenPin)
	return nil
}

func (d *BeagleBoneFSDriver) Close() {
	// @todo call unexport on all open pins
}

// create an openPin object and put it in the map.
func (d *BeagleBoneFSDriver) makeOpenPin(pin Pin, gpioLogicalPin int) *BeagleBoneFSOpenPin {
	result := &BeagleBoneFSOpenPin{pin: pin, gpioLogical: gpioLogicalPin}
	d.openPins[pin] = result
	return result
}

// For GPIO:
// - write GPIO pin to /sys/class/gpio/export. This is the port number plus pin on that port. Ports 0, 32, 64, 96.
// - write direction to /sys/class/gpio/gpio{nn}/direction. Values are 'in' and 'out'

func (d *BeagleBoneFSDriver) PinMode(pin Pin, mode PinIOMode) error {
	p := beaglePins[pin]

	// handle analog first, they are simplest from PinMode perspective
	if p.isAnalogPin() {
		if mode != INPUT {
			return errors.New(fmt.Sprintf("Pin %d is an analog pin, and the mode must be INPUT", p))
		}
		// @todo set up the analog pin
		return nil // nothing to set up
	}

	// Create an open pin object
	openPin := d.makeOpenPin(pin, p.gpioLogical)
	e := openPin.gpioExport()
	if e != nil {
		return e
	}

	if mode == OUTPUT {
		fmt.Printf("about to set pin %d to output\n", pin)
		e = openPin.gpioDirection("out")
		if e != nil {
			return e
		}
	} else {
		e = openPin.gpioDirection("in")
		// pull := BB_CONF_PULL_DISABLE
		// // note: pull up/down modes assume that CONF_PULLDOWN resets the pull disable bit
		// if mode == INPUT_PULLUP {
		// 	pull = BB_CONF_PULLUP
		// } else if mode == INPUT_PULLDOWN {
		// 	pull = BB_CONF_PULLDOWN
		// }

		if e != nil {
			return e
		}
	}
	return nil
}

func (d *BeagleBoneFSDriver) DigitalWrite(pin Pin, value int) (e error) {
	openPin := d.openPins[pin]
	if openPin == nil {
		return errors.New("Pin is being written but has not been opened")
	}
	openPin.gpioSetValue(value)
	return nil
}

func (d *BeagleBoneFSDriver) DigitalRead(pin Pin) (value int, e error) {
	openPin := d.openPins[pin]
	return openPin.gpioGetValue()
}

func (d *BeagleBoneFSDriver) AnalogWrite(pin Pin, value int) (e error) {
	return nil
}

func (d *BeagleBoneFSDriver) AnalogRead(pin Pin) (value int, e error) {
	return 0, nil
}

func (d *BeagleBoneFSDriver) PinMap() (pinMap HardwarePinMap) {
	pinMap = make(HardwarePinMap)

	for i, hw := range beaglePins {
		names := []string{hw.hwPin}
		if hw.hwPin != hw.gpioName {
			names = append(names, hw.gpioName)
		}
		pinMap.add(Pin(i), names, hw.profile)
	}

	return
}
<commit_msg>close open value files on exit on BB FS driver<commit_after>package hwio

// A driver for BeagleBone's running Linux kernel 3.8 or higher, which use device trees instead
// of the old driver.
//
// Notable differences between this driver and the other BeagleBone driver:
// - this uses the file system for everything.
// - will only work on linux kernel 3.8 and higher, irrespective of the board version.
// - memory mapping is no longer used, as it was unsupported anyway.
// - this will probably not have the raw performance of the memory map technique (this is yet to be measured)
// - this driver will likely support alot more functions, as it's leveraging drivers that already exist.
//
// This driver shares some information from the other driver, since the pin configuration information is essentially the same.
//
// Articles used in building this driver:
// GPIO:
// - http://www.avrfreaks.net/wiki/index.php/Documentation:Linux/GPIO#Example_of_GPIO_access_from_within_a_C_program
// Analog:
// - http://hipstercircuits.com/reading-analog-adc-values-on-beaglebone-black/
// Background on changes in linux kernal 3.8:
// - https://docs.google.com/document/d/17P54kZkZO_-JtTjrFuVz-Cp_RMMg7GB_8W9JK9sLKfA/edit?hl=en&forcehl=1#heading=h.mfjmczsbv38r

import (
	"errors"
	"fmt"
	"os"
	"strconv"
)

type BeagleBoneFSOpenPin struct {
	pin          Pin
	gpioLogical  int
	gpioBaseName string
	valueFile    *os.File
}

// Write a string to a file and close it again.
func writeStringToFile(filename string, value string) error {
	//	fmt.Printf("writing %s to file %s\n", value, filename)
	f, e := os.OpenFile(filename, os.O_WRONLY|os.O_TRUNC, 0666)
	if e != nil {
		return e
	}
	defer f.Close()

	f.WriteString(value)
	return nil
}

// Needs to be called to allocate the GPIO pin
func (op *BeagleBoneFSOpenPin) gpioExport() error {
	s := strconv.FormatInt(int64(op.gpioLogical), 10)
	e := writeStringToFile("/sys/class/gpio/export", s)
	if e != nil {
		return e
	}

	// calculate the base name for the gpio pin
	op.gpioBaseName = "/sys/class/gpio/gpio" + strconv.Itoa(op.gpioLogical)
	return nil
}

// Once exported, the direction of a GPIO can be set
func (op *BeagleBoneFSOpenPin) gpioDirection(dir string) error {
	if dir != "in" && dir != "out" {
		return errors.New("direction must be in or out")
	}
	f := op.gpioBaseName + "/direction"
	e := writeStringToFile(f, dir)

	mode := os.O_WRONLY | os.O_TRUNC
	if dir == "in" {
		mode = os.O_RDONLY
	}

	// open the value file with the correct mode. Put that file in 'op'. Note that we keep this file open
	// continuously for performance.
	// Preliminary tests on 200,000 DigitalWrites indicate an order of magnitude improvement when we don't have
	// to re-open the file each time. Re-seeking and writing a new value suffices.
	op.valueFile, e = os.OpenFile(op.gpioBaseName+"/value", mode, 0666)

	return e
}

// Get the value. Will return HIGH or LOW
func (op *BeagleBoneFSOpenPin) gpioGetValue() (int, error) {
	var b []byte
	b = make([]byte, 1)
	n, e := op.valueFile.ReadAt(b, 0)
	value := 0
	if n > 0 {
		if b[0] == '1' {
			value = HIGH
		} else {
			value = LOW
		}
	}
	return value, e
}

// Set the value, Expects HIGH or LOW
func (op *BeagleBoneFSOpenPin) gpioSetValue(value int) error {
	if op.valueFile == nil {
		fmt.Printf("value file no set\n")
		return errors.New("value file is not defined")
	}

	// Seek the start of the value file before writing. This is sufficient for the driver to accept a new value.
	_, e := op.valueFile.Seek(0, 0)
	if e != nil {
		return e
	}

	// Write a 1 or 0.
	// @todo investigate if we'd get better performance if we have precalculated []byte values with 0 and 1, and
	// use write directly instead of WriteString. Probably only marginal.
	if value == 0 {
		op.valueFile.WriteString("0")
	} else {
		op.valueFile.WriteString("1")
	}

	return nil
}

type BeagleBoneFSDriver struct {
	openPins map[Pin]*BeagleBoneFSOpenPin
}

func (d *BeagleBoneFSDriver) Init() error {
	d.openPins = make(map[Pin]*BeagleBoneFSOpenPin)
	return nil
}

func (d *BeagleBoneFSDriver) Close() {
	// close all value files now we're finished with them.
	// @todo how do we unexport the pins?
	for _, open := range d.openPins {
		if open.valueFile != nil {
			open.valueFile.Close()
		}
	}
}

// create an openPin object and put it in the map.
func (d *BeagleBoneFSDriver) makeOpenPin(pin Pin, gpioLogicalPin int) *BeagleBoneFSOpenPin {
	result := &BeagleBoneFSOpenPin{pin: pin, gpioLogical: gpioLogicalPin}
	d.openPins[pin] = result
	return result
}

// For GPIO:
// - write GPIO pin to /sys/class/gpio/export. This is the port number plus pin on that port. Ports 0, 32, 64, 96.
// - write direction to /sys/class/gpio/gpio{nn}/direction. Values are 'in' and 'out'

func (d *BeagleBoneFSDriver) PinMode(pin Pin, mode PinIOMode) error {
	p := beaglePins[pin]

	// handle analog first, they are simplest from PinMode perspective
	if p.isAnalogPin() {
		if mode != INPUT {
			return errors.New(fmt.Sprintf("Pin %d is an analog pin, and the mode must be INPUT", p))
		}
		// @todo set up the analog pin
		return nil // nothing to set up
	}

	// Create an open pin object
	openPin := d.makeOpenPin(pin, p.gpioLogical)
	e := openPin.gpioExport()
	if e != nil {
		return e
	}

	if mode == OUTPUT {
		fmt.Printf("about to set pin %d to output\n", pin)
		e = openPin.gpioDirection("out")
		if e != nil {
			return e
		}
	} else {
		e = openPin.gpioDirection("in")
		// pull := BB_CONF_PULL_DISABLE
		// // note: pull up/down modes assume that CONF_PULLDOWN resets the pull disable bit
		// if mode == INPUT_PULLUP {
		// 	pull = BB_CONF_PULLUP
		// } else if mode == INPUT_PULLDOWN {
		// 	pull = BB_CONF_PULLDOWN
		// }

		if e != nil {
			return e
		}
	}
	return nil
}

func (d *BeagleBoneFSDriver) DigitalWrite(pin Pin, value int) (e error) {
	openPin := d.openPins[pin]
	if openPin == nil {
		return errors.New("Pin is being written but has not been opened")
	}
	openPin.gpioSetValue(value)
	return nil
}

func (d *BeagleBoneFSDriver) DigitalRead(pin Pin) (value int, e error) {
	openPin := d.openPins[pin]
	return openPin.gpioGetValue()
}

func (d *BeagleBoneFSDriver) AnalogWrite(pin Pin, value int) (e error) {
	return nil
}

func (d *BeagleBoneFSDriver) AnalogRead(pin Pin) (value int, e error) {
	return 0, nil
}

func (d *BeagleBoneFSDriver) PinMap() (pinMap HardwarePinMap) {
	pinMap = make(HardwarePinMap)

	for i, hw := range beaglePins {
		names := []string{hw.hwPin}
		if hw.hwPin != hw.gpioName {
			names = append(names, hw.gpioName)
		}
		pinMap.add(Pin(i), names, hw.profile)
	}

	return
}
<|endoftext|>


<commit_before>/*
Copyright IBM Corp. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/

package aclmgmt

import (
	"fmt"

	"github.com/hyperledger/fabric/common/policies"
	"github.com/hyperledger/fabric/core/ledger"
	"github.com/hyperledger/fabric/core/peer"
	"github.com/hyperledger/fabric/core/policy"
	"github.com/hyperledger/fabric/msp/mgmt"
	"github.com/hyperledger/fabric/protos/common"
	pb "github.com/hyperledger/fabric/protos/peer"
)

const (
	CHANNELREADERS = policies.ChannelApplicationReaders
	CHANNELWRITERS = policies.ChannelApplicationWriters
)

//defaultACLProvider if RSCC not provided use the default pre 1.0 implementation
type defaultACLProvider struct {
	policyChecker policy.PolicyChecker

	//peer wide policy (currently not used)
	pResourcePolicyMap map[string]string

	//channel specific policy
	cResourcePolicyMap map[string]string
}

func newDefaultACLProvider() ACLProvider {
	d := &defaultACLProvider{}
	d.initialize()

	return d
}

func (d *defaultACLProvider) initialize() {
	d.policyChecker = policy.NewPolicyChecker(
		peer.NewChannelPolicyManagerGetter(),
		mgmt.GetLocalMSP(),
		mgmt.NewLocalMSPPrincipalGetter(),
	)

	d.pResourcePolicyMap = make(map[string]string)
	d.cResourcePolicyMap = make(map[string]string)

	//-------------- LSCC --------------
	//p resources (implemented by the chaincode currently)
	d.pResourcePolicyMap[LSCC_INSTALL] = ""
	d.pResourcePolicyMap[LSCC_GETCHAINCODES] = ""
	d.pResourcePolicyMap[LSCC_GETINSTALLEDCHAINCODES] = ""

	//c resources
	d.cResourcePolicyMap[LSCC_DEPLOY] = ""  //ACL check covered by PROPOSAL
	d.cResourcePolicyMap[LSCC_UPGRADE] = "" //ACL check covered by PROPOSAL
	d.cResourcePolicyMap[LSCC_GETCCINFO] = CHANNELREADERS
	d.cResourcePolicyMap[LSCC_GETDEPSPEC] = CHANNELREADERS
	d.cResourcePolicyMap[LSCC_GETCCDATA] = CHANNELREADERS

	//-------------- QSCC --------------
	//p resources (none)

	//c resources
	d.cResourcePolicyMap[QSCC_GetChainInfo] = CHANNELREADERS
	d.cResourcePolicyMap[QSCC_GetBlockByNumber] = CHANNELREADERS
	d.cResourcePolicyMap[QSCC_GetBlockByHash] = CHANNELREADERS
	d.cResourcePolicyMap[QSCC_GetTransactionByID] = CHANNELREADERS
	d.cResourcePolicyMap[QSCC_GetBlockByTxID] = CHANNELREADERS

	//--------------- CSCC resources -----------
	//p resources (implemented by the chaincode currently)
	d.pResourcePolicyMap[CSCC_JoinChain] = ""
	d.cResourcePolicyMap[CSCC_GetChannels] = ""

	//c resources
	d.pResourcePolicyMap[CSCC_GetConfigBlock] = CHANNELREADERS

	//---------------- non-scc resources ------------
	//Propose
	d.cResourcePolicyMap[PROPOSE] = CHANNELWRITERS

	//Chaincode-to-Chaincode
	d.cResourcePolicyMap[CC2CC] = CHANNELWRITERS

	//Events (not used currently - for future)
	d.cResourcePolicyMap[BLOCKEVENT] = CHANNELREADERS
	d.cResourcePolicyMap[FILTEREDBLOCKEVENT] = CHANNELREADERS
}

//this should cover an exhaustive list of everything called from the peer
func (d *defaultACLProvider) defaultPolicy(resName string, cprovider bool) string {
	var pol string
	if cprovider {
		pol = d.cResourcePolicyMap[resName]
	} else {
		pol = d.pResourcePolicyMap[resName]
	}
	return pol
}

//CheckACL provides default (v 1.0) behavior by mapping resources to their ACL for a channel
func (d *defaultACLProvider) CheckACL(resName string, channelID string, idinfo interface{}) error {
	policy := d.defaultPolicy(resName, true)
	if policy == "" {
		aclLogger.Errorf("Unmapped policy for %s", resName)
		return fmt.Errorf("Unmapped policy for %s", resName)
	}

	switch idinfo.(type) {
	case *pb.SignedProposal:
		return d.policyChecker.CheckPolicy(channelID, policy, idinfo.(*pb.SignedProposal))
	default:
		aclLogger.Errorf("Unmapped id on checkACL %s", resName)
		return fmt.Errorf("Unknown id on checkACL %s", resName)
	}
}

//GenerateSimulationResults does nothing for default provider currently as it defaults to
//1.0 behavior
func (d *defaultACLProvider) GenerateSimulationResults(txEnvelop *common.Envelope, simulator ledger.TxSimulator) error {
	return nil
}
<commit_msg>[FAB-5945] make CSCC.GetConfigBlock chan. wide<commit_after>/*
Copyright IBM Corp. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/

package aclmgmt

import (
	"fmt"

	"github.com/hyperledger/fabric/common/policies"
	"github.com/hyperledger/fabric/core/ledger"
	"github.com/hyperledger/fabric/core/peer"
	"github.com/hyperledger/fabric/core/policy"
	"github.com/hyperledger/fabric/msp/mgmt"
	"github.com/hyperledger/fabric/protos/common"
	pb "github.com/hyperledger/fabric/protos/peer"
)

const (
	CHANNELREADERS = policies.ChannelApplicationReaders
	CHANNELWRITERS = policies.ChannelApplicationWriters
)

//defaultACLProvider if RSCC not provided use the default pre 1.0 implementation
type defaultACLProvider struct {
	policyChecker policy.PolicyChecker

	//peer wide policy (currently not used)
	pResourcePolicyMap map[string]string

	//channel specific policy
	cResourcePolicyMap map[string]string
}

func newDefaultACLProvider() ACLProvider {
	d := &defaultACLProvider{}
	d.initialize()

	return d
}

func (d *defaultACLProvider) initialize() {
	d.policyChecker = policy.NewPolicyChecker(
		peer.NewChannelPolicyManagerGetter(),
		mgmt.GetLocalMSP(),
		mgmt.NewLocalMSPPrincipalGetter(),
	)

	d.pResourcePolicyMap = make(map[string]string)
	d.cResourcePolicyMap = make(map[string]string)

	//-------------- LSCC --------------
	//p resources (implemented by the chaincode currently)
	d.pResourcePolicyMap[LSCC_INSTALL] = ""
	d.pResourcePolicyMap[LSCC_GETCHAINCODES] = ""
	d.pResourcePolicyMap[LSCC_GETINSTALLEDCHAINCODES] = ""

	//c resources
	d.cResourcePolicyMap[LSCC_DEPLOY] = ""  //ACL check covered by PROPOSAL
	d.cResourcePolicyMap[LSCC_UPGRADE] = "" //ACL check covered by PROPOSAL
	d.cResourcePolicyMap[LSCC_GETCCINFO] = CHANNELREADERS
	d.cResourcePolicyMap[LSCC_GETDEPSPEC] = CHANNELREADERS
	d.cResourcePolicyMap[LSCC_GETCCDATA] = CHANNELREADERS

	//-------------- QSCC --------------
	//p resources (none)

	//c resources
	d.cResourcePolicyMap[QSCC_GetChainInfo] = CHANNELREADERS
	d.cResourcePolicyMap[QSCC_GetBlockByNumber] = CHANNELREADERS
	d.cResourcePolicyMap[QSCC_GetBlockByHash] = CHANNELREADERS
	d.cResourcePolicyMap[QSCC_GetTransactionByID] = CHANNELREADERS
	d.cResourcePolicyMap[QSCC_GetBlockByTxID] = CHANNELREADERS

	//--------------- CSCC resources -----------
	//p resources (implemented by the chaincode currently)
	d.pResourcePolicyMap[CSCC_JoinChain] = ""
	d.pResourcePolicyMap[CSCC_GetChannels] = ""

	//c resources
	d.cResourcePolicyMap[CSCC_GetConfigBlock] = CHANNELREADERS

	//---------------- non-scc resources ------------
	//Propose
	d.cResourcePolicyMap[PROPOSE] = CHANNELWRITERS

	//Chaincode-to-Chaincode
	d.cResourcePolicyMap[CC2CC] = CHANNELWRITERS

	//Events (not used currently - for future)
	d.cResourcePolicyMap[BLOCKEVENT] = CHANNELREADERS
	d.cResourcePolicyMap[FILTEREDBLOCKEVENT] = CHANNELREADERS
}

//this should cover an exhaustive list of everything called from the peer
func (d *defaultACLProvider) defaultPolicy(resName string, cprovider bool) string {
	var pol string
	if cprovider {
		pol = d.cResourcePolicyMap[resName]
	} else {
		pol = d.pResourcePolicyMap[resName]
	}
	return pol
}

//CheckACL provides default (v 1.0) behavior by mapping resources to their ACL for a channel
func (d *defaultACLProvider) CheckACL(resName string, channelID string, idinfo interface{}) error {
	policy := d.defaultPolicy(resName, true)
	if policy == "" {
		aclLogger.Errorf("Unmapped policy for %s", resName)
		return fmt.Errorf("Unmapped policy for %s", resName)
	}

	switch idinfo.(type) {
	case *pb.SignedProposal:
		return d.policyChecker.CheckPolicy(channelID, policy, idinfo.(*pb.SignedProposal))
	default:
		aclLogger.Errorf("Unmapped id on checkACL %s", resName)
		return fmt.Errorf("Unknown id on checkACL %s", resName)
	}
}

//GenerateSimulationResults does nothing for default provider currently as it defaults to
//1.0 behavior
func (d *defaultACLProvider) GenerateSimulationResults(txEnvelop *common.Envelope, simulator ledger.TxSimulator) error {
	return nil
}
<|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.

package frontend

import (
	"context"
	"strings"
	"testing"

	"github.com/google/go-cmp/cmp"
	"golang.org/x/pkgsite/internal"
	"golang.org/x/pkgsite/internal/experiment"
	"golang.org/x/pkgsite/internal/source"
	"golang.org/x/pkgsite/internal/testing/sample"
)

func TestReadme(t *testing.T) {
	ctx := experiment.NewContext(context.Background(), internal.ExperimentGoldmark)
	mod := &internal.ModuleInfo{
		Version:    sample.VersionString,
		SourceInfo: source.NewGitHubInfo(sample.ModulePath, "", sample.VersionString),
	}
	for _, tc := range []struct {
		name        string
		mi          *internal.ModuleInfo
		readme      *internal.Readme
		wantHTML    string
		wantOutline []*Heading
	}{
		{
			name: "Top level heading of h4 becomes h3, and following header levels become hN-1",
			mi:   mod,
			readme: &internal.Readme{
				Filepath: sample.ReadmeFilePath,
				Contents: "#### Heading Rank 4\n\n##### Heading Rank 5",
			},
			wantHTML: "
Heading Rank 4
\n
Heading Rank 5
",
			wantOutline: []*Heading{
				{Level: 4, Text: "Heading Rank 4", ID: "heading-rank-4"},
				{Level: 5, Text: "Heading Rank 5", ID: "heading-rank-5"},
			},
		},
		{
			name: "Github markdown emoji markup is properly rendered",
			mi:   mod,
			readme: &internal.Readme{
				Filepath: sample.ReadmeFilePath,
				Contents: "# :zap: Zap \n\n :joy:",
			},
			wantHTML: "
⚡ Zap
\n
😂
",
			wantOutline: []*Heading{
				{Level: 1, Text: " Zap", ID: "zap-zap"},
			},
		},
	} {
		t.Run(tc.name, func(t *testing.T) {
			unit := internal.Unit{
				Readme: tc.readme,
				UnitMeta: internal.UnitMeta{
					SourceInfo: tc.mi.SourceInfo,
				},
			}
			html, gotOutline, err := Readme(ctx, &unit)
			if err != nil {
				t.Fatal(err)
			}
			gotHTML := strings.TrimSpace(html.String())
			if diff := cmp.Diff(tc.wantHTML, gotHTML); diff != "" {
				t.Errorf("Readme(%v) html mismatch (-want +got):\n%s", tc.mi, diff)
			}
			if diff := cmp.Diff(tc.wantOutline, gotOutline); diff != "" {
				t.Errorf("Readme(%v) outline mismatch (-want +got):\n%s", tc.mi, diff)
			}
		})
	}
}
<commit_msg>internal/frontend: add test cases for goldmark readme processing<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.

package frontend

import (
	"context"
	"strings"
	"testing"

	"github.com/google/go-cmp/cmp"
	"golang.org/x/pkgsite/internal"
	"golang.org/x/pkgsite/internal/experiment"
	"golang.org/x/pkgsite/internal/source"
	"golang.org/x/pkgsite/internal/testing/sample"
)

func TestReadme(t *testing.T) {
	ctx := experiment.NewContext(context.Background(), internal.ExperimentGoldmark)
	unit := sample.UnitEmpty(sample.PackagePath, sample.ModulePath, sample.VersionString)
	for _, tc := range []struct {
		name         string
		unit         *internal.Unit
		readme       *internal.Readme
		wantHTML     string
		wantUnitPage string
		wantOutline  []*Heading
	}{
		{
			name: "Top level heading of h4 becomes h3, and following header levels become hN-1",
			unit: unit,
			readme: &internal.Readme{
				Filepath: sample.ReadmeFilePath,
				Contents: "#### Four\n\n##### Five",
			},
			wantHTML: "
Four
\n" +
				"
Five
",
			wantOutline: []*Heading{
				{Level: 4, Text: "Four", ID: "four"},
				{Level: 5, Text: "Five", ID: "five"},
			},
		},
		{
			name: "The top 2 level headings are kept within outline",
			unit: unit,
			readme: &internal.Readme{
				Filepath: sample.ReadmeFilePath,
				Contents: "#### Four\n\n##### Five\n\n###### Six",
			},
			wantHTML: "
Four
\n" +
				"
Five
\n" +
				"
Six
",
			wantOutline: []*Heading{
				{Level: 4, Text: "Four", ID: "four"},
				{Level: 5, Text: "Five", ID: "five"},
			},
		},
		{
			name: "Heading levels out of order",
			unit: unit,
			readme: &internal.Readme{
				Filepath: sample.ReadmeFilePath,
				Contents: "## Two\n\n# One\n\n### Three",
			},
			wantHTML: "
Two
\n" +
				"
One
\n" +
				"
Three
",
			wantOutline: []*Heading{
				{Level: 2, Text: "Two", ID: "two"},
				{Level: 1, Text: "One", ID: "one"},
			},
		},
		{
			name: "Heading levels not consecutive",
			unit: unit,
			readme: &internal.Readme{
				Filepath: sample.ReadmeFilePath,
				Contents: "# One\n\n#### Four\n\n#### Four",
			},
			wantHTML: "
One
\n" +
				"
Four
\n" +
				"
Four
",
			wantOutline: []*Heading{
				{Level: 1, Text: "One", ID: "one"},
				{Level: 4, Text: "Four", ID: "four"},
				{Level: 4, Text: "Four", ID: "four-1"},
			},
		},
		{
			name: "Heading levels in reverse",
			unit: unit,
			readme: &internal.Readme{
				Filepath: sample.ReadmeFilePath,
				Contents: "### Three\n\n## Two\n\n# One",
			},
			wantHTML: "
Three
\n" +
				"
Two
\n" +
				"
One
",
			wantOutline: []*Heading{
				{Level: 2, Text: "Two", ID: "two"},
				{Level: 1, Text: "One", ID: "one"},
			},
		},
		{
			name: "Github markdown emoji markup is properly rendered",
			unit: unit,
			readme: &internal.Readme{
				Filepath: sample.ReadmeFilePath,
				Contents: "# :zap: Zap \n\n :joy:",
			},
			wantHTML: "
⚡ Zap
\n
😂
",
			wantOutline: []*Heading{
				{Level: 1, Text: " Zap", ID: "zap-zap"},
			},
		},
		{
			name: "valid markdown readme",
			unit: &internal.Unit{},
			readme: &internal.Readme{
				Filepath: "README.md",
				Contents: "This package collects pithy sayings.\n\n" +
					"It's part of a demonstration of\n" +
					"[package versioning in Go](https://research.swtch.com/vgo1).",
			},
			wantHTML: "
This package collects pithy sayings.
\n" +
				"
It's part of a demonstration of\n" +
				`<a href="https://research.swtch.com/vgo1" rel="nofollow">package versioning in Go</a>.</p>`,
			wantOutline: nil,
		},
		{
			name: "valid markdown readme with alternative case and extension",
			unit: &internal.Unit{},
			readme: &internal.Readme{
				Filepath: "README.MARKDOWN",
				Contents: "This package collects pithy sayings.\n\n" +
					"It's part of a demonstration of\n" +
					"[package versioning in Go](https://research.swtch.com/vgo1).",
			},
			wantHTML: "
This package collects pithy sayings.
\n" +
				"
It's part of a demonstration of\n" +
				`<a href="https://research.swtch.com/vgo1" rel="nofollow">package versioning in Go</a>.</p>`,
			wantOutline: nil,
		},
		{
			name: "valid markdown readme with CRLF",
			unit: &internal.Unit{},
			readme: &internal.Readme{
				Filepath: "README.md",
				Contents: "This package collects pithy sayings.\r\n\r\n" +
					"- It's part of a demonstration of\r\n" +
					"- [package versioning in Go](https://research.swtch.com/vgo1).",
			},
			wantHTML: "
This package collects pithy sayings.
\n" +
				"
\n" +
				"
It's part of a demonstration of
\n" +
				`<li><a href="https://research.swtch.com/vgo1" rel="nofollow">package versioning in Go</a>.</li>` + "\n" +
				"
",
			wantOutline: nil,
		},
		{
			name: "not markdown readme",
			unit: &internal.Unit{},
			readme: &internal.Readme{
				Filepath: "README.rst",
				Contents: "This package collects pithy sayings.\n\n" +
					"It's part of a demonstration of\n" +
					"[package versioning in Go](https://research.swtch.com/vgo1).",
			},
			wantHTML: "
This package collects pithy sayings.\n\n" +
				"It's part of a demonstration of\n[package versioning in Go](https://research.swtch.com/vgo1).
",
			wantOutline: nil,
		},
		{
			name:        "empty readme",
			unit:        &internal.Unit{},
			wantHTML:    "",
			wantOutline: nil,
		},
		{
			name: "sanitized readme",
			unit: &internal.Unit{},
			readme: &internal.Readme{
				Filepath: "README",
				Contents: `<a onblur="alert(secret)" href="http://www.google.com">Google</a>`,
			},
			wantHTML:    `<pre class="readme"><a onblur="alert(secret)" href="http://www.google.com">Google</a></pre>`,
			wantOutline: nil,
		},
		{
			name: "relative image markdown is made absolute for GitHub",
			unit: &internal.Unit{
				UnitMeta: internal.UnitMeta{SourceInfo: source.NewGitHubInfo("http://github.com/golang/go", "", "master")},
			},
			readme: &internal.Readme{
				Filepath: "README.md",
				Contents: "![Go logo](doc/logo.png)",
			},
			wantHTML:    `<p><img src="http://github.com/golang/go/raw/master/doc/logo.png" alt="Go logo"/></p>`,
			wantOutline: nil,
		},
		{
			name: "relative image markdown is left alone for unknown origins",
			unit: &internal.Unit{},
			readme: &internal.Readme{
				Filepath: "README.md",
				Contents: "![Go logo](doc/logo.png)",
			},
			wantHTML:    `<p><img src="doc/logo.png" alt="Go logo"/></p>`,
			wantOutline: nil,
		},
		{
			name: "module versions are referenced in relative images",
			unit: unit,
			readme: &internal.Readme{
				Filepath: "README.md",
				Contents: "![Hugo logo](doc/logo.png)",
			},
			wantHTML:    `<p><img src="https://github.com/valid/module_name/raw/v1.0.0/doc/logo.png" alt="Hugo logo"/></p>`,
			wantOutline: nil,
		},
		{
			name: "image URLs relative to README directory",
			unit: unit,
			readme: &internal.Readme{
				Filepath: "dir/sub/README.md",
				Contents: "![alt](img/thing.png)",
			},
			wantHTML:    `<p><img src="https://github.com/valid/module_name/raw/v1.0.0/dir/sub/img/thing.png" alt="alt"/></p>`,
			wantOutline: nil,
		},
		{
			name: "non-image links relative to README directory",
			unit: unit,
			readme: &internal.Readme{
				Filepath: "dir/sub/README.md",
				Contents: "[something](doc/thing.md)",
			},
			wantHTML:    `<p><a href="https://github.com/valid/module_name/blob/v1.0.0/dir/sub/doc/thing.md" rel="nofollow">something</a></p>`,
			wantOutline: nil,
		},
		{
			name: "image link in embedded HTML",
			unit: unit,
			readme: &internal.Readme{
				Filepath: "README.md",
				Contents: "\n\n# Heading\n",
			},
			wantHTML: `<p><img src="https://github.com/valid/module_name/raw/v1.0.0/resources/logoSmall.png"/></p>` + "\n" +
				`<h3 class="h1" id="heading">Heading</h3>`,
			wantUnitPage: `<p><img src="https://github.com/valid/module_name/raw/v1.0.0/resources/logoSmall.png"/></p>` + "\n" +
				`<h3 class="h1" id="heading">Heading</h3>`,
			wantOutline: []*Heading{
				{Level: 1, Text: "Heading", ID: "heading"},
			},
		},
		{
			name: "image link in embedded HTML with surrounding p tag",
			unit: unit,
			readme: &internal.Readme{
				Filepath: "README.md",
				Contents: "

\n\n# Heading",
			},
			wantHTML: `<p align="center"><img src="https://github.com/valid/module_name/raw/v1.0.0/foo.png"/></p>` + "\n" +
				`<h3 class="h1" id="heading">Heading</h3>`,
			wantUnitPage: `<p align="center"><img src="https://github.com/valid/module_name/raw/v1.0.0/foo.png"/></p>` + "\n" +
				`<h3 class="h1" id="heading">Heading</h3>`,
			wantOutline: []*Heading{
				{Level: 1, Text: "Heading", ID: "heading"},
			},
		},
		{
			name: "image link in embedded HTML with surrounding div",
			unit: unit,
			readme: &internal.Readme{
				Filepath: "README.md",
				Contents: "

\n\n# Heading",
			},
			wantHTML: `<div align="center"><img src="https://github.com/valid/module_name/raw/v1.0.0/foo.png"/></div>` + "\n" +
				`<h3 class="h1" id="heading">Heading</h3>`,
			wantUnitPage: `<div align="center"><img src="https://github.com/valid/module_name/raw/v1.0.0/foo.png"/></div>` + "\n" +
				`<h3 class="h1" id="heading">Heading</h3>`,
			wantOutline: []*Heading{
				{Level: 1, Text: "Heading", ID: "heading"},
			},
		},
		{
			name: "image link with bad URL",
			unit: &internal.Unit{
				UnitMeta: internal.UnitMeta{
					Version:    "v1.2.3",
					SourceInfo: source.NewGitHubInfo("https://github.com/some/


<commit_before>// Copyright 2021 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.

package history

import (
	"sort"
	"testing"
	"time"
)

func dateTime(d Date) time.Time {
	return time.Date(d.Year, time.Month(d.Month), d.Day, 0, 0, 0, 0, time.UTC)
}

func TestReleases(t *testing.T) {
	seen := make(map[Version]bool)
	lastMinor := make(map[Version]int)
	var last time.Time
	for _, r := range Releases {
		if seen[r.Version] {
			t.Errorf("version %v duplicated", r.Version)
			continue
		}
		seen[r.Version] = true
		rt := dateTime(r.Date)
		if !last.IsZero() && rt.After(last) {
			t.Errorf("version %v out of order: %v vs %v", r.Version, r.Date, last.Format("2006-01-02"))
		}
		last = rt
		major := r.Version
		major.Z = 0
		if z, ok := lastMinor[major]; ok && r.Version.Z != z-1 {
			old := major
			old.Z = z
			t.Errorf("jumped from %v to %v", old, r.Version)
		}
		lastMinor[major] = r.Version.Z
		if r.Security != nil {
			if p := r.Security.Packages; !sort.StringsAreSorted(p) {
				t.Errorf("version %v security fix packages out of order: %v vs %v", r.Version, p, sorted(p))
			}
		}
		if r.Bug != nil {
			if p := r.Bug.Packages; !sort.StringsAreSorted(p) {
				t.Errorf("version %v bug fix packages out of order: %v vs %v", r.Version, p, sorted(p))
			}
		}
	}
}

func sorted(s []string) []string {
	s = append([]string(nil), s...)
	sort.Strings(s)
	return s
}
<commit_msg>internal/history: remove redundant type conversion<commit_after>// Copyright 2021 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.

package history

import (
	"sort"
	"testing"
	"time"
)

func dateTime(d Date) time.Time {
	return time.Date(d.Year, d.Month, d.Day, 0, 0, 0, 0, time.UTC)
}

func TestReleases(t *testing.T) {
	seen := make(map[Version]bool)
	lastMinor := make(map[Version]int)
	var last time.Time
	for _, r := range Releases {
		if seen[r.Version] {
			t.Errorf("version %v duplicated", r.Version)
			continue
		}
		seen[r.Version] = true
		rt := dateTime(r.Date)
		if !last.IsZero() && rt.After(last) {
			t.Errorf("version %v out of order: %v vs %v", r.Version, r.Date, last.Format("2006-01-02"))
		}
		last = rt
		major := r.Version
		major.Z = 0
		if z, ok := lastMinor[major]; ok && r.Version.Z != z-1 {
			old := major
			old.Z = z
			t.Errorf("jumped from %v to %v", old, r.Version)
		}
		lastMinor[major] = r.Version.Z
		if r.Security != nil {
			if p := r.Security.Packages; !sort.StringsAreSorted(p) {
				t.Errorf("version %v security fix packages out of order: %v vs %v", r.Version, p, sorted(p))
			}
		}
		if r.Bug != nil {
			if p := r.Bug.Packages; !sort.StringsAreSorted(p) {
				t.Errorf("version %v bug fix packages out of order: %v vs %v", r.Version, p, sorted(p))
			}
		}
	}
}

func sorted(s []string) []string {
	s = append([]string(nil), s...)
	sort.Strings(s)
	return s
}
<|endoftext|>


<commit_before>// Copyright 2020 Google Inc. All Rights Reserved.
// This file is available under the Apache license.

package waker_test

import (
	"context"
	"sync"
	"testing"

	"github.com/google/mtail/internal/waker"
)

func TestTestWakerWakes(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	w, awaken := waker.NewTest(ctx, 1)
	c := w.Wake()
	select {
	case x := <-c:
		t.Errorf("<-w.Wake() == %v, expected nothing (should block)", x)
	default:
	}
	awaken(0)
	select {
	case <-c:
		// Luke Luck likes lakes.  Luke's duck likes lakes.
	default:
		t.Errorf("<-w.Wake() blocked, expected close")
	}
}

func TestTestWakerTwoWakees(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	w, awaken := waker.NewTest(ctx, 2)
	var wg1, wg2, wg3 sync.WaitGroup
	wg1.Add(1)
	wg2.Add(1)
	wg3.Add(1)
	go func() {
		defer wg3.Done()
		c := w.Wake()
		select {
		case x := <-c:
			t.Errorf("<-w.Wake() == %v, expected nothing (should block)", x)
		default:
		}
		wg1.Wait()
		select {
		case x := <-c:
			t.Errorf("<-w.Wake() == %v, expected nothing (should block)", x)
		default:
		}
		d := w.Wake()
		wg2.Wait()
		select {
		case <-c:
			// Luke Luck likes lakes.
		default:
			t.Errorf("c<-w.Wake() blocked, expected close")
		}
		select {
		case <-d:
			//   Luke's duck likes lakes.
		default:
			t.Errorf("d<-w.Wake() blocked, expected close")
		}
	}()
	wg1.Done()
	awaken(0) // wake 2, and await none
	wg2.Done()
	wg3.Wait()
}

func TestTestWakerTwoWakeups(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	w, awaken := waker.NewTest(ctx, 1)
	var wg sync.WaitGroup
	wg.Add(2)
	go func() {
		defer wg.Done()
		for i := 0; i < 2; i++ {
			c := w.Wake()
			select {
			case x := <-c:
				t.Errorf("<-w.Wake() == %v, expected nothing (should block)", x)
			default:
			}
		}
	}()
	go func() {
		defer wg.Done()
		awaken(1)
		awaken(0)
	}()
	wg.Wait()
}
<commit_msg>Use a barrier to ensure we awaken at the right moment to fix a flake.<commit_after>// Copyright 2020 Google Inc. All Rights Reserved.
// This file is available under the Apache license.

package waker_test

import (
	"context"
	"sync"
	"testing"

	"github.com/google/mtail/internal/waker"
)

func TestTestWakerWakes(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	w, awaken := waker.NewTest(ctx, 1)
	c := w.Wake()
	select {
	case x := <-c:
		t.Errorf("<-w.Wake() == %v, expected nothing (should block)", x)
	default:
	}
	awaken(0)
	select {
	case <-c:
		// Luke Luck likes lakes.  Luke's duck likes lakes.
	default:
		t.Errorf("<-w.Wake() blocked, expected close")
	}
}

func TestTestWakerTwoWakees(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	w, awaken := waker.NewTest(ctx, 2)
	var wg1, wg2, wg3 sync.WaitGroup
	wg1.Add(1)
	wg2.Add(1)
	wg3.Add(1)
	go func() {
		defer wg3.Done()
		c := w.Wake()
		select {
		case x := <-c:
			t.Errorf("<-w.Wake() == %v, expected nothing (should block)", x)
		default:
		}
		wg1.Wait()
		select {
		case x := <-c:
			t.Errorf("<-w.Wake() == %v, expected nothing (should block)", x)
		default:
		}
		d := w.Wake()
		wg2.Wait()
		select {
		case <-c:
			// Luke Luck likes lakes.
		default:
			t.Errorf("c<-w.Wake() blocked, expected close")
		}
		select {
		case <-d:
			//   Luke's duck likes lakes.
		default:
			t.Errorf("d<-w.Wake() blocked, expected close")
		}
	}()
	wg1.Done()
	awaken(0) // wake 2, and await none
	wg2.Done()
	wg3.Wait()
}

func TestTestWakerTwoWakeups(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	w, awaken := waker.NewTest(ctx, 1)
	s := make(chan struct{})
	var wg sync.WaitGroup
	wg.Add(2)
	go func() {
		defer wg.Done()
		for i := 0; i < 2; i++ {
			c := w.Wake()
			select {
			case x := <-c:
				t.Errorf("<-w.Wake() == %v, expected nothing (should block), pass %d", x, i)
			default:
			}
			s <- struct{}{}

		}
	}()
	go func() {
		defer wg.Done()
		<-s
		awaken(1)
		<-s
		awaken(0)
	}()
	wg.Wait()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"go.pedge.io/dockervolume"
	"go.pedge.io/env"
	"go.pedge.io/pkg/map"

	"github.com/pachyderm/pachyderm/src/pfs/fuse"
	"github.com/satori/go.uuid"
)

const (
	defaultShard   = 0
	defaultModulus = 1
)

var (
	defaultEnv = map[string]string{
		"PFS_ADDRESS":        "0.0.0.0:650",
		"BASE_MOUNTPOINT":    "/tmp/pfs-volume-driver",
		"GRPC_PORT":          "2150",
		"HTTP_PORT":          "1950",
		"VOLUME_DRIVER_NAME": "pfs",
	}
)

type appEnv struct {
	PachydermPfsd1Port string `env:"PACHYDERM_PFSD_1_PORT"`
	PfsAddress         string `env:"PFS_ADDRESS"`
	BaseMountpoint     string `env:"BASE_MOUNTPOINT"`
	GRPCPort           int    `env:"GRPC_PORT"`
	HTTPPort           int    `env:"HTTP_PORT"`
	VolumeDriverName   string `env:"VOLUME_DRIVER_NAME"`
}

func main() {
	env.Main(do, &appEnv{}, defaultEnv)
}

func do(appEnvObj interface{}) error {
	return newServer(appEnvObj.(*appEnv)).Serve()
}

func newServer(appEnv *appEnv) dockervolume.Server {
	return dockervolume.NewTCPServer(
		newVolumeDriver(
			fuse.NewMounterProvider(getPFSAddress(appEnv)),
			appEnv.BaseMountpoint,
		),
		appEnv.VolumeDriverName,
		fmt.Sprintf(":%d", appEnv.HTTPPort),
		dockervolume.ServerOptions{
			GRPCPort: uint16(appEnv.GRPCPort),
		},
	)
}

func getPFSAddress(appEnv *appEnv) string {
	address := appEnv.PachydermPfsd1Port
	if address == "" {
		return appEnv.PfsAddress
	}
	return strings.Replace(address, "tcp://", "", -1)
}

type volumeDriver struct {
	mounterProvider fuse.MounterProvider
	baseMountpoint  string
}

func newVolumeDriver(
	mounterProvider fuse.MounterProvider,
	baseMountpoint string,
) *volumeDriver {
	return &volumeDriver{
		mounterProvider,
		baseMountpoint,
	}
}

func (v *volumeDriver) Create(_ string, _ pkgmap.StringStringMap) error {
	return nil
}

func (v *volumeDriver) Remove(_ string, _ pkgmap.StringStringMap, _ string) error {
	return nil
}

func (v *volumeDriver) Mount(name string, opts pkgmap.StringStringMap) (string, error) {
	mount, err := getMount(opts, v.baseMountpoint)
	if err != nil {
		return "", err
	}
	if err := mount.init(); err != nil {
		return "", err
	}
	mounter, err := v.mounterProvider.Get()
	if err != nil {
		return "", err
	}
	if err := mounter.Mount(
		mount.repository,
		mount.commitID,
		mount.mountpoint,
		mount.shard,
		mount.modulus,
	); err != nil {
		return "", err
	}
	return mount.mountpoint, nil
}

func (v *volumeDriver) Unmount(_ string, _ pkgmap.StringStringMap, mountpoint string) error {
	mounter, err := v.mounterProvider.Get()
	if err != nil {
		return err
	}
	if err := mounter.Unmount(mountpoint); err != nil {
		return err
	}
	return mounter.Wait(mountpoint)
}

type mount struct {
	repository string
	commitID   string
	shard      uint64
	modulus    uint64
	mountpoint string
}

func getMount(opts pkgmap.StringStringMap, baseMountpoint string) (*mount, error) {
	repository, err := opts.GetRequiredString("repository")
	if err != nil {
		return nil, err
	}
	commitID, err := opts.GetRequiredString("commit_id")
	if err != nil {
		return nil, err
	}
	shard, err := opts.GetUint64("shard")
	if err != nil {
		return nil, err
	}
	if shard == 0 {
		shard = defaultShard
	}
	modulus, err := opts.GetUint64("modulus")
	if err != nil {
		return nil, err
	}
	if modulus == 0 {
		modulus = defaultModulus
	}
	return &mount{
		repository,
		commitID,
		shard,
		modulus,
		filepath.Join(baseMountpoint, fmt.Sprintf("%s-%s-%d-%d-%s", repository, commitID, shard, modulus, strings.Replace(uuid.NewV4().String(), "-", "", -1))),
	}, nil
}

func (m *mount) init() error {
	return os.MkdirAll(m.mountpoint, 0777)
}
<commit_msg>Things are building again.<commit_after>package main

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"go.pedge.io/dockervolume"
	"go.pedge.io/env"
	"go.pedge.io/pkg/map"

	"github.com/pachyderm/pachyderm/src/pfs/fuse"
	"github.com/satori/go.uuid"
)

const (
	defaultShard   = 0
	defaultModulus = 1
)

var (
	defaultEnv = map[string]string{
		"PFS_ADDRESS":        "0.0.0.0:650",
		"BASE_MOUNTPOINT":    "/tmp/pfs-volume-driver",
		"GRPC_PORT":          "2150",
		"HTTP_PORT":          "1950",
		"VOLUME_DRIVER_NAME": "pfs",
	}
)

type appEnv struct {
	PachydermPfsd1Port string `env:"PACHYDERM_PFSD_1_PORT"`
	PfsAddress         string `env:"PFS_ADDRESS"`
	BaseMountpoint     string `env:"BASE_MOUNTPOINT"`
	GRPCPort           int    `env:"GRPC_PORT"`
	HTTPPort           int    `env:"HTTP_PORT"`
	VolumeDriverName   string `env:"VOLUME_DRIVER_NAME"`
}

func main() {
	env.Main(do, &appEnv{}, defaultEnv)
}

func do(appEnvObj interface{}) error {
	return newServer(appEnvObj.(*appEnv)).Serve()
}

func newServer(appEnv *appEnv) dockervolume.Server {
	return dockervolume.NewTCPServer(
		newVolumeDriver(
			getPFSAddress(appEnv),
			fuse.NewMounterProvider(getPFSAddress(appEnv)),
			appEnv.BaseMountpoint,
		),
		appEnv.VolumeDriverName,
		fmt.Sprintf(":%d", appEnv.HTTPPort),
		dockervolume.ServerOptions{
			GRPCPort: uint16(appEnv.GRPCPort),
		},
	)
}

func getPFSAddress(appEnv *appEnv) string {
	address := appEnv.PachydermPfsd1Port
	if address == "" {
		return appEnv.PfsAddress
	}
	return strings.Replace(address, "tcp://", "", -1)
}

type volumeDriver struct {
	pfsAddress      string
	mounterProvider fuse.MounterProvider
	baseMountpoint  string
}

func newVolumeDriver(
	pfsAddress string,
	mounterProvider fuse.MounterProvider,
	baseMountpoint string,
) *volumeDriver {
	return &volumeDriver{
		pfsAddress,
		mounterProvider,
		baseMountpoint,
	}
}

func (v *volumeDriver) Create(_ string, _ pkgmap.StringStringMap) error {
	return nil
}

func (v *volumeDriver) Remove(_ string, _ pkgmap.StringStringMap, _ string) error {
	return nil
}

func (v *volumeDriver) Mount(name string, opts pkgmap.StringStringMap) (string, error) {
	mount, err := getMount(opts, v.baseMountpoint)
	if err != nil {
		return "", err
	}
	if err := mount.init(); err != nil {
		return "", err
	}
	mounter, err := v.mounterProvider.Get()
	if err != nil {
		return "", err
	}
	if err := mounter.Mount(
		v.pfsAddress,
		mount.mountpoint,
		mount.shard,
		mount.modulus,
	); err != nil {
		return "", err
	}
	return mount.mountpoint, nil
}

func (v *volumeDriver) Unmount(_ string, _ pkgmap.StringStringMap, mountpoint string) error {
	mounter, err := v.mounterProvider.Get()
	if err != nil {
		return err
	}
	return mounter.Unmount(mountpoint)
}

type mount struct {
	repository string
	commitID   string
	shard      uint64
	modulus    uint64
	mountpoint string
}

func getMount(opts pkgmap.StringStringMap, baseMountpoint string) (*mount, error) {
	repository, err := opts.GetRequiredString("repository")
	if err != nil {
		return nil, err
	}
	commitID, err := opts.GetRequiredString("commit_id")
	if err != nil {
		return nil, err
	}
	shard, err := opts.GetUint64("shard")
	if err != nil {
		return nil, err
	}
	if shard == 0 {
		shard = defaultShard
	}
	modulus, err := opts.GetUint64("modulus")
	if err != nil {
		return nil, err
	}
	if modulus == 0 {
		modulus = defaultModulus
	}
	return &mount{
		repository,
		commitID,
		shard,
		modulus,
		filepath.Join(baseMountpoint, fmt.Sprintf("%s-%s-%d-%d-%s", repository, commitID, shard, modulus, strings.Replace(uuid.NewV4().String(), "-", "", -1))),
	}, nil
}

func (m *mount) init() error {
	return os.MkdirAll(m.mountpoint, 0777)
}
<|endoftext|>


<commit_before>/*
Copyright 2017 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 v1

import (
	"fmt"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// +genclient=true
// +nonNamespaced=true
// +noMethods=true

// SubjectAccessReview checks whether or not a user or group can perform an action.
type SubjectAccessReview struct {
	metav1.TypeMeta `json:",inline"`
	// +optional
	metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`

	// Spec holds information about the request being evaluated
	Spec SubjectAccessReviewSpec `json:"spec" protobuf:"bytes,2,opt,name=spec"`

	// Status is filled in by the server and indicates whether the request is allowed or not
	// +optional
	Status SubjectAccessReviewStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
}

// +genclient=true
// +nonNamespaced=true
// +noMethods=true

// SelfSubjectAccessReview checks whether or the current user can perform an action.  Not filling in a
// spec.namespace means "in all namespaces".  Self is a special case, because users should always be able
// to check whether they can perform an action
type SelfSubjectAccessReview struct {
	metav1.TypeMeta `json:",inline"`
	// +optional
	metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`

	// Spec holds information about the request being evaluated.  user and groups must be empty
	Spec SelfSubjectAccessReviewSpec `json:"spec" protobuf:"bytes,2,opt,name=spec"`

	// Status is filled in by the server and indicates whether the request is allowed or not
	// +optional
	Status SubjectAccessReviewStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
}

// +genclient=true
// +noMethods=true

// LocalSubjectAccessReview checks whether or not a user or group can perform an action in a given namespace.
// Having a namespace scoped resource makes it much easier to grant namespace scoped policy that includes permissions
// checking.
type LocalSubjectAccessReview struct {
	metav1.TypeMeta `json:",inline"`
	// +optional
	metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`

	// Spec holds information about the request being evaluated.  spec.namespace must be equal to the namespace
	// you made the request against.  If empty, it is defaulted.
	Spec SubjectAccessReviewSpec `json:"spec" protobuf:"bytes,2,opt,name=spec"`

	// Status is filled in by the server and indicates whether the request is allowed or not
	// +optional
	Status SubjectAccessReviewStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
}

// ResourceAttributes includes the authorization attributes available for resource requests to the Authorizer interface
type ResourceAttributes struct {
	// Namespace is the namespace of the action being requested.  Currently, there is no distinction between no namespace and all namespaces
	// "" (empty) is defaulted for LocalSubjectAccessReviews
	// "" (empty) is empty for cluster-scoped resources
	// "" (empty) means "all" for namespace scoped resources from a SubjectAccessReview or SelfSubjectAccessReview
	// +optional
	Namespace string `json:"namespace,omitempty" protobuf:"bytes,1,opt,name=namespace"`
	// Verb is a kubernetes resource API verb, like: get, list, watch, create, update, delete, proxy.  "*" means all.
	// +optional
	Verb string `json:"verb,omitempty" protobuf:"bytes,2,opt,name=verb"`
	// Group is the API Group of the Resource.  "*" means all.
	// +optional
	Group string `json:"group,omitempty" protobuf:"bytes,3,opt,name=group"`
	// Version is the API Version of the Resource.  "*" means all.
	// +optional
	Version string `json:"version,omitempty" protobuf:"bytes,4,opt,name=version"`
	// Resource is one of the existing resource types.  "*" means all.
	// +optional
	Resource string `json:"resource,omitempty" protobuf:"bytes,5,opt,name=resource"`
	// Subresource is one of the existing resource types.  "" means none.
	// +optional
	Subresource string `json:"subresource,omitempty" protobuf:"bytes,6,opt,name=subresource"`
	// Name is the name of the resource being requested for a "get" or deleted for a "delete". "" (empty) means all.
	// +optional
	Name string `json:"name,omitempty" protobuf:"bytes,7,opt,name=name"`
}

// NonResourceAttributes includes the authorization attributes available for non-resource requests to the Authorizer interface
type NonResourceAttributes struct {
	// Path is the URL path of the request
	// +optional
	Path string `json:"path,omitempty" protobuf:"bytes,1,opt,name=path"`
	// Verb is the standard HTTP verb
	// +optional
	Verb string `json:"verb,omitempty" protobuf:"bytes,2,opt,name=verb"`
}

// SubjectAccessReviewSpec is a description of the access request.  Exactly one of ResourceAuthorizationAttributes
// and NonResourceAuthorizationAttributes must be set
type SubjectAccessReviewSpec struct {
	// ResourceAuthorizationAttributes describes information for a resource access request
	// +optional
	ResourceAttributes *ResourceAttributes `json:"resourceAttributes,omitempty" protobuf:"bytes,1,opt,name=resourceAttributes"`
	// NonResourceAttributes describes information for a non-resource access request
	// +optional
	NonResourceAttributes *NonResourceAttributes `json:"nonResourceAttributes,omitempty" protobuf:"bytes,2,opt,name=nonResourceAttributes"`

	// User is the user you're testing for.
	// If you specify "User" but not "Group", then is it interpreted as "What if User were not a member of any groups
	// +optional
	User string `json:"user,omitempty" protobuf:"bytes,3,opt,name=verb"`
	// Groups is the groups you're testing for.
	// +optional
	Groups []string `json:"group,omitempty" protobuf:"bytes,4,rep,name=group"`
	// Extra corresponds to the user.Info.GetExtra() method from the authenticator.  Since that is input to the authorizer
	// it needs a reflection here.
	// +optional
	Extra map[string]ExtraValue `json:"extra,omitempty" protobuf:"bytes,5,rep,name=extra"`
}

// ExtraValue masks the value so protobuf can generate
// +protobuf.nullable=true
// +protobuf.options.(gogoproto.goproto_stringer)=false
type ExtraValue []string

func (t ExtraValue) String() string {
	return fmt.Sprintf("%v", []string(t))
}

// SelfSubjectAccessReviewSpec is a description of the access request.  Exactly one of ResourceAuthorizationAttributes
// and NonResourceAuthorizationAttributes must be set
type SelfSubjectAccessReviewSpec struct {
	// ResourceAuthorizationAttributes describes information for a resource access request
	// +optional
	ResourceAttributes *ResourceAttributes `json:"resourceAttributes,omitempty" protobuf:"bytes,1,opt,name=resourceAttributes"`
	// NonResourceAttributes describes information for a non-resource access request
	// +optional
	NonResourceAttributes *NonResourceAttributes `json:"nonResourceAttributes,omitempty" protobuf:"bytes,2,opt,name=nonResourceAttributes"`
}

// SubjectAccessReviewStatus
type SubjectAccessReviewStatus struct {
	// Allowed is required.  True if the action would be allowed, false otherwise.
	Allowed bool `json:"allowed" protobuf:"varint,1,opt,name=allowed"`
	// Reason is optional.  It indicates why a request was allowed or denied.
	// +optional
	Reason string `json:"reason,omitempty" protobuf:"bytes,2,opt,name=reason"`
	// EvaluationError is an indication that some error occurred during the authorization check.
	// It is entirely possible to get an error and be able to continue determine authorization status in spite of it.
	// For instance, RBAC can be missing a role, but enough roles are still present and bound to reason about the request.
	// +optional
	EvaluationError string `json:"evaluationError,omitempty" protobuf:"bytes,3,opt,name=evaluationError"`
}
<commit_msg>Fix typo in v1beta1 field name<commit_after>/*
Copyright 2017 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 v1

import (
	"fmt"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// +genclient=true
// +nonNamespaced=true
// +noMethods=true

// SubjectAccessReview checks whether or not a user or group can perform an action.
type SubjectAccessReview struct {
	metav1.TypeMeta `json:",inline"`
	// +optional
	metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`

	// Spec holds information about the request being evaluated
	Spec SubjectAccessReviewSpec `json:"spec" protobuf:"bytes,2,opt,name=spec"`

	// Status is filled in by the server and indicates whether the request is allowed or not
	// +optional
	Status SubjectAccessReviewStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
}

// +genclient=true
// +nonNamespaced=true
// +noMethods=true

// SelfSubjectAccessReview checks whether or the current user can perform an action.  Not filling in a
// spec.namespace means "in all namespaces".  Self is a special case, because users should always be able
// to check whether they can perform an action
type SelfSubjectAccessReview struct {
	metav1.TypeMeta `json:",inline"`
	// +optional
	metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`

	// Spec holds information about the request being evaluated.  user and groups must be empty
	Spec SelfSubjectAccessReviewSpec `json:"spec" protobuf:"bytes,2,opt,name=spec"`

	// Status is filled in by the server and indicates whether the request is allowed or not
	// +optional
	Status SubjectAccessReviewStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
}

// +genclient=true
// +noMethods=true

// LocalSubjectAccessReview checks whether or not a user or group can perform an action in a given namespace.
// Having a namespace scoped resource makes it much easier to grant namespace scoped policy that includes permissions
// checking.
type LocalSubjectAccessReview struct {
	metav1.TypeMeta `json:",inline"`
	// +optional
	metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`

	// Spec holds information about the request being evaluated.  spec.namespace must be equal to the namespace
	// you made the request against.  If empty, it is defaulted.
	Spec SubjectAccessReviewSpec `json:"spec" protobuf:"bytes,2,opt,name=spec"`

	// Status is filled in by the server and indicates whether the request is allowed or not
	// +optional
	Status SubjectAccessReviewStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
}

// ResourceAttributes includes the authorization attributes available for resource requests to the Authorizer interface
type ResourceAttributes struct {
	// Namespace is the namespace of the action being requested.  Currently, there is no distinction between no namespace and all namespaces
	// "" (empty) is defaulted for LocalSubjectAccessReviews
	// "" (empty) is empty for cluster-scoped resources
	// "" (empty) means "all" for namespace scoped resources from a SubjectAccessReview or SelfSubjectAccessReview
	// +optional
	Namespace string `json:"namespace,omitempty" protobuf:"bytes,1,opt,name=namespace"`
	// Verb is a kubernetes resource API verb, like: get, list, watch, create, update, delete, proxy.  "*" means all.
	// +optional
	Verb string `json:"verb,omitempty" protobuf:"bytes,2,opt,name=verb"`
	// Group is the API Group of the Resource.  "*" means all.
	// +optional
	Group string `json:"group,omitempty" protobuf:"bytes,3,opt,name=group"`
	// Version is the API Version of the Resource.  "*" means all.
	// +optional
	Version string `json:"version,omitempty" protobuf:"bytes,4,opt,name=version"`
	// Resource is one of the existing resource types.  "*" means all.
	// +optional
	Resource string `json:"resource,omitempty" protobuf:"bytes,5,opt,name=resource"`
	// Subresource is one of the existing resource types.  "" means none.
	// +optional
	Subresource string `json:"subresource,omitempty" protobuf:"bytes,6,opt,name=subresource"`
	// Name is the name of the resource being requested for a "get" or deleted for a "delete". "" (empty) means all.
	// +optional
	Name string `json:"name,omitempty" protobuf:"bytes,7,opt,name=name"`
}

// NonResourceAttributes includes the authorization attributes available for non-resource requests to the Authorizer interface
type NonResourceAttributes struct {
	// Path is the URL path of the request
	// +optional
	Path string `json:"path,omitempty" protobuf:"bytes,1,opt,name=path"`
	// Verb is the standard HTTP verb
	// +optional
	Verb string `json:"verb,omitempty" protobuf:"bytes,2,opt,name=verb"`
}

// SubjectAccessReviewSpec is a description of the access request.  Exactly one of ResourceAuthorizationAttributes
// and NonResourceAuthorizationAttributes must be set
type SubjectAccessReviewSpec struct {
	// ResourceAuthorizationAttributes describes information for a resource access request
	// +optional
	ResourceAttributes *ResourceAttributes `json:"resourceAttributes,omitempty" protobuf:"bytes,1,opt,name=resourceAttributes"`
	// NonResourceAttributes describes information for a non-resource access request
	// +optional
	NonResourceAttributes *NonResourceAttributes `json:"nonResourceAttributes,omitempty" protobuf:"bytes,2,opt,name=nonResourceAttributes"`

	// User is the user you're testing for.
	// If you specify "User" but not "Groups", then is it interpreted as "What if User were not a member of any groups
	// +optional
	User string `json:"user,omitempty" protobuf:"bytes,3,opt,name=verb"`
	// Groups is the groups you're testing for.
	// +optional
	Groups []string `json:"groups,omitempty" protobuf:"bytes,4,rep,name=groups"`
	// Extra corresponds to the user.Info.GetExtra() method from the authenticator.  Since that is input to the authorizer
	// it needs a reflection here.
	// +optional
	Extra map[string]ExtraValue `json:"extra,omitempty" protobuf:"bytes,5,rep,name=extra"`
}

// ExtraValue masks the value so protobuf can generate
// +protobuf.nullable=true
// +protobuf.options.(gogoproto.goproto_stringer)=false
type ExtraValue []string

func (t ExtraValue) String() string {
	return fmt.Sprintf("%v", []string(t))
}

// SelfSubjectAccessReviewSpec is a description of the access request.  Exactly one of ResourceAuthorizationAttributes
// and NonResourceAuthorizationAttributes must be set
type SelfSubjectAccessReviewSpec struct {
	// ResourceAuthorizationAttributes describes information for a resource access request
	// +optional
	ResourceAttributes *ResourceAttributes `json:"resourceAttributes,omitempty" protobuf:"bytes,1,opt,name=resourceAttributes"`
	// NonResourceAttributes describes information for a non-resource access request
	// +optional
	NonResourceAttributes *NonResourceAttributes `json:"nonResourceAttributes,omitempty" protobuf:"bytes,2,opt,name=nonResourceAttributes"`
}

// SubjectAccessReviewStatus
type SubjectAccessReviewStatus struct {
	// Allowed is required.  True if the action would be allowed, false otherwise.
	Allowed bool `json:"allowed" protobuf:"varint,1,opt,name=allowed"`
	// Reason is optional.  It indicates why a request was allowed or denied.
	// +optional
	Reason string `json:"reason,omitempty" protobuf:"bytes,2,opt,name=reason"`
	// EvaluationError is an indication that some error occurred during the authorization check.
	// It is entirely possible to get an error and be able to continue determine authorization status in spite of it.
	// For instance, RBAC can be missing a role, but enough roles are still present and bound to reason about the request.
	// +optional
	EvaluationError string `json:"evaluationError,omitempty" protobuf:"bytes,3,opt,name=evaluationError"`
}
<|endoftext|>


<commit_before>// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of Cilium

package watchers

import (
	"sync"

	v1 "k8s.io/api/core/v1"
	v1meta "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/fields"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/cache"

	"github.com/cilium/cilium/pkg/k8s"
	"github.com/cilium/cilium/pkg/k8s/informer"
	slim_discover_v1 "github.com/cilium/cilium/pkg/k8s/slim/k8s/api/discovery/v1"
	slim_discover_v1beta1 "github.com/cilium/cilium/pkg/k8s/slim/k8s/api/discovery/v1beta1"
	"github.com/cilium/cilium/pkg/k8s/watchers/resources"
	"github.com/cilium/cilium/pkg/lock"
	"github.com/cilium/cilium/pkg/option"
)

// endpointSlicesInit returns true if the cluster contains endpoint slices.
func (k *K8sWatcher) endpointSlicesInit(k8sClient kubernetes.Interface, swgEps *lock.StoppableWaitGroup) bool {
	var (
		hasEndpointSlices = make(chan struct{})
		once              sync.Once
		esClient          rest.Interface
		objType           runtime.Object
		addFunc, delFunc  func(obj interface{})
		updateFunc        func(oldObj, newObj interface{})
		apiGroup          string
	)

	if k8s.SupportsEndpointSliceV1() {
		apiGroup = resources.K8sAPIGroupEndpointSliceV1Discovery
		esClient = k8sClient.DiscoveryV1().RESTClient()
		objType = &slim_discover_v1.EndpointSlice{}
		addFunc = func(obj interface{}) {
			once.Do(func() {
				// signalize that we have received an endpoint slice
				// so it means the cluster has endpoint slices enabled.
				close(hasEndpointSlices)
			})
			var valid, equal bool
			defer func() {
				k.K8sEventReceived(apiGroup, resources.MetricEndpointSlice, resources.MetricCreate, valid, equal)
			}()
			if k8sEP := k8s.ObjToV1EndpointSlice(obj); k8sEP != nil {
				valid = true
				k.updateK8sEndpointSliceV1(k8sEP, swgEps)
				k.K8sEventProcessed(resources.MetricEndpointSlice, resources.MetricCreate, true)
			}
		}
		updateFunc = func(oldObj, newObj interface{}) {
			var valid, equal bool
			defer func() {
				k.K8sEventReceived(apiGroup, resources.MetricEndpointSlice, resources.MetricUpdate, valid, equal)
			}()
			if oldk8sEP := k8s.ObjToV1EndpointSlice(oldObj); oldk8sEP != nil {
				if newk8sEP := k8s.ObjToV1EndpointSlice(newObj); newk8sEP != nil {
					valid = true
					if oldk8sEP.DeepEqual(newk8sEP) {
						equal = true
						return
					}

					k.updateK8sEndpointSliceV1(newk8sEP, swgEps)
					k.K8sEventProcessed(resources.MetricEndpointSlice, resources.MetricUpdate, true)
				}
			}
		}
		delFunc = func(obj interface{}) {
			var valid, equal bool
			defer func() {
				k.K8sEventReceived(apiGroup, resources.MetricEndpointSlice, resources.MetricDelete, valid, equal)
			}()
			k8sEP := k8s.ObjToV1EndpointSlice(obj)
			if k8sEP == nil {
				return
			}
			valid = true
			k.K8sSvcCache.DeleteEndpointSlices(k8sEP, swgEps)
			k.K8sEventProcessed(resources.MetricEndpointSlice, resources.MetricDelete, true)
		}
	} else {
		apiGroup = resources.K8sAPIGroupEndpointSliceV1Beta1Discovery
		esClient = k8sClient.DiscoveryV1beta1().RESTClient()
		objType = &slim_discover_v1beta1.EndpointSlice{}
		addFunc = func(obj interface{}) {
			once.Do(func() {
				// signalize that we have received an endpoint slice
				// so it means the cluster has endpoint slices enabled.
				close(hasEndpointSlices)
			})
			var valid, equal bool
			defer func() {
				k.K8sEventReceived(apiGroup, resources.MetricEndpointSlice, resources.MetricCreate, valid, equal)
			}()
			if k8sEP := k8s.ObjToV1Beta1EndpointSlice(obj); k8sEP != nil {
				valid = true
				k.updateK8sEndpointSliceV1Beta1(k8sEP, swgEps)
				k.K8sEventProcessed(resources.MetricEndpointSlice, resources.MetricCreate, true)
			}
		}
		updateFunc = func(oldObj, newObj interface{}) {
			var valid, equal bool
			defer func() {
				k.K8sEventReceived(apiGroup, resources.MetricEndpointSlice, resources.MetricUpdate, valid, equal)
			}()
			if oldk8sEP := k8s.ObjToV1Beta1EndpointSlice(oldObj); oldk8sEP != nil {
				if newk8sEP := k8s.ObjToV1Beta1EndpointSlice(newObj); newk8sEP != nil {
					valid = true
					if oldk8sEP.DeepEqual(newk8sEP) {
						equal = true
						return
					}

					k.updateK8sEndpointSliceV1Beta1(newk8sEP, swgEps)
					k.K8sEventProcessed(resources.MetricEndpointSlice, resources.MetricUpdate, true)
				}
			}
		}
		delFunc = func(obj interface{}) {
			var valid, equal bool
			defer func() {
				k.K8sEventReceived(apiGroup, resources.MetricEndpointSlice, resources.MetricDelete, valid, equal)
			}()
			k8sEP := k8s.ObjToV1Beta1EndpointSlice(obj)
			if k8sEP == nil {
				return
			}
			valid = true
			k.K8sSvcCache.DeleteEndpointSlices(k8sEP, swgEps)
			k.K8sEventProcessed(resources.MetricEndpointSlice, resources.MetricDelete, true)
		}
	}

	_, endpointController := informer.NewInformer(
		cache.NewListWatchFromClient(esClient,
			"endpointslices", v1.NamespaceAll, fields.Everything()),
		objType,
		0,
		cache.ResourceEventHandlerFuncs{
			AddFunc:    addFunc,
			UpdateFunc: updateFunc,
			DeleteFunc: delFunc,
		},
		nil,
	)
	ecr := make(chan struct{})
	k.blockWaitGroupToSyncResources(ecr, swgEps, endpointController.HasSynced, apiGroup)
	go endpointController.Run(ecr)
	k.k8sAPIGroups.AddAPI(apiGroup)

	if k8s.HasEndpointSlice(hasEndpointSlices, endpointController) {
		return true
	}

	// K8s is not running with endpoint slices enabled, stop the endpoint slice
	// controller to avoid watching for unnecessary stuff in k8s.
	k.k8sAPIGroups.RemoveAPI(apiGroup)
	close(ecr)
	return false
}

func (k *K8sWatcher) updateK8sEndpointSliceV1(eps *slim_discover_v1.EndpointSlice, swgEps *lock.StoppableWaitGroup) {
	k.K8sSvcCache.UpdateEndpointSlicesV1(eps, swgEps)

	if option.Config.BGPAnnounceLBIP {
		k.bgpSpeakerManager.OnUpdateEndpointSliceV1(eps)
	}

	k.addKubeAPIServerServiceEPSliceV1(eps)
}

func (k *K8sWatcher) updateK8sEndpointSliceV1Beta1(eps *slim_discover_v1beta1.EndpointSlice, swgEps *lock.StoppableWaitGroup) {
	k.K8sSvcCache.UpdateEndpointSlicesV1Beta1(eps, swgEps)

	if option.Config.BGPAnnounceLBIP {
		k.bgpSpeakerManager.OnUpdateEndpointSliceV1Beta1(eps)
	}

	k.addKubeAPIServerServiceEPSliceV1Beta1(eps)
}

func (k *K8sWatcher) addKubeAPIServerServiceEPSliceV1(eps *slim_discover_v1.EndpointSlice) {
	if eps == nil ||
		eps.GetLabels()[slim_discover_v1.LabelServiceName] != "kubernetes" ||
		eps.Namespace != "default" {
		return
	}

	desiredIPs := make(map[string]struct{})
	for _, e := range eps.Endpoints {
		for _, addr := range e.Addresses {
			desiredIPs[addr] = struct{}{}
		}
	}

	k.handleKubeAPIServerServiceEPChanges(desiredIPs)
}

func (k *K8sWatcher) addKubeAPIServerServiceEPSliceV1Beta1(eps *slim_discover_v1beta1.EndpointSlice) {
	if eps == nil ||
		eps.GetLabels()[slim_discover_v1beta1.LabelServiceName] != "kubernetes" ||
		eps.Namespace != "default" {
		return
	}

	desiredIPs := make(map[string]struct{})
	for _, e := range eps.Endpoints {
		for _, addr := range e.Addresses {
			desiredIPs[addr] = struct{}{}
		}
	}

	k.handleKubeAPIServerServiceEPChanges(desiredIPs)
}

// initEndpointsOrSlices initializes either the "Endpoints" or "EndpointSlice"
// resources for Kubernetes service backends.
func (k *K8sWatcher) initEndpointsOrSlices(k8sClient kubernetes.Interface, serviceOptModifier func(*v1meta.ListOptions)) {
	swgEps := lock.NewStoppableWaitGroup()
	switch {
	case k8s.SupportsEndpointSlice():
		// We don't add the service option modifier here, as endpointslices do not
		// mirror service proxy name label present in the corresponding service.
		connected := k.endpointSlicesInit(k8sClient, swgEps)
		// The cluster has endpoint slices so we should not check for v1.Endpoints
		if connected {
			break
		}
		fallthrough
	default:
		k.endpointsInit(k8sClient, swgEps, serviceOptModifier)
	}
}
<commit_msg>pkg/k8s: do not wait for endpointslice cache sync in k8s >= 1.17<commit_after>// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of Cilium

package watchers

import (
	"sync"

	v1 "k8s.io/api/core/v1"
	v1meta "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/fields"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/cache"

	"github.com/cilium/cilium/pkg/k8s"
	"github.com/cilium/cilium/pkg/k8s/informer"
	slim_discover_v1 "github.com/cilium/cilium/pkg/k8s/slim/k8s/api/discovery/v1"
	slim_discover_v1beta1 "github.com/cilium/cilium/pkg/k8s/slim/k8s/api/discovery/v1beta1"
	"github.com/cilium/cilium/pkg/k8s/watchers/resources"
	"github.com/cilium/cilium/pkg/lock"
	"github.com/cilium/cilium/pkg/option"
)

// endpointSlicesInit returns true if the cluster contains endpoint slices.
func (k *K8sWatcher) endpointSlicesInit(k8sClient kubernetes.Interface, swgEps *lock.StoppableWaitGroup) bool {
	var (
		hasEndpointSlices = make(chan struct{})
		once              sync.Once
		esClient          rest.Interface
		objType           runtime.Object
		addFunc, delFunc  func(obj interface{})
		updateFunc        func(oldObj, newObj interface{})
		apiGroup          string
	)

	if k8s.SupportsEndpointSliceV1() {
		apiGroup = resources.K8sAPIGroupEndpointSliceV1Discovery
		esClient = k8sClient.DiscoveryV1().RESTClient()
		objType = &slim_discover_v1.EndpointSlice{}
		addFunc = func(obj interface{}) {
			once.Do(func() {
				// signalize that we have received an endpoint slice
				// so it means the cluster has endpoint slices enabled.
				close(hasEndpointSlices)
			})
			var valid, equal bool
			defer func() {
				k.K8sEventReceived(apiGroup, resources.MetricEndpointSlice, resources.MetricCreate, valid, equal)
			}()
			if k8sEP := k8s.ObjToV1EndpointSlice(obj); k8sEP != nil {
				valid = true
				k.updateK8sEndpointSliceV1(k8sEP, swgEps)
				k.K8sEventProcessed(resources.MetricEndpointSlice, resources.MetricCreate, true)
			}
		}
		updateFunc = func(oldObj, newObj interface{}) {
			var valid, equal bool
			defer func() {
				k.K8sEventReceived(apiGroup, resources.MetricEndpointSlice, resources.MetricUpdate, valid, equal)
			}()
			if oldk8sEP := k8s.ObjToV1EndpointSlice(oldObj); oldk8sEP != nil {
				if newk8sEP := k8s.ObjToV1EndpointSlice(newObj); newk8sEP != nil {
					valid = true
					if oldk8sEP.DeepEqual(newk8sEP) {
						equal = true
						return
					}

					k.updateK8sEndpointSliceV1(newk8sEP, swgEps)
					k.K8sEventProcessed(resources.MetricEndpointSlice, resources.MetricUpdate, true)
				}
			}
		}
		delFunc = func(obj interface{}) {
			var valid, equal bool
			defer func() {
				k.K8sEventReceived(apiGroup, resources.MetricEndpointSlice, resources.MetricDelete, valid, equal)
			}()
			k8sEP := k8s.ObjToV1EndpointSlice(obj)
			if k8sEP == nil {
				return
			}
			valid = true
			k.K8sSvcCache.DeleteEndpointSlices(k8sEP, swgEps)
			k.K8sEventProcessed(resources.MetricEndpointSlice, resources.MetricDelete, true)
		}
	} else {
		apiGroup = resources.K8sAPIGroupEndpointSliceV1Beta1Discovery
		esClient = k8sClient.DiscoveryV1beta1().RESTClient()
		objType = &slim_discover_v1beta1.EndpointSlice{}
		addFunc = func(obj interface{}) {
			once.Do(func() {
				// signalize that we have received an endpoint slice
				// so it means the cluster has endpoint slices enabled.
				close(hasEndpointSlices)
			})
			var valid, equal bool
			defer func() {
				k.K8sEventReceived(apiGroup, resources.MetricEndpointSlice, resources.MetricCreate, valid, equal)
			}()
			if k8sEP := k8s.ObjToV1Beta1EndpointSlice(obj); k8sEP != nil {
				valid = true
				k.updateK8sEndpointSliceV1Beta1(k8sEP, swgEps)
				k.K8sEventProcessed(resources.MetricEndpointSlice, resources.MetricCreate, true)
			}
		}
		updateFunc = func(oldObj, newObj interface{}) {
			var valid, equal bool
			defer func() {
				k.K8sEventReceived(apiGroup, resources.MetricEndpointSlice, resources.MetricUpdate, valid, equal)
			}()
			if oldk8sEP := k8s.ObjToV1Beta1EndpointSlice(oldObj); oldk8sEP != nil {
				if newk8sEP := k8s.ObjToV1Beta1EndpointSlice(newObj); newk8sEP != nil {
					valid = true
					if oldk8sEP.DeepEqual(newk8sEP) {
						equal = true
						return
					}

					k.updateK8sEndpointSliceV1Beta1(newk8sEP, swgEps)
					k.K8sEventProcessed(resources.MetricEndpointSlice, resources.MetricUpdate, true)
				}
			}
		}
		delFunc = func(obj interface{}) {
			var valid, equal bool
			defer func() {
				k.K8sEventReceived(apiGroup, resources.MetricEndpointSlice, resources.MetricDelete, valid, equal)
			}()
			k8sEP := k8s.ObjToV1Beta1EndpointSlice(obj)
			if k8sEP == nil {
				return
			}
			valid = true
			k.K8sSvcCache.DeleteEndpointSlices(k8sEP, swgEps)
			k.K8sEventProcessed(resources.MetricEndpointSlice, resources.MetricDelete, true)
		}
	}

	_, endpointController := informer.NewInformer(
		cache.NewListWatchFromClient(esClient,
			"endpointslices", v1.NamespaceAll, fields.Everything()),
		objType,
		0,
		cache.ResourceEventHandlerFuncs{
			AddFunc:    addFunc,
			UpdateFunc: updateFunc,
			DeleteFunc: delFunc,
		},
		nil,
	)
	ecr := make(chan struct{})
	k.blockWaitGroupToSyncResources(ecr, swgEps, endpointController.HasSynced, apiGroup)
	go endpointController.Run(ecr)
	k.k8sAPIGroups.AddAPI(apiGroup)

	if k8s.HasEndpointSlice(hasEndpointSlices, endpointController) {
		return true
	}

	// K8s is not running with endpoint slices enabled, stop the endpoint slice
	// controller to avoid watching for unnecessary stuff in k8s.
	k.cancelWaitGroupToSyncResources(apiGroup)
	k.k8sAPIGroups.RemoveAPI(apiGroup)
	close(ecr)
	return false
}

func (k *K8sWatcher) updateK8sEndpointSliceV1(eps *slim_discover_v1.EndpointSlice, swgEps *lock.StoppableWaitGroup) {
	k.K8sSvcCache.UpdateEndpointSlicesV1(eps, swgEps)

	if option.Config.BGPAnnounceLBIP {
		k.bgpSpeakerManager.OnUpdateEndpointSliceV1(eps)
	}

	k.addKubeAPIServerServiceEPSliceV1(eps)
}

func (k *K8sWatcher) updateK8sEndpointSliceV1Beta1(eps *slim_discover_v1beta1.EndpointSlice, swgEps *lock.StoppableWaitGroup) {
	k.K8sSvcCache.UpdateEndpointSlicesV1Beta1(eps, swgEps)

	if option.Config.BGPAnnounceLBIP {
		k.bgpSpeakerManager.OnUpdateEndpointSliceV1Beta1(eps)
	}

	k.addKubeAPIServerServiceEPSliceV1Beta1(eps)
}

func (k *K8sWatcher) addKubeAPIServerServiceEPSliceV1(eps *slim_discover_v1.EndpointSlice) {
	if eps == nil ||
		eps.GetLabels()[slim_discover_v1.LabelServiceName] != "kubernetes" ||
		eps.Namespace != "default" {
		return
	}

	desiredIPs := make(map[string]struct{})
	for _, e := range eps.Endpoints {
		for _, addr := range e.Addresses {
			desiredIPs[addr] = struct{}{}
		}
	}

	k.handleKubeAPIServerServiceEPChanges(desiredIPs)
}

func (k *K8sWatcher) addKubeAPIServerServiceEPSliceV1Beta1(eps *slim_discover_v1beta1.EndpointSlice) {
	if eps == nil ||
		eps.GetLabels()[slim_discover_v1beta1.LabelServiceName] != "kubernetes" ||
		eps.Namespace != "default" {
		return
	}

	desiredIPs := make(map[string]struct{})
	for _, e := range eps.Endpoints {
		for _, addr := range e.Addresses {
			desiredIPs[addr] = struct{}{}
		}
	}

	k.handleKubeAPIServerServiceEPChanges(desiredIPs)
}

// initEndpointsOrSlices initializes either the "Endpoints" or "EndpointSlice"
// resources for Kubernetes service backends.
func (k *K8sWatcher) initEndpointsOrSlices(k8sClient kubernetes.Interface, serviceOptModifier func(*v1meta.ListOptions)) {
	swgEps := lock.NewStoppableWaitGroup()
	switch {
	case k8s.SupportsEndpointSlice():
		// We don't add the service option modifier here, as endpointslices do not
		// mirror service proxy name label present in the corresponding service.
		connected := k.endpointSlicesInit(k8sClient, swgEps)
		// The cluster has endpoint slices so we should not check for v1.Endpoints
		if connected {
			break
		}
		fallthrough
	default:
		k.endpointsInit(k8sClient, swgEps, serviceOptModifier)
	}
}
<|endoftext|>


<commit_before>package instructions

import (
	"github.com/zxh0/jvm.go/rtda/heap"
	"testing"

	"github.com/stretchr/testify/require"

	"github.com/zxh0/jvm.go/instructions/base"
	"github.com/zxh0/jvm.go/rtda"
)

func TestAConst(t *testing.T) {
	frame := rtda.NewFrame(0, 1)
	aconst_null.Execute(frame)
}

func TestDConst(t *testing.T) {
	frame := rtda.NewFrame(0, 1)
	dconst_0.Execute(frame)
	require.Equal(t, 0.0, frame.OperandStack().PopDouble())
	dconst_1.Execute(frame)
	require.Equal(t, 1.0, frame.OperandStack().PopDouble())
}

func TestFConst(t *testing.T) {
	frame := rtda.NewFrame(0, 1)
	fconst_0.Execute(frame)
	require.Equal(t, float32(0.0), frame.OperandStack().PopFloat())
	fconst_1.Execute(frame)
	require.Equal(t, float32(1.0), frame.OperandStack().PopFloat())
	fconst_2.Execute(frame)
	require.Equal(t, float32(2.0), frame.OperandStack().PopFloat())
}

func TestIConst(t *testing.T) {
	frame := rtda.NewFrame(0, 1)
	iconst_m1.Execute(frame)
	require.Equal(t, int32(-1), frame.OperandStack().PopInt())
	iconst_0.Execute(frame)
	require.Equal(t, int32(0), frame.OperandStack().PopInt())
	iconst_1.Execute(frame)
	require.Equal(t, int32(1), frame.OperandStack().PopInt())
	iconst_2.Execute(frame)
	require.Equal(t, int32(2), frame.OperandStack().PopInt())
	iconst_3.Execute(frame)
	require.Equal(t, int32(3), frame.OperandStack().PopInt())
	iconst_4.Execute(frame)
	require.Equal(t, int32(4), frame.OperandStack().PopInt())
	iconst_5.Execute(frame)
	require.Equal(t, int32(5), frame.OperandStack().PopInt())
}

func TestLConst(t *testing.T) {
	frame := rtda.NewFrame(0, 1)
	lconst_0.Execute(frame)
	require.Equal(t, int64(0), frame.OperandStack().PopLong())
	lconst_1.Execute(frame)
	require.Equal(t, int64(1), frame.OperandStack().PopLong())
}

func TestILoad(t *testing.T) {
	frame := rtda.NewFrame(8, 1)
	instrs := []base.Instruction{iload_0, iload_1, iload_2, iload_3}
	for i, instr := range instrs {
		frame.LocalVars().SetInt(uint(i), 100)
		instr.Execute(frame)
		require.Equal(t, int32(100), frame.OperandStack().PopInt())
	}
}

func TestLLoad(t *testing.T) {
	frame := rtda.NewFrame(8, 1)
	instrs := []base.Instruction{lload_0, lload_1, lload_2, lload_3}
	for i, instr := range instrs {
		frame.LocalVars().SetLong(uint(i), 100)
		instr.Execute(frame)
		require.Equal(t, int64(100), frame.OperandStack().PopLong())
	}
}

func TestFLoad(t *testing.T) {
	frame := rtda.NewFrame(8, 1)
	instrs := []base.Instruction{fload_0, fload_1, fload_2, fload_3}
	for i, instr := range instrs {
		frame.LocalVars().SetFloat(uint(i), 100)
		instr.Execute(frame)
		require.Equal(t, float32(100), frame.OperandStack().PopFloat())
	}
}

func TestDLoad(t *testing.T) {
	frame := rtda.NewFrame(8, 1)
	instrs := []base.Instruction{dload_0, dload_1, dload_2, dload_3}
	for i, instr := range instrs {
		frame.LocalVars().SetDouble(uint(i), 100)
		instr.Execute(frame)
		require.Equal(t, float64(100), frame.OperandStack().PopDouble())
	}
}

func TestALoad(t *testing.T) {
	frame := rtda.NewFrame(8, 1)
	instrs := []base.Instruction{aload_0, aload_1, aload_2, aload_3}
	for i, instr := range instrs {
		obj := &heap.Object{}
		frame.LocalVars().SetRef(uint(i), obj)
		instr.Execute(frame)
		require.Equal(t, obj, frame.OperandStack().PopRef())
	}
}

func TestIStore(t *testing.T) {
	frame := rtda.NewFrame(8, 1)
	instrs := []base.Instruction{istore_0, istore_1, istore_2, istore_3}
	for i, instr := range instrs {
		frame.OperandStack().PushInt(100)
		instr.Execute(frame)
		require.Equal(t, int32(100), frame.LocalVars().GetInt(uint(i)))
	}
}

func TestLStore(t *testing.T) {
	frame := rtda.NewFrame(8, 1)
	instrs := []base.Instruction{lstore_0, lstore_1, lstore_2, lstore_3}
	for i, instr := range instrs {
		frame.OperandStack().PushLong(100)
		instr.Execute(frame)
		require.Equal(t, int64(100), frame.LocalVars().GetLong(uint(i)))
	}
}

func TestFStore(t *testing.T) {
	frame := rtda.NewFrame(8, 1)
	instrs := []base.Instruction{fstore_0, fstore_1, fstore_2, fstore_3}
	for i, instr := range instrs {
		frame.OperandStack().PushFloat(100)
		instr.Execute(frame)
		require.Equal(t, float32(100), frame.LocalVars().GetFloat(uint(i)))
	}
}

func TestDStore(t *testing.T) {
	frame := rtda.NewFrame(8, 1)
	instrs := []base.Instruction{dstore_0, dstore_1, dstore_2, dstore_3}
	for i, instr := range instrs {
		frame.OperandStack().PushDouble(100)
		instr.Execute(frame)
		require.Equal(t, float64(100), frame.LocalVars().GetDouble(uint(i)))
	}
}

func TestAStore(t *testing.T) {
	frame := rtda.NewFrame(8, 1)
	instrs := []base.Instruction{astore_0, astore_1, astore_2, astore_3}
	for i, instr := range instrs {
		obj := &heap.Object{}
		frame.OperandStack().PushRef(obj)
		instr.Execute(frame)
		require.Equal(t, obj, frame.LocalVars().GetRef(uint(i)))
	}
}
<commit_msg>Sort imports<commit_after>package instructions

import (
	"testing"

	"github.com/stretchr/testify/require"

	"github.com/zxh0/jvm.go/instructions/base"
	"github.com/zxh0/jvm.go/rtda"
	"github.com/zxh0/jvm.go/rtda/heap"
)

func TestAConst(t *testing.T) {
	frame := rtda.NewFrame(0, 1)
	aconst_null.Execute(frame)
}

func TestDConst(t *testing.T) {
	frame := rtda.NewFrame(0, 1)
	dconst_0.Execute(frame)
	require.Equal(t, 0.0, frame.OperandStack().PopDouble())
	dconst_1.Execute(frame)
	require.Equal(t, 1.0, frame.OperandStack().PopDouble())
}

func TestFConst(t *testing.T) {
	frame := rtda.NewFrame(0, 1)
	fconst_0.Execute(frame)
	require.Equal(t, float32(0.0), frame.OperandStack().PopFloat())
	fconst_1.Execute(frame)
	require.Equal(t, float32(1.0), frame.OperandStack().PopFloat())
	fconst_2.Execute(frame)
	require.Equal(t, float32(2.0), frame.OperandStack().PopFloat())
}

func TestIConst(t *testing.T) {
	frame := rtda.NewFrame(0, 1)
	iconst_m1.Execute(frame)
	require.Equal(t, int32(-1), frame.OperandStack().PopInt())
	iconst_0.Execute(frame)
	require.Equal(t, int32(0), frame.OperandStack().PopInt())
	iconst_1.Execute(frame)
	require.Equal(t, int32(1), frame.OperandStack().PopInt())
	iconst_2.Execute(frame)
	require.Equal(t, int32(2), frame.OperandStack().PopInt())
	iconst_3.Execute(frame)
	require.Equal(t, int32(3), frame.OperandStack().PopInt())
	iconst_4.Execute(frame)
	require.Equal(t, int32(4), frame.OperandStack().PopInt())
	iconst_5.Execute(frame)
	require.Equal(t, int32(5), frame.OperandStack().PopInt())
}

func TestLConst(t *testing.T) {
	frame := rtda.NewFrame(0, 1)
	lconst_0.Execute(frame)
	require.Equal(t, int64(0), frame.OperandStack().PopLong())
	lconst_1.Execute(frame)
	require.Equal(t, int64(1), frame.OperandStack().PopLong())
}

func TestILoad(t *testing.T) {
	frame := rtda.NewFrame(8, 1)
	instrs := []base.Instruction{iload_0, iload_1, iload_2, iload_3}
	for i, instr := range instrs {
		frame.LocalVars().SetInt(uint(i), 100)
		instr.Execute(frame)
		require.Equal(t, int32(100), frame.OperandStack().PopInt())
	}
}

func TestLLoad(t *testing.T) {
	frame := rtda.NewFrame(8, 1)
	instrs := []base.Instruction{lload_0, lload_1, lload_2, lload_3}
	for i, instr := range instrs {
		frame.LocalVars().SetLong(uint(i), 100)
		instr.Execute(frame)
		require.Equal(t, int64(100), frame.OperandStack().PopLong())
	}
}

func TestFLoad(t *testing.T) {
	frame := rtda.NewFrame(8, 1)
	instrs := []base.Instruction{fload_0, fload_1, fload_2, fload_3}
	for i, instr := range instrs {
		frame.LocalVars().SetFloat(uint(i), 100)
		instr.Execute(frame)
		require.Equal(t, float32(100), frame.OperandStack().PopFloat())
	}
}

func TestDLoad(t *testing.T) {
	frame := rtda.NewFrame(8, 1)
	instrs := []base.Instruction{dload_0, dload_1, dload_2, dload_3}
	for i, instr := range instrs {
		frame.LocalVars().SetDouble(uint(i), 100)
		instr.Execute(frame)
		require.Equal(t, float64(100), frame.OperandStack().PopDouble())
	}
}

func TestALoad(t *testing.T) {
	frame := rtda.NewFrame(8, 1)
	instrs := []base.Instruction{aload_0, aload_1, aload_2, aload_3}
	for i, instr := range instrs {
		obj := &heap.Object{}
		frame.LocalVars().SetRef(uint(i), obj)
		instr.Execute(frame)
		require.Equal(t, obj, frame.OperandStack().PopRef())
	}
}

func TestIStore(t *testing.T) {
	frame := rtda.NewFrame(8, 1)
	instrs := []base.Instruction{istore_0, istore_1, istore_2, istore_3}
	for i, instr := range instrs {
		frame.OperandStack().PushInt(100)
		instr.Execute(frame)
		require.Equal(t, int32(100), frame.LocalVars().GetInt(uint(i)))
	}
}

func TestLStore(t *testing.T) {
	frame := rtda.NewFrame(8, 1)
	instrs := []base.Instruction{lstore_0, lstore_1, lstore_2, lstore_3}
	for i, instr := range instrs {
		frame.OperandStack().PushLong(100)
		instr.Execute(frame)
		require.Equal(t, int64(100), frame.LocalVars().GetLong(uint(i)))
	}
}

func TestFStore(t *testing.T) {
	frame := rtda.NewFrame(8, 1)
	instrs := []base.Instruction{fstore_0, fstore_1, fstore_2, fstore_3}
	for i, instr := range instrs {
		frame.OperandStack().PushFloat(100)
		instr.Execute(frame)
		require.Equal(t, float32(100), frame.LocalVars().GetFloat(uint(i)))
	}
}

func TestDStore(t *testing.T) {
	frame := rtda.NewFrame(8, 1)
	instrs := []base.Instruction{dstore_0, dstore_1, dstore_2, dstore_3}
	for i, instr := range instrs {
		frame.OperandStack().PushDouble(100)
		instr.Execute(frame)
		require.Equal(t, float64(100), frame.LocalVars().GetDouble(uint(i)))
	}
}

func TestAStore(t *testing.T) {
	frame := rtda.NewFrame(8, 1)
	instrs := []base.Instruction{astore_0, astore_1, astore_2, astore_3}
	for i, instr := range instrs {
		obj := &heap.Object{}
		frame.OperandStack().PushRef(obj)
		instr.Execute(frame)
		require.Equal(t, obj, frame.LocalVars().GetRef(uint(i)))
	}
}
<|endoftext|>


<commit_before>package endpoint

import (
	"crypto/tls"
	"crypto/x509"
	"errors"
	"fmt"
	"io/ioutil"
	"sync"
	"time"

	lg "log"

	"github.com/Shopify/sarama"
	"github.com/tidwall/gjson"
	"github.com/tidwall/tile38/internal/log"
)

const kafkaExpiresAfter = time.Second * 30

// KafkaConn is an endpoint connection
type KafkaConn struct {
	mu   sync.Mutex
	ep   Endpoint
	conn sarama.SyncProducer
	ex   bool
	t    time.Time
}

// Expired returns true if the connection has expired
func (conn *KafkaConn) Expired() bool {
	conn.mu.Lock()
	defer conn.mu.Unlock()
	if !conn.ex {
		if time.Now().Sub(conn.t) > kafkaExpiresAfter {
			if conn.conn != nil {
				conn.close()
			}
			conn.ex = true
		}
	}
	return conn.ex
}

func (conn *KafkaConn) close() {
	if conn.conn != nil {
		conn.conn.Close()
		conn.conn = nil
	}
}

// Send sends a message
func (conn *KafkaConn) Send(msg string) error {
	conn.mu.Lock()
	defer conn.mu.Unlock()

	if conn.ex {
		return errExpired
	}
	conn.t = time.Now()

	if log.Level > 2 {
		sarama.Logger = lg.New(log.Output(), "[sarama] ", 0)
	}

	uri := fmt.Sprintf("%s:%d", conn.ep.Kafka.Host, conn.ep.Kafka.Port)
	if conn.conn == nil {
		cfg := sarama.NewConfig()
		cfg.ClientID = "Tile38" // otherwise defaults to sarama

		if conn.ep.Kafka.TLS {
			log.Debugf("building kafka tls config")
			tlsConfig, err := newKafkaTLSConfig(conn.ep.Kafka.CertFile, conn.ep.Kafka.KeyFile, conn.ep.Kafka.CACertFile)
			if err != nil {
				return err
			}
			cfg.Net.TLS.Enable = true
			cfg.Net.TLS.Config = tlsConfig
		}

		cfg.Net.DialTimeout = time.Second
		cfg.Net.ReadTimeout = time.Second * 5
		cfg.Net.WriteTimeout = time.Second * 5
		// Fix #333 : fix backward incompatibility introduced by sarama library
		cfg.Producer.Return.Successes = true
		cfg.Version = sarama.V0_10_0_0

		c, err := sarama.NewSyncProducer([]string{uri}, cfg)
		if err != nil {
			return err
		}

		conn.conn = c
	}

	// parse json again to get out info for our kafka key
	key := gjson.Get(msg, "key")
	id := gjson.Get(msg, "id")
	keyValue := fmt.Sprintf("%s-%s", key.String(), id.String())

	message := &sarama.ProducerMessage{
		Topic: conn.ep.Kafka.TopicName,
		Key:   sarama.StringEncoder(keyValue),
		Value: sarama.StringEncoder(msg),
	}

	_, offset, err := conn.conn.SendMessage(message)
	if err != nil {
		conn.close()
		return err
	}

	if offset < 0 {
		conn.close()
		return errors.New("invalid kafka reply")
	}

	return nil
}

func newKafkaConn(ep Endpoint) *KafkaConn {
	return &KafkaConn{
		ep: ep,
		t:  time.Now(),
	}
}

func newKafkaTLSConfig(CertFile, KeyFile, CACertFile string) (*tls.Config, error) {
	tlsConfig := tls.Config{}

	// Load client cert
	cert, err := tls.LoadX509KeyPair(CertFile, KeyFile)
	if err != nil {
		return &tlsConfig, err
	}
	tlsConfig.Certificates = []tls.Certificate{cert}

	// Load CA cert
	caCert, err := ioutil.ReadFile(CACertFile)
	if err != nil {
		return &tlsConfig, err
	}
	caCertPool := x509.NewCertPool()
	caCertPool.AppendCertsFromPEM(caCert)
	tlsConfig.RootCAs = caCertPool

	tlsConfig.BuildNameToCertificate()
	return &tlsConfig, err
}
<commit_msg>refactor: dont set client id<commit_after>package endpoint

import (
	"crypto/tls"
	"crypto/x509"
	"errors"
	"fmt"
	"io/ioutil"
	"sync"
	"time"

	lg "log"

	"github.com/Shopify/sarama"
	"github.com/tidwall/gjson"
	"github.com/tidwall/tile38/internal/log"
)

const kafkaExpiresAfter = time.Second * 30

// KafkaConn is an endpoint connection
type KafkaConn struct {
	mu   sync.Mutex
	ep   Endpoint
	conn sarama.SyncProducer
	ex   bool
	t    time.Time
}

// Expired returns true if the connection has expired
func (conn *KafkaConn) Expired() bool {
	conn.mu.Lock()
	defer conn.mu.Unlock()
	if !conn.ex {
		if time.Now().Sub(conn.t) > kafkaExpiresAfter {
			if conn.conn != nil {
				conn.close()
			}
			conn.ex = true
		}
	}
	return conn.ex
}

func (conn *KafkaConn) close() {
	if conn.conn != nil {
		conn.conn.Close()
		conn.conn = nil
	}
}

// Send sends a message
func (conn *KafkaConn) Send(msg string) error {
	conn.mu.Lock()
	defer conn.mu.Unlock()

	if conn.ex {
		return errExpired
	}
	conn.t = time.Now()

	if log.Level > 2 {
		sarama.Logger = lg.New(log.Output(), "[sarama] ", 0)
	}

	uri := fmt.Sprintf("%s:%d", conn.ep.Kafka.Host, conn.ep.Kafka.Port)
	if conn.conn == nil {
		cfg := sarama.NewConfig()

		if conn.ep.Kafka.TLS {
			log.Debugf("building kafka tls config")
			tlsConfig, err := newKafkaTLSConfig(conn.ep.Kafka.CertFile, conn.ep.Kafka.KeyFile, conn.ep.Kafka.CACertFile)
			if err != nil {
				return err
			}
			cfg.Net.TLS.Enable = true
			cfg.Net.TLS.Config = tlsConfig
		}

		cfg.Net.DialTimeout = time.Second
		cfg.Net.ReadTimeout = time.Second * 5
		cfg.Net.WriteTimeout = time.Second * 5
		// Fix #333 : fix backward incompatibility introduced by sarama library
		cfg.Producer.Return.Successes = true
		cfg.Version = sarama.V0_10_0_0

		c, err := sarama.NewSyncProducer([]string{uri}, cfg)
		if err != nil {
			return err
		}

		conn.conn = c
	}

	// parse json again to get out info for our kafka key
	key := gjson.Get(msg, "key")
	id := gjson.Get(msg, "id")
	keyValue := fmt.Sprintf("%s-%s", key.String(), id.String())

	message := &sarama.ProducerMessage{
		Topic: conn.ep.Kafka.TopicName,
		Key:   sarama.StringEncoder(keyValue),
		Value: sarama.StringEncoder(msg),
	}

	_, offset, err := conn.conn.SendMessage(message)
	if err != nil {
		conn.close()
		return err
	}

	if offset < 0 {
		conn.close()
		return errors.New("invalid kafka reply")
	}

	return nil
}

func newKafkaConn(ep Endpoint) *KafkaConn {
	return &KafkaConn{
		ep: ep,
		t:  time.Now(),
	}
}

func newKafkaTLSConfig(CertFile, KeyFile, CACertFile string) (*tls.Config, error) {
	tlsConfig := tls.Config{}

	// Load client cert
	cert, err := tls.LoadX509KeyPair(CertFile, KeyFile)
	if err != nil {
		return &tlsConfig, err
	}
	tlsConfig.Certificates = []tls.Certificate{cert}

	// Load CA cert
	caCert, err := ioutil.ReadFile(CACertFile)
	if err != nil {
		return &tlsConfig, err
	}
	caCertPool := x509.NewCertPool()
	caCertPool.AppendCertsFromPEM(caCert)
	tlsConfig.RootCAs = caCertPool

	tlsConfig.BuildNameToCertificate()
	return &tlsConfig, err
}
<|endoftext|>