<commit_before>// Copyright 2020 DSR Corporation
//
// 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 types

import (
	"encoding/json"

	sdk "github.com/cosmos/cosmos-sdk/types"
	sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
	authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
)

/*
	Account Role
*/

type AccountRole string

const (
	Vendor              AccountRole = "Vendor"
	CertificationCenter AccountRole = "CertificationCenter"
	Trustee             AccountRole = "Trustee"
	NodeAdmin           AccountRole = "NodeAdmin"
)

var Roles = AccountRoles{Vendor, CertificationCenter, Trustee, NodeAdmin}

func (role AccountRole) Validate() error {
	for _, r := range Roles {
		if role == r {
			return nil
		}
	}

	return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "Invalid Account Role: %v. Supported roles: [%v]", role, Roles)
}

/*
	List of Account Roles
*/

type AccountRoles []AccountRole

/*
	Account
*/

type DCLAccountI interface {
	authtypes.AccountI

	GetRoles() []AccountRole
	GetVendorID() int32
	GetApprovals() []*Grant
}

// NewAccount creates a new Account object.
func NewAccount(ba *authtypes.BaseAccount, roles AccountRoles, approvals []*Grant, vendorID int32) *Account {
	return &Account{
		BaseAccount: ba,
		Roles:       roles,
		Approvals:   approvals,
		VendorID:    vendorID,
	}
}

// Validate checks for errors on the vesting and module account parameters.
func (acc Account) Validate() error {
	err := acc.BaseAccount.Validate()
	if err != nil {
		return err
	}

	for _, role := range acc.Roles {
		if err := role.Validate(); err != nil {
			return err
		}
	}

	// If creating an account with Vendor Role, we need to have a associated VendorID
	if acc.HasRole(Vendor) && acc.VendorID <= 0 {
		return ErrMissingVendorIDForVendorAccount()
	}

	return nil
}

func (acc Account) GetRoles() []AccountRole {
	return acc.Roles
}

func (acc Account) GetApprovals() []*Grant {
	return acc.Approvals
}

func (acc Account) GetVendorID() int32 {
	return acc.VendorID
}

func (acc Account) HasRole(targetRole AccountRole) bool {
	for _, role := range acc.Roles {
		if role == targetRole {
			return true
		}
	}

	return false
}

func (acc Account) String() string {
	out, _ := acc.MarshalYAML()
	return out.(string)
}

/*
	Pending Account
*/

// NewPendingAccount creates a new PendingAccount object.
func NewPendingAccount(acc *Account, approval sdk.AccAddress, info string, time int64) *PendingAccount {
	pendingAccount := &PendingAccount{
		Account: acc,
	}

	pendingAccount.Approvals = []*Grant{
		{
			Address: approval.String(),
			Time:    time,
			Info:    info,
		},
	}

	return pendingAccount
}

func (acc PendingAccount) HasApprovalFrom(address sdk.AccAddress) bool {
	addrStr := address.String()
	for _, approval := range acc.Approvals {
		if approval.Address == addrStr {
			return true
		}
	}

	return false
}

/*
	Pending Account Revocation
*/

// NewPendingAccountRevocation creates a new PendingAccountRevocation object.
func NewPendingAccountRevocation(address sdk.AccAddress,
	info string, time int64, approval sdk.AccAddress) PendingAccountRevocation {
	pendingAccountRevocation := PendingAccountRevocation{
		Address: address.String(),
	}
	pendingAccountRevocation.Approvals = []*Grant{
		{
			Address: approval.String(),
			Time:    time,
			Info:    info,
		},
	}
	return pendingAccountRevocation
}

// String implements fmt.Stringer.
func (revoc PendingAccountRevocation) String() string {
	bytes, err := json.Marshal(revoc)
	if err != nil {
		panic(err)
	}

	return string(bytes)
}

// Validate checks for errors on the vesting and module account parameters.
func (revoc PendingAccountRevocation) Validate() error {
	if revoc.Address == "" {
		return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest,
			"Invalid Pending Account Revocation: Value: %s. Error: Missing Address", revoc.Address,
		)
	}

	return nil
}

func (revoc PendingAccountRevocation) HasRevocationFrom(address sdk.AccAddress) bool {
	addrStr := address.String()
	for _, approvals := range revoc.Approvals {
		if approvals.Address == addrStr {
			return true
		}
	}

	return false
}
<commit_msg>Add function for creating a new object type of RevokedAccount<commit_after>// Copyright 2020 DSR Corporation
//
// 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 types

import (
	"encoding/json"

	sdk "github.com/cosmos/cosmos-sdk/types"
	sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
	authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
)

/*
	Account Role
*/

type AccountRole string

const (
	Vendor              AccountRole = "Vendor"
	CertificationCenter AccountRole = "CertificationCenter"
	Trustee             AccountRole = "Trustee"
	NodeAdmin           AccountRole = "NodeAdmin"
)

var Roles = AccountRoles{Vendor, CertificationCenter, Trustee, NodeAdmin}

func (role AccountRole) Validate() error {
	for _, r := range Roles {
		if role == r {
			return nil
		}
	}

	return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "Invalid Account Role: %v. Supported roles: [%v]", role, Roles)
}

/*
	List of Account Roles
*/

type AccountRoles []AccountRole

/*
	Account
*/

type DCLAccountI interface {
	authtypes.AccountI

	GetRoles() []AccountRole
	GetVendorID() int32
	GetApprovals() []*Grant
}

// NewAccount creates a new Account object.
func NewAccount(ba *authtypes.BaseAccount, roles AccountRoles, approvals []*Grant, vendorID int32) *Account {
	return &Account{
		BaseAccount: ba,
		Roles:       roles,
		Approvals:   approvals,
		VendorID:    vendorID,
	}
}

// Validate checks for errors on the vesting and module account parameters.
func (acc Account) Validate() error {
	err := acc.BaseAccount.Validate()
	if err != nil {
		return err
	}

	for _, role := range acc.Roles {
		if err := role.Validate(); err != nil {
			return err
		}
	}

	// If creating an account with Vendor Role, we need to have a associated VendorID
	if acc.HasRole(Vendor) && acc.VendorID <= 0 {
		return ErrMissingVendorIDForVendorAccount()
	}

	return nil
}

func (acc Account) GetRoles() []AccountRole {
	return acc.Roles
}

func (acc Account) GetApprovals() []*Grant {
	return acc.Approvals
}

func (acc Account) GetVendorID() int32 {
	return acc.VendorID
}

func (acc Account) HasRole(targetRole AccountRole) bool {
	for _, role := range acc.Roles {
		if role == targetRole {
			return true
		}
	}

	return false
}

func (acc Account) String() string {
	out, _ := acc.MarshalYAML()
	return out.(string)
}

/*
	Pending Account
*/

// NewPendingAccount creates a new PendingAccount object.
func NewPendingAccount(acc *Account, approval sdk.AccAddress, info string, time int64) *PendingAccount {
	pendingAccount := &PendingAccount{
		Account: acc,
	}

	pendingAccount.Approvals = []*Grant{
		{
			Address: approval.String(),
			Time:    time,
			Info:    info,
		},
	}

	return pendingAccount
}

func (acc PendingAccount) HasApprovalFrom(address sdk.AccAddress) bool {
	addrStr := address.String()
	for _, approval := range acc.Approvals {
		if approval.Address == addrStr {
			return true
		}
	}

	return false
}

/*
	Pending Account Revocation
*/

// NewPendingAccountRevocation creates a new PendingAccountRevocation object.
func NewPendingAccountRevocation(address sdk.AccAddress,
	info string, time int64, approval sdk.AccAddress) PendingAccountRevocation {
	pendingAccountRevocation := PendingAccountRevocation{
		Address: address.String(),
	}
	pendingAccountRevocation.Approvals = []*Grant{
		{
			Address: approval.String(),
			Time:    time,
			Info:    info,
		},
	}
	return pendingAccountRevocation
}

// NewRevokedAccount creates a new RevokedAccount object
func NewRevokedAccount(acc *Account, approvals []*Grant, info string, time int64) *RevokedAccount {
	revokedAccount := &RevokedAccount{
		Account: acc,
	}

	revokedAccount.RevokeApprovals = approvals

	return revokedAccount
}

// String implements fmt.Stringer.
func (revoc PendingAccountRevocation) String() string {
	bytes, err := json.Marshal(revoc)
	if err != nil {
		panic(err)
	}

	return string(bytes)
}

// Validate checks for errors on the vesting and module account parameters.
func (revoc PendingAccountRevocation) Validate() error {
	if revoc.Address == "" {
		return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest,
			"Invalid Pending Account Revocation: Value: %s. Error: Missing Address", revoc.Address,
		)
	}

	return nil
}

func (revoc PendingAccountRevocation) HasRevocationFrom(address sdk.AccAddress) bool {
	addrStr := address.String()
	for _, approvals := range revoc.Approvals {
		if approvals.Address == addrStr {
			return true
		}
	}

	return false
}
<|endoftext|>


<commit_before>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package manual

import (
	"fmt"
	"os"

	gc "launchpad.net/gocheck"

	envtesting "launchpad.net/juju-core/environs/testing"
	"launchpad.net/juju-core/instance"
	"launchpad.net/juju-core/juju/testing"
	"launchpad.net/juju-core/state/api/params"
	jc "launchpad.net/juju-core/testing/checkers"
	"launchpad.net/juju-core/version"
)

type provisionerSuite struct {
	testing.JujuConnSuite
}

var _ = gc.Suite(&provisionerSuite{})

func (s *provisionerSuite) getArgs(c *gc.C) ProvisionMachineArgs {
	hostname, err := os.Hostname()
	c.Assert(err, gc.IsNil)
	return ProvisionMachineArgs{
		Host:    hostname,
		EnvName: "dummyenv",
	}
}

func (s *provisionerSuite) TestProvisionMachine(c *gc.C) {
	const series = "precise"
	const arch = "amd64"

	args := s.getArgs(c)
	hostname := args.Host
	args.Host = "ubuntu@" + args.Host

	envtesting.RemoveTools(c, s.Conn.Environ.Storage())
	defer fakeSSH{
		Series: series, Arch: arch, SkipProvisionAgent: true,
	}.install(c).Restore()
	// Attempt to provision a machine with no tools available, expect it to fail.
	machineId, err := ProvisionMachine(args)
	c.Assert(err, jc.Satisfies, params.IsCodeNotFound)
	c.Assert(machineId, gc.Equals, "")

	cfg := s.Conn.Environ.Config()
	number, ok := cfg.AgentVersion()
	c.Assert(ok, jc.IsTrue)
	binVersion := version.Binary{number, series, arch}
	envtesting.AssertUploadFakeToolsVersions(c, s.Conn.Environ.Storage(), binVersion)

	for i, errorCode := range []int{255, 0} {
		c.Logf("test %d: code %d", i, errorCode)
		defer fakeSSH{
			Series: series,
			Arch:   arch,
			ProvisionAgentExitCode: errorCode,
		}.install(c).Restore()
		machineId, err = ProvisionMachine(args)
		if errorCode != 0 {
			c.Assert(err, gc.ErrorMatches, fmt.Sprintf("exit status %d", errorCode))
			c.Assert(machineId, gc.Equals, "")
		} else {
			c.Assert(err, gc.IsNil)
			c.Assert(machineId, gc.Not(gc.Equals), "")
			// machine ID will be incremented. Even though we failed and the
			// machine is removed, the ID is not reused.
			c.Assert(machineId, gc.Equals, fmt.Sprint(i+1))
			m, err := s.State.Machine(machineId)
			c.Assert(err, gc.IsNil)
			instanceId, err := m.InstanceId()
			c.Assert(err, gc.IsNil)
			c.Assert(instanceId, gc.Equals, instance.Id("manual:"+hostname))
		}
	}

	// Attempting to provision a machine twice should fail. We effect
	// this by checking for existing juju upstart configurations.
	defer installFakeSSH(c, "", "/etc/init/jujud-machine-0.conf", 0)()
	_, err = ProvisionMachine(args)
	c.Assert(err, gc.Equals, ErrProvisioned)
	defer installFakeSSH(c, "", "/etc/init/jujud-machine-0.conf", 255)()
	_, err = ProvisionMachine(args)
	c.Assert(err, gc.ErrorMatches, "error checking if provisioned: exit status 255")
}
<commit_msg>[r=axwalk] environs/manual: add test for API/State info<commit_after>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package manual

import (
	"fmt"
	"os"

	gc "launchpad.net/gocheck"

	envtesting "launchpad.net/juju-core/environs/testing"
	"launchpad.net/juju-core/instance"
	"launchpad.net/juju-core/juju/testing"
	"launchpad.net/juju-core/state"
	"launchpad.net/juju-core/state/api/params"
	jc "launchpad.net/juju-core/testing/checkers"
	"launchpad.net/juju-core/version"
)

type provisionerSuite struct {
	testing.JujuConnSuite
}

var _ = gc.Suite(&provisionerSuite{})

func (s *provisionerSuite) getArgs(c *gc.C) ProvisionMachineArgs {
	hostname, err := os.Hostname()
	c.Assert(err, gc.IsNil)
	return ProvisionMachineArgs{
		Host:    hostname,
		EnvName: "dummyenv",
	}
}

