<commit_before>package util

import (
	"context"
	"fmt"
	"strconv"
	"strings"
	"sync"
	"time"

	"google.golang.org/grpc"
	"google.golang.org/grpc/keepalive"
)

var (
	// cache grpc connections
	grpcClients     = make(map[string]*grpc.ClientConn)
	grpcClientsLock sync.Mutex
)

func NewGrpcServer(opts ...grpc.ServerOption) *grpc.Server {
	var options []grpc.ServerOption
	options = append(options, grpc.KeepaliveParams(keepalive.ServerParameters{
		Time:    10 * time.Second, // wait time before ping if no activity
		Timeout: 20 * time.Second, // ping timeout
	}), grpc.KeepaliveEnforcementPolicy(keepalive.EnforcementPolicy{
		MinTime: 60 * time.Second, // min time a client should wait before sending a ping
	}))
	for _, opt := range opts {
		if opt != nil {
			options = append(options, opt)
		}
	}
	return grpc.NewServer(options...)
}

func GrpcDial(ctx context.Context, address string, opts ...grpc.DialOption) (*grpc.ClientConn, error) {
	// opts = append(opts, grpc.WithBlock())
	// opts = append(opts, grpc.WithTimeout(time.Duration(5*time.Second)))
	var options []grpc.DialOption
	options = append(options,
		// grpc.WithInsecure(),
		grpc.WithKeepaliveParams(keepalive.ClientParameters{
			Time:    30 * time.Second, // client ping server if no activity for this long
			Timeout: 20 * time.Second,
		}))
	for _, opt := range opts {
		if opt != nil {
			options = append(options, opt)
		}
	}
	return grpc.DialContext(ctx, address, options...)
}

func WithCachedGrpcClient(ctx context.Context, fn func(*grpc.ClientConn) error, address string, opts ...grpc.DialOption) error {

	grpcClientsLock.Lock()

	existingConnection, found := grpcClients[address]
	if found {
		grpcClientsLock.Unlock()
		return fn(existingConnection)
	}

	grpcConnection, err := GrpcDial(ctx, address, opts...)
	if err != nil {
		grpcClientsLock.Unlock()
		return fmt.Errorf("fail to dial %s: %v", address, err)
	}

	grpcClients[address] = grpcConnection
	grpcClientsLock.Unlock()

	err = fn(grpcConnection)
	if err != nil {
		grpcClientsLock.Lock()
		delete(grpcClients, address)
		grpcClientsLock.Unlock()
	}

	return err
}

func ParseServerToGrpcAddress(server string) (serverGrpcAddress string, err error) {
	hostnameAndPort := strings.Split(server, ":")
	if len(hostnameAndPort) != 2 {
		return "", fmt.Errorf("server should have hostname:port format: %v", hostnameAndPort)
	}

	port, parseErr := strconv.ParseUint(hostnameAndPort[1], 10, 64)
	if parseErr != nil {
		return "", fmt.Errorf("server port parse error: %v", parseErr)
	}

	grpcPort := int(port) + 10000

	return fmt.Sprintf("%s:%d", hostnameAndPort[0], grpcPort), nil
}

func ServerToGrpcAddress(server string) (serverGrpcAddress string) {
	hostnameAndPort := strings.Split(server, ":")
	if len(hostnameAndPort) != 2 {
		return fmt.Sprintf("unexpected server address: %s", server)
	}

	port, parseErr := strconv.ParseUint(hostnameAndPort[1], 10, 64)
	if parseErr != nil {
		return fmt.Sprintf("failed to parse port for %s:%s", hostnameAndPort[0], hostnameAndPort[1])
	}

	grpcPort := int(port) + 10000

	return fmt.Sprintf("%s:%d", hostnameAndPort[0], grpcPort)
}
<commit_msg>set default http idle connection per host<commit_after>package util

import (
	"context"
	"fmt"
	"net/http"
	"strconv"
	"strings"
	"sync"
	"time"

	"google.golang.org/grpc"
	"google.golang.org/grpc/keepalive"
)

var (
	// cache grpc connections
	grpcClients     = make(map[string]*grpc.ClientConn)
	grpcClientsLock sync.Mutex
)

func init(){
	http.DefaultTransport.(*http.Transport).MaxIdleConnsPerHost = 100
}

func NewGrpcServer(opts ...grpc.ServerOption) *grpc.Server {
	var options []grpc.ServerOption
	options = append(options, grpc.KeepaliveParams(keepalive.ServerParameters{
		Time:    10 * time.Second, // wait time before ping if no activity
		Timeout: 20 * time.Second, // ping timeout
	}), grpc.KeepaliveEnforcementPolicy(keepalive.EnforcementPolicy{
		MinTime: 60 * time.Second, // min time a client should wait before sending a ping
	}))
	for _, opt := range opts {
		if opt != nil {
			options = append(options, opt)
		}
	}
	return grpc.NewServer(options...)
}

func GrpcDial(ctx context.Context, address string, opts ...grpc.DialOption) (*grpc.ClientConn, error) {
	// opts = append(opts, grpc.WithBlock())
	// opts = append(opts, grpc.WithTimeout(time.Duration(5*time.Second)))
	var options []grpc.DialOption
	options = append(options,
		// grpc.WithInsecure(),
		grpc.WithKeepaliveParams(keepalive.ClientParameters{
			Time:    30 * time.Second, // client ping server if no activity for this long
			Timeout: 20 * time.Second,
		}))
	for _, opt := range opts {
		if opt != nil {
			options = append(options, opt)
		}
	}
	return grpc.DialContext(ctx, address, options...)
}

func WithCachedGrpcClient(ctx context.Context, fn func(*grpc.ClientConn) error, address string, opts ...grpc.DialOption) error {

	grpcClientsLock.Lock()

	existingConnection, found := grpcClients[address]
	if found {
		grpcClientsLock.Unlock()
		return fn(existingConnection)
	}

	grpcConnection, err := GrpcDial(ctx, address, opts...)
	if err != nil {
		grpcClientsLock.Unlock()
		return fmt.Errorf("fail to dial %s: %v", address, err)
	}

	grpcClients[address] = grpcConnection
	grpcClientsLock.Unlock()

	err = fn(grpcConnection)
	if err != nil {
		grpcClientsLock.Lock()
		delete(grpcClients, address)
		grpcClientsLock.Unlock()
	}

	return err
}

func ParseServerToGrpcAddress(server string) (serverGrpcAddress string, err error) {
	hostnameAndPort := strings.Split(server, ":")
	if len(hostnameAndPort) != 2 {
		return "", fmt.Errorf("server should have hostname:port format: %v", hostnameAndPort)
	}

	port, parseErr := strconv.ParseUint(hostnameAndPort[1], 10, 64)
	if parseErr != nil {
		return "", fmt.Errorf("server port parse error: %v", parseErr)
	}

	grpcPort := int(port) + 10000

	return fmt.Sprintf("%s:%d", hostnameAndPort[0], grpcPort), nil
}

func ServerToGrpcAddress(server string) (serverGrpcAddress string) {
	hostnameAndPort := strings.Split(server, ":")
	if len(hostnameAndPort) != 2 {
		return fmt.Sprintf("unexpected server address: %s", server)
	}

	port, parseErr := strconv.ParseUint(hostnameAndPort[1], 10, 64)
	if parseErr != nil {
		return fmt.Sprintf("failed to parse port for %s:%s", hostnameAndPort[0], hostnameAndPort[1])
	}

	grpcPort := int(port) + 10000

	return fmt.Sprintf("%s:%d", hostnameAndPort[0], grpcPort)
}
<|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 device_manager

import (
	"math"
	"os"
	"time"

	"kubevirt.io/client-go/log"
)

const (
	KVMPath      = "/dev/kvm"
	KVMName      = "kvm"
	TunPath      = "/dev/net/tun"
	TunName      = "tun"
	VhostNetPath = "/dev/vhost-net"
	VhostNetName = "vhost-net"
)

type DeviceController struct {
	devicePlugins []GenericDevice
	host          string
	maxDevices    int
	backoff       []time.Duration
}

func NewDeviceController(host string, maxDevices int) *DeviceController {
	return &DeviceController{
		devicePlugins: []GenericDevice{
			NewGenericDevicePlugin(KVMName, KVMPath, maxDevices, false),
			NewGenericDevicePlugin(TunName, TunPath, maxDevices, true),
			NewGenericDevicePlugin(VhostNetName, VhostNetPath, maxDevices, true),
		},
		host:       host,
		maxDevices: maxDevices,
		backoff:    []time.Duration{1 * time.Second, 2 * time.Second, 5 * time.Second, 10 * time.Second},
	}
}

func (c *DeviceController) nodeHasDevice(devicePath string) bool {
	_, err := os.Stat(devicePath)
	// Since this is a boolean question, any error means "no"
	return (err == nil)
}

func (c *DeviceController) startDevicePlugin(dev GenericDevice, stop chan struct{}) {
	logger := log.DefaultLogger()
	deviceName := dev.GetDeviceName()
	retries := 0

	for {
		err := dev.Start(stop)
		if err != nil {
			logger.Reason(err).Errorf("Error starting %s device plugin", deviceName)
			retries = int(math.Min(float64(retries+1), float64(len(c.backoff)-1)))
		} else {
			retries = 0
		}

		select {
		case <-stop:
			// Ok we don't want to re-register
			return
		default:
			// Wait a little bit and re-register
			time.Sleep(c.backoff[retries])
		}
	}
}

func (c *DeviceController) Run(stop chan struct{}) error {
	logger := log.DefaultLogger()
	logger.Info("Starting device plugin controller")

	for _, dev := range c.devicePlugins {
		go c.startDevicePlugin(dev, stop)
	}

	<-stop

	logger.Info("Shutting down device plugin controller")
	return nil
}

func (c *DeviceController) Initialized() bool {
	for _, dev := range c.devicePlugins {
		if !dev.GetInitialized() {
			return false
		}
	}

	return true
}
<commit_msg>add virt-config to device controller<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 device_manager

import (
	"math"
	"os"
	"time"
	"strings"

	"kubevirt.io/client-go/log"
	virtconfig "kubevirt.io/kubevirt/pkg/virt-config"
)

const (
	KVMPath      = "/dev/kvm"
	KVMName      = "kvm"
	TunPath      = "/dev/net/tun"
	TunName      = "tun"
	VhostNetPath = "/dev/vhost-net"
	VhostNetName = "vhost-net"
)

type DeviceController struct {
	devicePlugins []GenericDevice
	host          string
	maxDevices    int
	backoff       []time.Duration
	virtConfig    *virtconfig.ClusterConfig
}

func NewDeviceController(host string, maxDevices int, clusterConfig *virtconfig.ClusterConfig) *DeviceController {
	controller := &DeviceController{
		devicePlugins: []GenericDevice{
			NewGenericDevicePlugin(KVMName, KVMPath, maxDevices, false),
			NewGenericDevicePlugin(TunName, TunPath, maxDevices, true),
			NewGenericDevicePlugin(VhostNetName, VhostNetPath, maxDevices, true),
		},
		host:       host,
		maxDevices: maxDevices,
		backoff:    []time.Duration{1 * time.Second, 2 * time.Second, 5 * time.Second, 10 * time.Second},
	}
	controller.virtConfig = clusterConfig

	return controller
}

func (c *DeviceController) nodeHasDevice(devicePath string) bool {
	_, err := os.Stat(devicePath)
	// Since this is a boolean question, any error means "no"
	return (err == nil)
}

func (c *DeviceController) startDevicePlugin(dev GenericDevice, stop chan struct{}) {
	logger := log.DefaultLogger()
	deviceName := dev.GetDeviceName()
	retries := 0

	for {
		err := dev.Start(stop)
		if err != nil {
			logger.Reason(err).Errorf("Error starting %s device plugin", deviceName)
			retries = int(math.Min(float64(retries+1), float64(len(c.backoff)-1)))
		} else {
			retries = 0
		}

		select {
		case <-stop:
			// Ok we don't want to re-register
			return
		default:
			// Wait a little bit and re-register
			time.Sleep(c.backoff[retries])
		}
	}
}

func (c *DeviceController) Run(stop chan struct{}) error {
	logger := log.DefaultLogger()
	logger.Info("Starting device plugin controller")

	for _, dev := range c.devicePlugins {
		go c.startDevicePlugin(dev, stop)
	}

	<-stop

	logger.Info("Shutting down device plugin controller")
	return nil
}

func (c *DeviceController) Initialized() bool {
	for _, dev := range c.devicePlugins {
		if !dev.GetInitialized() {
			return false
		}
	}

	return true
}
<|endoftext|>