func (s *provisionerSuite) TestProvisionMachine(c *gc.C) {
	const series = "precise"
	const arch = "amd64"

	args := s.getArgs(c)
	hostname := args.Host
	args.Host = "ubuntu@" + args.Host

	envtesting.RemoveTools(c, s.Conn.Environ.Storage())
	defer fakeSSH{
		Series: series, Arch: arch, SkipProvisionAgent: true,
	}.install(c).Restore()
	// Attempt to provision a machine with no tools available, expect it to fail.
	machineId, err := ProvisionMachine(args)
	c.Assert(err, jc.Satisfies, params.IsCodeNotFound)
	c.Assert(machineId, gc.Equals, "")

	cfg := s.Conn.Environ.Config()
	number, ok := cfg.AgentVersion()
	c.Assert(ok, jc.IsTrue)
	binVersion := version.Binary{number, series, arch}
	envtesting.AssertUploadFakeToolsVersions(c, s.Conn.Environ.Storage(), binVersion)

	for i, errorCode := range []int{255, 0} {
		c.Logf("test %d: code %d", i, errorCode)
		defer fakeSSH{
			Series: series,
			Arch:   arch,
			ProvisionAgentExitCode: errorCode,
		}.install(c).Restore()
		machineId, err = ProvisionMachine(args)
		if errorCode != 0 {
			c.Assert(err, gc.ErrorMatches, fmt.Sprintf("exit status %d", errorCode))
			c.Assert(machineId, gc.Equals, "")
		} else {
			c.Assert(err, gc.IsNil)
			c.Assert(machineId, gc.Not(gc.Equals), "")
			// machine ID will be incremented. Even though we failed and the
			// machine is removed, the ID is not reused.
			c.Assert(machineId, gc.Equals, fmt.Sprint(i+1))
			m, err := s.State.Machine(machineId)
			c.Assert(err, gc.IsNil)
			instanceId, err := m.InstanceId()
			c.Assert(err, gc.IsNil)
			c.Assert(instanceId, gc.Equals, instance.Id("manual:"+hostname))
		}
	}

	// Attempting to provision a machine twice should fail. We effect
	// this by checking for existing juju upstart configurations.
	defer installFakeSSH(c, "", "/etc/init/jujud-machine-0.conf", 0)()
	_, err = ProvisionMachine(args)
	c.Assert(err, gc.Equals, ErrProvisioned)
	defer installFakeSSH(c, "", "/etc/init/jujud-machine-0.conf", 255)()
	_, err = ProvisionMachine(args)
	c.Assert(err, gc.ErrorMatches, "error checking if provisioned: exit status 255")
}

func (s *provisionerSuite) TestCreateMachineConfig(c *gc.C) {
	const series = "precise"
	const arch = "amd64"
	defer fakeSSH{Series: series, Arch: arch}.install(c).Restore()
	machineId, err := ProvisionMachine(s.getArgs(c))
	c.Assert(err, gc.IsNil)

	// Now check what we would've configured it with.
	client := s.APIConn.State.Client()
	mcfg, err := createMachineConfig(client, machineId, series, arch, state.BootstrapNonce, "/var/lib/juju")
	c.Assert(err, gc.IsNil)
	c.Assert(mcfg, gc.NotNil)
	c.Assert(mcfg.APIInfo, gc.NotNil)
	c.Assert(mcfg.StateInfo, gc.NotNil)

	stateInfo, apiInfo, err := s.APIConn.Environ.StateInfo()
	c.Assert(err, gc.IsNil)
	c.Assert(mcfg.APIInfo.Addrs, gc.DeepEquals, apiInfo.Addrs)
	c.Assert(mcfg.StateInfo.Addrs, gc.DeepEquals, stateInfo.Addrs)
}
<|endoftext|>


<commit_before>/*
   Written in Go 2015 by Eric Lagergren (contact@ericlagergren.com)
   Written in C 2014 by Sebastiano Vigna (vigna@acm.org) and
   Kenji Rikitake (kenji.rikitake@acm.org).

To the extent possible under law, the author has dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.

See <http://creativecommons.org/publicdomain/zero/1.0/>. */
package prng

import (
	"crypto/rand"
	"encoding/binary"
	"io"
)

// Guarenteed to be fair using a dice roll.
const randSeed = 16256612229375771919

type XORShift interface {
	Next() uint64
	Seed()
}

// randUint reads from the OS' crypto PRNG and uses its output
// to create a slice of uint64s with the given lenght, n.
func randUint(n int) []uint64 {
	s := make([]uint64, n)

	// Fill the array the user gave us but make sure there aren't any zeros.
	for i := 0; i < n; i++ {
		s[i] = randomNonZero()
	}

	return s
}

// randomNonZero fetches 8 bytes from the OS' CSPRNG and returns it as
// a non-zero uint64. Will panic if it can't read from rand.Reader.
func randomNonZero() uint64 {
	buf := make([]byte, 8)
	n, err := io.ReadFull(rand.Reader, buf)
	if err != nil || n != 8 {
		panic("Unable to fully read from rand.Reader")
	}
	u, x := binary.Uvarint(buf)
	if u == 0 || x == 0 || x < 0 {
		return randomNonZero()
	}
	return u
}

// fillWithXOR fills a slice using a xorshift64 generator, using a
// determined starting state (a large prime).
func fillWithXOR(n int) []uint64 {
	s := make([]uint64, n)
	r := new(Shift64Star)
	r.x = randSeed
	for i := range s {
		s[i] = r.Next()
	}
	return s
}

// genState generates a starting state using Go's 'crypto/rand'
// package. The state will be a 64-bit prime. It'll panic if
// rand.Prime returns an error.
func genState() uint64 {
	prime, err := rand.Prime(rand.Reader, 64)
	if err != nil {
		panic(err)
	}
	return prime.Uint64()
}

const uint58mask uint64 = (1 << 58) - 1

// Shift116Plus is a variant of xorshift128+ for dynamic languages, such
// as Erlang, that can use only 58 bits of a 64-bit integer. Only the lower
// 58 bits of each state word are valid (the upper six are zeroes).
//
// This generator passes BigCrush without systematic failures, but due to
// the relatively short period it is acceptable only for applications with
// a mild amount of parallelism; otherwise, use a xorshift1024* generator.
//
// The state must be seeded so that the lower 58 bits of s[ 0 ] and s[ 1 ]
// are not all zeroes. If you have a nonzero 64-bit seed, we suggest to
// pass it twice through MurmurHash3's avalanching function and take the
// lower 58 bits, taking care that they are not all zeroes (you can apply
// the avalanching function again if this happens).
type Shift116Plus struct {
	state [2]uint64
}

func (s *Shift116Plus) Next() uint64 {
	s0 := s.state[1]
	s1 := s.state[0]
	s.state[0] = s0
	s1 ^= (s1 << 24) & uint58mask // a
	s.state[1] = (s1 ^ s0 ^ (s1 >> 11) ^ (s0 >> 41))
	return (((s.state[1]) + s0) & uint58mask) // b, c
}

func (s *Shift116Plus) Seed() {
	copy(s.state[:], randUint(cap(s.state)))
}

// Shift128Plus is the fastest generator passing BigCrush without
// systematic failures, but due to the relatively short period it is
// acceptable only for applications with a mild amount of parallelism;
// otherwise, use a xorshift1024* generator.
//
// The state must be seeded so that it is not everywhere zero. If you have
// a nonzero 64-bit seed, we suggest to pass it twice through
// MurmurHash3's avalanching function.
type Shift128Plus struct {
	state [2]uint64
}

func (s *Shift128Plus) Next() uint64 {
	s0 := s.state[1]
	s1 := s.state[0]
	s.state[0] = s0
	s1 ^= s1 << 23 // a
	s.state[1] = (s1 ^ s0 ^ (s1 >> 17) ^ (s0 >> 26))
	return (s.state[1]) + s0 // b, c
}

func (s *Shift128Plus) Seed() {
	copy(s.state[:], randUint(cap(s.state)))
}

// Shift1024Star is a fast, top-quality generator. If 1024 bits of state are
// too much, try a xorshift128+ or generator.
//
// The state must be seeded so that it is not everywhere zero. If you have
// a 64-bit seed,  we suggest to seed a xorshift64* generator and use its
// output to fill s.
type Shift1024Star struct {
	state [16]uint64
	p     int
}

func (s *Shift1024Star) Next() uint64 {
	s0 := s.state[s.p]
	s.p = (s.p + 1) & 15
	s1 := s.state[s.p]
	s1 ^= s1 << 31
	s1 ^= s1 >> 11
	s0 ^= s0 >> 30
	s.state[s.p] = s0 ^ s1
	return s.state[s.p] * 1181783497276652981
}

func (s *Shift1024Star) Seed() {
	copy(s.state[:], fillWithXOR(cap(s.state)))
	s.p = 0
}

// Shift40956 is usable, but we suggest you use a
// xorshift1024* generator.
//
// The state must be seeded so that it is not everywhere zero. If you have
// a 64-bit seed,  we suggest to seed a xorshift64* generator and use its
// output to fill s.
type Shift4096Star struct {
	state [64]uint64
	p     int
}

func (s *Shift4096Star) Next() uint64 {
	s0 := s.state[s.p]
	s.p = (s.p + 1) & 63
	s1 := s.state[s.p]
	s1 ^= s1 << 25 // a
	s1 ^= s1 >> 3  // b
	s0 ^= s0 >> 49 // c
	s.state[s.p] = s0 ^ s1
	return (s.state[s.p]) * 8372773778140471301
}

func (s *Shift4096Star) Seed() {
	copy(s.state[:], fillWithXOR(cap(s.state)))
	s.p = 0
}

// Shift64Star is a fast, good generator if you're short on memory, but
// otherwise we rather suggest to use a xorshift128+ or xorshift1024*
// (for a very long period) generator.
type Shift64Star struct {
	x uint64 // state
}

func (s *Shift64Star) Next() uint64 {
	s.x ^= s.x >> 12 // a
	s.x ^= s.x << 25 // b
	s.x ^= s.x >> 27 // c
	return s.x * 2685821657736338717
}

func (s *Shift64Star) Seed() {
	s.x = genState()
}
<commit_msg>better seeding<commit_after>/*
   Written in Go 2015 by Eric Lagergren (contact@ericlagergren.com)
   Written in C 2014 by Sebastiano Vigna (vigna@acm.org) and
   Kenji Rikitake (kenji.rikitake@acm.org).

To the extent possible under law, the author has dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.

See <http://creativecommons.org/publicdomain/zero/1.0/>. */
package prng

import (
	"crypto/rand"
	"encoding/binary"
	"io"
)

type XORShift interface {
	Next() uint64
	Seed()
}

// randUint reads from the OS' crypto PRNG and uses its output
// to create a slice of uint64s with the given lenght, n.
func randUint(n int) []uint64 {
	s := make([]uint64, n)

	// Fill the array the user gave us but make sure there aren't any zeros.
	for i := 0; i < n; i++ {
		s[i] = randomNonZero()
	}

	return s
}

// randomNonZero fetches 8 bytes from the OS' CSPRNG and returns it as
// a non-zero uint64. Will panic if it can't read from rand.Reader.
func randomNonZero() uint64 {
	buf := make([]byte, 8)
	n, err := io.ReadFull(rand.Reader, buf)
	if err != nil || n != 8 {
		panic("Unable to fully read from rand.Reader")
	}
	u, x := binary.Uvarint(buf)
	if u == 0 || x == 0 || x < 0 {
		return randomNonZero()
	}
	return u
}

// genState generates a starting state using Go's 'crypto/rand'
// package. The state will be a 64-bit prime. It'll panic if
// rand.Prime returns an error.
func genState() uint64 {
	prime, err := rand.Prime(rand.Reader, 64)
	if err != nil {
		panic(err)
	}
	return prime.Uint64()
}

const uint58mask uint64 = (1 << 58) - 1

// Shift116Plus is a variant of xorshift128+ for dynamic languages, such
// as Erlang, that can use only 58 bits of a 64-bit integer. Only the lower
// 58 bits of each state word are valid (the upper six are zeroes).
//
// This generator passes BigCrush without systematic failures, but due to
// the relatively short period it is acceptable only for applications with
// a mild amount of parallelism; otherwise, use a xorshift1024* generator.
//
// The state must be seeded so that the lower 58 bits of s[ 0 ] and s[ 1 ]
// are not all zeroes. If you have a nonzero 64-bit seed, we suggest to
// pass it twice through MurmurHash3's avalanching function and take the
// lower 58 bits, taking care that they are not all zeroes (you can apply
// the avalanching function again if this happens).
type Shift116Plus struct {
	state [2]uint64
}

func (s *Shift116Plus) Next() uint64 {
	s0 := s.state[1]
	s1 := s.state[0]
	s.state[0] = s0
	s1 ^= (s1 << 24) & uint58mask // a
	s.state[1] = (s1 ^ s0 ^ (s1 >> 11) ^ (s0 >> 41))
	return (((s.state[1]) + s0) & uint58mask) // b, c
}

func (s *Shift116Plus) Seed() {
	copy(s.state[:], randUint(cap(s.state)))
}

// Shift128Plus is the fastest generator passing BigCrush without
// systematic failures, but due to the relatively short period it is
// acceptable only for applications with a mild amount of parallelism;
// otherwise, use a xorshift1024* generator.
//
// The state must be seeded so that it is not everywhere zero. If you have
// a nonzero 64-bit seed, we suggest to pass it twice through
// MurmurHash3's avalanching function.
type Shift128Plus struct {
	state [2]uint64
}

func (s *Shift128Plus) Next() uint64 {
	s0 := s.state[1]
	s1 := s.state[0]
	s.state[0] = s0
	s1 ^= s1 << 23 // a
	s.state[1] = (s1 ^ s0 ^ (s1 >> 17) ^ (s0 >> 26))
	return (s.state[1]) + s0 // b, c
}

func (s *Shift128Plus) Seed() {
	copy(s.state[:], randUint(cap(s.state)))
}

// Shift1024Star is a fast, top-quality generator. If 1024 bits of state are
// too much, try a xorshift128+ or generator.
//
// The state must be seeded so that it is not everywhere zero. If you have
// a 64-bit seed,  we suggest to seed a xorshift64* generator and use its
// output to fill s.
type Shift1024Star struct {
	state [16]uint64
	p     int
}

func (s *Shift1024Star) Next() uint64 {
	s0 := s.state[s.p]
	s.p = (s.p + 1) & 15
	s1 := s.state[s.p]
	s1 ^= s1 << 31
	s1 ^= s1 >> 11
	s0 ^= s0 >> 30
	s.state[s.p] = s0 ^ s1
	return s.state[s.p] * 1181783497276652981
}

func (s *Shift1024Star) Seed() {
	copy(s.state[:], randUint(cap(s.state)))
	s.p = 0
}

// Shift40956 is usable, but we suggest you use a
// xorshift1024* generator.
//
// The state must be seeded so that it is not everywhere zero. If you have
// a 64-bit seed,  we suggest to seed a xorshift64* generator and use its
// output to fill s.
type Shift4096Star struct {
	state [64]uint64
	p     int
}

func (s *Shift4096Star) Next() uint64 {
	s0 := s.state[s.p]
	s.p = (s.p + 1) & 63
	s1 := s.state[s.p]
	s1 ^= s1 << 25 // a
	s1 ^= s1 >> 3  // b
	s0 ^= s0 >> 49 // c
	s.state[s.p] = s0 ^ s1
	return (s.state[s.p]) * 8372773778140471301
}

func (s *Shift4096Star) Seed() {
	copy(s.state[:], randUint(cap(s.state)))
	s.p = 0
}

// Shift64Star is a fast, good generator if you're short on memory, but
// otherwise we rather suggest to use a xorshift128+ or xorshift1024*
// (for a very long period) generator.
type Shift64Star struct {
	x uint64 // state
}

func (s *Shift64Star) Next() uint64 {
	s.x ^= s.x >> 12 // a
	s.x ^= s.x << 25 // b
	s.x ^= s.x >> 27 // c
	return s.x * 2685821657736338717
}

func (s *Shift64Star) Seed() {
	s.x = genState()
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"encoding/hex"
	"encoding/json"
	"fmt"
	MQTT "git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git"
	"github.com/PandoCloud/pando-cloud/pkg/protocol"
	"github.com/PandoCloud/pando-cloud/pkg/tlv"
	"log"
	"os"
	"strings"
	"time"
)

const (
	commonCmdGetStatus = uint16(65528)
)

// device register args
type DeviceRegisterArgs struct {
	ProductKey string `json:"product_key"  binding:"required"`
	DeviceCode string `json:"device_code"  binding:"required"`
	Version    string `json:"version"  binding:"required"`
}

// device authentication args
type DeviceAuthArgs struct {
	DeviceId     int64  `json:"device_id" binding:"required"`
	DeviceSecret string `json:"device_secret" binding:"required"`
	Protocol     string `json:"protocol" binding:"required"`
}

// common response fields
type Common struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
}

// device register response data field
type DeviceRegisterData struct {
	DeviceId         int64  `json:"device_id"`
	DeviceSecret     string `json:"device_secret"`
	DeviceKey        string `json:"device_key"`
	DeviceIdentifier string `json:"device_identifier"`
}

// device register response
type DeviceRegisterResponse struct {
	Common
	Data DeviceRegisterData `json:"data"`
}

// device auth response data field
type DeviceAuthData struct {
	AccessToken string `json:"access_token"`
	AccessAddr  string `json:"access_addr"`
}

// device auth response
type DeviceAuthResponse struct {
	Common
	Data DeviceAuthData `json:"data"`
}

type Device struct {
	// API URL
	Url string

	// basic info
	ProductKey string
	DeviceCode string
	Version    string

	// private things
	id      int64
	secrect string
	token   []byte
	access  string
}

func NewDevice(url string, productkey string, code string, version string) *Device {

	return &Device{
		Url:        url,
		ProductKey: productkey,
		DeviceCode: code,
		Version:    version,
	}
}

func (d *Device) DoRegister() error {
	args := DeviceRegisterArgs{
		ProductKey: d.ProductKey,
		DeviceCode: d.DeviceCode,
		Version:    d.Version,
	}
	regUrl := fmt.Sprintf("%v%v", d.Url, "/v1/devices/registration")
	request, err := json.Marshal(args)
	if err != nil {
		return err
	}
	jsonresp, err := SendHttpRequest(regUrl, string(request), "POST", nil)
	if err != nil {
		return err
	}
	response := DeviceRegisterResponse{}
	err = json.Unmarshal(jsonresp, &response)
	if err != nil {
		return err
	}
	err = CheckHttpsCode(response)
	if err != nil {
		return err
	}

	d.id = response.Data.DeviceId
	d.secrect = response.Data.DeviceSecret

	return nil
}

func (d *Device) DoLogin() error {
	args := DeviceAuthArgs{
		DeviceId:     d.id,
		DeviceSecret: d.secrect,
		Protocol:     "mqtt",
	}
	regUrl := fmt.Sprintf("%v%v", d.Url, "/v1/devices/authentication")
	request, err := json.Marshal(args)
	if err != nil {
		return err
	}
	jsonresp, err := SendHttpRequest(regUrl, string(request), "POST", nil)
	if err != nil {
		return err
	}
	response := DeviceAuthResponse{}
	err = json.Unmarshal(jsonresp, &response)
	if err != nil {
		return err
	}
	err = CheckHttpsCode(response)
	if err != nil {
		return err
	}
	// ecode hex
	htoken, err := hex.DecodeString(response.Data.AccessToken)
	if err != nil {
		return err
	}
	d.token = htoken
	d.access = response.Data.AccessAddr

	return nil
}

func (d *Device) reportStatus(client *MQTT.Client) {

	payloadHead := protocol.DataHead{
		Flag:      0,
		Timestamp: uint64(time.Now().Unix() * 1000),
	}
	param := []interface{}{uint8(1)}
	params, err := tlv.MakeTLVs(param)
	if err != nil {
		fmt.Println(err)
		return
	}
	sub := protocol.SubData{
		Head: protocol.SubDataHead{
			SubDeviceid: uint16(1),
			PropertyNum: uint16(1),
			ParamsCount: uint16(len(params)),
		},
		Params: params,
	}

	status := protocol.Data{
		Head:    payloadHead,
		SubData: []protocol.SubData{},
	}

	status.SubData = append(status.SubData, sub)

	payload, err := status.Marshal()
	if err != nil {
		fmt.Println(err)
		return
	}

	deviceid := fmt.Sprint("%x", d.id)
	client.Publish(deviceid+"/d", 1, false, payload)

}

func (d *Device) statusHandler(client *MQTT.Client, msg MQTT.Message) {
	status := protocol.Data{}

	err := status.UnMarshal(msg.Payload())
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println("device receiving status set : ")

	for _, one := range status.SubData {
		fmt.Println("subdeviceid : ", one.Head.SubDeviceid)
		fmt.Println("no : ", one.Head.PropertyNum)
		fmt.Println("params : ", one.Params)
	}
}

func (d *Device) commandHandler(client *MQTT.Client, msg MQTT.Message) {
	cmd := protocol.Command{}

	err := cmd.UnMarshal(msg.Payload())
	if err != nil {
		fmt.Println(err)
		return
	}

	switch cmd.Head.No {
	case commonCmdGetStatus:
		d.reportStatus(client)
	default:
		fmt.Println("unsuported command : %v", cmd.Head.No)
	}
}

func (d *Device) messageHandler(client *MQTT.Client, msg MQTT.Message) {
	fmt.Printf("TOPIC: %s\n", msg.Topic())
	fmt.Printf("MSG: %x\n", msg.Payload())
	topicPieces := strings.Split(msg.Topic(), "/")
	clientid := topicPieces[0]
	msgtype := topicPieces[1]
	fmt.Println(clientid, msgtype)

	switch msgtype {
	case "c":
		d.commandHandler(client, msg)
	case "s":
		d.statusHandler(client, msg)
	default:
		fmt.Println("unsuported message type :", msgtype)
	}
}

func (d *Device) DoAccess() error {
	logger := log.New(os.Stdout, "", log.LstdFlags)
	MQTT.ERROR = logger
	MQTT.CRITICAL = logger
	MQTT.WARN = logger
	MQTT.DEBUG = logger

	//create a ClientOptions struct setting the broker address, clientid, turn
	//off trace output and set the default message handler
	opts := MQTT.NewClientOptions().AddBroker("tls://" + d.access)
	clientid := fmt.Sprintf("%x", d.id)
	opts.SetClientID(clientid)
	opts.SetUsername(clientid) // clientid as username
	opts.SetPassword(hex.EncodeToString(d.token))
	opts.SetKeepAlive(30 * time.Second)
	opts.SetDefaultPublishHandler(d.messageHandler)
	opts.SetTLSConfig(&tls.Config{Certificates: nil, InsecureSkipVerify: true})

	//create and start a client using the above ClientOptions
	c := MQTT.NewClient(opts)
	if token := c.Connect(); token.Wait() && token.Error() != nil {
		return token.Error()
	}

	// we just pause here to wait for messages
	<-make(chan int)

	defer c.Disconnect(250)

	return nil
}
<commit_msg>fix test device topic mismatch bug.<commit_after>package main

import (
	"crypto/tls"
	"encoding/hex"
	"encoding/json"
	"fmt"
	MQTT "git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git"
	"github.com/PandoCloud/pando-cloud/pkg/protocol"
	"github.com/PandoCloud/pando-cloud/pkg/tlv"
	"log"
	"os"
	"time"
)

const (
	commonCmdGetStatus = uint16(65528)
)

// device register args
type DeviceRegisterArgs struct {
	ProductKey string `json:"product_key"  binding:"required"`
	DeviceCode string `json:"device_code"  binding:"required"`
	Version    string `json:"version"  binding:"required"`
}

// device authentication args
type DeviceAuthArgs struct {
	DeviceId     int64  `json:"device_id" binding:"required"`
	DeviceSecret string `json:"device_secret" binding:"required"`
	Protocol     string `json:"protocol" binding:"required"`
}

// common response fields
type Common struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
}

// device register response data field
type DeviceRegisterData struct {
	DeviceId         int64  `json:"device_id"`
	DeviceSecret     string `json:"device_secret"`
	DeviceKey        string `json:"device_key"`
	DeviceIdentifier string `json:"device_identifier"`
}

// device register response
type DeviceRegisterResponse struct {
	Common
	Data DeviceRegisterData `json:"data"`
}

// device auth response data field
type DeviceAuthData struct {
	AccessToken string `json:"access_token"`
	AccessAddr  string `json:"access_addr"`
}

// device auth response
type DeviceAuthResponse struct {
	Common
	Data DeviceAuthData `json:"data"`
}

type Device struct {
	// API URL
	Url string

	// basic info
	ProductKey string
	DeviceCode string
	Version    string

	// private things
	id      int64
	secrect string
	token   []byte
	access  string
}

func NewDevice(url string, productkey string, code string, version string) *Device {

	return &Device{
		Url:        url,
		ProductKey: productkey,
		DeviceCode: code,
		Version:    version,
	}
}

func (d *Device) DoRegister() error {
	args := DeviceRegisterArgs{
		ProductKey: d.ProductKey,
		DeviceCode: d.DeviceCode,
		Version:    d.Version,
	}
	regUrl := fmt.Sprintf("%v%v", d.Url, "/v1/devices/registration")
	request, err := json.Marshal(args)
	if err != nil {
		return err
	}
	jsonresp, err := SendHttpRequest(regUrl, string(request), "POST", nil)
	if err != nil {
		return err
	}
	response := DeviceRegisterResponse{}
	err = json.Unmarshal(jsonresp, &response)
	if err != nil {
		return err
	}
	err = CheckHttpsCode(response)
	if err != nil {
		return err
	}

	d.id = response.Data.DeviceId
	d.secrect = response.Data.DeviceSecret

	return nil
}

func (d *Device) DoLogin() error {
	args := DeviceAuthArgs{
		DeviceId:     d.id,
		DeviceSecret: d.secrect,
		Protocol:     "mqtt",
	}
	regUrl := fmt.Sprintf("%v%v", d.Url, "/v1/devices/authentication")
	request, err := json.Marshal(args)
	if err != nil {
		return err
	}
	jsonresp, err := SendHttpRequest(regUrl, string(request), "POST", nil)
	if err != nil {
		return err
	}
	response := DeviceAuthResponse{}
	err = json.Unmarshal(jsonresp, &response)
	if err != nil {
		return err
	}
	err = CheckHttpsCode(response)
	if err != nil {
		return err
	}
	// ecode hex
	htoken, err := hex.DecodeString(response.Data.AccessToken)
	if err != nil {
		return err
	}
	d.token = htoken
	d.access = response.Data.AccessAddr

	return nil
}

func (d *Device) reportStatus(client *MQTT.Client) {

	payloadHead := protocol.DataHead{
		Flag:      0,
		Timestamp: uint64(time.Now().Unix() * 1000),
	}
	param := []interface{}{uint8(1)}
	params, err := tlv.MakeTLVs(param)
	if err != nil {
		fmt.Println(err)
		return
	}
	sub := protocol.SubData{
		Head: protocol.SubDataHead{
			SubDeviceid: uint16(1),
			PropertyNum: uint16(1),
			ParamsCount: uint16(len(params)),
		},
		Params: params,
	}

	status := protocol.Data{
		Head:    payloadHead,
		SubData: []protocol.SubData{},
	}

	status.SubData = append(status.SubData, sub)

	payload, err := status.Marshal()
	if err != nil {
		fmt.Println(err)
		return
	}

	client.Publish("d", 1, false, payload)

}

func (d *Device) statusHandler(client *MQTT.Client, msg MQTT.Message) {
	status := protocol.Data{}

	err := status.UnMarshal(msg.Payload())
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println("device receiving status set : ")

	for _, one := range status.SubData {
		fmt.Println("subdeviceid : ", one.Head.SubDeviceid)
		fmt.Println("no : ", one.Head.PropertyNum)
		fmt.Println("params : ", one.Params)
	}
}

func (d *Device) commandHandler(client *MQTT.Client, msg MQTT.Message) {
	cmd := protocol.Command{}

	err := cmd.UnMarshal(msg.Payload())
	if err != nil {
		fmt.Println(err)
		return
	}

	switch cmd.Head.No {
	case commonCmdGetStatus:
		d.reportStatus(client)
	default:
		fmt.Println("unsuported command : %v", cmd.Head.No)
	}
}

func (d *Device) messageHandler(client *MQTT.Client, msg MQTT.Message) {
	fmt.Printf("TOPIC: %s\n", msg.Topic())
	fmt.Printf("MSG: %x\n", msg.Payload())
	msgtype := msg.Topic()
	fmt.Println(msgtype)

	switch msgtype {
	case "c":
		d.commandHandler(client, msg)
	case "s":
		d.statusHandler(client, msg)
	default:
		fmt.Println("unsuported message type :", msgtype)
	}
}