<commit_before>/* Copyright 2018 Google Inc.

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

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

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

// The test_kit program is a tool that tests gNMI functionalities of an AP device.
package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"time"

	log "github.com/golang/glog"
	"google.golang.org/grpc"

	"github.com/google/gnxi/utils/credentials"

	"github.com/google/link022/testkit/common"
	"github.com/google/link022/testkit/gnmitest"

	pb "github.com/openconfig/gnmi/proto/gnmi"
)

type arrayFlags []string

func (i *arrayFlags) String() string {
	return "my string representation"
}

func (i *arrayFlags) Set(value string) error {
	*i = append(*i, value)
	return nil
}

var (
	gnmiTests  arrayFlags
	targetAddr = flag.String("target_addr", "localhost:10161", "The target address in the format of host:port")
	targetName = flag.String("target_name", "hostname.com", "The target name used to verify the hostname returned by TLS handshake")
	timeout    = flag.Duration("time_out", 30*time.Second, "Timeout for each request, 30 seconds by default")
)

func loadTests(testFiles []string) ([]*common.GNMITest, error) {
	var tests []*common.GNMITest
	for _, testFile := range testFiles {
		testContent, err := ioutil.ReadFile(testFile)
		if err != nil {
			return nil, err
		}
		test := &common.GNMITest{}
		if err := json.Unmarshal(testContent, test); err != nil {
			return nil, err
		}
		tests = append(tests, test)
		log.Infof("Loaded [%s].", test.Name)
	}
	return tests, nil
}

func runTest(client pb.GNMIClient, gNMITest *common.GNMITest, timeout time.Duration) *common.TestResult {
	var testCaseResults []*common.TestCaseResult

	// Run gNMI config tests.
	log.Infof("Running [%s].", gNMITest.Name)
	var passedNum, failedNum int
	for _, testcase := range gNMITest.GNMITestCase {
		err := gnmitest.RunTest(client, testcase, timeout)
		if err != nil {
			failedNum += 1
			log.Errorf("[%s] failed: %v.", testcase.Name, err)
		} else {
			passedNum += 1
			log.Infof("[%s] succeeded.", testcase.Name)
		}

		result := &common.TestCaseResult{
			Name: testcase.Name,
			Err:  err,
		}
		testCaseResults = append(testCaseResults, result)
	}

	// TODO: Run gNMI state-related tests.

	if failedNum > 0 {
		log.Errorf("[%s] failed.", gNMITest.Name)
	} else {
		log.Infof("[%s] succeeded.", gNMITest.Name)
	}

	return &common.TestResult{
		Name:      gNMITest.Name,
		PassedNum: passedNum,
		FailedNum: failedNum,
		Details:   testCaseResults,
	}
}

func resultString(passed bool) string {
	if passed {
		return "PASS"
	}
	return "FAIL"
}

func printResult(results []*common.TestResult) {
	fmt.Println("=Test results=")
	// Print details of each test.
	for _, test := range results {
		fmt.Println("--------------------")
		fmt.Printf("[%s] %s\n", resultString(test.FailedNum == 0), test.Name)
		for _, testCase := range test.Details {
			passed := testCase.Err == nil
			fmt.Printf("|-[%s] %s\n", resultString(passed), testCase.Name)
			if !passed {
				fmt.Printf(" \\- %v\n", testCase.Err)
			}
		}
	}
	// Print test result summay.
	fmt.Println("--------------------")
	for _, test := range results {
		fmt.Printf("[%s] [%s] Passed - %d, Failed - %d\n", resultString(test.FailedNum == 0), test.Name, test.PassedNum, test.FailedNum)
	}
}

func main() {
	flag.Var(&gnmiTests, "test_file", "The file containing gNMI test.")
	flag.Parse()

	log.Info("Test kit started.")

	// Load test cases.
	tests, err := loadTests(gnmiTests)
	if err != nil {
		log.Fatalf("Failed to load tests. Error: %v.", err)
	}
	log.Infof("Loaded %d test files..", len(tests))

	// Create gNMI client.
	opts := credentials.ClientCredentials(*targetName)
	conn, err := grpc.Dial(*targetAddr, opts...)
	if err != nil {
		log.Fatalf("Dialing to %q failed: %v", *targetAddr, err)
	}
	defer conn.Close()
	client := pb.NewGNMIClient(conn)

	// Run all tests.
	var results []*common.TestResult
	for _, test := range tests {
		results = append(results, runTest(client, test, *timeout))
	}

	// Print out the result.
	printResult(results)
}
<commit_msg>Added the pause_mode in test kit.<commit_after>/* Copyright 2018 Google Inc.

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

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

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

// The test_kit program is a tool that tests gNMI functionalities of an AP device.
package main

import (
	"bufio"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"time"

	log "github.com/golang/glog"
	"google.golang.org/grpc"

	"github.com/google/gnxi/utils/credentials"

	"github.com/google/link022/testkit/common"
	"github.com/google/link022/testkit/gnmitest"

	pb "github.com/openconfig/gnmi/proto/gnmi"
)

type arrayFlags []string

func (i *arrayFlags) String() string {
	return "my string representation"
}

func (i *arrayFlags) Set(value string) error {
	*i = append(*i, value)
	return nil
}

var (
	gnmiTests  arrayFlags
	targetAddr = flag.String("target_addr", "localhost:10161", "The target address in the format of host:port")
	targetName = flag.String("target_name", "hostname.com", "The target name used to verify the hostname returned by TLS handshake")
	timeout    = flag.Duration("time_out", 30*time.Second, "Timeout for each request, 30 seconds by default")
	pauseMode  = flag.Bool("pause_mode", false, "Pause after each test case")
)

func loadTests(testFiles []string) ([]*common.GNMITest, error) {
	var tests []*common.GNMITest
	for _, testFile := range testFiles {
		testContent, err := ioutil.ReadFile(testFile)
		if err != nil {
			return nil, err
		}
		test := &common.GNMITest{}
		if err := json.Unmarshal(testContent, test); err != nil {
			return nil, err
		}
		tests = append(tests, test)
		log.Infof("Loaded [%s].", test.Name)
	}
	return tests, nil
}

func runTest(client pb.GNMIClient, gNMITest *common.GNMITest, timeout time.Duration) *common.TestResult {
	var testCaseResults []*common.TestCaseResult

	// Run gNMI config tests.
	log.Infof("Running [%s].", gNMITest.Name)
	var passedNum, failedNum int
	totalNum := len(gNMITest.GNMITestCase)
	for i, testcase := range gNMITest.GNMITestCase {
		log.Infof("Started [%s].", testcase.Name)
		err := gnmitest.RunTest(client, testcase, timeout)
		if err != nil {
			failedNum += 1
			log.Errorf("[%d/%d] [%s] failed: %v.", i+1, totalNum, testcase.Name, err)
		} else {
			passedNum += 1
			log.Infof("[%d/%d] [%s] succeeded.", i+1, totalNum, testcase.Name)
		}

		result := &common.TestCaseResult{
			Name: testcase.Name,
			Err:  err,
		}
		testCaseResults = append(testCaseResults, result)

		if *pauseMode && i < totalNum {
			reader := bufio.NewReader(os.Stdin)
			// Pause until user triggers next test case manually.
			fmt.Println("Press ENTER to start the next test case.")
			_, _ = reader.ReadString('\n')
		}
	}

	if failedNum > 0 {
		log.Errorf("[%s] failed.", gNMITest.Name)
	} else {
		log.Infof("[%s] succeeded.", gNMITest.Name)
	}

	return &common.TestResult{
		Name:      gNMITest.Name,
		PassedNum: passedNum,
		FailedNum: failedNum,
		Details:   testCaseResults,
	}
}

func resultString(passed bool) string {
	if passed {
		return "PASS"
	}
	return "FAIL"
}

func printResult(results []*common.TestResult) {
	fmt.Println("=Test results=")
	// Print details of each test.
	for _, test := range results {
		fmt.Println("--------------------")
		fmt.Printf("[%s] %s\n", resultString(test.FailedNum == 0), test.Name)
		for _, testCase := range test.Details {
			passed := testCase.Err == nil
			fmt.Printf("|-[%s] %s\n", resultString(passed), testCase.Name)
			if !passed {
				fmt.Printf(" \\- %v\n", testCase.Err)
			}
		}
	}
	// Print test result summay.
	fmt.Println("--------------------")
	for _, test := range results {
		fmt.Printf("[%s] [%s] Passed - %d, Failed - %d\n", resultString(test.FailedNum == 0), test.Name, test.PassedNum, test.FailedNum)
	}
}

func main() {
	flag.Var(&gnmiTests, "test_file", "The file containing gNMI test.")
	flag.Parse()

	log.Info("Test kit started.")

	// Load test cases.
	tests, err := loadTests(gnmiTests)
	if err != nil {
		log.Fatalf("Failed to load tests. Error: %v.", err)
	}
	log.Infof("Loaded %d test files..", len(tests))

	// Create gNMI client.
	opts := credentials.ClientCredentials(*targetName)
	conn, err := grpc.Dial(*targetAddr, opts...)
	if err != nil {
		log.Fatalf("Dialing to %q failed: %v", *targetAddr, err)
	}
	defer conn.Close()
	client := pb.NewGNMIClient(conn)

	// Run all tests.
	var results []*common.TestResult
	for _, test := range tests {
		results = append(results, runTest(client, test, *timeout))
	}

	// Print out the result.
	printResult(results)
}
<|endoftext|>


<commit_before>// Copyright 2015 Red Hat, Inc.
//
// 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 cephapi

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/skyrings/bigfin/backend"
	"github.com/skyrings/bigfin/backend/cephapi/handler"
	"github.com/skyrings/bigfin/backend/cephapi/models"
	"github.com/skyrings/skyring/conf"
	"github.com/skyrings/skyring/db"
	"github.com/skyrings/skyring/tools/uuid"
	"gopkg.in/mgo.v2/bson"
	"io"
	"io/ioutil"
	"net/http"
	"strings"
	"time"

	skyringmodels "github.com/skyrings/skyring/models"
)

type CephApi struct {
}

func (c CephApi) CreateCluster(clusterName string, fsid uuid.UUID, mons []backend.Mon) (bool, error) {
	return true, nil
}

func (c CephApi) AddMon(clusterName string, mons []backend.Mon) (bool, error) {
	return true, nil
}

func (c CephApi) StartMon(nodes []string) (bool, error) {
	return true, nil
}

func (c CephApi) AddOSD(clusterName string, osd backend.OSD) (bool, error) {
	return true, nil
}

func (c CephApi) CreatePool(name string, mon string, clusterName string, pgnum uint, replicas int, quotaMaxObjects int, quotaMaxBytes uint64) (bool, error) {
	// Get the cluster id
	cluster_id, err := cluster_id(clusterName)
	if err != nil {
		return false, errors.New(fmt.Sprintf("Could not get id for cluster: %v", err))
	}

	// Replace cluster id in route pattern
	createPoolRoute := CEPH_API_ROUTES["CreatePool"]
	createPoolRoute.Pattern = strings.Replace(createPoolRoute.Pattern, "{cluster-fsid}", cluster_id, 1)

	pool := models.CephPoolRequest{
		Name:                name,
		Size:                replicas,
		MinSize:             1,
		QuotaMaxObjects:     quotaMaxObjects,
		HashPsPool:          false,
		QuotaMaxBytes:       quotaMaxBytes,
		PgNum:               int(pgnum),
		PgpNum:              int(pgnum),
		CrashReplayInterval: 0,
	}
	buf, err := json.Marshal(pool)
	if err != nil {
		return false, errors.New(fmt.Sprintf("Error formaing request body: %v", err))
	}
	body := bytes.NewBuffer(buf)
	resp, err := route_request(createPoolRoute, mon, body)
	if err != nil || (resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusAccepted) {
		return false, errors.New(fmt.Sprintf("Failed to create pool: %v", err))
	} else {
		var asyncReq models.CephAsyncRequest
		respBodyStr, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return false, errors.New(fmt.Sprintf("Error parsing response data: %v", err))
		}
		if err := json.Unmarshal(respBodyStr, &asyncReq); err != nil {
			return false, errors.New(fmt.Sprintf("Error parsing response data: %v", err))
		}
		// Keep checking for the status of the request, and if completed return
		for {
			time.Sleep(2 * time.Second)
			route := CEPH_API_ROUTES["GetRequestStatus"]
			route.Pattern = strings.Replace(route.Pattern, "{request-fsid}", asyncReq.RequestId, 1)
			resp, err := route_request(route, mon, bytes.NewBuffer([]byte{}))
			if err != nil {
				return false, errors.New("Error syncing request status from cluster")
			}
			var reqStatus models.CephRequestStatus
			respBodyStr, err := ioutil.ReadAll(resp.Body)
			if err != nil {
				return false, errors.New(fmt.Sprintf("Error parsing response data: %v", err))
			}
			if err := json.Unmarshal(respBodyStr, &reqStatus); err != nil {
				return false, errors.New(fmt.Sprintf("Error parsing response data: %v", err))
			}
			if reqStatus.State == "complete" {
				break
			}
		}
	}
	return true, nil
}

func (c CephApi) ListPool(mon string, clusterName string) ([]string, error) {
	return []string{}, nil
}

func (c CephApi) ClusterUp(mon string, clusterName string) (status bool, err error) {
	return true, nil
}

func New() backend.Backend {
	api := new(CephApi)
	api.LoadRoutes()
	return api
}

func cluster_id(clusterName string) (string, error) {
	sessionCopy := db.GetDatastore().Copy()
	defer sessionCopy.Close()
	var cluster skyringmodels.Cluster
	coll := sessionCopy.DB(conf.SystemConfig.DBConfig.Database).C(skyringmodels.COLL_NAME_STORAGE_CLUSTERS)
	if err := coll.Find(bson.M{"name": clusterName}).One(&cluster); err != nil {
		return "", err
	}
	return cluster.ClusterId.String(), nil
}

func route_request(route CephApiRoute, mon string, body io.Reader) (*http.Response, error) {
	if route.Method == "POST" {
		return handler.HttpPost(
			mon,
			fmt.Sprintf("http://%s:%d/%s/v%d/%s", mon, models.CEPH_API_PORT, models.CEPH_API_DEFAULT_PREFIX, route.Version, route.Pattern),
			"application/json",
			body)
	}
	if route.Method == "GET" {
		return handler.HttpGet(fmt.Sprintf("http://%s:%d/%s/v%d/%s", mon, models.CEPH_API_PORT, models.CEPH_API_DEFAULT_PREFIX, route.Version, route.Pattern))
	}
	return nil, errors.New("Invalid method type")
}
<commit_msg>bigfin: Removed default settting of fields for pool<commit_after>// Copyright 2015 Red Hat, Inc.
//
// 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 cephapi

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/skyrings/bigfin/backend"
	"github.com/skyrings/bigfin/backend/cephapi/handler"
	"github.com/skyrings/bigfin/backend/cephapi/models"
	"github.com/skyrings/skyring/conf"
	"github.com/skyrings/skyring/db"
	"github.com/skyrings/skyring/tools/uuid"
	"gopkg.in/mgo.v2/bson"
	"io"
	"io/ioutil"
	"net/http"
	"strings"
	"time"

	skyringmodels "github.com/skyrings/skyring/models"
)

type CephApi struct {
}

func (c CephApi) CreateCluster(clusterName string, fsid uuid.UUID, mons []backend.Mon) (bool, error) {
	return true, nil
}

func (c CephApi) AddMon(clusterName string, mons []backend.Mon) (bool, error) {
	return true, nil
}

func (c CephApi) StartMon(nodes []string) (bool, error) {
	return true, nil
}

func (c CephApi) AddOSD(clusterName string, osd backend.OSD) (bool, error) {
	return true, nil
}

func (c CephApi) CreatePool(name string, mon string, clusterName string, pgnum uint, replicas int, quotaMaxObjects int, quotaMaxBytes uint64) (bool, error) {
	// Get the cluster id
	cluster_id, err := cluster_id(clusterName)
	if err != nil {
		return false, errors.New(fmt.Sprintf("Could not get id for cluster: %v", err))
	}

	// Replace cluster id in route pattern
	createPoolRoute := CEPH_API_ROUTES["CreatePool"]
	createPoolRoute.Pattern = strings.Replace(createPoolRoute.Pattern, "{cluster-fsid}", cluster_id, 1)

	pool := map[string]interface{}{
		"name":              name,
		"size":              replicas,
		"quota_max_objects": quotaMaxObjects,
		"quota_max_bytes":   quotaMaxBytes,
		"pg_num":            int(pgnum),
		"pgp_num":           int(pgnum),
	}

	buf, err := json.Marshal(pool)
	if err != nil {
		return false, errors.New(fmt.Sprintf("Error formaing request body: %v", err))
	}
	body := bytes.NewBuffer(buf)
	resp, err := route_request(createPoolRoute, mon, body)
	if err != nil || (resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusAccepted) {
		return false, errors.New(fmt.Sprintf("Failed to create pool: %v", err))
	} else {
		var asyncReq models.CephAsyncRequest
		respBodyStr, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return false, errors.New(fmt.Sprintf("Error parsing response data: %v", err))
		}
		if err := json.Unmarshal(respBodyStr, &asyncReq); err != nil {
			return false, errors.New(fmt.Sprintf("Error parsing response data: %v", err))
		}
		// Keep checking for the status of the request, and if completed return
		for {
			time.Sleep(2 * time.Second)
			route := CEPH_API_ROUTES["GetRequestStatus"]
			route.Pattern = strings.Replace(route.Pattern, "{request-fsid}", asyncReq.RequestId, 1)
			resp, err := route_request(route, mon, bytes.NewBuffer([]byte{}))
			if err != nil {
				return false, errors.New("Error syncing request status from cluster")
			}
			var reqStatus models.CephRequestStatus
			respBodyStr, err := ioutil.ReadAll(resp.Body)
			if err != nil {
				return false, errors.New(fmt.Sprintf("Error parsing response data: %v", err))
			}
			if err := json.Unmarshal(respBodyStr, &reqStatus); err != nil {
				return false, errors.New(fmt.Sprintf("Error parsing response data: %v", err))
			}
			if reqStatus.State == "complete" {
				break
			}
		}
	}
	return true, nil
}

func (c CephApi) ListPool(mon string, clusterName string) ([]string, error) {
	return []string{}, nil
}

func (c CephApi) ClusterUp(mon string, clusterName string) (status bool, err error) {
	return true, nil
}

func New() backend.Backend {
	api := new(CephApi)
	api.LoadRoutes()
	return api
}

func cluster_id(clusterName string) (string, error) {
	sessionCopy := db.GetDatastore().Copy()
	defer sessionCopy.Close()
	var cluster skyringmodels.Cluster
	coll := sessionCopy.DB(conf.SystemConfig.DBConfig.Database).C(skyringmodels.COLL_NAME_STORAGE_CLUSTERS)
	if err := coll.Find(bson.M{"name": clusterName}).One(&cluster); err != nil {
		return "", err
	}
	return cluster.ClusterId.String(), nil
}

func route_request(route CephApiRoute, mon string, body io.Reader) (*http.Response, error) {
	if route.Method == "POST" {
		return handler.HttpPost(
			mon,
			fmt.Sprintf("http://%s:%d/%s/v%d/%s", mon, models.CEPH_API_PORT, models.CEPH_API_DEFAULT_PREFIX, route.Version, route.Pattern),
			"application/json",
			body)
	}
	if route.Method == "GET" {
		return handler.HttpGet(fmt.Sprintf("http://%s:%d/%s/v%d/%s", mon, models.CEPH_API_PORT, models.CEPH_API_DEFAULT_PREFIX, route.Version, route.Pattern))
	}
	return nil, errors.New("Invalid method type")
}
<|endoftext|>


<commit_before>// Copyright 2016 Red Hat, Inc. and/or its affiliates
// and other contributors.
//
// 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 backend
package mongo

import (
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	"log"
	"net/url"
	"time"

	"github.com/yaacov/mohawk/backend"
)

type Backend struct {
	dbURL        string
	mongoSession *mgo.Session
}

// Backend functions
// Required by backend interface

func (r Backend) Name() string {
	return "Backend-Mongo"
}

func (r *Backend) Open(options url.Values) {
	var err error

	// get backend options
	r.dbURL = options.Get("db-url")
	if r.dbURL == "" {
		r.dbURL = "127.0.0.1"
	}

	// We need this object to establish a session to our MongoDB.
	mongoDBDialInfo := &mgo.DialInfo{
		Addrs:    []string{r.dbURL},
		Timeout:  10 * time.Second,
		Username: "",
		Password: "",
	}

	// Create a session which maintains a pool of socket connections
	// to our MongoDB.
	r.mongoSession, err = mgo.DialWithInfo(mongoDBDialInfo)
	if err != nil {
		panic(err)
	}

	r.mongoSession.SetMode(mgo.Monotonic, true)
}

func (r Backend) GetTenants() []backend.Tenant {
	res := make([]backend.Tenant, 0)

	// copy backend session
	sessionCopy := r.mongoSession.Copy()
	defer sessionCopy.Close()

	// return a list of tenants
	names, err := sessionCopy.DatabaseNames()
	if err != nil {
		log.Printf("%q\n", err)
		return res
	}
	for _, t := range names {
		if t != "admin" && t != "local" {
			res = append(res, backend.Tenant{Id: t})
		}
	}

	return res
}

func (r Backend) GetItemList(tenant string, tags map[string]string) []backend.Item {
	var query bson.M
	res := make([]backend.Item, 0)

	// copy backend session
	sessionCopy := r.mongoSession.Copy()
	defer sessionCopy.Close()

	c := sessionCopy.DB(tenant).C("ids")

	// Query taged items
	if len(tags) > 0 {
		query = bson.M{}

		for key, value := range tags {
			query["tags."+key] = bson.RegEx{"^" + value + "$", ""}
		}
	}

	err := c.Find(query).Sort("_id").All(&res)
	if err != nil {
		log.Printf("%q\n", err)
		return res
	}

	return res
}

func (r Backend) GetRawData(tenant string, id string, end int64, start int64, limit int64, order string) []backend.DataItem {
	var sort string
	res := make([]backend.DataItem, 0)

	// copy backend session
	sessionCopy := r.mongoSession.Copy()
	defer sessionCopy.Close()

	// order to sort
	if order == "DESC" {
		sort = "timestamp"
	} else {
		sort = "-timestamp"
	}

	c := sessionCopy.DB(tenant).C(id)

	// Query
	err := c.Find(bson.M{"timestamp": bson.M{"$gte": start, "$lt": end}}).Sort(sort).Limit(int(limit)).All(&res)
	if err != nil {
		log.Printf("%q\n", err)
		return res
	}

	return res
}

func (r Backend) GetStatData(tenant string, id string, end int64, start int64, limit int64, order string, bucketDuration int64) []backend.StatItem {
	var sort int
	res := make([]backend.StatItem, 0)

	// copy backend session
	sessionCopy := r.mongoSession.Copy()
	defer sessionCopy.Close()

	// order to sort
	if order == "DESC" {
		sort = -1
	} else {
		sort = 1
	}

	c := sessionCopy.DB(tenant).C(id)

	// Query
	err := c.Pipe(
		[]bson.M{
			{
				"$match": bson.M{"timestamp": bson.M{"$gte": start, "$lt": end}},
			},
			{
				"$group": bson.M{
					"_id": bson.M{
						"$trunc": bson.M{"$divide": []interface{}{"$timestamp", bucketDuration * 1000}},
					},
					"start": bson.M{"$first": bson.M{"$multiply": []interface{}{
						bson.M{"$trunc": bson.M{"$divide": []interface{}{
							"$timestamp",
							bucketDuration * 1000,
						}}},
						bucketDuration * 1000,
					}}},
					"end": bson.M{"$first": bson.M{"$multiply": []interface{}{
						bson.M{"$ceil": bson.M{"$divide": []interface{}{
							"$timestamp",
							bucketDuration * 1000,
						}}},
						bucketDuration * 1000,
					}}},
					"first":   bson.M{"$first": "$value"},
					"last":    bson.M{"$last": "$value"},
					"sum":     bson.M{"$sum": "$value"},
					"avg":     bson.M{"$avg": "$value"},
					"min":     bson.M{"$min": "$value"},
					"max":     bson.M{"$max": "$value"},
					"samples": bson.M{"$sum": 1},
				},
			},
			{
				"$sort": bson.M{"start": sort},
			},
			{
				"$limit": int(limit),
			},
		},
	).All(&res)
	if err != nil {
		log.Printf("%q\n", err)
		return res
	}
	return res
}

// unimplemented requests should fail silently

func (r Backend) PostRawData(tenant string, id string, t int64, v float64) bool {
	// check if id exist
	if !r.IdExist(tenant, id) {
		r.createId(tenant, id)
	}

	r.insertData(tenant, id, t, v)
	return true
}

func (r Backend) PutTags(tenant string, id string, tags map[string]string) bool {
	// check if id exist
	if !r.IdExist(tenant, id) {
		r.createId(tenant, id)
	}

	for k, v := range tags {
		r.insertTag(tenant, id, k, v)
	}
	return true
}

func (r Backend) DeleteData(tenant string, id string, end int64, start int64) bool {
	return true
}

func (r Backend) DeleteTags(tenant string, id string, tags []string) bool {
	return true
}

// Helper functions
// Not required by backend interface

func (r Backend) IdExist(tenant string, id string) bool {
	result := backend.Item{}

	// copy backend session
	sessionCopy := r.mongoSession.Copy()
	defer sessionCopy.Close()

	c := sessionCopy.DB(tenant).C("ids")

	err := c.Find(bson.M{"_id": id}).One(&result)
	return err == nil
}

func (r Backend) createId(tenant string, id string) bool {
	// copy backend session
	sessionCopy := r.mongoSession.Copy()
	defer sessionCopy.Close()

	c := sessionCopy.DB(tenant).C("ids")

	err := c.Insert(&backend.Item{Id: id, Type: "gauge", Tags: map[string]string{}, LastValues: []backend.DataItem{}})
	if err != nil {
		log.Printf("%q\n", err)
		return false
	}

	return true
}

func (r Backend) insertTag(tenant string, id string, k string, v string) {
	result := backend.Item{}

	// copy backend session
	sessionCopy := r.mongoSession.Copy()
	defer sessionCopy.Close()

	c := sessionCopy.DB(tenant).C("ids")

	// get current tags
	err := c.Find(bson.M{"_id": id}).One(&result)
	if err != nil {
		log.Printf("%q\n", err)
	}

	// Update
	result.Tags[k] = v
	err = c.Update(bson.M{"_id": id}, bson.M{"$set": bson.M{"tags": result.Tags}})
	if err != nil {
		log.Printf("%q\n", err)
	}
}

func (r Backend) insertData(tenant string, id string, t int64, v float64) {
	// copy backend session
	sessionCopy := r.mongoSession.Copy()
	defer sessionCopy.Close()

	c := sessionCopy.DB(tenant).C(id)
	err := c.Insert(&backend.DataItem{Timestamp: t, Value: v})

	if err != nil {
		log.Printf("%q\n", err)
	}
}
<commit_msg>add requires to spec<commit_after>// Copyright 2016 Red Hat, Inc. and/or its affiliates
// and other contributors.
//
// 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 backend
package mongo

import (
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
	"log"
	"net/url"
	"time"

	"github.com/yaacov/mohawk/backend"
)

type Backend struct {
	dbURL        string
	mongoSession *mgo.Session
}

// Backend functions
// Required by backend interface

func (r Backend) Name() string {
	return "Backend-Mongo"
}

func (r *Backend) Open(options url.Values) {
	var err error

	// get backend options
	r.dbURL = options.Get("db-url")
	if r.dbURL == "" {
		r.dbURL = "127.0.0.1"
	}

	// We need this object to establish a session to our MongoDB.
	mongoDBDialInfo := &mgo.DialInfo{
		Addrs:    []string{r.dbURL},
		Timeout:  10 * time.Second,
		Username: "",
		Password: "",
	}

	// Create a session which maintains a pool of socket connections
	// to our MongoDB.
	r.mongoSession, err = mgo.DialWithInfo(mongoDBDialInfo)
	if err != nil {
		panic(err)
	}

	r.mongoSession.SetMode(mgo.Monotonic, true)
}

func (r Backend) GetTenants() []backend.Tenant {
	res := make([]backend.Tenant, 0)

	// copy backend session
	sessionCopy := r.mongoSession.Copy()
	defer sessionCopy.Close()

	// return a list of tenants
	names, err := sessionCopy.DatabaseNames()
	if err != nil {
		log.Printf("%q\n", err)
		return res
	}
	for _, t := range names {
		if t != "admin" && t != "local" {
			res = append(res, backend.Tenant{Id: t})
		}
	}

	return res
}

func (r Backend) GetItemList(tenant string, tags map[string]string) []backend.Item {
	var query bson.M
	res := make([]backend.Item, 0)

	// copy backend session
	sessionCopy := r.mongoSession.Copy()
	defer sessionCopy.Close()

	c := sessionCopy.DB(tenant).C("ids")

	// Query taged items
	if len(tags) > 0 {
		query = bson.M{}

		for key, value := range tags {
			query["tags."+key] = bson.RegEx{"^" + value + "$", ""}
		}
	}

	err := c.Find(query).Sort("_id").All(&res)
	if err != nil {
		log.Printf("%q\n", err)
		return res
	}

	return res
}

func (r Backend) GetRawData(tenant string, id string, end int64, start int64, limit int64, order string) []backend.DataItem {
	var sort string
	res := make([]backend.DataItem, 0)

	// copy backend session
	sessionCopy := r.mongoSession.Copy()
	defer sessionCopy.Close()

	// order to sort
	if order == "DESC" {
		sort = "timestamp"
	} else {
		sort = "-timestamp"
	}

	c := sessionCopy.DB(tenant).C(id)

	// Query
	err := c.Find(bson.M{"timestamp": bson.M{"$gte": start, "$lt": end}}).Sort(sort).Limit(int(limit)).All(&res)
	if err != nil {
		log.Printf("%q\n", err)
		return res
	}

	return res
}

func (r Backend) GetStatData(tenant string, id string, end int64, start int64, limit int64, order string, bucketDuration int64) []backend.StatItem {
	var sort int
	res := make([]backend.StatItem, 0)

	// copy backend session
	sessionCopy := r.mongoSession.Copy()
	defer sessionCopy.Close()

	// order to sort
	if order == "DESC" {
		sort = -1
	} else {
		sort = 1
	}

	c := sessionCopy.DB(tenant).C(id)

	// Query
	err := c.Pipe(
		[]bson.M{
			{
				"$match": bson.M{"timestamp": bson.M{"$gte": start, "$lt": end}},
			},
			{
				"$group": bson.M{
					"_id": bson.M{
						"$trunc": bson.M{"$divide": []interface{}{"$timestamp", bucketDuration * 1000}},
					},
					"start": bson.M{"$first": bson.M{"$multiply": []interface{}{
						bson.M{"$trunc": bson.M{"$divide": []interface{}{
							"$timestamp",
							bucketDuration * 1000,
						}}},
						bucketDuration * 1000,
					}}},
					"end": bson.M{"$first": bson.M{"$multiply": []interface{}{
						bson.M{"$ceil": bson.M{"$divide": []interface{}{
							"$timestamp",
							bucketDuration * 1000,
						}}},
						bucketDuration * 1000,
					}}},
					"first":   bson.M{"$first": "$value"},
					"last":    bson.M{"$last": "$value"},
					"sum":     bson.M{"$sum": "$value"},
					"avg":     bson.M{"$avg": "$value"},
					"min":     bson.M{"$min": "$value"},
					"max":     bson.M{"$max": "$value"},
					"samples": bson.M{"$sum": 1},
				},
			},
			{
				"$sort": bson.M{"start": sort},
			},
			{
				"$limit": int(limit),
			},
		},
	).All(&res)
	if err != nil {
		log.Printf("%q\n", err)
		return res
	}
	return res
}

// unimplemented requests should fail silently

func (r Backend) PostRawData(tenant string, id string, t int64, v float64) bool {
	// check if id exist
	if !r.IdExist(tenant, id) {
		r.createId(tenant, id)
	}

	r.insertData(tenant, id, t, v)
	return true
}

func (r Backend) PutTags(tenant string, id string, tags map[string]string) bool {
	// check if id exist
	if !r.IdExist(tenant, id) {
		r.createId(tenant, id)
	}

	for k, v := range tags {
		r.insertTag(tenant, id, k, v)
	}
	return true
}

func (r Backend) DeleteData(tenant string, id string, end int64, start int64) bool {
	return true
}

func (r Backend) DeleteTags(tenant string, id string, tags []string) bool {
	return true
}

// Helper functions
// Not required by backend interface

func (r Backend) IdExist(tenant string, id string) bool {
	result := backend.Item{}

	// copy backend session
	sessionCopy := r.mongoSession.Copy()
	defer sessionCopy.Close()

	c := sessionCopy.DB(tenant).C("ids")

	err := c.Find(bson.M{"_id": id}).One(&result)
	return err == nil
}

func (r Backend) createId(tenant string, id string) bool {
	// copy backend session
	sessionCopy := r.mongoSession.Copy()
	defer sessionCopy.Close()

	c := sessionCopy.DB(tenant).C("ids")

	err := c.Insert(&backend.Item{Id: id, Type: "gauge", Tags: map[string]string{}, LastValues: []backend.DataItem{}})
	if err != nil {
		log.Printf("%q\n", err)
		return false
	}

	return true
}

func (r Backend) insertTag(tenant string, id string, k string, v string) {
	result := backend.Item{}

	// copy backend session
	sessionCopy := r.mongoSession.Copy()
	defer sessionCopy.Close()

	c := sessionCopy.DB(tenant).C("ids")

	// get current tags
	err := c.Find(bson.M{"_id": id}).One(&result)
	if err != nil {
		log.Printf("%q\n", err)
	}

	// Update
	result.Tags[k] = v
	err = c.Update(bson.M{"_id": id}, bson.M{"$set": bson.M{"tags": result.Tags}})
	if err != nil {
		log.Printf("%q\n", err)
	}
}

func (r Backend) insertData(tenant string, id string, t int64, v float64) {
	// copy backend session
	sessionCopy := r.mongoSession.Copy()
	defer sessionCopy.Close()

	c := sessionCopy.DB(tenant).C(id)
	err := c.Insert(&backend.DataItem{Timestamp: t, Value: v})

	if err != nil {
		log.Printf("%q\n", err)
	}
}
<|endoftext|>


<commit_before>/*
The MIT License (MIT)

Copyright (c) 2016 Ivan Dejanovic

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

package cfg

import (
	"bufio"
	"fmt"
	"mlpl/types"
	"os"
	"strings"
)

const (
	minus       = "-"
	doubleMinus = "--"
	empty       = ""
	usage       = "Usage: mlpl <codefilename> [configurationfilename]"
)

func getDefaultReserved() []types.ReservedWord {
	reserved := make([]types.ReservedWord, 0, 8)

	reserved = append(reserved, types.ReservedWord{types.IF, "if"})
	reserved = append(reserved, types.ReservedWord{types.THEN, "then"})
	reserved = append(reserved, types.ReservedWord{types.ELSE, "else"})
	reserved = append(reserved, types.ReservedWord{types.END, "end"})
	reserved = append(reserved, types.ReservedWord{types.REPEAT, "repeat"})
	reserved = append(reserved, types.ReservedWord{types.UNTIL, "until"})
	reserved = append(reserved, types.ReservedWord{types.READ, "read"})
	reserved = append(reserved, types.ReservedWord{types.WRITE, "write"})

	return reserved
}

func getConfigReservedWords(configFile string) []types.ReservedWord {
	reserved := make([]types.ReservedWord, 0, 8)
	var localization []string
	const length = 8

	config, err := os.Open(configFile)
	if err != nil {
		panic(err)
	}

	scanner := bufio.NewScanner(config)
	for scanner.Scan() {
		localization = append(localization, scanner.Text())
	}

	defer config.Close()

	if len(localization) != length {
		fmt.Println("Configuration file must contain localizations for eight key word.")
	}

	reserved = append(reserved, types.ReservedWord{types.IF, localization[0]})
	reserved = append(reserved, types.ReservedWord{types.THEN, localization[1]})
	reserved = append(reserved, types.ReservedWord{types.ELSE, localization[2]})
	reserved = append(reserved, types.ReservedWord{types.END, localization[3]})
	reserved = append(reserved, types.ReservedWord{types.REPEAT, localization[4]})
	reserved = append(reserved, types.ReservedWord{types.UNTIL, localization[5]})
	reserved = append(reserved, types.ReservedWord{types.READ, localization[6]})
	reserved = append(reserved, types.ReservedWord{types.WRITE, localization[7]})

	return reserved
}

func HandleArgs() (bool, string, []types.ReservedWord) {
	var abort bool = true
	var codeFile string
	var reserved []types.ReservedWord

	args := os.Args[1:]
	argc := len(args)

	for index := 0; index < argc; index++ {
		var flag string = empty
		var flagArg string = args[index]

		if strings.HasPrefix(flagArg, minus) {
			flag = strings.TrimPrefix(flagArg, minus)
		} else if strings.HasPrefix(flagArg, doubleMinus) {
			flag = strings.TrimPrefix(flagArg, doubleMinus)
		}

		if flag != empty {
			switch flag {
			case "h", "help":
				fmt.Println()
				fmt.Println(usage)
				fmt.Println()
				fmt.Println("Options:")
				fmt.Println("  -h, --help       Prints help")
				fmt.Println("  -v, --version    Prints version")
			case "v", "version":
				fmt.Println("MLPL interpreter version 0.1.0")
			default:
				fmt.Println("Invalid usage. For correct usage examples please try: mlpl -h")
			}
			return abort, codeFile, reserved
		}
	}

	if argc < 1 || argc > 2 {
		fmt.Println(usage)
		return abort, codeFile, reserved
	}

	if argc == 2 {
		reserved = getConfigReservedWords(args[1])
	} else {
		reserved = getDefaultReserved()
	}

	//If we get this far we have good data to process
	abort = false
	codeFile = args[0]

	return abort, codeFile, reserved
}
<commit_msg>Fixed bug.<commit_after>/*
The MIT License (MIT)

Copyright (c) 2016 Ivan Dejanovic

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

package cfg

import (
	"bufio"
	"fmt"
	"mlpl/types"
	"os"
	"strings"
)

const (
	minus       = "-"
	doubleMinus = "--"
	empty       = ""
	usage       = "Usage: mlpl <codefilename> [configurationfilename]"
)

func getDefaultReserved() []types.ReservedWord {
	reserved := make([]types.ReservedWord, 0, 8)

	reserved = append(reserved, types.ReservedWord{types.IF, "if"})
	reserved = append(reserved, types.ReservedWord{types.THEN, "then"})
	reserved = append(reserved, types.ReservedWord{types.ELSE, "else"})
	reserved = append(reserved, types.ReservedWord{types.END, "end"})
	reserved = append(reserved, types.ReservedWord{types.REPEAT, "repeat"})
	reserved = append(reserved, types.ReservedWord{types.UNTIL, "until"})
	reserved = append(reserved, types.ReservedWord{types.READ, "read"})
	reserved = append(reserved, types.ReservedWord{types.WRITE, "write"})

	return reserved
}

func getConfigReservedWords(configFile string) []types.ReservedWord {
	reserved := make([]types.ReservedWord, 0, 8)
	var localization []string
	const length = 8

	config, err := os.Open(configFile)
	if err != nil {
		panic(err)
	}

	scanner := bufio.NewScanner(config)
	for scanner.Scan() {
		localization = append(localization, scanner.Text())
	}

	defer config.Close()

	if len(localization) != length {
		fmt.Println("Configuration file must contain localizations for eight key word.")
	}

	reserved = append(reserved, types.ReservedWord{types.IF, localization[0]})
	reserved = append(reserved, types.ReservedWord{types.THEN, localization[1]})
	reserved = append(reserved, types.ReservedWord{types.ELSE, localization[2]})
	reserved = append(reserved, types.ReservedWord{types.END, localization[3]})
	reserved = append(reserved, types.ReservedWord{types.REPEAT, localization[4]})
	reserved = append(reserved, types.ReservedWord{types.UNTIL, localization[5]})
	reserved = append(reserved, types.ReservedWord{types.READ, localization[6]})
	reserved = append(reserved, types.ReservedWord{types.WRITE, localization[7]})

	return reserved
}

func HandleArgs() (bool, string, []types.ReservedWord) {
	var abort bool = true
	var codeFile string
	var reserved []types.ReservedWord

	args := os.Args[1:]
	argc := len(args)

	for index := 0; index < argc; index++ {
		var flag string = empty
		var flagArg string = args[index]

		if strings.HasPrefix(flagArg, doubleMinus) {
			flag = strings.TrimPrefix(flagArg, doubleMinus)
		} else if strings.HasPrefix(flagArg, minus) {
			flag = strings.TrimPrefix(flagArg, minus)
		}

		if flag != empty {
			switch flag {
			case "h", "help":
				fmt.Println()
				fmt.Println(usage)
				fmt.Println()
				fmt.Println("Options:")
				fmt.Println("  -h, --help       Prints help")
				fmt.Println("  -v, --version    Prints version")
			case "v", "version":
				fmt.Println("MLPL interpreter version 0.1.0")
			default:
				fmt.Println("Invalid usage. For correct usage examples please try: mlpl -h")
			}
			return abort, codeFile, reserved
		}
	}

	if argc < 1 || argc > 2 {
		fmt.Println(usage)
		return abort, codeFile, reserved
	}

	if argc == 2 {
		reserved = getConfigReservedWords(args[1])
	} else {
		reserved = getDefaultReserved()
	}

	//If we get this far we have good data to process
	abort = false
	codeFile = args[0]

	return abort, codeFile, reserved
}
<|endoftext|>


<commit_before>package mongo

import (
	"encoding/json"
	"errors"
	"net/http"
	"net/http/httptest"
	"net/url"
	"reflect"
	"strconv"
	"testing"

	"github.com/basvdlei/godatatables/types"

	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

type RequestTestCase struct {
	Request      types.Request
	SortColumns  []string
	Result       []map[string]string
	ResponseData []types.Row
	Filter       bson.M
}

var RequestTests = []RequestTestCase{
	{
		Request: types.Request{
			Draw:   1,
			Start:  5,
			Length: 10,
			Order:  nil,
			Search: types.Search{
				Value: "test",
				Regex: false,
			},
			Columns: []types.Column{
				{
					Data:       "foo",
					Name:       "",
					Orderable:  true,
					Searchable: true,
					Search: types.Search{
						Value: "",
						Regex: false,
					},
				},
				{
					Data:       "bar",
					Name:       "",
					Orderable:  false,
					Searchable: false,
					Search:     types.Search{},
				},
			},
		},
		SortColumns: []string{},
		Result: []map[string]string{
			{
				"foo": "1",
				"bar": "2",
			},
			{
				"foo": "3",
				"bar": "4",
			},
		},
		ResponseData: []types.Row{
			{
				Data: map[string]string{
					"foo": "1",
					"bar": "2",
				},
			},
			{
				Data: map[string]string{
					"foo": "3",
					"bar": "4",
				},
			},
		},
		Filter: bson.M{
			"$or": []bson.M{
				{
					"foo": bson.RegEx{
						Pattern: "test",
					},
				},
				{
					"bar": bson.RegEx{
						Pattern: "test",
					},
				},
			},
		},
	},
	{
		Request: types.Request{
			Draw:   10,
			Start:  25,
			Length: 100,
			Order: []types.Order{
				{
					Column: 1,
					Dir:    types.OrderDescending,
				},
			},
			Search: types.Search{
				Value: "^test$",
				Regex: true,
			},
			Columns: []types.Column{
				{
					Data:       "foo",
					Name:       "",
					Orderable:  false,
					Searchable: true,
					Search: types.Search{
						Value: "test",
						Regex: false,
					},
				},
				{
					Data:       "bar",
					Name:       "",
					Orderable:  true,
					Searchable: true,
					Search: types.Search{
						Value: "^test$",
						Regex: true,
					},
				},
			},
		},
		SortColumns: []string{"-bar"},
		Result: []map[string]string{
			{
				"foo": "1",
				"bar": "2",
			},
			{
				"foo": "3",
				"bar": "4",
			},
		},
		ResponseData: []types.Row{
			{
				Data: map[string]string{
					"foo": "1",
					"bar": "2",
				},
			},
			{
				Data: map[string]string{
					"foo": "3",
					"bar": "4",
				},
			},
		},
		Filter: bson.M{
			"$and": []bson.M{
				{
					"$or": []bson.M{
						{
							"foo": bson.RegEx{
								Pattern: "^test$",
							},
						},
						{
							"bar": bson.RegEx{
								Pattern: "^test$",
							},
						},
					},
				},
				{
					"$and": []bson.M{
						{
							"foo": bson.RegEx{
								Pattern: "test",
							},
						},
						{
							"bar": bson.RegEx{
								Pattern: "^test$",
							},
						},
					},
				},
			},
		},
	},
}

type QueryMock struct {
	Result      []map[string]string
	CountCalled bool
	LimitValue  int
	SkipValue   int
	SortValue   []string
}

func (q *QueryMock) All(result interface{}) error {
	if v, ok := result.(*[]map[string]string); ok {
		*v = append(*v, q.Result...)
		return nil
	}
	return errors.New("unkown type")
}
func (q *QueryMock) Count() (n int, err error) {
	q.CountCalled = true
	return
}
func (q *QueryMock) Limit(n int) Query {
	q.LimitValue = n
	return q
}
func (q *QueryMock) Skip(n int) Query {
	q.SkipValue = n
	return q
}
func (q *QueryMock) Sort(fields ...string) Query {
	q.SortValue = fields
	return q
}

type CollectionMock struct {
	count int
	err   error
	query *QueryMock
}

func (c *CollectionMock) Count() (n int, err error) {
	return c.count, c.err
}
func (c *CollectionMock) Find(query interface{}) Query {
	return c.query
}

func TestCollectionHandlerServeHTTP(t *testing.T) {
	for i, c := range RequestTests {
		var totalRecords = 100
		ch := &CollectionHandler{
			Collection: &CollectionMock{
				count: totalRecords,
				err:   nil,
				query: &QueryMock{
					Result: c.Result,
				},
			},
		}
		req := &http.Request{
			Method: "GET",
			URL:    &url.URL{Path: "/"},
			Form: url.Values{
				"draw": []string{strconv.Itoa(c.Request.Draw)},
			},
		}
		w := httptest.NewRecorder()
		ch.ServeHTTP(w, req)
		resp := w.Result()
		if resp.StatusCode != http.StatusOK {
			t.Errorf("case %d: unexpected statuscode, want %d, got %d",
				i, http.StatusOK, resp.StatusCode)
		}
		dec := json.NewDecoder(resp.Body)
		var dtResponse types.Response
		err := dec.Decode(&dtResponse)
		if err != nil {
			t.Errorf("case %d: could not marshal reponse: %v", i, err)
		}
		if dtResponse.Error != "" {
			t.Errorf("case %d: unexpected error returned. want %v, got %v",
				i, "", dtResponse.Error)
		}
		if dtResponse.Draw != c.Request.Draw {
			t.Errorf("case %d: draw value does not match. want %d, got %d",
				i, c.Request.Draw, dtResponse.Draw)
		}
		if dtResponse.RecordsTotal != totalRecords {
			t.Errorf("case %d: totalRecords does not match. want %d, got %d",
				i, totalRecords, dtResponse.RecordsTotal)
		}
		if !reflect.DeepEqual(dtResponse.Data, c.ResponseData) {
			t.Errorf("case %d: data does not match. want %v, got %v",
				i, c.ResponseData, dtResponse.Data)
		}
	}
}

func TestResponseData(t *testing.T) {
	for i, c := range RequestTests {
		q := &QueryMock{
			Result: c.Result,
		}
		data, err := ResponseData(q)
		if err != nil {
			t.Errorf("case %d: error %v", i, err)
		}
		if !reflect.DeepEqual(data, c.ResponseData) {
			t.Errorf("case %d: data does not match, want %+v, got %+v",
				i, c.ResponseData, data)
		}
	}
}

func TestSortQuery(t *testing.T) {
	for i, c := range RequestTests {
		q := SortQuery(&QueryMock{}, c.Request)
		if v, ok := q.(*QueryMock); ok {
			if len(v.SortValue) != len(c.SortColumns) {
				t.Errorf("case %d: sort columns count does not match, want %d, got %d",
					i, len(c.SortColumns), len(v.SortValue))
			}
			for i, s := range c.SortColumns {
				if v.SortValue[i] != s {
					t.Errorf("case %d: sortcolumn does not match, want %s, got %s",
						i, v.SortValue[i], s)
				}
			}
		} else {
			t.Errorf("bad query type")
		}
	}
}

func TestRangeQuery(t *testing.T) {
	for i, c := range RequestTests {
		q := RangeQuery(&QueryMock{}, c.Request)
		if v, ok := q.(*QueryMock); ok {
			if v.LimitValue != c.Request.Length {
				t.Errorf("case %d: limit does not match, want %d, got %d",
					i, c.Request.Length, v.LimitValue)
			}
			if v.SkipValue != c.Request.Start {
				t.Errorf("case %d: skip does not match, want %d, got %d",
					i, c.Request.Start, v.SkipValue)
			}
		} else {
			t.Errorf("bad query type")
		}
	}
}

func TestCreateFilter(t *testing.T) {
	for i, c := range RequestTests {
		f := CreateFilter(c.Request)
		if !reflect.DeepEqual(f, c.Filter) {
			t.Errorf("case %d: filter not match, want %+v, got %+v",
				i, c.Filter, f)
		}
	}
}

func ExampleCollectionHandler() {
	session, _ := mgo.Dial("mymongohost")
	c := session.DB("mydb").C("mycollection")
	http.Handle("/mycollection", NewCollectionHandler(c))
	http.ListenAndServe(":8080", nil)
}
<commit_msg>mongo: Fix minor spelling errors<commit_after>package mongo

import (
	"encoding/json"
	"errors"
	"net/http"
	"net/http/httptest"
	"net/url"
	"reflect"
	"strconv"
	"testing"

	"github.com/basvdlei/godatatables/types"

	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

type RequestTestCase struct {
	Request      types.Request
	SortColumns  []string
	Result       []map[string]string
	ResponseData []types.Row
	Filter       bson.M
}

var RequestTests = []RequestTestCase{
	{
		Request: types.Request{
			Draw:   1,
			Start:  5,
			Length: 10,
			Order:  nil,
			Search: types.Search{
				Value: "test",
				Regex: false,
			},
			Columns: []types.Column{
				{
					Data:       "foo",
					Name:       "",
					Orderable:  true,
					Searchable: true,
					Search: types.Search{
						Value: "",
						Regex: false,
					},
				},
				{
					Data:       "bar",
					Name:       "",
					Orderable:  false,
					Searchable: false,
					Search:     types.Search{},
				},
			},
		},
		SortColumns: []string{},
		Result: []map[string]string{
			{
				"foo": "1",
				"bar": "2",
			},
			{
				"foo": "3",
				"bar": "4",
			},
		},
		ResponseData: []types.Row{
			{
				Data: map[string]string{
					"foo": "1",
					"bar": "2",
				},
			},
			{
				Data: map[string]string{
					"foo": "3",
					"bar": "4",
				},
			},
		},
		Filter: bson.M{
			"$or": []bson.M{
				{
					"foo": bson.RegEx{
						Pattern: "test",
					},
				},
				{
					"bar": bson.RegEx{
						Pattern: "test",
					},
				},
			},
		},
	},
	{
		Request: types.Request{
			Draw:   10,
			Start:  25,
			Length: 100,
			Order: []types.Order{
				{
					Column: 1,
					Dir:    types.OrderDescending,
				},
			},
			Search: types.Search{
				Value: "^test$",
				Regex: true,
			},
			Columns: []types.Column{
				{
					Data:       "foo",
					Name:       "",
					Orderable:  false,
					Searchable: true,
					Search: types.Search{
						Value: "test",
						Regex: false,
					},
				},
				{
					Data:       "bar",
					Name:       "",
					Orderable:  true,
					Searchable: true,
					Search: types.Search{
						Value: "^test$",
						Regex: true,
					},
				},
			},
		},
		SortColumns: []string{"-bar"},
		Result: []map[string]string{
			{
				"foo": "1",
				"bar": "2",
			},
			{
				"foo": "3",
				"bar": "4",
			},
		},
		ResponseData: []types.Row{
			{
				Data: map[string]string{
					"foo": "1",
					"bar": "2",
				},
			},
			{
				Data: map[string]string{
					"foo": "3",
					"bar": "4",
				},
			},
		},
		Filter: bson.M{
			"$and": []bson.M{
				{
					"$or": []bson.M{
						{
							"foo": bson.RegEx{
								Pattern: "^test$",
							},
						},
						{
							"bar": bson.RegEx{
								Pattern: "^test$",
							},
						},
					},
				},
				{
					"$and": []bson.M{
						{
							"foo": bson.RegEx{
								Pattern: "test",
							},
						},
						{
							"bar": bson.RegEx{
								Pattern: "^test$",
							},
						},
					},
				},
			},
		},
	},
}

type QueryMock struct {
	Result      []map[string]string
	CountCalled bool
	LimitValue  int
	SkipValue   int
	SortValue   []string
}

func (q *QueryMock) All(result interface{}) error {
	if v, ok := result.(*[]map[string]string); ok {
		*v = append(*v, q.Result...)
		return nil
	}
	return errors.New("unknown type")
}
func (q *QueryMock) Count() (n int, err error) {
	q.CountCalled = true
	return
}
func (q *QueryMock) Limit(n int) Query {
	q.LimitValue = n
	return q
}
func (q *QueryMock) Skip(n int) Query {
	q.SkipValue = n
	return q
}
func (q *QueryMock) Sort(fields ...string) Query {
	q.SortValue = fields
	return q
}

type CollectionMock struct {
	count int
	err   error
	query *QueryMock
}

func (c *CollectionMock) Count() (n int, err error) {
	return c.count, c.err
}
func (c *CollectionMock) Find(query interface{}) Query {
	return c.query
}

func TestCollectionHandlerServeHTTP(t *testing.T) {
	for i, c := range RequestTests {
		var totalRecords = 100
		ch := &CollectionHandler{
			Collection: &CollectionMock{
				count: totalRecords,
				err:   nil,
				query: &QueryMock{
					Result: c.Result,
				},
			},
		}
		req := &http.Request{
			Method: "GET",
			URL:    &url.URL{Path: "/"},
			Form: url.Values{
				"draw": []string{strconv.Itoa(c.Request.Draw)},
			},
		}
		w := httptest.NewRecorder()
		ch.ServeHTTP(w, req)
		resp := w.Result()
		if resp.StatusCode != http.StatusOK {
			t.Errorf("case %d: unexpected statuscode, want %d, got %d",
				i, http.StatusOK, resp.StatusCode)
		}
		dec := json.NewDecoder(resp.Body)
		var dtResponse types.Response
		err := dec.Decode(&dtResponse)
		if err != nil {
			t.Errorf("case %d: could not marshal response: %v", i, err)
		}
		if dtResponse.Error != "" {
			t.Errorf("case %d: unexpected error returned. want %v, got %v",
				i, "", dtResponse.Error)
		}
		if dtResponse.Draw != c.Request.Draw {
			t.Errorf("case %d: draw value does not match. want %d, got %d",
				i, c.Request.Draw, dtResponse.Draw)
		}
		if dtResponse.RecordsTotal != totalRecords {
			t.Errorf("case %d: totalRecords does not match. want %d, got %d",
				i, totalRecords, dtResponse.RecordsTotal)
		}
		if !reflect.DeepEqual(dtResponse.Data, c.ResponseData) {
			t.Errorf("case %d: data does not match. want %v, got %v",
				i, c.ResponseData, dtResponse.Data)
		}
	}
}

func TestResponseData(t *testing.T) {
	for i, c := range RequestTests {
		q := &QueryMock{
			Result: c.Result,
		}
		data, err := ResponseData(q)
		if err != nil {
			t.Errorf("case %d: error %v", i, err)
		}
		if !reflect.DeepEqual(data, c.ResponseData) {
			t.Errorf("case %d: data does not match, want %+v, got %+v",
				i, c.ResponseData, data)
		}
	}
}

func TestSortQuery(t *testing.T) {
	for i, c := range RequestTests {
		q := SortQuery(&QueryMock{}, c.Request)
		if v, ok := q.(*QueryMock); ok {
			if len(v.SortValue) != len(c.SortColumns) {
				t.Errorf("case %d: sort columns count does not match, want %d, got %d",
					i, len(c.SortColumns), len(v.SortValue))
			}
			for i, s := range c.SortColumns {
				if v.SortValue[i] != s {
					t.Errorf("case %d: sortcolumn does not match, want %s, got %s",
						i, v.SortValue[i], s)
				}
			}
		} else {
			t.Errorf("bad query type")
		}
	}
}

func TestRangeQuery(t *testing.T) {
	for i, c := range RequestTests {
		q := RangeQuery(&QueryMock{}, c.Request)
		if v, ok := q.(*QueryMock); ok {
			if v.LimitValue != c.Request.Length {
				t.Errorf("case %d: limit does not match, want %d, got %d",
					i, c.Request.Length, v.LimitValue)
			}
			if v.SkipValue != c.Request.Start {
				t.Errorf("case %d: skip does not match, want %d, got %d",
					i, c.Request.Start, v.SkipValue)
			}
		} else {
			t.Errorf("bad query type")
		}
	}
}

func TestCreateFilter(t *testing.T) {
	for i, c := range RequestTests {
		f := CreateFilter(c.Request)
		if !reflect.DeepEqual(f, c.Filter) {
			t.Errorf("case %d: filter not match, want %+v, got %+v",
				i, c.Filter, f)
		}
	}
}

func ExampleCollectionHandler() {
	session, _ := mgo.Dial("mymongohost")
	c := session.DB("mydb").C("mycollection")
	http.Handle("/mycollection", NewCollectionHandler(c))
	http.ListenAndServe(":8080", nil)
}
<|endoftext|>


<commit_before>// Copyright 2013 The lime Authors.
// Use of this source code is governed by a 2-clause
// BSD-style license that can be found in the LICENSE file.

package backend

import (
	"testing"
)

func TestWindowNewFile(t *testing.T) {
	w := GetEditor().NewWindow()
	defer w.Close()

	v := w.NewFile()
	defer func() {
		v.SetScratch(true)
		v.Close()
	}()

	if len(w.Views()) != 1 {
		t.Errorf("Expected 1 view, but got %d", len(w.Views()))
	}
}

func TestWindowRemove(t *testing.T) {
	w := GetEditor().NewWindow()
	defer w.Close()

	v0 := w.NewFile()
	defer v0.Close()

	v1 := w.NewFile()
	defer v1.Close()

	v2 := w.NewFile()
	defer v2.Close()

	l := len(w.Views())

	w.remove(v1)

	if len(w.Views()) != l-1 {
		t.Errorf("Expected %d open views, but got %d", l-1, len(w.Views()))
	}
}

func TestWindowActiveView(t *testing.T) {
	w := GetEditor().NewWindow()
	defer w.Close()

	v0 := w.NewFile()
	defer v0.Close()

	v1 := w.NewFile()
	defer v1.Close()

	if w.ActiveView() != v1 {
		t.Error("Expected v1 to be the active view, but it wasn't")
	}
}

func TestWindowClose(t *testing.T) {
	ed := GetEditor()
	l := len(ed.Windows())
	w := ed.NewWindow()

	for _, v := range w.Views() {
		v.SetScratch(true)
		v.Close()
	}

	w.Close()

	if len(ed.Windows()) != l {
		t.Errorf("Expected window to close, but we have %d still open", len(ed.Windows()))
	}
}

func TestWindowCloseAllViews(t *testing.T) {
	w := GetEditor().NewWindow()
	defer w.Close()

	w.NewFile()
	w.NewFile()

	w.CloseAllViews()

	if len(w.Views()) != 0 {
		t.Errorf("Expected 0 open views, but got %d", len(w.Views()))
	}
}
<commit_msg>[backend] Add some tests to Window.<commit_after>// Copyright 2013 The lime Authors.
// Use of this source code is governed by a 2-clause
// BSD-style license that can be found in the LICENSE file.

package backend

import (
	"testing"
)

func TestWindowNewFile(t *testing.T) {
	w := GetEditor().NewWindow()
	defer w.Close()

	v := w.NewFile()
	defer func() {
		v.SetScratch(true)
		v.Close()
	}()

	if len(w.Views()) != 1 {
		t.Errorf("Expected 1 view, but got %d", len(w.Views()))
	}
}

func TestWindowRemove(t *testing.T) {
	w := GetEditor().NewWindow()
	defer w.Close()

	v0 := w.NewFile()
	defer v0.Close()

	v1 := w.NewFile()
	defer v1.Close()

	v2 := w.NewFile()
	defer v2.Close()

	l := len(w.Views())

	w.remove(v1)

	if len(w.Views()) != l-1 {
		t.Errorf("Expected %d open views, but got %d", l-1, len(w.Views()))
	}
}

func TestWindowActiveView(t *testing.T) {
	w := GetEditor().NewWindow()
	defer w.Close()

	v0 := w.NewFile()
	defer v0.Close()

	v1 := w.NewFile()
	defer v1.Close()

	if w.ActiveView() != v1 {
		t.Error("Expected v1 to be the active view, but it wasn't")
	}
}

func TestWindowClose(t *testing.T) {
	ed := GetEditor()
	l := len(ed.Windows())
	w := ed.NewWindow()

	for _, v := range w.Views() {
		v.SetScratch(true)
		v.Close()
	}

	w.Close()

	if len(ed.Windows()) != l {
		t.Errorf("Expected window to close, but we have %d still open", len(ed.Windows()))
	}
}

func TestWindowCloseFail(t *testing.T) {
	ed := GetEditor()

	fe := ed.Frontend()
	if dfe, ok := fe.(*DummyFrontend); ok {
		dfe.SetDefaultAction(false)
	}

	w := ed.NewWindow()
	l := len(ed.Windows())

	v := w.NewFile()
	defer func() {
		v.SetScratch(true)
		v.Close()
	}()

	edit := v.BeginEdit()
	v.Insert(edit, 0, "test")
	v.EndEdit(edit)

	if w.Close() {
		t.Errorf("Expected window to fail to close, but it didn't")
	}

	if len(ed.Windows()) != l {
		t.Error("Expected window not to close, but it did")
	}
}

func TestWindowCloseAllViews(t *testing.T) {
	w := GetEditor().NewWindow()
	defer w.Close()

	w.NewFile()
	w.NewFile()

	w.CloseAllViews()

	if len(w.Views()) != 0 {
		t.Errorf("Expected 0 open views, but got %d", len(w.Views()))
	}
}

func TestWindowCloseAllViewsFail(t *testing.T) {
	ed := GetEditor()

	fe := ed.Frontend()
	if dfe, ok := fe.(*DummyFrontend); ok {
		dfe.SetDefaultAction(false)
	}

	w := ed.NewWindow()
	defer w.Close()

	w.NewFile()
	v := w.NewFile()

	l := len(w.Views())

	w.NewFile()
	defer func() {
		for _, vw := range w.Views() {
			vw.SetScratch(true)
			vw.Close()
		}
	}()

	edit := v.BeginEdit()
	v.Insert(edit, 0, "test")
	v.EndEdit(edit)

	if w.CloseAllViews() {
		t.Errorf("Expected views to fail to close, but they didn't")
	}

	if len(w.Views()) != l {
		t.Error("Expected only one view to close, but more did")
	}
}
<|endoftext|>


<commit_before>// Package kite is a library for creating micro-services.  Two main types
// implemented by this package are Kite for creating a micro-service server
// called "Kite" and Client for communicating with another kites.
package kite

import (
	"crypto/tls"
	"errors"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"os"
	"strings"

	"github.com/dgrijalva/jwt-go"
	"github.com/koding/kite/config"
	"github.com/koding/kite/protocol"
	"github.com/nu7hatch/gouuid"
	"gopkg.in/igm/sockjs-go.v2/sockjs"
)

var hostname string

func init() {
	var err error
	hostname, err = os.Hostname()
	if err != nil {
		panic(fmt.Sprintf("kite: cannot get hostname: %s", err.Error()))
	}
}

// Kite defines a single process that enables distributed service messaging
// amongst the peers it is connected. A Kite process acts as a Client and as a
// Server. That means it can receive request, process them, but it also can
// make request to other kites.
//
// Do not use this struct directly. Use kite.New function, add your handlers
// with HandleFunc mehtod, then call Run method to start the inbuilt server (or
// pass it to any http.Handler compatible server)
type Kite struct {
	Config *config.Config

	// Log logs with the given Logger interface
	Log Logger

	// SetLogLevel changes the level of the logger. Default is INFO.
	SetLogLevel func(Level)

	// Contains different functions for authenticating user from request.
	// Keys are the authentication types (options.auth.type).
	Authenticators map[string]func(*Request) error

	// Kontrol keys to trust. Kontrol will issue access tokens for kites
	// that are signed with the private counterpart of these keys.
	// Key data must be PEM encoded.
	trustedKontrolKeys map[string]string

	// Handlers added with Kite.HandleFunc().
	handlers     map[string]*Method // method map for exported methods
	preHandlers  []Handler          // a list of handlers that are executed before any handler
	postHandlers []Handler          // a list of handlers that are executed after any handler

	// MethodHandling defines how the kite is returning the response for
	// multiple handlers
	MethodHandling MethodHandling

	httpHandler http.Handler

	// kontrolclient is used to register to kontrol and query third party kites
	// from kontrol
	kontrol *kontrolClient

	// Handlers to call when a new connection is received.
	onConnectHandlers []func(*Client)

	// Handlers to call before the first request of connected kite.
	onFirstRequestHandlers []func(*Client)

	// Handlers to call when a client has disconnected.
	onDisconnectHandlers []func(*Client)

	// server fields, are initialized and used when
	// TODO: move them to their own struct, just like KontrolClient
	listener  net.Listener
	TLSConfig *tls.Config
	readyC    chan bool // To signal when kite is ready to accept connections
	closeC    chan bool // To signal when kite is closed with Close()

	name    string
	version string
	Id      string // Unique kite instance id
}

// New creates, initialize and then returns a new Kite instance. Version must
// be in 3-digit semantic form. Name is important that it's also used to be
// searched by others.
func New(name, version string) *Kite {
	if name == "" {
		panic("kite: name cannot be empty")
	}

	if digits := strings.Split(version, "."); len(digits) != 3 {
		panic("kite: version must be 3-digits semantic version")
	}

	kiteID, err := uuid.NewV4()
	if err != nil {
		panic(fmt.Sprintf("kite: cannot generate unique ID: %s", err.Error()))
	}

	l, setlevel := newLogger(name)

	kClient := &kontrolClient{
		readyConnected:  make(chan struct{}),
		readyRegistered: make(chan struct{}),
		registerChan:    make(chan *url.URL, 1),
	}

	k := &Kite{
		Config:             config.New(),
		Log:                l,
		SetLogLevel:        setlevel,
		Authenticators:     make(map[string]func(*Request) error),
		trustedKontrolKeys: make(map[string]string),
		handlers:           make(map[string]*Method),
		preHandlers:        make([]Handler, 0),
		postHandlers:       make([]Handler, 0),
		kontrol:            kClient,
		name:               name,
		version:            version,
		Id:                 kiteID.String(),
		readyC:             make(chan bool),
		closeC:             make(chan bool),
	}

	k.httpHandler = sockjs.NewHandler("/kite", sockjs.DefaultOptions, k.sockjsHandler)

	k.OnConnect(func(c *Client) { k.Log.Info("New session: %s", c.session.ID()) })
	k.OnFirstRequest(func(c *Client) { k.Log.Info("Session %q is identified as %q", c.session.ID(), c.Kite) })
	k.OnDisconnect(func(c *Client) { k.Log.Info("Kite has disconnected: %q", c.Kite) })

	// Every kite should be able to authenticate the user from token.
	// Tokens are granted by Kontrol Kite.
	k.Authenticators["token"] = k.AuthenticateFromToken

	// A kite accepts requests with the same username.
	k.Authenticators["kiteKey"] = k.AuthenticateFromKiteKey

	// Register default methods.
	k.addDefaultHandlers()

	return k
}

// Kite returns the definition of the kite.
func (k *Kite) Kite() *protocol.Kite {
	return &protocol.Kite{
		Username:    k.Config.Username,
		Environment: k.Config.Environment,
		Name:        k.name,
		Version:     k.version,
		Region:      k.Config.Region,
		Hostname:    hostname,
		ID:          k.Id,
	}
}

// Trust a Kontrol key for validating tokens.
func (k *Kite) TrustKontrolKey(issuer, key string) {
	k.trustedKontrolKeys[issuer] = key
}

func (k *Kite) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	k.httpHandler.ServeHTTP(w, req)
}

func (k *Kite) sockjsHandler(session sockjs.Session) {
	defer session.Close(0, "")

	// This Client also handles the connected client.
	// Since both sides can send/receive messages the client code is reused here.
	c := k.NewClient("")
	c.session = session

	k.callOnConnectHandlers(c)

	// Run after methods are registered and delegate is set
	c.readLoop()

	c.callOnDisconnectHandlers()
	k.callOnDisconnectHandlers(c)
}

func (k *Kite) OnConnect(handler func(*Client)) {
	k.onConnectHandlers = append(k.onConnectHandlers, handler)
}

// OnFirstRequest registers a function to run when a Kite connects to this Kite.
func (k *Kite) OnFirstRequest(handler func(*Client)) {
	k.onFirstRequestHandlers = append(k.onFirstRequestHandlers, handler)
}

// OnDisconnect registers a function to run when a connected Kite is disconnected.
func (k *Kite) OnDisconnect(handler func(*Client)) {
	k.onDisconnectHandlers = append(k.onDisconnectHandlers, handler)
}

func (k *Kite) callOnConnectHandlers(c *Client) {
	for _, handler := range k.onConnectHandlers {
		handler(c)
	}
}

func (k *Kite) callOnFirstRequestHandlers(c *Client) {
	for _, handler := range k.onFirstRequestHandlers {
		handler(c)
	}
}

func (k *Kite) callOnDisconnectHandlers(c *Client) {
	for _, handler := range k.onDisconnectHandlers {
		handler(c)
	}
}

// RSAKey returns the corresponding public key for the issuer of the token.
// It is called by jwt-go package when validating the signature in the token.
func (k *Kite) RSAKey(token *jwt.Token) ([]byte, error) {
	if k.Config.KontrolKey == "" {
		panic("kontrol key is not set in config")
	}

	issuer, ok := token.Claims["iss"].(string)
	if !ok {
		return nil, errors.New("token does not contain a valid issuer claim")
	}

	if issuer != k.Config.KontrolUser {
		return nil, fmt.Errorf("issuer is not trusted: %s", issuer)
	}

	return []byte(k.Config.KontrolKey), nil
}
<commit_msg>kite: disable new session logs, make them debug<commit_after>// Package kite is a library for creating micro-services.  Two main types
// implemented by this package are Kite for creating a micro-service server
// called "Kite" and Client for communicating with another kites.
package kite

import (
	"crypto/tls"
	"errors"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"os"
	"strings"

	"github.com/dgrijalva/jwt-go"
	"github.com/koding/kite/config"
	"github.com/koding/kite/protocol"
	"github.com/nu7hatch/gouuid"
	"gopkg.in/igm/sockjs-go.v2/sockjs"
)

var hostname string

func init() {
	var err error
	hostname, err = os.Hostname()
	if err != nil {
		panic(fmt.Sprintf("kite: cannot get hostname: %s", err.Error()))
	}
}

// Kite defines a single process that enables distributed service messaging
// amongst the peers it is connected. A Kite process acts as a Client and as a
// Server. That means it can receive request, process them, but it also can
// make request to other kites.
//
// Do not use this struct directly. Use kite.New function, add your handlers
// with HandleFunc mehtod, then call Run method to start the inbuilt server (or
// pass it to any http.Handler compatible server)
type Kite struct {
	Config *config.Config

	// Log logs with the given Logger interface
	Log Logger

	// SetLogLevel changes the level of the logger. Default is INFO.
	SetLogLevel func(Level)

	// Contains different functions for authenticating user from request.
	// Keys are the authentication types (options.auth.type).
	Authenticators map[string]func(*Request) error

	// Kontrol keys to trust. Kontrol will issue access tokens for kites
	// that are signed with the private counterpart of these keys.
	// Key data must be PEM encoded.
	trustedKontrolKeys map[string]string

	// Handlers added with Kite.HandleFunc().
	handlers     map[string]*Method // method map for exported methods
	preHandlers  []Handler          // a list of handlers that are executed before any handler
	postHandlers []Handler          // a list of handlers that are executed after any handler

	// MethodHandling defines how the kite is returning the response for
	// multiple handlers
	MethodHandling MethodHandling

	httpHandler http.Handler

	// kontrolclient is used to register to kontrol and query third party kites
	// from kontrol
	kontrol *kontrolClient

	// Handlers to call when a new connection is received.
	onConnectHandlers []func(*Client)

	// Handlers to call before the first request of connected kite.
	onFirstRequestHandlers []func(*Client)

	// Handlers to call when a client has disconnected.
	onDisconnectHandlers []func(*Client)

	// server fields, are initialized and used when
	// TODO: move them to their own struct, just like KontrolClient
	listener  net.Listener
	TLSConfig *tls.Config
	readyC    chan bool // To signal when kite is ready to accept connections
	closeC    chan bool // To signal when kite is closed with Close()

	name    string
	version string
	Id      string // Unique kite instance id
}

// New creates, initialize and then returns a new Kite instance. Version must
// be in 3-digit semantic form. Name is important that it's also used to be
// searched by others.
func New(name, version string) *Kite {
	if name == "" {
		panic("kite: name cannot be empty")
	}

	if digits := strings.Split(version, "."); len(digits) != 3 {
		panic("kite: version must be 3-digits semantic version")
	}

	kiteID, err := uuid.NewV4()
	if err != nil {
		panic(fmt.Sprintf("kite: cannot generate unique ID: %s", err.Error()))
	}

	l, setlevel := newLogger(name)

	kClient := &kontrolClient{
		readyConnected:  make(chan struct{}),
		readyRegistered: make(chan struct{}),
		registerChan:    make(chan *url.URL, 1),
	}

	k := &Kite{
		Config:             config.New(),
		Log:                l,
		SetLogLevel:        setlevel,
		Authenticators:     make(map[string]func(*Request) error),
		trustedKontrolKeys: make(map[string]string),
		handlers:           make(map[string]*Method),
		preHandlers:        make([]Handler, 0),
		postHandlers:       make([]Handler, 0),
		kontrol:            kClient,
		name:               name,
		version:            version,
		Id:                 kiteID.String(),
		readyC:             make(chan bool),
		closeC:             make(chan bool),
	}

	k.httpHandler = sockjs.NewHandler("/kite", sockjs.DefaultOptions, k.sockjsHandler)

	// Add useful debug logs
	k.OnConnect(func(c *Client) { k.Log.Debug("New session: %s", c.session.ID()) })
	k.OnFirstRequest(func(c *Client) { k.Log.Debug("Session %q is identified as %q", c.session.ID(), c.Kite) })
	k.OnDisconnect(func(c *Client) { k.Log.Debug("Kite has disconnected: %q", c.Kite) })

	// Every kite should be able to authenticate the user from token.
	// Tokens are granted by Kontrol Kite.
	k.Authenticators["token"] = k.AuthenticateFromToken

	// A kite accepts requests with the same username.
	k.Authenticators["kiteKey"] = k.AuthenticateFromKiteKey

	// Register default methods.
	k.addDefaultHandlers()

	return k
}

// Kite returns the definition of the kite.
func (k *Kite) Kite() *protocol.Kite {
	return &protocol.Kite{
		Username:    k.Config.Username,
		Environment: k.Config.Environment,
		Name:        k.name,
		Version:     k.version,
		Region:      k.Config.Region,
		Hostname:    hostname,
		ID:          k.Id,
	}
}

// Trust a Kontrol key for validating tokens.
func (k *Kite) TrustKontrolKey(issuer, key string) {
	k.trustedKontrolKeys[issuer] = key
}

func (k *Kite) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	k.httpHandler.ServeHTTP(w, req)
}

func (k *Kite) sockjsHandler(session sockjs.Session) {
	defer session.Close(0, "")

	// This Client also handles the connected client.
	// Since both sides can send/receive messages the client code is reused here.
	c := k.NewClient("")
	c.session = session

	k.callOnConnectHandlers(c)

	// Run after methods are registered and delegate is set
	c.readLoop()

	c.callOnDisconnectHandlers()
	k.callOnDisconnectHandlers(c)
}

func (k *Kite) OnConnect(handler func(*Client)) {
	k.onConnectHandlers = append(k.onConnectHandlers, handler)
}

// OnFirstRequest registers a function to run when a Kite connects to this Kite.
func (k *Kite) OnFirstRequest(handler func(*Client)) {
	k.onFirstRequestHandlers = append(k.onFirstRequestHandlers, handler)
}

// OnDisconnect registers a function to run when a connected Kite is disconnected.
func (k *Kite) OnDisconnect(handler func(*Client)) {
	k.onDisconnectHandlers = append(k.onDisconnectHandlers, handler)
}

func (k *Kite) callOnConnectHandlers(c *Client) {
	for _, handler := range k.onConnectHandlers {
		handler(c)
	}
}

func (k *Kite) callOnFirstRequestHandlers(c *Client) {
	for _, handler := range k.onFirstRequestHandlers {
		handler(c)
	}
}

func (k *Kite) callOnDisconnectHandlers(c *Client) {
	for _, handler := range k.onDisconnectHandlers {
		handler(c)
	}
}

// RSAKey returns the corresponding public key for the issuer of the token.
// It is called by jwt-go package when validating the signature in the token.
func (k *Kite) RSAKey(token *jwt.Token) ([]byte, error) {
	if k.Config.KontrolKey == "" {
		panic("kontrol key is not set in config")
	}

	issuer, ok := token.Claims["iss"].(string)
	if !ok {
		return nil, errors.New("token does not contain a valid issuer claim")
	}

	if issuer != k.Config.KontrolUser {
		return nil, fmt.Errorf("issuer is not trusted: %s", issuer)
	}

	return []byte(k.Config.KontrolKey), nil
}
<|endoftext|>


<commit_before>package users

import (
	"net/http"

	"github.com/muesli/polly/api/db"
	"github.com/muesli/polly/api/utils"

	"github.com/emicklei/go-restful"
	"github.com/muesli/smolder"
)

// UserPostStruct holds all values of an incoming POST request
type UserPostStruct struct {
	User struct {
		Email string `json:"email"`
	} `json:"user"`
}

// PostAuthRequired returns true because all requests need authentication
func (r *UserResource) PostAuthRequired() bool {
	return true
}

// PostDoc returns the description of this API endpoint
func (r *UserResource) PostDoc() string {
	return "create a new user invitation"
}

// PostParams returns the parameters supported by this API endpoint
func (r *UserResource) PostParams() []*restful.Parameter {
	return nil
}

// Post processes an incoming POST (create) request
func (r *UserResource) Post(context smolder.APIContext, request *restful.Request, response *restful.Response) {
	auth, err := context.Authentication(request)
	if err != nil || auth.(db.User).ID != 1 {
		smolder.ErrorResponseHandler(request, response, smolder.NewErrorResponse(
			http.StatusUnauthorized,
			false,
			"Admin permission required for this operation",
			"UserResource POST"))
		return
	}

	ups := UserPostStruct{}
	err = request.ReadEntity(&ups)
	if err != nil {
		smolder.ErrorResponseHandler(request, response, smolder.NewErrorResponse(
			http.StatusBadRequest,
			false,
			"Can't parse POST data",
			"UserResource POST"))
		return
	}

	user := db.User{
		Username: ups.User.Email,
		Email:    ups.User.Email,
	}
	err = user.Save(context.(*db.PollyContext))
	if err != nil {
		smolder.ErrorResponseHandler(request, response, smolder.NewErrorResponse(
			http.StatusInternalServerError,
			true,
			"Can't create user",
			"UserResource POST"))
		return
	}

	utils.SendInvitation(&user)

	resp := UserResponse{}
	resp.Init(context)
	resp.AddUser(&user)
	resp.Send(response)
}
<commit_msg>Receive and insert about field in UserResource<commit_after>package users

import (
	"net/http"

	"github.com/muesli/polly/api/db"
	"github.com/muesli/polly/api/utils"

	"github.com/emicklei/go-restful"
	"github.com/muesli/smolder"
)

// UserPostStruct holds all values of an incoming POST request
type UserPostStruct struct {
	User struct {
		Email string `json:"email"`
		About string `json:"about"`
	} `json:"user"`
}

// PostAuthRequired returns true because all requests need authentication
func (r *UserResource) PostAuthRequired() bool {
	return true
}

// PostDoc returns the description of this API endpoint
func (r *UserResource) PostDoc() string {
	return "create a new user invitation"
}

// PostParams returns the parameters supported by this API endpoint
func (r *UserResource) PostParams() []*restful.Parameter {
	return nil
}

// Post processes an incoming POST (create) request
func (r *UserResource) Post(context smolder.APIContext, request *restful.Request, response *restful.Response) {
	auth, err := context.Authentication(request)
	if err != nil || auth.(db.User).ID != 1 {
		smolder.ErrorResponseHandler(request, response, smolder.NewErrorResponse(
			http.StatusUnauthorized,
			false,
			"Admin permission required for this operation",
			"UserResource POST"))
		return
	}

	ups := UserPostStruct{}
	err = request.ReadEntity(&ups)
	if err != nil {
		smolder.ErrorResponseHandler(request, response, smolder.NewErrorResponse(
			http.StatusBadRequest,
			false,
			"Can't parse POST data",
			"UserResource POST"))
		return
	}

	if ups.User.About == "" {
		ups.User.About = ups.User.Email
	}

	user := db.User{
		Username: ups.User.Email,
		Email:    ups.User.Email,
		About:    ups.User.About,
	}
	err = user.Save(context.(*db.PollyContext))
	if err != nil {
		smolder.ErrorResponseHandler(request, response, smolder.NewErrorResponse(
			http.StatusInternalServerError,
			true,
			"Can't create user",
			"UserResource POST"))
		return
	}

	utils.SendInvitation(&user)

	resp := UserResponse{}
	resp.Init(context)
	resp.AddUser(&user)
	resp.Send(response)
}
<|endoftext|>


<commit_before>package bban

import (
	"testing"

	"github.com/stretchr/testify/require"
)

var (
	charTypeTests = []struct {
		in       string
		charType charType
		want     bool
	}{
		{"0123", Num, true},
		{"AB23", Num, false},
		{"AB", Num, false},
		{"", Num, false},
		{"DSA", AlphaUpper, true},
		{"dsa", AlphaUpper, false},
		{"32", AlphaUpper, false},
		{"", AlphaUpper, false},
		{"AB2", AlphaNum, true},
		{"AB", AlphaNum, true},
		{"", AlphaNum, false},
	}
	partTests = []struct {
		length    int
		entryType EntryType
		charType  charType
		val       string
		want      bool
	}{
		{4, BankCode, Num, "213", true},
		{5, BranchCode, AlphaNum, "213", true},
		{8, AccountNumber, AlphaUpper, "213", false},
		{4, NationalCheckDigit, Num, "213", true},
		{3, AccountType, AlphaNum, "213", true},
		{1, OwnerAccountType, AlphaUpper, "ABCD", true},
		{2, IdentificationNumber, Num, "213", true},
	}
	newPartTests = []struct {
		new  func(length int, char charType) Part
		want EntryType
	}{
		{NewBankCode, BankCode},
		{NewBranchCode, BranchCode},
		{NewAccountNumber, AccountNumber},
		{NewNationalCheckDigit, NationalCheckDigit},
		{NewAccountType, AccountType},
		{NewOwnerAccountType, OwnerAccountType},
		{NewIdentificationNumber, IdentificationNumber},
	}
)

func TestCharTypeValidate(t *testing.T) {
	for _, tc := range charTypeTests {
		t.Run(tc.in, func(t *testing.T) {
			result := tc.charType.Validate(tc.in)
			require.Equal(t, tc.want, result)
		})
	}
}

func TestPartValidate(t *testing.T) {
	for _, tc := range partTests {
		t.Run(tc.val, func(t *testing.T) {
			part := NewPart(tc.length, tc.charType, tc.entryType)
			result := part.Validate(tc.val)
			require.Equal(t, tc.want, result)
		})
	}
}

func TestNewPart(t *testing.T) {
	for _, tc := range newPartTests {
		t.Run(tc.want.String(), func(t *testing.T) {
			part := tc.new(4, Num)
			require.Equal(t, tc.want, part.EntryType)
			require.Equal(t, part.String(), part.EntryType.String())
		})
	}
}

func TestPartString(t *testing.T) {
	for _, tc := range newPartTests {
		t.Run(tc.want.String(), func(t *testing.T) {
			part := tc.new(3, AlphaNum)
			require.Equal(t, part.String(), part.EntryType.String())
		})
	}
}

func TestStructureLength(t *testing.T) {
	st1 := NewStructure()
	require.Equal(t, 0, st1.Length())

	st2 := NewStructure(Part{Length: 2}, Part{Length: 4})
	require.Equal(t, 6, st2.Length())
}
<commit_msg>Add test for Currency part.<commit_after>package bban

import (
	"testing"

	"github.com/stretchr/testify/require"
)

var (
	charTypeTests = []struct {
		in       string
		charType charType
		want     bool
	}{
		{"0123", Num, true},
		{"AB23", Num, false},
		{"AB", Num, false},
		{"", Num, false},
		{"DSA", AlphaUpper, true},
		{"dsa", AlphaUpper, false},
		{"32", AlphaUpper, false},
		{"", AlphaUpper, false},
		{"AB2", AlphaNum, true},
		{"AB", AlphaNum, true},
		{"", AlphaNum, false},
	}
	partTests = []struct {
		length    int
		entryType EntryType
		charType  charType
		val       string
		want      bool
	}{
		{4, BankCode, Num, "213", true},
		{5, BranchCode, AlphaNum, "213", true},
		{8, AccountNumber, AlphaUpper, "213", false},
		{4, NationalCheckDigit, Num, "213", true},
		{3, AccountType, AlphaNum, "213", true},
		{1, OwnerAccountType, AlphaUpper, "ABCD", true},
		{2, IdentificationNumber, Num, "213", true},
		{3, Currency, AlphaUpper, "MUR", true},
	}
	newPartTests = []struct {
		new  func(length int, char charType) Part
		want EntryType
	}{
		{NewBankCode, BankCode},
		{NewBranchCode, BranchCode},
		{NewAccountNumber, AccountNumber},
		{NewNationalCheckDigit, NationalCheckDigit},
		{NewAccountType, AccountType},
		{NewOwnerAccountType, OwnerAccountType},
		{NewIdentificationNumber, IdentificationNumber},
		{NewCurrency, Currency},
	}
)

func TestCharTypeValidate(t *testing.T) {
	for _, tc := range charTypeTests {
		t.Run(tc.in, func(t *testing.T) {
			result := tc.charType.Validate(tc.in)
			require.Equal(t, tc.want, result)
		})
	}
}

func TestPartValidate(t *testing.T) {
	for _, tc := range partTests {
		t.Run(tc.val, func(t *testing.T) {
			part := NewPart(tc.length, tc.charType, tc.entryType)
			result := part.Validate(tc.val)
			require.Equal(t, tc.want, result)
		})
	}
}

func TestNewPart(t *testing.T) {
	for _, tc := range newPartTests {
		t.Run(tc.want.String(), func(t *testing.T) {
			part := tc.new(4, Num)
			require.Equal(t, tc.want, part.EntryType)
			require.Equal(t, part.String(), part.EntryType.String())
		})
	}
}

func TestPartString(t *testing.T) {
	for _, tc := range newPartTests {
		t.Run(tc.want.String(), func(t *testing.T) {
			part := tc.new(3, AlphaNum)
			require.Equal(t, part.String(), part.EntryType.String())
		})
	}
}

func TestStructureLength(t *testing.T) {
	st1 := NewStructure()
	require.Equal(t, 0, st1.Length())

	st2 := NewStructure(Part{Length: 2}, Part{Length: 4})
	require.Equal(t, 6, st2.Length())
}
<|endoftext|>