func (d *Device) DoAccess() error {
	logger := log.New(os.Stdout, "", log.LstdFlags)
	MQTT.ERROR = logger
	MQTT.CRITICAL = logger
	MQTT.WARN = logger
	MQTT.DEBUG = logger

	//create a ClientOptions struct setting the broker address, clientid, turn
	//off trace output and set the default message handler
	opts := MQTT.NewClientOptions().AddBroker("tls://" + d.access)
	clientid := fmt.Sprintf("%x", d.id)
	opts.SetClientID(clientid)
	opts.SetUsername(clientid) // clientid as username
	opts.SetPassword(hex.EncodeToString(d.token))
	opts.SetKeepAlive(30 * time.Second)
	opts.SetDefaultPublishHandler(d.messageHandler)
	opts.SetTLSConfig(&tls.Config{Certificates: nil, InsecureSkipVerify: true})

	//create and start a client using the above ClientOptions
	c := MQTT.NewClient(opts)
	if token := c.Connect(); token.Wait() && token.Error() != nil {
		return token.Error()
	}

	// we just pause here to wait for messages
	<-make(chan int)

	defer c.Disconnect(250)

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"cuckood"
	"cuckood/cucache/text"
	"encoding/binary"
	"flag"
	"fmt"
	"io"
	"math"
	"net"
	"os"
	"os/signal"
	"runtime/pprof"
	"strconv"
	"sync"
	"syscall"
	"time"

	gomem "github.com/dustin/gomemcached"
)

var c cuckoo.Cuckoo

func main() {
	cpuprofile := flag.String("cpuprofile", "", "CPU profile output file")
	flag.Parse()

	c = cuckoo.New()

	var pf *os.File
	sigs := make(chan os.Signal, 1)
	signal.Notify(sigs, os.Interrupt, syscall.SIGABRT)
	go func() {
		for s := range sigs {
			if pf != nil {
				pprof.StopCPUProfile()
				err := pf.Close()
				if err != nil {
					fmt.Println("could not end cpu profile:", err)
				}
			}
			if s == os.Interrupt {
				os.Exit(0)
			}
		}
	}()

	var err error
	if cpuprofile != nil && *cpuprofile != "" {
		fmt.Println("starting CPU profiling")
		pf, err = os.Create(*cpuprofile)
		if err != nil {
			fmt.Printf("could not create CPU profile file %v: %v\n", *cpuprofile, err)
			return
		}
		err = pprof.StartCPUProfile(pf)
		if err != nil {
			fmt.Printf("could not start CPU profiling: %v\n", err)
			return
		}
	}

	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		defer wg.Done()
		ln, err := net.Listen("tcp", ":11211")
		if err != nil {
			panic(err)
		}
		for {
			conn, err := ln.Accept()
			if err != nil {
				fmt.Println(err)
				continue
			}
			go handleConnection(conn)
		}
	}()
	wg.Add(1)
	go func() {
		defer wg.Done()
		ln, err := net.ListenPacket("udp", ":11211")
		if err != nil {
			panic(err)
		}
		for {
			b := make([]byte, 0, 10240)
			_, addr, err := ln.ReadFrom(b)
			if err != nil {
				fmt.Println(err)
				continue
			}
			go replyTo(b, addr.(*net.UDPAddr))
		}
	}()
	wg.Wait()
}

func wtf(req gomem.MCRequest, v cuckoo.MemopRes) {
	panic(fmt.Sprintf("unexpected result when handling %v: %v\n", req.Opcode, v))
}

func tm(i uint32) (t time.Time) {
	if i == 0 {
		return
	}

	if i < 60*60*24*30 {
		t = time.Now().Add(time.Duration(i) * time.Second)
	} else {
		t = time.Unix(int64(i), 0)
	}
	return
}

func deal(in_ io.Reader, out io.Writer) {
	var getq []*gomem.MCResponse

	in := bufio.NewReader(in_)
	for {
		b, err := in.Peek(1)
		if err != nil {
			if err == io.EOF {
				return
			}
			// TODO print error
			return
		}

		isbinary := true
		var req gomem.MCRequest
		var res gomem.MCResponse
		if b[0] == gomem.REQ_MAGIC {
			_, err := req.Receive(in, nil)
			if err != nil {
				if err == io.EOF {
					return
				}
				// TODO: print error
				continue
			}
			res.Opaque = req.Opaque
		} else {
			// text protocol fallback
			cmd, err := in.ReadString('\n')
			if err != nil {
				if err == io.EOF {
					return
				}
				// TODO: print error
				return
			}

			req, err = text.ToMCRequest(cmd, in)
			isbinary = false
		}

		switch req.Opcode {
		case gomem.GET, gomem.GETQ, gomem.GETK, gomem.GETKQ:
			res.Status = gomem.KEY_ENOENT
			v, ok := c.Get(req.Key)
			if ok {
				res.Status = gomem.SUCCESS
				res.Extras = make([]byte, 4)
				binary.BigEndian.PutUint32(res.Extras, v.Flags)
				res.Cas = v.Casid
				res.Body = v.Bytes

				if req.Opcode == gomem.GETK || req.Opcode == gomem.GETKQ {
					res.Key = req.Key
				}
			}
		case gomem.SET, gomem.SETQ,
			gomem.ADD, gomem.ADDQ,
			gomem.REPLACE, gomem.REPLACEQ:

			flags := binary.BigEndian.Uint32(req.Extras[0:4])
			expiry := tm(binary.BigEndian.Uint32(req.Extras[4:8]))
			var v cuckoo.MemopRes
			switch req.Opcode {
			case gomem.SET, gomem.SETQ:
				if req.Cas == 0 {
					v = c.Set(req.Key, req.Body, flags, expiry)
				} else {
					v = c.CAS(req.Key, req.Body, flags, expiry, req.Cas)
				}
			case gomem.ADD, gomem.ADDQ:
				v = c.Add(req.Key, req.Body, flags, expiry)
			case gomem.REPLACE, gomem.REPLACEQ:
				if req.Cas == 0 {
					v = c.Replace(req.Key, req.Body, flags, expiry)
				} else {
					v = c.CAS(req.Key, req.Body, flags, expiry, req.Cas)
				}
			}

			switch v.T {
			case cuckoo.STORED:
				res.Status = gomem.SUCCESS
				res.Cas = v.V.(uint64)
			case cuckoo.NOT_STORED:
				res.Status = gomem.NOT_STORED
			case cuckoo.NOT_FOUND:
				res.Status = gomem.KEY_ENOENT
			case cuckoo.EXISTS:
				res.Status = gomem.KEY_EEXISTS
			case cuckoo.SERVER_ERROR:
				res.Status = gomem.ENOMEM
				fmt.Println(v.V.(error))
			default:
				wtf(req, v)
			}
		case gomem.DELETE, gomem.DELETEQ:
			v := c.Delete(req.Key, req.Cas)

			switch v.T {
			case cuckoo.STORED:
				res.Status = gomem.SUCCESS
			case cuckoo.NOT_FOUND:
				res.Status = gomem.KEY_ENOENT
			case cuckoo.EXISTS:
				res.Status = gomem.KEY_EEXISTS
			default:
				wtf(req, v)
			}
		case gomem.INCREMENT, gomem.INCREMENTQ,
			gomem.DECREMENT, gomem.DECREMENTQ:

			by := binary.BigEndian.Uint64(req.Extras[0:8])
			def := binary.BigEndian.Uint64(req.Extras[8:16])
			exp := tm(binary.BigEndian.Uint32(req.Extras[16:20]))

			if binary.BigEndian.Uint32(req.Extras[16:20]) == 0xffffffff {
				exp = time.Unix(math.MaxInt64, 0)
			}

			var v cuckoo.MemopRes
			if req.Opcode == gomem.INCREMENT || req.Opcode == gomem.INCREMENTQ {
				v = c.Incr(req.Key, by, def, exp)
			} else {
				v = c.Decr(req.Key, by, def, exp)
			}

			switch v.T {
			case cuckoo.STORED:
				res.Status = gomem.SUCCESS
				cv := v.V.(cuckoo.CasVal)
				res.Cas = cv.Casid
				res.Body = make([]byte, 8)
				binary.BigEndian.PutUint64(res.Body, cv.NewVal)
			case cuckoo.CLIENT_ERROR:
				res.Status = gomem.DELTA_BADVAL
			case cuckoo.NOT_FOUND:
				res.Status = gomem.KEY_ENOENT
			default:
				wtf(req, v)
			}
		case gomem.QUIT, gomem.QUITQ:
			return
		case gomem.FLUSH, gomem.FLUSHQ:
			// TODO: handle optional "now" argument
			// TODO: this is probably terrible
			c = cuckoo.New()
			res.Status = gomem.SUCCESS
		case gomem.NOOP:
			res.Status = gomem.SUCCESS
		case gomem.VERSION:
			res.Status = gomem.SUCCESS
			// TODO: res.Body =
		case gomem.APPEND, gomem.APPENDQ,
			gomem.PREPEND, gomem.PREPENDQ:

			var v cuckoo.MemopRes
			switch req.Opcode {
			case gomem.APPEND, gomem.APPENDQ:
				v = c.Append(req.Key, req.Body, req.Cas)
			case gomem.PREPEND, gomem.PREPENDQ:
				v = c.Prepend(req.Key, req.Body, req.Cas)
			}

			switch v.T {
			case cuckoo.STORED:
				res.Status = gomem.SUCCESS
			case cuckoo.EXISTS:
				res.Status = gomem.KEY_EEXISTS
			case cuckoo.NOT_FOUND:
				res.Status = gomem.KEY_ENOENT
			default:
				wtf(req, v)
			}
		default:
			res.Status = gomem.UNKNOWN_COMMAND
		}

		if req.Opcode.IsQuiet() && res.Status == gomem.SUCCESS {
			if req.Opcode == gomem.GETQ || req.Opcode == gomem.GETKQ {
				getq = append(getq, &res)
				continue
			} else {
				continue
			}
		}

		if (req.Opcode == gomem.GETQ || req.Opcode == gomem.GETKQ) && res.Status == gomem.KEY_ENOENT {
			// no warning on cache miss
			continue
		}

		if res.Status != gomem.SUCCESS {
			if !(res.Status == gomem.KEY_ENOENT && (req.Opcode == gomem.GET || req.Opcode == gomem.GETK)) {
				fmt.Println(req.Opcode, res.Status)
			}
		}

		if isbinary {
			// "The getq command is both mum on cache miss and quiet,
			// holding its response until a non-quiet command is issued."
			if !req.Opcode.IsQuiet() && len(getq) != 0 {
				// flush quieted get replies
				for _, r := range getq {
					r.Transmit(out)
				}
				getq = getq[:0]
			}

			res.Transmit(out)
			continue
		}

		if req.Opcode.IsQuiet() && res.Status == gomem.SUCCESS && req.Opcode != gomem.GET {
			// there is absolutely no reason to reply here
			continue
		}

		// TODO: return when writes fail
		switch res.Status {
		case gomem.SUCCESS:
			switch req.Opcode {
			case gomem.GET, gomem.GETQ:
				flags := binary.BigEndian.Uint32(res.Extras[0:4])
				out.Write([]byte(fmt.Sprintf("VALUE %s %d %d %d\r\n", req.Key, flags, len(res.Body), res.Cas)))
				out.Write(res.Body)
				out.Write([]byte{'\r', '\n'})
				out.Write([]byte("END\r\n"))
			case gomem.SET, gomem.ADD, gomem.REPLACE:
				out.Write([]byte("STORED\r\n"))
			case gomem.DELETE:
				out.Write([]byte("DELETED\r\n"))
			case gomem.INCREMENT, gomem.DECREMENT:
				v := binary.BigEndian.Uint64(res.Body)
				out.Write([]byte(strconv.FormatUint(v, 10) + "\r\n"))
			}
		case gomem.KEY_ENOENT:
			out.Write([]byte("NOT_FOUND\r\n"))
		case gomem.KEY_EEXISTS:
			out.Write([]byte("EXISTS\r\n"))
		case gomem.NOT_STORED:
			out.Write([]byte("NOT_STORED\r\n"))
		case gomem.ENOMEM:
			out.Write([]byte("SERVER_ERROR no space for new entry\r\n"))
		case gomem.DELTA_BADVAL:
			out.Write([]byte("CLIENT_ERROR incr/decr on non-numeric field\r\n"))
		case gomem.UNKNOWN_COMMAND:
			out.Write([]byte("ERROR\r\n"))
		}
	}
}

func replyTo(in []byte, to *net.UDPAddr) {
	u, err := net.ListenPacket("udp", "127.0.0.1:0")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer u.Close()

	var o bytes.Buffer
	deal(bytes.NewBuffer(in), &o)
	_, err = u.WriteTo(o.Bytes(), to)
	if err != nil {
		fmt.Println(err)
	}
}

func handleConnection(c net.Conn) {
	deal(c, c)
	c.Close()
}
<commit_msg>Return req opcode in res<commit_after>package main

import (
	"bufio"
	"bytes"
	"cuckood"
	"cuckood/cucache/text"
	"encoding/binary"
	"flag"
	"fmt"
	"io"
	"math"
	"net"
	"os"
	"os/signal"
	"runtime/pprof"
	"strconv"
	"sync"
	"syscall"
	"time"

	gomem "github.com/dustin/gomemcached"
)

var c cuckoo.Cuckoo

func main() {
	cpuprofile := flag.String("cpuprofile", "", "CPU profile output file")
	flag.Parse()

	c = cuckoo.New()

	var pf *os.File
	sigs := make(chan os.Signal, 1)
	signal.Notify(sigs, os.Interrupt, syscall.SIGABRT)
	go func() {
		for s := range sigs {
			if pf != nil {
				pprof.StopCPUProfile()
				err := pf.Close()
				if err != nil {
					fmt.Println("could not end cpu profile:", err)
				}
			}
			if s == os.Interrupt {
				os.Exit(0)
			}
		}
	}()

	var err error
	if cpuprofile != nil && *cpuprofile != "" {
		fmt.Println("starting CPU profiling")
		pf, err = os.Create(*cpuprofile)
		if err != nil {
			fmt.Printf("could not create CPU profile file %v: %v\n", *cpuprofile, err)
			return
		}
		err = pprof.StartCPUProfile(pf)
		if err != nil {
			fmt.Printf("could not start CPU profiling: %v\n", err)
			return
		}
	}

	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		defer wg.Done()
		ln, err := net.Listen("tcp", ":11211")
		if err != nil {
			panic(err)
		}
		for {
			conn, err := ln.Accept()
			if err != nil {
				fmt.Println(err)
				continue
			}
			go handleConnection(conn)
		}
	}()
	wg.Add(1)
	go func() {
		defer wg.Done()
		ln, err := net.ListenPacket("udp", ":11211")
		if err != nil {
			panic(err)
		}
		for {
			b := make([]byte, 0, 10240)
			_, addr, err := ln.ReadFrom(b)
			if err != nil {
				fmt.Println(err)
				continue
			}
			go replyTo(b, addr.(*net.UDPAddr))
		}
	}()
	wg.Wait()
}

func wtf(req gomem.MCRequest, v cuckoo.MemopRes) {
	panic(fmt.Sprintf("unexpected result when handling %v: %v\n", req.Opcode, v))
}

func tm(i uint32) (t time.Time) {
	if i == 0 {
		return
	}

	if i < 60*60*24*30 {
		t = time.Now().Add(time.Duration(i) * time.Second)
	} else {
		t = time.Unix(int64(i), 0)
	}
	return
}

func deal(in_ io.Reader, out io.Writer) {
	var getq []*gomem.MCResponse

	in := bufio.NewReader(in_)
	for {
		b, err := in.Peek(1)
		if err != nil {
			if err == io.EOF {
				return
			}
			// TODO print error
			return
		}

		isbinary := true
		var req gomem.MCRequest
		var res gomem.MCResponse
		if b[0] == gomem.REQ_MAGIC {
			_, err := req.Receive(in, nil)
			if err != nil {
				if err == io.EOF {
					return
				}
				// TODO: print error
				continue
			}
			res.Opaque = req.Opaque
		} else {
			// text protocol fallback
			cmd, err := in.ReadString('\n')
			if err != nil {
				if err == io.EOF {
					return
				}
				// TODO: print error
				return
			}

			req, err = text.ToMCRequest(cmd, in)
			isbinary = false
		}
		res.Opcode = req.Opcode

		switch req.Opcode {
		case gomem.GET, gomem.GETQ, gomem.GETK, gomem.GETKQ:
			res.Status = gomem.KEY_ENOENT
			v, ok := c.Get(req.Key)
			if ok {
				res.Status = gomem.SUCCESS
				res.Extras = make([]byte, 4)
				binary.BigEndian.PutUint32(res.Extras, v.Flags)
				res.Cas = v.Casid
				res.Body = v.Bytes

				if req.Opcode == gomem.GETK || req.Opcode == gomem.GETKQ {
					res.Key = req.Key
				}
			}
		case gomem.SET, gomem.SETQ,
			gomem.ADD, gomem.ADDQ,
			gomem.REPLACE, gomem.REPLACEQ:

			flags := binary.BigEndian.Uint32(req.Extras[0:4])
			expiry := tm(binary.BigEndian.Uint32(req.Extras[4:8]))
			var v cuckoo.MemopRes
			switch req.Opcode {
			case gomem.SET, gomem.SETQ:
				if req.Cas == 0 {
					v = c.Set(req.Key, req.Body, flags, expiry)
				} else {
					v = c.CAS(req.Key, req.Body, flags, expiry, req.Cas)
				}
			case gomem.ADD, gomem.ADDQ:
				v = c.Add(req.Key, req.Body, flags, expiry)
			case gomem.REPLACE, gomem.REPLACEQ:
				if req.Cas == 0 {
					v = c.Replace(req.Key, req.Body, flags, expiry)
				} else {
					v = c.CAS(req.Key, req.Body, flags, expiry, req.Cas)
				}
			}

			switch v.T {
			case cuckoo.STORED:
				res.Status = gomem.SUCCESS
				res.Cas = v.V.(uint64)
			case cuckoo.NOT_STORED:
				res.Status = gomem.NOT_STORED
			case cuckoo.NOT_FOUND:
				res.Status = gomem.KEY_ENOENT
			case cuckoo.EXISTS:
				res.Status = gomem.KEY_EEXISTS
			case cuckoo.SERVER_ERROR:
				res.Status = gomem.ENOMEM
				fmt.Println(v.V.(error))
			default:
				wtf(req, v)
			}
		case gomem.DELETE, gomem.DELETEQ:
			v := c.Delete(req.Key, req.Cas)

			switch v.T {
			case cuckoo.STORED:
				res.Status = gomem.SUCCESS
			case cuckoo.NOT_FOUND:
				res.Status = gomem.KEY_ENOENT
			case cuckoo.EXISTS:
				res.Status = gomem.KEY_EEXISTS
			default:
				wtf(req, v)
			}
		case gomem.INCREMENT, gomem.INCREMENTQ,
			gomem.DECREMENT, gomem.DECREMENTQ:

			by := binary.BigEndian.Uint64(req.Extras[0:8])
			def := binary.BigEndian.Uint64(req.Extras[8:16])
			exp := tm(binary.BigEndian.Uint32(req.Extras[16:20]))

			if binary.BigEndian.Uint32(req.Extras[16:20]) == 0xffffffff {
				exp = time.Unix(math.MaxInt64, 0)
			}

			var v cuckoo.MemopRes
			if req.Opcode == gomem.INCREMENT || req.Opcode == gomem.INCREMENTQ {
				v = c.Incr(req.Key, by, def, exp)
			} else {
				v = c.Decr(req.Key, by, def, exp)
			}

			switch v.T {
			case cuckoo.STORED:
				res.Status = gomem.SUCCESS
				cv := v.V.(cuckoo.CasVal)
				res.Cas = cv.Casid
				res.Body = make([]byte, 8)
				binary.BigEndian.PutUint64(res.Body, cv.NewVal)
			case cuckoo.CLIENT_ERROR:
				res.Status = gomem.DELTA_BADVAL
			case cuckoo.NOT_FOUND:
				res.Status = gomem.KEY_ENOENT
			default:
				wtf(req, v)
			}
		case gomem.QUIT, gomem.QUITQ:
			return
		case gomem.FLUSH, gomem.FLUSHQ:
			// TODO: handle optional "now" argument
			// TODO: this is probably terrible
			c = cuckoo.New()
			res.Status = gomem.SUCCESS
		case gomem.NOOP:
			res.Status = gomem.SUCCESS
		case gomem.VERSION:
			res.Status = gomem.SUCCESS
			// TODO: res.Body =
		case gomem.APPEND, gomem.APPENDQ,
			gomem.PREPEND, gomem.PREPENDQ:

			var v cuckoo.MemopRes
			switch req.Opcode {
			case gomem.APPEND, gomem.APPENDQ:
				v = c.Append(req.Key, req.Body, req.Cas)
			case gomem.PREPEND, gomem.PREPENDQ:
				v = c.Prepend(req.Key, req.Body, req.Cas)
			}

			switch v.T {
			case cuckoo.STORED:
				res.Status = gomem.SUCCESS
			case cuckoo.EXISTS:
				res.Status = gomem.KEY_EEXISTS
			case cuckoo.NOT_FOUND:
				res.Status = gomem.KEY_ENOENT
			default:
				wtf(req, v)
			}
		default:
			res.Status = gomem.UNKNOWN_COMMAND
		}

		if req.Opcode.IsQuiet() && res.Status == gomem.SUCCESS {
			if req.Opcode == gomem.GETQ || req.Opcode == gomem.GETKQ {
				getq = append(getq, &res)
				continue
			} else {
				continue
			}
		}

		if (req.Opcode == gomem.GETQ || req.Opcode == gomem.GETKQ) && res.Status == gomem.KEY_ENOENT {
			// no warning on cache miss
			continue
		}

		if res.Status != gomem.SUCCESS {
			if !(res.Status == gomem.KEY_ENOENT && (req.Opcode == gomem.GET || req.Opcode == gomem.GETK)) {
				fmt.Println(req.Opcode, res.Status)
			}
		}

		if isbinary {
			// "The getq command is both mum on cache miss and quiet,
			// holding its response until a non-quiet command is issued."
			if !req.Opcode.IsQuiet() && len(getq) != 0 {
				// flush quieted get replies
				for _, r := range getq {
					r.Transmit(out)
				}
				getq = getq[:0]
			}

			res.Transmit(out)
			continue
		}

		if req.Opcode.IsQuiet() && res.Status == gomem.SUCCESS && req.Opcode != gomem.GET {
			// there is absolutely no reason to reply here
			continue
		}

		// TODO: return when writes fail
		switch res.Status {
		case gomem.SUCCESS:
			switch req.Opcode {
			case gomem.GET, gomem.GETQ:
				flags := binary.BigEndian.Uint32(res.Extras[0:4])
				out.Write([]byte(fmt.Sprintf("VALUE %s %d %d %d\r\n", req.Key, flags, len(res.Body), res.Cas)))
				out.Write(res.Body)
				out.Write([]byte{'\r', '\n'})
				out.Write([]byte("END\r\n"))
			case gomem.SET, gomem.ADD, gomem.REPLACE:
				out.Write([]byte("STORED\r\n"))
			case gomem.DELETE:
				out.Write([]byte("DELETED\r\n"))
			case gomem.INCREMENT, gomem.DECREMENT:
				v := binary.BigEndian.Uint64(res.Body)
				out.Write([]byte(strconv.FormatUint(v, 10) + "\r\n"))
			}
		case gomem.KEY_ENOENT:
			out.Write([]byte("NOT_FOUND\r\n"))
		case gomem.KEY_EEXISTS:
			out.Write([]byte("EXISTS\r\n"))
		case gomem.NOT_STORED:
			out.Write([]byte("NOT_STORED\r\n"))
		case gomem.ENOMEM:
			out.Write([]byte("SERVER_ERROR no space for new entry\r\n"))
		case gomem.DELTA_BADVAL:
			out.Write([]byte("CLIENT_ERROR incr/decr on non-numeric field\r\n"))
		case gomem.UNKNOWN_COMMAND:
			out.Write([]byte("ERROR\r\n"))
		}
	}
}

func replyTo(in []byte, to *net.UDPAddr) {
	u, err := net.ListenPacket("udp", "127.0.0.1:0")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer u.Close()

	var o bytes.Buffer
	deal(bytes.NewBuffer(in), &o)
	_, err = u.WriteTo(o.Bytes(), to)
	if err != nil {
		fmt.Println(err)
	}
}

func handleConnection(c net.Conn) {
	deal(c, c)
	c.Close()
}
<|endoftext|>


<commit_before>// +build selenium

/*
 * Copyright (C) 2017 Red Hat, Inc.
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
 */

package tests

import (
	"fmt"
	"net"
	"os"
	"testing"
	"time"

	"github.com/tebeka/selenium"

	gclient "github.com/skydive-project/skydive/cmd/client"
	shttp "github.com/skydive-project/skydive/http"
	"github.com/skydive-project/skydive/tests/helper"
)

func TestSelenium(t *testing.T) {
	gopath := os.Getenv("GOPATH")
	topology := gopath + "/src/github.com/skydive-project/skydive/scripts/simple.sh"

	setupCmds := []helper.Cmd{
		{fmt.Sprintf("%s start 124.65.54.42/24 124.65.54.43/24", topology), true},
		{"sudo docker pull elgalu/selenium", true},
		{"sudo docker run -d --name=grid -p 4444:24444 -p 5900:25900 -e --shm-size=1g elgalu/selenium", true},
		{"docker exec grid wait_all_done 30s", true},
	}

	tearDownCmds := []helper.Cmd{
		{fmt.Sprintf("%s stop", topology), true},
		{"sudo docker exec grid stop", true},
		{"sudo docker stop grid", true},
		{"sudo docker rm grid", true},
	}

	helper.ExecCmds(t, setupCmds...)
	defer helper.ExecCmds(t, tearDownCmds...)

	caps := selenium.Capabilities{"browserName": "chrome"}
	webdriver, err := selenium.NewRemote(caps, "http://127.0.0.1:4444/wd/hub")
	if err != nil {
		t.Fatal(err)
	}
	defer webdriver.Quit()

	ipaddr, err := getIPv4Addr()
	if err != nil {
		t.Fatal("Not able to find Analayzer addr: %v", err)
	}

	if err := webdriver.Get("http://" + ipaddr + ":8082"); err != nil {
		t.Fatal(err)
	}
	time.Sleep(5 * time.Second)

	startCapture := func(wd selenium.WebDriver) error {
		captureTab, err := wd.FindElement(selenium.ByXPATH, ".//*[@id='Captures']")
		if err != nil || captureTab == nil {
			return fmt.Errorf("Not found capture tab: %v", err)
		}
		if err := captureTab.Click(); err != nil {
			return fmt.Errorf("%v", err)
		}
		createBtn, err := wd.FindElement(selenium.ByXPATH, ".//*[@id='create-capture']")
		if err != nil || createBtn == nil {
			return fmt.Errorf("Not found create button : %v", err)
		}
		if err := createBtn.Click(); err != nil {
			return fmt.Errorf("%v", err)
		}
		time.Sleep(2 * time.Second)

		gremlinRdoBtn, err := wd.FindElement(selenium.ByXPATH, ".//*[@id='by-gremlin']")
		if err != nil || gremlinRdoBtn == nil {
			return fmt.Errorf("Not found gremlin expression radio button: %v", err)
		}
		if err := gremlinRdoBtn.Click(); err != nil {
			return err
		}

		queryTxtBox, err := wd.FindElement(selenium.ByXPATH, ".//*[@id='capture-query']")
		if err != nil || queryTxtBox == nil {
			return fmt.Errorf("Not found Query text box: %v", err)
		}
		if err := queryTxtBox.Clear(); err != nil {
			return err
		}
		if err := queryTxtBox.SendKeys("G.V().Has('Name', 'br-int', 'Type', 'ovsbridge')"); err != nil {
			return err
		}

		startBtn, err := wd.FindElement(selenium.ByXPATH, ".//*[@id='start-capture']")
		if err != nil || startBtn == nil {
			return fmt.Errorf("Not found start button: %v", err)
		}
		if err := startBtn.Click(); err != nil {
			return err
		}
		time.Sleep(3 * time.Second)

		//check capture created with the given query
		captures, err := wd.FindElements(selenium.ByClassName, "query")
		if err != nil {
			return err
		}
		var foundCapture bool
		for _, capture := range captures {
			if txt, _ := capture.Text(); txt == "G.V().Has('Name', 'br-int', 'Type', 'ovsbridge')" {
				foundCapture = true
				break
			}

		}
		if !foundCapture {
			return fmt.Errorf("Capture not found in the list")
		}
		return nil

	}

	injectPacket := func(wd selenium.WebDriver) error {
		generatorTab, err := wd.FindElement(selenium.ByXPATH, ".//*[@id='Generator']")
		if err != nil || generatorTab == nil {
			return fmt.Errorf("Generator tab not found: %v", err)
		}
		if err := generatorTab.Click(); err != nil {
			return err
		}

		injectSrc, err := wd.FindElement(selenium.ByXPATH, ".//*[@id='inject-src']/input")
		if err != nil || injectSrc == nil {
			return err
		}
		if err := injectSrc.Click(); err != nil {
			return err
		}

		authOptions := &shttp.AuthenticationOpts{}
		gh := gclient.NewGremlinQueryHelper(authOptions)

		node1, err := gh.GetNode("G.V().Has('Name', 'eth0', 'IPV4', Contains('124.65.54.42/24')).HasKey('TID')")
		if err != nil {
			return err
		}

		node2, err := gh.GetNode("G.V().Has('Name', 'eth0', 'IPV4', Contains('124.65.54.43/24')).HasKey('TID')")
		if err != nil {
			return err
		}

		tid1, _ := node1.GetFieldString("TID")
		tid2, _ := node2.GetFieldString("TID")

		srcNode, err := wd.FindElement(selenium.ByXPATH, ".//*[@tid='"+tid1+"']")
		if err != nil || srcNode == nil {
			return err
		}
		if err := srcNode.Click(); err != nil {
			return err
		}

		injectDst, err := wd.FindElement(selenium.ByXPATH, ".//*[@id='inject-dst']/input")
		if err != nil || injectDst == nil {
			return err
		}
		if err := injectDst.Click(); err != nil {
			return err
		}
		dstNode, err := wd.FindElement(selenium.ByXPATH, ".//*[@tid='"+tid2+"']")
		if err != nil || dstNode == nil {
			return err
		}
		if err := dstNode.Click(); err != nil {
			return err
		}

		injectBtn, err := wd.FindElement(selenium.ByXPATH, ".//*[@id='inject']")
		if err != nil || injectBtn == nil {
			return nil
		}
		if err := injectBtn.Click(); err != nil {
			return err
		}

		var alertMsg selenium.WebElement
		for i := 1; i <= 10; i++ {
			alertMsg, err = wd.FindElement(selenium.ByClassName, "alert-success")
			if err != nil {
				time.Sleep(500 * time.Millisecond)
				continue
			}
			break
		}
		if alertMsg == nil {
			return fmt.Errorf("No success alert msg.")
		}
		return nil
	}

	if err := startCapture(webdriver); err != nil {
		t.Fatal(err)
	}

	if err := injectPacket(webdriver); err != nil {
		t.Fatal(err)
	}

}

func getIPv4Addr() (string, error) {
	ifaces, err := net.Interfaces()
	if err != nil {
		return "", err
	}

	for _, iface := range ifaces {
		//neglect interfaces which are down
		if iface.Flags&net.FlagUp == 0 {
			continue
		}
		//neglect loopback interface
		if iface.Flags&net.FlagLoopback != 0 {
			continue
		}
		addrs, err := iface.Addrs()
		if err != nil {
			return "", err
		}
		for _, addr := range addrs {
			var ip net.IP
			switch t := addr.(type) {
			case *net.IPNet:
				ip = t.IP
			case *net.IPAddr:
				ip = t.IP
			}
			if ip == nil || ip.IsLoopback() {
				continue
			}
			ip = ip.To4()
			if ip != nil {
				return ip.String(), nil
			}
		}
	}
	return "", fmt.Errorf("No IP found")
}
<commit_msg>test: selenium test to verify flows<commit_after>// +build selenium

/*
 * Copyright (C) 2017 Red Hat, Inc.
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
 */

package tests

import (
	"fmt"
	"net"
	"os"
	"testing"
	"time"

	"github.com/tebeka/selenium"

	gclient "github.com/skydive-project/skydive/cmd/client"
	shttp "github.com/skydive-project/skydive/http"
	"github.com/skydive-project/skydive/tests/helper"
)

func TestSelenium(t *testing.T) {
	gopath := os.Getenv("GOPATH")
	topology := gopath + "/src/github.com/skydive-project/skydive/scripts/simple.sh"

	setupCmds := []helper.Cmd{
		{fmt.Sprintf("%s start 124.65.54.42/24 124.65.54.43/24", topology), true},
		{"sudo docker pull elgalu/selenium", true},
		{"sudo docker run -d --name=grid -p 4444:24444 -p 5900:25900 -e --shm-size=1g elgalu/selenium", true},
		{"docker exec grid wait_all_done 30s", true},
	}

	tearDownCmds := []helper.Cmd{
		{fmt.Sprintf("%s stop", topology), true},
		{"sudo docker exec grid stop", true},
		{"sudo docker stop grid", true},
		{"sudo docker rm grid", true},
	}

	helper.ExecCmds(t, setupCmds...)
	defer helper.ExecCmds(t, tearDownCmds...)

	caps := selenium.Capabilities{"browserName": "chrome"}
	webdriver, err := selenium.NewRemote(caps, "http://127.0.0.1:4444/wd/hub")
	if err != nil {
		t.Fatal(err)
	}
	defer webdriver.Quit()

	ipaddr, err := getIPv4Addr()
	if err != nil {
		t.Fatal("Not able to find Analayzer addr: %v", err)
	}

	if err := webdriver.Get("http://" + ipaddr + ":8082"); err != nil {
		t.Fatal(err)
	}
	time.Sleep(5 * time.Second)

	startCapture := func(wd selenium.WebDriver) error {
		captureTab, err := wd.FindElement(selenium.ByXPATH, ".//*[@id='Captures']")
		if err != nil || captureTab == nil {
			return fmt.Errorf("Not found capture tab: %v", err)
		}
		if err := captureTab.Click(); err != nil {
			return fmt.Errorf("%v", err)
		}
		createBtn, err := wd.FindElement(selenium.ByXPATH, ".//*[@id='create-capture']")
		if err != nil || createBtn == nil {
			return fmt.Errorf("Not found create button : %v", err)
		}
		if err := createBtn.Click(); err != nil {
			return fmt.Errorf("%v", err)
		}
		time.Sleep(2 * time.Second)

		gremlinRdoBtn, err := wd.FindElement(selenium.ByXPATH, ".//*[@id='by-gremlin']")
		if err != nil || gremlinRdoBtn == nil {
			return fmt.Errorf("Not found gremlin expression radio button: %v", err)
		}
		if err := gremlinRdoBtn.Click(); err != nil {
			return err
		}

		queryTxtBox, err := wd.FindElement(selenium.ByXPATH, ".//*[@id='capture-query']")
		if err != nil || queryTxtBox == nil {
			return fmt.Errorf("Not found Query text box: %v", err)
		}
		if err := queryTxtBox.Clear(); err != nil {
			return err
		}
		if err := queryTxtBox.SendKeys("G.V().Has('Name', 'br-int', 'Type', 'ovsbridge')"); err != nil {
			return err
		}

		startBtn, err := wd.FindElement(selenium.ByXPATH, ".//*[@id='start-capture']")
		if err != nil || startBtn == nil {
			return fmt.Errorf("Not found start button: %v", err)
		}
		if err := startBtn.Click(); err != nil {
			return err
		}
		time.Sleep(3 * time.Second)

		//check capture created with the given query
		captures, err := wd.FindElements(selenium.ByClassName, "query")
		if err != nil {
			return err
		}
		var foundCapture bool
		for _, capture := range captures {
			if txt, _ := capture.Text(); txt == "G.V().Has('Name', 'br-int', 'Type', 'ovsbridge')" {
				foundCapture = true
				break
			}

		}
		if !foundCapture {
			return fmt.Errorf("Capture not found in the list")
		}
		return nil

	}

	injectPacket := func(wd selenium.WebDriver) error {
		generatorTab, err := wd.FindElement(selenium.ByXPATH, ".//*[@id='Generator']")
		if err != nil || generatorTab == nil {
			return fmt.Errorf("Generator tab not found: %v", err)
		}
		if err := generatorTab.Click(); err != nil {
			return err
		}

		injectSrc, err := wd.FindElement(selenium.ByXPATH, ".//*[@id='inject-src']/input")
		if err != nil || injectSrc == nil {
			return err
		}
		if err := injectSrc.Click(); err != nil {
			return err
		}

		authOptions := &shttp.AuthenticationOpts{}
		gh := gclient.NewGremlinQueryHelper(authOptions)

		node1, err := gh.GetNode("G.V().Has('Name', 'eth0', 'IPV4', Contains('124.65.54.42/24')).HasKey('TID')")
		if err != nil {
			return err
		}

		node2, err := gh.GetNode("G.V().Has('Name', 'eth0', 'IPV4', Contains('124.65.54.43/24')).HasKey('TID')")
		if err != nil {
			return err
		}

		tid1, _ := node1.GetFieldString("TID")
		tid2, _ := node2.GetFieldString("TID")

		srcNode, err := wd.FindElement(selenium.ByXPATH, ".//*[@tid='"+tid1+"']")
		if err != nil || srcNode == nil {
			return err
		}
		if err := srcNode.Click(); err != nil {
			return err
		}

		injectDst, err := wd.FindElement(selenium.ByXPATH, ".//*[@id='inject-dst']/input")
		if err != nil || injectDst == nil {
			return err
		}
		if err := injectDst.Click(); err != nil {
			return err
		}
		dstNode, err := wd.FindElement(selenium.ByXPATH, ".//*[@tid='"+tid2+"']")
		if err != nil || dstNode == nil {
			return err
		}
		if err := dstNode.Click(); err != nil {
			return err
		}

		injectBtn, err := wd.FindElement(selenium.ByXPATH, ".//*[@id='inject']")
		if err != nil || injectBtn == nil {
			return nil
		}
		if err := injectBtn.Click(); err != nil {
			return err
		}

		var alertMsg selenium.WebElement
		for i := 1; i <= 10; i++ {
			alertMsg, err = wd.FindElement(selenium.ByClassName, "alert-success")
			if err != nil {
				time.Sleep(500 * time.Millisecond)
				continue
			}
			break
		}
		if alertMsg != nil {
			closeBtn, _ := alertMsg.FindElement(selenium.ByClassName, "close")
			if closeBtn != nil {
				closeBtn.Click()
			}
		} else {
			return fmt.Errorf("No success alert msg.")
		}
		return nil
	}

	verifyFlows := func(wd selenium.WebDriver) error {
		time.Sleep(3 * time.Second)

		flowsTab, err := wd.FindElement(selenium.ByXPATH, ".//*[@id='Flows']")
		if err != nil || flowsTab == nil {
			return fmt.Errorf("Flows tab not found: %v", err)
		}
		if err := flowsTab.Click(); err != nil {
			return err
		}

		flowQuery, err := wd.FindElement(selenium.ByXPATH, ".//*[@id='flow-table-query']")
		if err != nil || flowQuery == nil {
			return err
		}
		if err := flowQuery.Clear(); err != nil {
			return err
		}
		query := "G.Flows().Has('Network.A', '124.65.54.42', 'Network.B', '124.65.54.43')"
		if err := flowQuery.SendKeys(query); err != nil {
			return err
		}

		time.Sleep(2 * time.Second)

		flowRow, err := wd.FindElement(selenium.ByClassName, "flow-row")
		if err != nil || flowRow == nil {
			return err
		}
		rowData, err := flowRow.FindElements(selenium.ByTagName, "td")
		if err != nil {
			return err
		}
		if len(rowData) != 7 {
			return fmt.Errorf("By default 7 rows should be return")
		}
		txt, err := rowData[1].Text()
		if err != nil {
			return err
		}
		if txt != "124.65.54.42" {
			fmt.Errorf("Network.A should be '124.65.54.42' but got: %s", txt)
		}
		return nil
	}

	if err := startCapture(webdriver); err != nil {
		t.Fatal(err)
	}

	if err := injectPacket(webdriver); err != nil {
		t.Fatal(err)
	}

	if err := verifyFlows(webdriver); err != nil {
		t.Fatal(err)
	}
}

func getIPv4Addr() (string, error) {
	ifaces, err := net.Interfaces()
	if err != nil {
		return "", err
	}

	for _, iface := range ifaces {
		//neglect interfaces which are down
		if iface.Flags&net.FlagUp == 0 {
			continue
		}
		//neglect loopback interface
		if iface.Flags&net.FlagLoopback != 0 {
			continue
		}
		addrs, err := iface.Addrs()
		if err != nil {
			return "", err
		}
		for _, addr := range addrs {
			var ip net.IP
			switch t := addr.(type) {
			case *net.IPNet:
				ip = t.IP
			case *net.IPAddr:
				ip = t.IP
			}
			if ip == nil || ip.IsLoopback() {
				continue
			}
			ip = ip.To4()
			if ip != nil {
				return ip.String(), nil
			}
		}
	}
	return "", fmt.Errorf("No IP found")
}
<|endoftext|>


<commit_before>/*
 * This file is part of the KubeVirt project
 *
 * 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.
 *
 * Copyright 2018 Red Hat, Inc.
 *
 */

package tests_test

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/api/resource"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/rand"

	"kubevirt.io/client-go/kubecli"
	"kubevirt.io/kubevirt/tests"
	vmsgen "kubevirt.io/kubevirt/tools/vms-generator/utils"
)

const (
	defaultNamePrefix = "testvm-"
	defaultCPUCores   = "2"
	defaultMemory     = "2Gi"
)

var _ = Describe("Templates", func() {
	tests.FlagParse()

	virtClient, err := kubecli.GetKubevirtClient()
	tests.PanicOnError(err)

	var (
		templateParams map[string]string
		workDir        string
		templateFile   string
		vmName         string
	)

	BeforeEach(func() {
		tests.SkipIfNoCmd("oc")
		tests.BeforeTestCleanup()
		SetDefaultEventuallyTimeout(120 * time.Second)
		SetDefaultEventuallyPollingInterval(2 * time.Second)

		workDir, err = ioutil.TempDir("", tests.TempDirPrefix+"-")
		Expect(err).ToNot(HaveOccurred())
	})

	AfterEach(func() {
		if workDir != "" {
			err := os.RemoveAll(workDir)
			Expect(err).ToNot(HaveOccurred())
			workDir = ""
		}
	})

	Describe("Creating VM from Template", func() {

		AssertTestSetupSuccess := func() func() {
			return func() {
				templateParams = map[string]string{
					"NAME":      defaultNamePrefix + rand.String(12),
					"CPU_CORES": defaultCPUCores,
					"MEMORY":    defaultMemory,
				}
				templateFile = ""
				ExpectWithOffset(1, templateParams).To(HaveKeyWithValue("NAME", Not(BeEmpty())), "invalid NAME parameter: VirtualMachine name cannot be empty string")
				ExpectWithOffset(1, templateParams).To(HaveKeyWithValue("CPU_CORES", MatchRegexp(`^[0-9]+$`)), "invalid CPU_CORES parameter: %q is not unsigned integer", templateParams["CPU_CORES"])
				ExpectWithOffset(1, templateParams).To(HaveKeyWithValue("MEMORY", MatchRegexp(`^([+-]?[0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$`)), "invalid MEMORY parameter: %q is not valid quantity", templateParams["MEMORY"])
				vmName = templateParams["NAME"]
				vm, err := virtClient.VirtualMachine(tests.NamespaceTestDefault).Get(vmName, &metav1.GetOptions{})
				ExpectWithOffset(1, errors.IsNotFound(err) || vm.ObjectMeta.DeletionTimestamp != nil).To(BeTrue(), "invalid NAME parameter: VirtualMachine %q already exists", vmName)
			}
		}

		AssertTemplateSetupSuccess := func(template *vmsgen.Template, params map[string]string) func() {
			return func() {
				ExpectWithOffset(1, template).NotTo(BeNil(), "template object was not provided")
				By("Creating the Template JSON file")
				var err error
				templateFile, err = tests.GenerateTemplateJson(template, workDir)
				ExpectWithOffset(1, err).ToNot(HaveOccurred(), "failed to write template JSON file: %v", err)
				ExpectWithOffset(1, templateFile).To(BeAnExistingFile(), "template JSON file %q was not created", templateFile)

				if params != nil {
					By("Validating template parameters")
					for param, value := range params {
						switch param {
						case "NAME":
							ExpectWithOffset(1, value).NotTo(BeEmpty(), "invalid NAME parameter: VirtualMachine name cannot be empty string")
							vmName = value
							vm, err := virtClient.VirtualMachine(tests.NamespaceTestDefault).Get(vmName, &metav1.GetOptions{})
							ExpectWithOffset(1, errors.IsNotFound(err) || vm.ObjectMeta.DeletionTimestamp != nil).To(BeTrue(), "invalid NAME parameter: VirtualMachine %q already exists", vmName)
						case "CPU_CORES":
							ExpectWithOffset(1, templateParams).To(HaveKeyWithValue("CPU_CORES", MatchRegexp(`^[0-9]+$`)), "invalid CPU_CORES parameter: %q is not unsigned integer", templateParams["CPU_CORES"])
						case "MEMORY":
							ExpectWithOffset(1, templateParams).To(HaveKeyWithValue("MEMORY", MatchRegexp(`^([+-]?[0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$`)), "invalid MEMORY parameter: %q is not valid quantity", templateParams["MEMORY"])
						}
						templateParams[param] = value
					}
				}
			}
		}

		AssertTestCleanupSuccess := func() func() {
			return func() {
				if vm, err := virtClient.VirtualMachine(tests.NamespaceTestDefault).Get(vmName, &metav1.GetOptions{}); err == nil && vm.ObjectMeta.DeletionTimestamp == nil {
					By("Deleting the VirtualMachine")
					ExpectWithOffset(1, virtClient.VirtualMachine(tests.NamespaceTestDefault).Delete(vmName, &metav1.DeleteOptions{})).To(Succeed(), "failed to delete VirtualMachine %q: %v", vmName, err)
					EventuallyWithOffset(1, func() bool {
						obj, err := virtClient.VirtualMachine(tests.NamespaceTestDefault).Get(vmName, &metav1.GetOptions{})
						return errors.IsNotFound(err) || obj.ObjectMeta.DeletionTimestamp != nil
					}).Should(BeTrue(), "VirtualMachine %q still exists and the deletion timestamp was not set", vmName)
				}
				if templateFile != "" {
					if _, err := os.Stat(templateFile); !os.IsNotExist(err) {
						By("Deleting template JSON file")
						ExpectWithOffset(1, os.RemoveAll(filepath.Dir(templateFile))).To(Succeed(), "failed to remove template JSON file %q: %v", templateFile, err)
						ExpectWithOffset(1, templateFile).NotTo(BeAnExistingFile(), "template JSON file %q was not removed", templateFile)
					}
				}
			}
		}

		AssertVMCreationSuccess := func() func() {
			return func() {
				By("Creating VirtualMachine from Template via oc command")
				ocProcessCommand := []string{"oc", "process", "-f", templateFile}
				for param, value := range templateParams {
					ocProcessCommand = append(ocProcessCommand, "-p", fmt.Sprintf("%s=%s", param, value))
				}
				out, stderr, err := tests.RunCommandPipe(ocProcessCommand, []string{"oc", "create", "-f", "-"})
				ExpectWithOffset(1, err).ToNot(HaveOccurred(), "failed to create VirtualMachine %q via command \"%s | oc create -f -\": %s: %v", vmName, strings.Join(ocProcessCommand, " "), out+stderr, err)
				ExpectWithOffset(1, out).To(MatchRegexp(`"?%s"? created\n`, vmName), "command \"%s | oc create -f -\" did not print expected message: %s", strings.Join(ocProcessCommand, " "), out+stderr)
				By("Checking if the VirtualMachine exists")
				EventuallyWithOffset(1, func() error {
					_, err := virtClient.VirtualMachine(tests.NamespaceTestDefault).Get(vmName, &metav1.GetOptions{})
					return err
				}).Should(Succeed(), "VirtualMachine %q still does not exist", vmName)
			}
		}

		AssertVMCreationFailure := func() func() {
			return func() {
				By("Creating VirtualMachine from Template via oc command")
				ocProcessCommand := []string{"oc", "process", "-f", templateFile}
				for param, value := range templateParams {
					ocProcessCommand = append(ocProcessCommand, "-p", fmt.Sprintf("%s=%s", param, value))
				}
				out, stderr, err := tests.RunCommandPipe(ocProcessCommand, []string{"oc", "create", "-f", "-"})
				ExpectWithOffset(1, err).To(HaveOccurred(), "creation of VirtualMachine %q via command \"%s | oc create -f -\" succeeded: %s: %v", vmName, strings.Join(ocProcessCommand, " "), out+stderr, err)
			}
		}

		AssertVMDeletionSuccess := func() func() {
			return func() {
				By("Deleting the VirtualMachine via oc command")
				out, stderr, err := tests.RunCommand("oc", "delete", "vm", vmName)
				ExpectWithOffset(1, err).ToNot(HaveOccurred(), "failed to delete VirtualMachine via command \"oc delete vm %s\": %s: %v", vmName, out+stderr, err)
				ExpectWithOffset(1, out).To(MatchRegexp(`"?%s"? deleted\n`, vmName), "command \"oc delete vm %s\" did not print expected message: %s", vmName, out)

				By("Checking if the VM does not exist anymore")
				EventuallyWithOffset(1, func() bool {
					vm, err := virtClient.VirtualMachine(tests.NamespaceTestDefault).Get(vmName, &metav1.GetOptions{})
					return errors.IsNotFound(err) || vm.ObjectMeta.DeletionTimestamp != nil
				}).Should(BeTrue(), "the VirtualMachine %q still exists and deletion timestamp was not set", vmName)
			}
		}

		AssertVMDeletionFailure := func() func() {
			return func() {
				By("Deleting the VirtualMachine via oc command")
				out, stderr, err := tests.RunCommand("oc", "delete", "vm", vmName)
				ExpectWithOffset(1, err).To(HaveOccurred(), "failed to delete VirtualMachine via command \"oc delete vm %s\": %s: %v", vmName, out+stderr, err)
			}
		}

		AssertVMStartSuccess := func(command string) func() {
			return func() {
				switch command {
				case "oc":
					By("Starting VirtualMachine via oc command")
					patch := `{"spec":{"running":true}}`
					out, stderr, err := tests.RunCommand("oc", "patch", "vm", vmName, "--type=merge", "-p", patch)
					ExpectWithOffset(1, err).ToNot(HaveOccurred(), "failed schedule VirtualMachine %q start via command \"oc patch vm %s --type=merge -p '%s'\": %s: %v", vmName, vmName, patch, out+stderr, err)
					ExpectWithOffset(1, out).To(MatchRegexp(`"?%s"? patched\n`, vmName), "command \"oc patch vm %s --type=merge -p '%s'\" did not print expected message: %s", vmName, patch, out+stderr)

				case "virtctl":
					By("Starting VirtualMachine via virtctl command")
					out, stderr, err := tests.RunCommand("virtctl", "start", vmName)
					ExpectWithOffset(1, err).ToNot(HaveOccurred(), "failed to schedule VirtualMachine %q start via command \"virtctl start %s\": %s: %v", vmName, vmName, out+stderr, err)
					ExpectWithOffset(1, out).To(ContainSubstring("%s was scheduled to start\n", vmName), "command \"virtctl start %s\" did not print expected message: %s", vmName, out+stderr)
				}

				By("Checking if the VirtualMachineInstance was created")
				EventuallyWithOffset(1, func() error {
					_, err := virtClient.VirtualMachineInstance(tests.NamespaceTestDefault).Get(vmName, &metav1.GetOptions{})
					return err
				}).Should(Succeed(), "the VirtualMachineInstance %q still does not exist", vmName)

				By("Checking if the VirtualMachine has status ready")
				EventuallyWithOffset(1, func() bool {
					vm, err := virtClient.VirtualMachine(tests.NamespaceTestDefault).Get(vmName, &metav1.GetOptions{})
					ExpectWithOffset(1, err).ToNot(HaveOccurred(), "failed to fetch VirtualMachine %q: %v", vmName, err)
					return vm.Status.Ready
				}).Should(BeTrue(), "VirtualMachine %q still does not have status ready", vmName)

				By("Checking if the VirtualMachineInstance specs match Template parameters")
				vmi, err := virtClient.VirtualMachineInstance(tests.NamespaceTestDefault).Get(vmName, &metav1.GetOptions{})
				ExpectWithOffset(1, err).ToNot(HaveOccurred(), "failed to fetch VirtualMachine %q: %v", vmName, err)
				vmiCPUCores := vmi.Spec.Domain.CPU.Cores
				templateParamCPUCores, err := strconv.ParseUint(templateParams["CPU_CORES"], 10, 32)
				ExpectWithOffset(1, err).ToNot(HaveOccurred(), "cannot parse CPU_CORES parameter: value %q: %v", templateParams["CPU_CORES"], err)
				ExpectWithOffset(1, vmiCPUCores).To(Equal(uint32(templateParamCPUCores)), "VirtualMachineInstance CPU cores (%d) does not match CPU_CORES parameter value: %s", vmiCPUCores, templateParams["CPU_CORES"])
				vmiMemory := vmi.Spec.Domain.Resources.Requests["memory"]
				templateParamMemory, err := resource.ParseQuantity(templateParams["MEMORY"])
				ExpectWithOffset(1, err).ToNot(HaveOccurred(), "cannot parse MEMORY parameter: value %q: %v", templateParams["MEMORY"], err)
				ExpectWithOffset(1, vmiMemory).To(Equal(templateParamMemory), "VirtualMachineInstance memory (%s) does not match MEMORY parameter value: %s", vmiMemory.String(), templateParams["MEMORY"])
			}
		}

		AssertTemplateTestSuccess := func() {
			It("[test_id:3292]should succeed to create VirtualMachine via oc command", AssertVMCreationSuccess())
			It("[test_id:3293]should fail to delete VirtualMachine via oc command", AssertVMDeletionFailure())

			When("the VirtualMachine was created", func() {
				BeforeEach(AssertVMCreationSuccess())
				It("[test_id:3294]should succeed to start the VirtualMachine via oc command", AssertVMStartSuccess("oc"))
				It("[test_id:3295]should succeed to delete VirtualMachine via oc command", AssertVMDeletionSuccess())
				It("[test_id:3308]should fail to create the same VirtualMachine via oc command", AssertVMCreationFailure())
			})
		}

		BeforeEach(AssertTestSetupSuccess())

		AfterEach(AssertTestCleanupSuccess())

		FContext("with Fedora Template", func() {
			BeforeEach(AssertTemplateSetupSuccess(vmsgen.GetTemplateFedoraWithContainerDisk(tests.ContainerDiskFor(tests.ContainerDiskFedora)), nil))

			AssertTemplateTestSuccess()
		})

		Context("[rfe_id:273][crit:medium][vendor:cnv-qe@redhat.com][level:component]with RHEL Template", func() {
			BeforeEach(func() {
				tests.SkipIfNoRhelImage(virtClient)
				AssertTemplateSetupSuccess(vmsgen.GetTestTemplateRHEL7(), nil)()
			})

			AssertTemplateTestSuccess()
		})
	})
})
<commit_msg>Removed test focus<commit_after>/*
 * This file is part of the KubeVirt project
 *
 * 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.
 *
 * Copyright 2018 Red Hat, Inc.
 *
 */

package tests_test

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/api/resource"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/rand"

	"kubevirt.io/client-go/kubecli"
	"kubevirt.io/kubevirt/tests"
	vmsgen "kubevirt.io/kubevirt/tools/vms-generator/utils"
)

const (
	defaultNamePrefix = "testvm-"
	defaultCPUCores   = "2"
	defaultMemory     = "2Gi"
)

var _ = Describe("Templates", func() {
	tests.FlagParse()

	virtClient, err := kubecli.GetKubevirtClient()
	tests.PanicOnError(err)

	var (
		templateParams map[string]string
		workDir        string
		templateFile   string
		vmName         string
	)

	BeforeEach(func() {
		tests.SkipIfNoCmd("oc")
		tests.BeforeTestCleanup()
		SetDefaultEventuallyTimeout(120 * time.Second)
		SetDefaultEventuallyPollingInterval(2 * time.Second)

		workDir, err = ioutil.TempDir("", tests.TempDirPrefix+"-")
		Expect(err).ToNot(HaveOccurred())
	})

	AfterEach(func() {
		if workDir != "" {
			err := os.RemoveAll(workDir)
			Expect(err).ToNot(HaveOccurred())
			workDir = ""
		}
	})

	Describe("Creating VM from Template", func() {

		AssertTestSetupSuccess := func() func() {
			return func() {
				templateParams = map[string]string{
					"NAME":      defaultNamePrefix + rand.String(12),
					"CPU_CORES": defaultCPUCores,
					"MEMORY":    defaultMemory,
				}
				templateFile = ""
				ExpectWithOffset(1, templateParams).To(HaveKeyWithValue("NAME", Not(BeEmpty())), "invalid NAME parameter: VirtualMachine name cannot be empty string")
				ExpectWithOffset(1, templateParams).To(HaveKeyWithValue("CPU_CORES", MatchRegexp(`^[0-9]+$`)), "invalid CPU_CORES parameter: %q is not unsigned integer", templateParams["CPU_CORES"])
				ExpectWithOffset(1, templateParams).To(HaveKeyWithValue("MEMORY", MatchRegexp(`^([+-]?[0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$`)), "invalid MEMORY parameter: %q is not valid quantity", templateParams["MEMORY"])
				vmName = templateParams["NAME"]
				vm, err := virtClient.VirtualMachine(tests.NamespaceTestDefault).Get(vmName, &metav1.GetOptions{})
				ExpectWithOffset(1, errors.IsNotFound(err) || vm.ObjectMeta.DeletionTimestamp != nil).To(BeTrue(), "invalid NAME parameter: VirtualMachine %q already exists", vmName)
			}
		}

		AssertTemplateSetupSuccess := func(template *vmsgen.Template, params map[string]string) func() {
			return func() {
				ExpectWithOffset(1, template).NotTo(BeNil(), "template object was not provided")
				By("Creating the Template JSON file")
				var err error
				templateFile, err = tests.GenerateTemplateJson(template, workDir)
				ExpectWithOffset(1, err).ToNot(HaveOccurred(), "failed to write template JSON file: %v", err)
				ExpectWithOffset(1, templateFile).To(BeAnExistingFile(), "template JSON file %q was not created", templateFile)

				if params != nil {
					By("Validating template parameters")
					for param, value := range params {
						switch param {
						case "NAME":
							ExpectWithOffset(1, value).NotTo(BeEmpty(), "invalid NAME parameter: VirtualMachine name cannot be empty string")
							vmName = value
							vm, err := virtClient.VirtualMachine(tests.NamespaceTestDefault).Get(vmName, &metav1.GetOptions{})
							ExpectWithOffset(1, errors.IsNotFound(err) || vm.ObjectMeta.DeletionTimestamp != nil).To(BeTrue(), "invalid NAME parameter: VirtualMachine %q already exists", vmName)
						case "CPU_CORES":
							ExpectWithOffset(1, templateParams).To(HaveKeyWithValue("CPU_CORES", MatchRegexp(`^[0-9]+$`)), "invalid CPU_CORES parameter: %q is not unsigned integer", templateParams["CPU_CORES"])
						case "MEMORY":
							ExpectWithOffset(1, templateParams).To(HaveKeyWithValue("MEMORY", MatchRegexp(`^([+-]?[0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$`)), "invalid MEMORY parameter: %q is not valid quantity", templateParams["MEMORY"])
						}
						templateParams[param] = value
					}
				}
			}
		}

		AssertTestCleanupSuccess := func() func() {
			return func() {
				if vm, err := virtClient.VirtualMachine(tests.NamespaceTestDefault).Get(vmName, &metav1.GetOptions{}); err == nil && vm.ObjectMeta.DeletionTimestamp == nil {
					By("Deleting the VirtualMachine")
					ExpectWithOffset(1, virtClient.VirtualMachine(tests.NamespaceTestDefault).Delete(vmName, &metav1.DeleteOptions{})).To(Succeed(), "failed to delete VirtualMachine %q: %v", vmName, err)
					EventuallyWithOffset(1, func() bool {
						obj, err := virtClient.VirtualMachine(tests.NamespaceTestDefault).Get(vmName, &metav1.GetOptions{})
						return errors.IsNotFound(err) || obj.ObjectMeta.DeletionTimestamp != nil
					}).Should(BeTrue(), "VirtualMachine %q still exists and the deletion timestamp was not set", vmName)
				}
				if templateFile != "" {
					if _, err := os.Stat(templateFile); !os.IsNotExist(err) {
						By("Deleting template JSON file")
						ExpectWithOffset(1, os.RemoveAll(filepath.Dir(templateFile))).To(Succeed(), "failed to remove template JSON file %q: %v", templateFile, err)
						ExpectWithOffset(1, templateFile).NotTo(BeAnExistingFile(), "template JSON file %q was not removed", templateFile)
					}
				}
			}
		}

		AssertVMCreationSuccess := func() func() {
			return func() {
				By("Creating VirtualMachine from Template via oc command")
				ocProcessCommand := []string{"oc", "process", "-f", templateFile}
				for param, value := range templateParams {
					ocProcessCommand = append(ocProcessCommand, "-p", fmt.Sprintf("%s=%s", param, value))
				}
				out, stderr, err := tests.RunCommandPipe(ocProcessCommand, []string{"oc", "create", "-f", "-"})
				ExpectWithOffset(1, err).ToNot(HaveOccurred(), "failed to create VirtualMachine %q via command \"%s | oc create -f -\": %s: %v", vmName, strings.Join(ocProcessCommand, " "), out+stderr, err)
				ExpectWithOffset(1, out).To(MatchRegexp(`"?%s"? created\n`, vmName), "command \"%s | oc create -f -\" did not print expected message: %s", strings.Join(ocProcessCommand, " "), out+stderr)
				By("Checking if the VirtualMachine exists")
				EventuallyWithOffset(1, func() error {
					_, err := virtClient.VirtualMachine(tests.NamespaceTestDefault).Get(vmName, &metav1.GetOptions{})
					return err
				}).Should(Succeed(), "VirtualMachine %q still does not exist", vmName)
			}
		}

		AssertVMCreationFailure := func() func() {
			return func() {
				By("Creating VirtualMachine from Template via oc command")
				ocProcessCommand := []string{"oc", "process", "-f", templateFile}
				for param, value := range templateParams {
					ocProcessCommand = append(ocProcessCommand, "-p", fmt.Sprintf("%s=%s", param, value))
				}
				out, stderr, err := tests.RunCommandPipe(ocProcessCommand, []string{"oc", "create", "-f", "-"})
				ExpectWithOffset(1, err).To(HaveOccurred(), "creation of VirtualMachine %q via command \"%s | oc create -f -\" succeeded: %s: %v", vmName, strings.Join(ocProcessCommand, " "), out+stderr, err)
			}
		}

		AssertVMDeletionSuccess := func() func() {
			return func() {
				By("Deleting the VirtualMachine via oc command")
				out, stderr, err := tests.RunCommand("oc", "delete", "vm", vmName)
				ExpectWithOffset(1, err).ToNot(HaveOccurred(), "failed to delete VirtualMachine via command \"oc delete vm %s\": %s: %v", vmName, out+stderr, err)
				ExpectWithOffset(1, out).To(MatchRegexp(`"?%s"? deleted\n`, vmName), "command \"oc delete vm %s\" did not print expected message: %s", vmName, out)

				By("Checking if the VM does not exist anymore")
				EventuallyWithOffset(1, func() bool {
					vm, err := virtClient.VirtualMachine(tests.NamespaceTestDefault).Get(vmName, &metav1.GetOptions{})
					return errors.IsNotFound(err) || vm.ObjectMeta.DeletionTimestamp != nil
				}).Should(BeTrue(), "the VirtualMachine %q still exists and deletion timestamp was not set", vmName)
			}
		}

		AssertVMDeletionFailure := func() func() {
			return func() {
				By("Deleting the VirtualMachine via oc command")
				out, stderr, err := tests.RunCommand("oc", "delete", "vm", vmName)
				ExpectWithOffset(1, err).To(HaveOccurred(), "failed to delete VirtualMachine via command \"oc delete vm %s\": %s: %v", vmName, out+stderr, err)
			}
		}

		AssertVMStartSuccess := func(command string) func() {
			return func() {
				switch command {
				case "oc":
					By("Starting VirtualMachine via oc command")
					patch := `{"spec":{"running":true}}`
					out, stderr, err := tests.RunCommand("oc", "patch", "vm", vmName, "--type=merge", "-p", patch)
					ExpectWithOffset(1, err).ToNot(HaveOccurred(), "failed schedule VirtualMachine %q start via command \"oc patch vm %s --type=merge -p '%s'\": %s: %v", vmName, vmName, patch, out+stderr, err)
					ExpectWithOffset(1, out).To(MatchRegexp(`"?%s"? patched\n`, vmName), "command \"oc patch vm %s --type=merge -p '%s'\" did not print expected message: %s", vmName, patch, out+stderr)

				case "virtctl":
					By("Starting VirtualMachine via virtctl command")
					out, stderr, err := tests.RunCommand("virtctl", "start", vmName)
					ExpectWithOffset(1, err).ToNot(HaveOccurred(), "failed to schedule VirtualMachine %q start via command \"virtctl start %s\": %s: %v", vmName, vmName, out+stderr, err)
					ExpectWithOffset(1, out).To(ContainSubstring("%s was scheduled to start\n", vmName), "command \"virtctl start %s\" did not print expected message: %s", vmName, out+stderr)
				}

				By("Checking if the VirtualMachineInstance was created")
				EventuallyWithOffset(1, func() error {
					_, err := virtClient.VirtualMachineInstance(tests.NamespaceTestDefault).Get(vmName, &metav1.GetOptions{})
					return err
				}).Should(Succeed(), "the VirtualMachineInstance %q still does not exist", vmName)

				By("Checking if the VirtualMachine has status ready")
				EventuallyWithOffset(1, func() bool {
					vm, err := virtClient.VirtualMachine(tests.NamespaceTestDefault).Get(vmName, &metav1.GetOptions{})
					ExpectWithOffset(1, err).ToNot(HaveOccurred(), "failed to fetch VirtualMachine %q: %v", vmName, err)
					return vm.Status.Ready
				}).Should(BeTrue(), "VirtualMachine %q still does not have status ready", vmName)

				By("Checking if the VirtualMachineInstance specs match Template parameters")
				vmi, err := virtClient.VirtualMachineInstance(tests.NamespaceTestDefault).Get(vmName, &metav1.GetOptions{})
				ExpectWithOffset(1, err).ToNot(HaveOccurred(), "failed to fetch VirtualMachine %q: %v", vmName, err)
				vmiCPUCores := vmi.Spec.Domain.CPU.Cores
				templateParamCPUCores, err := strconv.ParseUint(templateParams["CPU_CORES"], 10, 32)
				ExpectWithOffset(1, err).ToNot(HaveOccurred(), "cannot parse CPU_CORES parameter: value %q: %v", templateParams["CPU_CORES"], err)
				ExpectWithOffset(1, vmiCPUCores).To(Equal(uint32(templateParamCPUCores)), "VirtualMachineInstance CPU cores (%d) does not match CPU_CORES parameter value: %s", vmiCPUCores, templateParams["CPU_CORES"])
				vmiMemory := vmi.Spec.Domain.Resources.Requests["memory"]
				templateParamMemory, err := resource.ParseQuantity(templateParams["MEMORY"])
				ExpectWithOffset(1, err).ToNot(HaveOccurred(), "cannot parse MEMORY parameter: value %q: %v", templateParams["MEMORY"], err)
				ExpectWithOffset(1, vmiMemory).To(Equal(templateParamMemory), "VirtualMachineInstance memory (%s) does not match MEMORY parameter value: %s", vmiMemory.String(), templateParams["MEMORY"])
			}
		}

		AssertTemplateTestSuccess := func() {
			It("[test_id:3292]should succeed to create VirtualMachine via oc command", AssertVMCreationSuccess())
			It("[test_id:3293]should fail to delete VirtualMachine via oc command", AssertVMDeletionFailure())

			When("the VirtualMachine was created", func() {
				BeforeEach(AssertVMCreationSuccess())
				It("[test_id:3294]should succeed to start the VirtualMachine via oc command", AssertVMStartSuccess("oc"))
				It("[test_id:3295]should succeed to delete VirtualMachine via oc command", AssertVMDeletionSuccess())
				It("[test_id:3308]should fail to create the same VirtualMachine via oc command", AssertVMCreationFailure())
			})
		}

		BeforeEach(AssertTestSetupSuccess())

		AfterEach(AssertTestCleanupSuccess())

		Context("with Fedora Template", func() {
			BeforeEach(AssertTemplateSetupSuccess(vmsgen.GetTemplateFedoraWithContainerDisk(tests.ContainerDiskFor(tests.ContainerDiskFedora)), nil))

			AssertTemplateTestSuccess()
		})

		Context("[rfe_id:273][crit:medium][vendor:cnv-qe@redhat.com][level:component]with RHEL Template", func() {
			BeforeEach(func() {
				tests.SkipIfNoRhelImage(virtClient)
				AssertTemplateSetupSuccess(vmsgen.GetTestTemplateRHEL7(), nil)()
			})

			AssertTemplateTestSuccess()
		})
	})
})
<|endoftext|>