<commit_before>// Copyright (c) 2013-2017 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package service

import (
	"context"
	"errors"
	//"fmt"

	"github.com/btcboost/copernicus/log"
	"github.com/btcboost/copernicus/model/block"
	"github.com/btcboost/copernicus/model/tx"
	"github.com/btcboost/copernicus/rpc/btcjson"
	//"github.com/btcboost/copernicus/model/block"
	//"github.com/btcboost/copernicus/model/tx"
	"github.com/btcboost/copernicus/net/server"
	"github.com/btcboost/copernicus/net/wire"
	"github.com/btcboost/copernicus/peer"
	//"github.com/btcboost/copernicus/util"
	//"github.com/btcboost/copernicus/internal/btcjson"
)

type MsgHandle struct {
	recvFromNet <-chan *peer.PeerMessage
	server      *server.Server
}

var msgHandle *MsgHandle

// NewMsgHandle create a msgHandle for these message from peer And RPC.
// Then begins the core block handler which processes block and inv messages.
func NewMsgHandle(ctx context.Context, cmdCh <-chan *peer.PeerMessage, server *server.Server) {
	msg := &MsgHandle{recvFromNet: cmdCh}
	msg.server = server
	ctxChild, _ := context.WithCancel(ctx)
	go msg.startProcess(ctxChild)
	msgHandle = msg
}

func (mh *MsgHandle) startProcess(ctx context.Context) {

out:
	for {
		select {
		case msg := <-mh.recvFromNet:
			peerFrom := msg.Peerp
			switch data := msg.Msg.(type) {
			case *wire.MsgVersion:
				peerFrom.PushRejectMsg(data.Command(), wire.RejectDuplicate, "duplicate version message",
					nil, false)
				break out
			case *wire.MsgVerAck:
				if peerFrom.VerAckReceived() {
					log.Info("Already received 'verack' from peer %v -- "+
						"disconnecting", peerFrom)
					break out
				}
				peerFrom.SetAckReceived(true)
				if peerFrom.Cfg.Listeners.OnVerAck != nil {
					peerFrom.Cfg.Listeners.OnVerAck(peerFrom, data)
				}
			case *wire.MsgGetAddr:
				if peerFrom.Cfg.Listeners.OnGetAddr != nil {
					peerFrom.Cfg.Listeners.OnGetAddr(peerFrom, data)
				}
			case *wire.MsgAddr:
				if peerFrom.Cfg.Listeners.OnAddr != nil {
					peerFrom.Cfg.Listeners.OnAddr(peerFrom, data)
				}
			case *wire.MsgPing:
				peerFrom.HandlePingMsg(data)
				if peerFrom.Cfg.Listeners.OnPing != nil {
					peerFrom.Cfg.Listeners.OnPing(peerFrom, data)
				}
			case *wire.MsgPong:
				peerFrom.HandlePongMsg(data)
				if peerFrom.Cfg.Listeners.OnPong != nil {
					peerFrom.Cfg.Listeners.OnPong(peerFrom, data)
				}
			case *wire.MsgAlert:
				if peerFrom.Cfg.Listeners.OnAlert != nil {
					peerFrom.Cfg.Listeners.OnAlert(peerFrom, data)
				}
			case *wire.MsgMemPool:
				if peerFrom.Cfg.Listeners.OnMemPool != nil {
					peerFrom.Cfg.Listeners.OnMemPool(peerFrom, data)
				}
			case *wire.MsgTx:
				if peerFrom.Cfg.Listeners.OnTx != nil {
					peerFrom.Cfg.Listeners.OnTx(peerFrom, data)
				}
			case *wire.MsgBlock:
				if peerFrom.Cfg.Listeners.OnBlock != nil {
					peerFrom.Cfg.Listeners.OnBlock(peerFrom, data, msg.Buf)
				}
			case *wire.MsgInv:
				if peerFrom.Cfg.Listeners.OnInv != nil {
					peerFrom.Cfg.Listeners.OnInv(peerFrom, data)
				}
			case *wire.MsgHeaders:
				if peerFrom.Cfg.Listeners.OnHeaders != nil {
					peerFrom.Cfg.Listeners.OnHeaders(peerFrom, data)
				}
			case *wire.MsgNotFound:
				if peerFrom.Cfg.Listeners.OnNotFound != nil {
					peerFrom.Cfg.Listeners.OnNotFound(peerFrom, data)
				}
			case *wire.MsgGetData:
				if peerFrom.Cfg.Listeners.OnGetData != nil {
					peerFrom.Cfg.Listeners.OnGetData(peerFrom, data)
				}
			case *wire.MsgGetBlocks:
				if peerFrom.Cfg.Listeners.OnGetBlocks != nil {
					peerFrom.Cfg.Listeners.OnGetBlocks(peerFrom, data)
				}
			case *wire.MsgGetHeaders:
				if peerFrom.Cfg.Listeners.OnGetHeaders != nil {
					peerFrom.Cfg.Listeners.OnGetHeaders(peerFrom, data)
				}
			case *wire.MsgFeeFilter:
				if peerFrom.Cfg.Listeners.OnFeeFilter != nil {
					peerFrom.Cfg.Listeners.OnFeeFilter(peerFrom, data)
				}
			case *wire.MsgFilterAdd:
				if peerFrom.Cfg.Listeners.OnFilterAdd != nil {
					peerFrom.Cfg.Listeners.OnFilterAdd(peerFrom, data)
				}
			case *wire.MsgFilterClear:
				if peerFrom.Cfg.Listeners.OnFilterClear != nil {
					peerFrom.Cfg.Listeners.OnFilterClear(peerFrom, data)
				}
			case *wire.MsgFilterLoad:
				if peerFrom.Cfg.Listeners.OnFilterLoad != nil {
					peerFrom.Cfg.Listeners.OnFilterLoad(peerFrom, data)
				}
			case *wire.MsgMerkleBlock:
				if peerFrom.Cfg.Listeners.OnMerkleBlock != nil {
					peerFrom.Cfg.Listeners.OnMerkleBlock(peerFrom, data)
				}
			case *wire.MsgReject:
				if peerFrom.Cfg.Listeners.OnReject != nil {
					peerFrom.Cfg.Listeners.OnReject(peerFrom, data)
				}
			case *wire.MsgSendHeaders:
				if peerFrom.Cfg.Listeners.OnSendHeaders != nil {
					peerFrom.Cfg.Listeners.OnSendHeaders(peerFrom, data)
				}
			default:
				log.Debug("Received unhandled message of type %v "+
					"from %v", data.Command())
			}
		case <-ctx.Done():
			log.Info("msgHandle service exit. function : startProcess")
			break out
		}
	}

}

// Rpc process things
func ProcessForRpc(message interface{}) (rsp interface{}, err error) {
	switch m := message.(type) {

	case *GetConnectionCountRequest:
		return msgHandle.server.ConnectedCount(), nil

	case *wire.MsgPing:
		return msgHandle.server.BroadcastMessage(), nil

	case *GetPeersInfoRequest:
		return nil, nil

	case *btcjson.AddNodeCmd:
		err = msgHandle.NodeOpera(m)
		return

	case *btcjson.DisconnectNodeCmd:
		return

	case *btcjson.GetAddedNodeInfoCmd:
		return msgHandle.connManager.PersistentPeers(), nil

	case *GetNetTotalsRequest:
		return

	case *btcjson.GetNetworkInfoCmd:
		return

	case *btcjson.SetBanCmd:
		return

	case *ListBannedRequest:
		return

	case *ClearBannedRequest:
		return

	case *wire.InvVect:
		// todo
		return

	case *tx.Tx:
		msgHandle.recvChannel <- m
		ret := <-msgHandle.resultChannel
		switch r := ret.(type) {
		case error:
			return nil, r
		case []*tx.Tx:
			return r, nil
		}

	case *block.Block:
		msgHandle.recvChannel <- m
		ret := <-msgHandle.resultChannel
		switch r := ret.(type) {
		case error:
			return nil, r
		case BlockState:
			return r, nil
		}

	}

	return nil, errors.New("unknown rpc request")
}
<commit_msg>remove service rpc<commit_after>// Copyright (c) 2013-2017 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package service

import (
	"context"
	"errors"
	//"fmt"

	"github.com/btcboost/copernicus/log"
	//"github.com/btcboost/copernicus/model/block"
	//"github.com/btcboost/copernicus/model/tx"
	"github.com/btcboost/copernicus/net/server"
	"github.com/btcboost/copernicus/net/wire"
	"github.com/btcboost/copernicus/peer"
	//"github.com/btcboost/copernicus/util"
	//"github.com/btcboost/copernicus/internal/btcjson"
)

type MsgHandle struct {
	recvFromNet <-chan *peer.PeerMessage
	server      *server.Server
}

var msgHandle *MsgHandle

// NewMsgHandle create a msgHandle for these message from peer And RPC.
// Then begins the core block handler which processes block and inv messages.
func NewMsgHandle(ctx context.Context, cmdCh <-chan *peer.PeerMessage, server *server.Server) {
	msg := &MsgHandle{recvFromNet: cmdCh}
	msg.server = server
	ctxChild, _ := context.WithCancel(ctx)
	go msg.startProcess(ctxChild)
	msgHandle = msg
}

func (mh *MsgHandle) startProcess(ctx context.Context) {

out:
	for {
		select {
		case msg := <-mh.recvFromNet:
			peerFrom := msg.Peerp
			switch data := msg.Msg.(type) {
			case *wire.MsgVersion:
				peerFrom.PushRejectMsg(data.Command(), wire.RejectDuplicate, "duplicate version message",
					nil, false)
				break out
			case *wire.MsgVerAck:
				if peerFrom.VerAckReceived() {
					log.Info("Already received 'verack' from peer %v -- "+
						"disconnecting", peerFrom)
					break out
				}
				peerFrom.SetAckReceived(true)
				if peerFrom.Cfg.Listeners.OnVerAck != nil {
					peerFrom.Cfg.Listeners.OnVerAck(peerFrom, data)
				}
			case *wire.MsgGetAddr:
				if peerFrom.Cfg.Listeners.OnGetAddr != nil {
					peerFrom.Cfg.Listeners.OnGetAddr(peerFrom, data)
				}
			case *wire.MsgAddr:
				if peerFrom.Cfg.Listeners.OnAddr != nil {
					peerFrom.Cfg.Listeners.OnAddr(peerFrom, data)
				}
			case *wire.MsgPing:
				peerFrom.HandlePingMsg(data)
				if peerFrom.Cfg.Listeners.OnPing != nil {
					peerFrom.Cfg.Listeners.OnPing(peerFrom, data)
				}
			case *wire.MsgPong:
				peerFrom.HandlePongMsg(data)
				if peerFrom.Cfg.Listeners.OnPong != nil {
					peerFrom.Cfg.Listeners.OnPong(peerFrom, data)
				}
			case *wire.MsgAlert:
				if peerFrom.Cfg.Listeners.OnAlert != nil {
					peerFrom.Cfg.Listeners.OnAlert(peerFrom, data)
				}
			case *wire.MsgMemPool:
				if peerFrom.Cfg.Listeners.OnMemPool != nil {
					peerFrom.Cfg.Listeners.OnMemPool(peerFrom, data)
				}
			case *wire.MsgTx:
				if peerFrom.Cfg.Listeners.OnTx != nil {
					peerFrom.Cfg.Listeners.OnTx(peerFrom, data)
				}
			case *wire.MsgBlock:
				if peerFrom.Cfg.Listeners.OnBlock != nil {
					peerFrom.Cfg.Listeners.OnBlock(peerFrom, data, msg.Buf)
				}
			case *wire.MsgInv:
				if peerFrom.Cfg.Listeners.OnInv != nil {
					peerFrom.Cfg.Listeners.OnInv(peerFrom, data)
				}
			case *wire.MsgHeaders:
				if peerFrom.Cfg.Listeners.OnHeaders != nil {
					peerFrom.Cfg.Listeners.OnHeaders(peerFrom, data)
				}
			case *wire.MsgNotFound:
				if peerFrom.Cfg.Listeners.OnNotFound != nil {
					peerFrom.Cfg.Listeners.OnNotFound(peerFrom, data)
				}
			case *wire.MsgGetData:
				if peerFrom.Cfg.Listeners.OnGetData != nil {
					peerFrom.Cfg.Listeners.OnGetData(peerFrom, data)
				}
			case *wire.MsgGetBlocks:
				if peerFrom.Cfg.Listeners.OnGetBlocks != nil {
					peerFrom.Cfg.Listeners.OnGetBlocks(peerFrom, data)
				}
			case *wire.MsgGetHeaders:
				if peerFrom.Cfg.Listeners.OnGetHeaders != nil {
					peerFrom.Cfg.Listeners.OnGetHeaders(peerFrom, data)
				}
			case *wire.MsgFeeFilter:
				if peerFrom.Cfg.Listeners.OnFeeFilter != nil {
					peerFrom.Cfg.Listeners.OnFeeFilter(peerFrom, data)
				}
			case *wire.MsgFilterAdd:
				if peerFrom.Cfg.Listeners.OnFilterAdd != nil {
					peerFrom.Cfg.Listeners.OnFilterAdd(peerFrom, data)
				}
			case *wire.MsgFilterClear:
				if peerFrom.Cfg.Listeners.OnFilterClear != nil {
					peerFrom.Cfg.Listeners.OnFilterClear(peerFrom, data)
				}
			case *wire.MsgFilterLoad:
				if peerFrom.Cfg.Listeners.OnFilterLoad != nil {
					peerFrom.Cfg.Listeners.OnFilterLoad(peerFrom, data)
				}
			case *wire.MsgMerkleBlock:
				if peerFrom.Cfg.Listeners.OnMerkleBlock != nil {
					peerFrom.Cfg.Listeners.OnMerkleBlock(peerFrom, data)
				}
			case *wire.MsgReject:
				if peerFrom.Cfg.Listeners.OnReject != nil {
					peerFrom.Cfg.Listeners.OnReject(peerFrom, data)
				}
			case *wire.MsgSendHeaders:
				if peerFrom.Cfg.Listeners.OnSendHeaders != nil {
					peerFrom.Cfg.Listeners.OnSendHeaders(peerFrom, data)
				}
			default:
				log.Debug("Received unhandled message of type %v "+
					"from %v", data.Command())
			}
		case <-ctx.Done():
			log.Info("msgHandle service exit. function : startProcess")
			break out
		}
	}

}

// Rpc process things
func ProcessForRpc(message interface{}) (rsp interface{}, err error) {
	// switch m := message.(type) {
	//
	// case *GetConnectionCountRequest:
	// 	return msgHandle.server.ConnectedCount(), nil
	//
	// case *wire.MsgPing:
	// 	return msgHandle.server.BroadcastMessage(), nil
	//
	// case *GetPeersInfoRequest:
	// 	return nil, nil
	//
	// case *btcjson.AddNodeCmd:
	// 	err = msgHandle.NodeOpera(m)
	// 	return
	//
	// case *btcjson.DisconnectNodeCmd:
	// 	return
	//
	// case *btcjson.GetAddedNodeInfoCmd:
	// 	return msgHandle.connManager.PersistentPeers(), nil
	//
	// case *GetNetTotalsRequest:
	// 	return
	//
	// case *btcjson.GetNetworkInfoCmd:
	// 	return
	//
	// case *btcjson.SetBanCmd:
	// 	return
	//
	// case *ListBannedRequest:
	// 	return
	//
	// case *ClearBannedRequest:
	// 	return
	//
	// case *wire.InvVect:
	// 	// todo
	// 	return
	//
	// case *tx.Tx:
	// 	msgHandle.recvChannel <- m
	// 	ret := <-msgHandle.resultChannel
	// 	switch r := ret.(type) {
	// 	case error:
	// 		return nil, r
	// 	case []*tx.Tx:
	// 		return r, nil
	// 	}
	//
	// case *block.Block:
	// 	msgHandle.recvChannel <- m
	// 	ret := <-msgHandle.resultChannel
	// 	switch r := ret.(type) {
	// 	case error:
	// 		return nil, r
	// 	case BlockState:
	// 		return r, nil
	// 	}
	//
	// }

	return nil, errors.New("unknown rpc request")
}
<|endoftext|>


<commit_before>package kubernetes

import (
	"context"
	"fmt"
	"log"
	"time"

	"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
	"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
	batchv1 "k8s.io/api/batch/v1"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	pkgApi "k8s.io/apimachinery/pkg/types"
	"k8s.io/client-go/kubernetes"
)

func resourceKubernetesJob() *schema.Resource {
	return &schema.Resource{
		Create: resourceKubernetesJobCreate,
		Read:   resourceKubernetesJobRead,
		Update: resourceKubernetesJobUpdate,
		Delete: resourceKubernetesJobDelete,
		Exists: resourceKubernetesJobExists,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Timeouts: &schema.ResourceTimeout{
			Create: schema.DefaultTimeout(1 * time.Minute),
			Update: schema.DefaultTimeout(1 * time.Minute),
			Delete: schema.DefaultTimeout(1 * time.Minute),
		},

		Schema: map[string]*schema.Schema{
			"metadata": jobMetadataSchema(),
			"spec": {
				Type:        schema.TypeList,
				Description: "Spec of the job owned by the cluster",
				Required:    true,
				MaxItems:    1,
				ForceNew:    true,
				Elem: &schema.Resource{
					Schema: jobSpecFields(),
				},
			},
			"wait_for_completion": {
				Type:     schema.TypeBool,
				Optional: true,
			},
		},
	}
}

func resourceKubernetesJobCreate(d *schema.ResourceData, meta interface{}) error {
	conn, err := meta.(KubeClientsets).MainClientset()
	if err != nil {
		return err
	}
	ctx := context.TODO()

	metadata := expandMetadata(d.Get("metadata").([]interface{}))
	spec, err := expandJobSpec(d.Get("spec").([]interface{}))
	if err != nil {
		return err
	}

	job := batchv1.Job{
		ObjectMeta: metadata,
		Spec:       spec,
	}

	log.Printf("[INFO] Creating new Job: %#v", job)

	out, err := conn.BatchV1().Jobs(metadata.Namespace).Create(ctx, &job, metav1.CreateOptions{})
	if err != nil {
		return fmt.Errorf("Failed to create Job! API error: %s", err)
	}
	log.Printf("[INFO] Submitted new job: %#v", out)

	d.SetId(buildId(out.ObjectMeta))

	namespace, name, err := idParts(d.Id())
	if err != nil {
		return err
	}
	if d.Get("wait_for_completion").(bool) {
		return resource.Retry(d.Timeout(schema.TimeoutCreate),
			retryUntilJobIsFinished(ctx, conn, namespace, name))
	}

	return resourceKubernetesJobRead(d, meta)
}

func resourceKubernetesJobUpdate(d *schema.ResourceData, meta interface{}) error {
	conn, err := meta.(KubeClientsets).MainClientset()
	if err != nil {
		return err
	}
	ctx := context.TODO()

	namespace, name, err := idParts(d.Id())
	if err != nil {
		return err
	}

	ops := patchMetadata("metadata.0.", "/metadata/", d)

	data, err := ops.MarshalJSON()
	if err != nil {
		return fmt.Errorf("Failed to marshal update operations: %s", err)
	}

	log.Printf("[INFO] Updating job %s: %#v", d.Id(), ops)

	out, err := conn.BatchV1().Jobs(namespace).Patch(ctx, name, pkgApi.JSONPatchType, data, metav1.PatchOptions{})
	if err != nil {
		return fmt.Errorf("Failed to update Job! API error: %s", err)
	}
	log.Printf("[INFO] Submitted updated job: %#v", out)

	d.SetId(buildId(out.ObjectMeta))

	if d.Get("wait_for_completion").(bool) {
		return resource.Retry(d.Timeout(schema.TimeoutUpdate),
			retryUntilJobIsFinished(ctx, conn, namespace, name))
	}
	return resourceKubernetesJobRead(d, meta)
}

func resourceKubernetesJobRead(d *schema.ResourceData, meta interface{}) error {
	conn, err := meta.(KubeClientsets).MainClientset()
	if err != nil {
		return err
	}
	ctx := context.TODO()

	namespace, name, err := idParts(d.Id())
	if err != nil {
		return err
	}

	log.Printf("[INFO] Reading job %s", name)
	job, err := conn.BatchV1().Jobs(namespace).Get(ctx, name, metav1.GetOptions{})
	if err != nil {
		log.Printf("[DEBUG] Received error: %#v", err)
		return fmt.Errorf("Failed to read Job! API error: %s", err)
	}
	log.Printf("[INFO] Received job: %#v", job)

	// Remove server-generated labels unless using manual selector
	if _, ok := d.GetOk("spec.0.manual_selector"); !ok {
		labels := job.ObjectMeta.Labels

		if _, ok := labels["controller-uid"]; ok {
			delete(labels, "controller-uid")
		}

		if _, ok := labels["job-name"]; ok {
			delete(labels, "job-name")
		}

		labels = job.Spec.Selector.MatchLabels

		if _, ok := labels["controller-uid"]; ok {
			delete(labels, "controller-uid")
		}
	}

	err = d.Set("metadata", flattenMetadata(job.ObjectMeta, d))
	if err != nil {
		return err
	}

	jobSpec, err := flattenJobSpec(job.Spec, d)
	if err != nil {
		return err
	}

	return d.Set("spec", jobSpec)
}

func resourceKubernetesJobDelete(d *schema.ResourceData, meta interface{}) error {
	conn, err := meta.(KubeClientsets).MainClientset()
	if err != nil {
		return err
	}
	ctx := context.TODO()

	namespace, name, err := idParts(d.Id())
	if err != nil {
		return err
	}

	log.Printf("[INFO] Deleting job: %#v", name)
	err = conn.BatchV1().Jobs(namespace).Delete(ctx, name, deleteOptions)
	if err != nil {
		return fmt.Errorf("Failed to delete Job! API error: %s", err)
	}

	err = resource.Retry(d.Timeout(schema.TimeoutDelete), func() *resource.RetryError {
		_, err := conn.BatchV1().Jobs(namespace).Get(ctx, name, metav1.GetOptions{})
		if err != nil {
			if statusErr, ok := err.(*errors.StatusError); ok && statusErr.ErrStatus.Code == 404 {
				return nil
			}
			return resource.NonRetryableError(err)
		}

		e := fmt.Errorf("Job %s still exists", name)
		return resource.RetryableError(e)
	})
	if err != nil {
		return err
	}

	log.Printf("[INFO] Job %s deleted", name)

	d.SetId("")
	return nil
}

func resourceKubernetesJobExists(d *schema.ResourceData, meta interface{}) (bool, error) {
	conn, err := meta.(KubeClientsets).MainClientset()
	if err != nil {
		return false, err
	}
	ctx := context.TODO()

	namespace, name, err := idParts(d.Id())
	if err != nil {
		return false, err
	}

	log.Printf("[INFO] Checking job %s", name)
	_, err = conn.BatchV1().Jobs(namespace).Get(ctx, name, metav1.GetOptions{})
	if err != nil {
		if statusErr, ok := err.(*errors.StatusError); ok && statusErr.ErrStatus.Code == 404 {
			return false, nil
		}
		log.Printf("[DEBUG] Received error: %#v", err)
	}
	return true, err
}

// retryUntilJobIsFinished checks if a give job finished its execution and either in Complete or Failed state
func retryUntilJobIsFinished(ctx context.Context, conn *kubernetes.Clientset, ns, name string) resource.RetryFunc {
	return func() *resource.RetryError {
		job, err := conn.BatchV1().Jobs(ns).Get(ctx, name, metav1.GetOptions{})
		if err != nil {
			return resource.NonRetryableError(err)
		}

		for _, c := range job.Status.Conditions {
			if c.Status == corev1.ConditionTrue {
				log.Printf("[DEBUG] Current condition of job: %s/%s: %s\n", ns, name, c.Type)
				switch c.Type {
				case batchv1.JobComplete:
					return nil
				case batchv1.JobFailed:
					return resource.NonRetryableError(fmt.Errorf("job: %s/%s is in failed sate", ns, name))
				}
			}
		}

		return resource.RetryableError(fmt.Errorf("job: %s/%s is not in complete state", ns, name))
	}
}
<commit_msg>fix(job): typo in error message (#1048)<commit_after>package kubernetes

import (
	"context"
	"fmt"
	"log"
	"time"

	"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
	"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
	batchv1 "k8s.io/api/batch/v1"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	pkgApi "k8s.io/apimachinery/pkg/types"
	"k8s.io/client-go/kubernetes"
)

func resourceKubernetesJob() *schema.Resource {
	return &schema.Resource{
		Create: resourceKubernetesJobCreate,
		Read:   resourceKubernetesJobRead,
		Update: resourceKubernetesJobUpdate,
		Delete: resourceKubernetesJobDelete,
		Exists: resourceKubernetesJobExists,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Timeouts: &schema.ResourceTimeout{
			Create: schema.DefaultTimeout(1 * time.Minute),
			Update: schema.DefaultTimeout(1 * time.Minute),
			Delete: schema.DefaultTimeout(1 * time.Minute),
		},

		Schema: map[string]*schema.Schema{
			"metadata": jobMetadataSchema(),
			"spec": {
				Type:        schema.TypeList,
				Description: "Spec of the job owned by the cluster",
				Required:    true,
				MaxItems:    1,
				ForceNew:    true,
				Elem: &schema.Resource{
					Schema: jobSpecFields(),
				},
			},
			"wait_for_completion": {
				Type:     schema.TypeBool,
				Optional: true,
			},
		},
	}
}

func resourceKubernetesJobCreate(d *schema.ResourceData, meta interface{}) error {
	conn, err := meta.(KubeClientsets).MainClientset()
	if err != nil {
		return err
	}
	ctx := context.TODO()

	metadata := expandMetadata(d.Get("metadata").([]interface{}))
	spec, err := expandJobSpec(d.Get("spec").([]interface{}))
	if err != nil {
		return err
	}

	job := batchv1.Job{
		ObjectMeta: metadata,
		Spec:       spec,
	}

	log.Printf("[INFO] Creating new Job: %#v", job)

	out, err := conn.BatchV1().Jobs(metadata.Namespace).Create(ctx, &job, metav1.CreateOptions{})
	if err != nil {
		return fmt.Errorf("Failed to create Job! API error: %s", err)
	}
	log.Printf("[INFO] Submitted new job: %#v", out)

	d.SetId(buildId(out.ObjectMeta))

	namespace, name, err := idParts(d.Id())
	if err != nil {
		return err
	}
	if d.Get("wait_for_completion").(bool) {
		return resource.Retry(d.Timeout(schema.TimeoutCreate),
			retryUntilJobIsFinished(ctx, conn, namespace, name))
	}

	return resourceKubernetesJobRead(d, meta)
}

func resourceKubernetesJobUpdate(d *schema.ResourceData, meta interface{}) error {
	conn, err := meta.(KubeClientsets).MainClientset()
	if err != nil {
		return err
	}
	ctx := context.TODO()

	namespace, name, err := idParts(d.Id())
	if err != nil {
		return err
	}

	ops := patchMetadata("metadata.0.", "/metadata/", d)

	data, err := ops.MarshalJSON()
	if err != nil {
		return fmt.Errorf("Failed to marshal update operations: %s", err)
	}

	log.Printf("[INFO] Updating job %s: %#v", d.Id(), ops)

	out, err := conn.BatchV1().Jobs(namespace).Patch(ctx, name, pkgApi.JSONPatchType, data, metav1.PatchOptions{})
	if err != nil {
		return fmt.Errorf("Failed to update Job! API error: %s", err)
	}
	log.Printf("[INFO] Submitted updated job: %#v", out)

	d.SetId(buildId(out.ObjectMeta))

	if d.Get("wait_for_completion").(bool) {
		return resource.Retry(d.Timeout(schema.TimeoutUpdate),
			retryUntilJobIsFinished(ctx, conn, namespace, name))
	}
	return resourceKubernetesJobRead(d, meta)
}

func resourceKubernetesJobRead(d *schema.ResourceData, meta interface{}) error {
	conn, err := meta.(KubeClientsets).MainClientset()
	if err != nil {
		return err
	}
	ctx := context.TODO()

	namespace, name, err := idParts(d.Id())
	if err != nil {
		return err
	}

	log.Printf("[INFO] Reading job %s", name)
	job, err := conn.BatchV1().Jobs(namespace).Get(ctx, name, metav1.GetOptions{})
	if err != nil {
		log.Printf("[DEBUG] Received error: %#v", err)
		return fmt.Errorf("Failed to read Job! API error: %s", err)
	}
	log.Printf("[INFO] Received job: %#v", job)

	// Remove server-generated labels unless using manual selector
	if _, ok := d.GetOk("spec.0.manual_selector"); !ok {
		labels := job.ObjectMeta.Labels

		if _, ok := labels["controller-uid"]; ok {
			delete(labels, "controller-uid")
		}

		if _, ok := labels["job-name"]; ok {
			delete(labels, "job-name")
		}

		labels = job.Spec.Selector.MatchLabels

		if _, ok := labels["controller-uid"]; ok {
			delete(labels, "controller-uid")
		}
	}

	err = d.Set("metadata", flattenMetadata(job.ObjectMeta, d))
	if err != nil {
		return err
	}

	jobSpec, err := flattenJobSpec(job.Spec, d)
	if err != nil {
		return err
	}

	return d.Set("spec", jobSpec)
}

func resourceKubernetesJobDelete(d *schema.ResourceData, meta interface{}) error {
	conn, err := meta.(KubeClientsets).MainClientset()
	if err != nil {
		return err
	}
	ctx := context.TODO()

	namespace, name, err := idParts(d.Id())
	if err != nil {
		return err
	}

	log.Printf("[INFO] Deleting job: %#v", name)
	err = conn.BatchV1().Jobs(namespace).Delete(ctx, name, deleteOptions)
	if err != nil {
		return fmt.Errorf("Failed to delete Job! API error: %s", err)
	}

	err = resource.Retry(d.Timeout(schema.TimeoutDelete), func() *resource.RetryError {
		_, err := conn.BatchV1().Jobs(namespace).Get(ctx, name, metav1.GetOptions{})
		if err != nil {
			if statusErr, ok := err.(*errors.StatusError); ok && statusErr.ErrStatus.Code == 404 {
				return nil
			}
			return resource.NonRetryableError(err)
		}

		e := fmt.Errorf("Job %s still exists", name)
		return resource.RetryableError(e)
	})
	if err != nil {
		return err
	}

	log.Printf("[INFO] Job %s deleted", name)

	d.SetId("")
	return nil
}

func resourceKubernetesJobExists(d *schema.ResourceData, meta interface{}) (bool, error) {
	conn, err := meta.(KubeClientsets).MainClientset()
	if err != nil {
		return false, err
	}
	ctx := context.TODO()

	namespace, name, err := idParts(d.Id())
	if err != nil {
		return false, err
	}

	log.Printf("[INFO] Checking job %s", name)
	_, err = conn.BatchV1().Jobs(namespace).Get(ctx, name, metav1.GetOptions{})
	if err != nil {
		if statusErr, ok := err.(*errors.StatusError); ok && statusErr.ErrStatus.Code == 404 {
			return false, nil
		}
		log.Printf("[DEBUG] Received error: %#v", err)
	}
	return true, err
}

// retryUntilJobIsFinished checks if a give job finished its execution and either in Complete or Failed state
func retryUntilJobIsFinished(ctx context.Context, conn *kubernetes.Clientset, ns, name string) resource.RetryFunc {
	return func() *resource.RetryError {
		job, err := conn.BatchV1().Jobs(ns).Get(ctx, name, metav1.GetOptions{})
		if err != nil {
			return resource.NonRetryableError(err)
		}

		for _, c := range job.Status.Conditions {
			if c.Status == corev1.ConditionTrue {
				log.Printf("[DEBUG] Current condition of job: %s/%s: %s\n", ns, name, c.Type)
				switch c.Type {
				case batchv1.JobComplete:
					return nil
				case batchv1.JobFailed:
					return resource.NonRetryableError(fmt.Errorf("job: %s/%s is in failed state", ns, name))
				}
			}
		}

		return resource.RetryableError(fmt.Errorf("job: %s/%s is not in complete state", ns, name))
	}
}
<|endoftext|>


<commit_before>package evaluation

import (
	"github.com/sjwhitworth/golearn/base"
	. "github.com/smartystreets/goconvey/convey"
	"testing"
)

func TestMetrics(t *testing.T) {
	Convey("Quantities derived from a confusion matrix", t, func() {
		confusionMat := make(ConfusionMatrix)
		confusionMat["a"] = make(map[string]int)
		confusionMat["b"] = make(map[string]int)
		confusionMat["a"]["a"] = 75
		confusionMat["a"]["b"] = 5
		confusionMat["b"]["a"] = 10
		confusionMat["b"]["b"] = 10

		Convey("True Positives", func() {
			So(GetTruePositives("a", confusionMat), ShouldAlmostEqual, 75, 1)
			So(GetTruePositives("b", confusionMat), ShouldAlmostEqual, 10, 1)
		})

		Convey("True Negatives", func() {
			So(GetTrueNegatives("a", confusionMat), ShouldAlmostEqual, 10, 1)
			So(GetTrueNegatives("b", confusionMat), ShouldAlmostEqual, 75, 1)
		})

		Convey("False Positives", func() {
			So(GetFalsePositives("a", confusionMat), ShouldAlmostEqual, 10, 1)
			So(GetFalsePositives("b", confusionMat), ShouldAlmostEqual, 5, 1)
		})

		Convey("False Negatives", func() {
			So(GetFalseNegatives("a", confusionMat), ShouldAlmostEqual, 5, 1)
			So(GetFalseNegatives("b", confusionMat), ShouldAlmostEqual, 10, 1)
		})

		Convey("Precision", func() {
			So(GetPrecision("a", confusionMat), ShouldAlmostEqual, 0.88, 0.01)
			So(GetPrecision("b", confusionMat), ShouldAlmostEqual, 0.666, 0.01)
		})

		Convey("Recall", func() {
			So(GetRecall("a", confusionMat), ShouldAlmostEqual, 0.94, 0.01)
			So(GetRecall("b", confusionMat), ShouldAlmostEqual, 0.50, 0.01)
		})

		Convey("MicroPrecision", func() {
			So(GetMicroPrecision(confusionMat), ShouldAlmostEqual, 0.85, 0.01)
		})

		Convey("MicroRecall", func() {
			So(GetMicroRecall(confusionMat), ShouldAlmostEqual, 0.85, 0.01)
		})

		Convey("MacroPrecision", func() {
			So(GetMacroPrecision(confusionMat), ShouldAlmostEqual, 0.775, 0.01)
		})

		Convey("MacroRecall", func() {
			So(GetMacroRecall(confusionMat), ShouldAlmostEqual, 0.719, 0.01)
		})

		Convey("F1Score", func() {
			So(GetF1Score("a", confusionMat), ShouldAlmostEqual, 0.91, 0.1)
			So(GetF1Score("b", confusionMat), ShouldAlmostEqual, 0.571, 0.01)
		})

		Convey("Accuracy", func() {
			So(GetAccuracy(confusionMat), ShouldAlmostEqual, 0.85, 0.1)
		})

		Convey("Get Summary", func() {
			output := GetSummary(confusionMat)
			So(output, ShouldStartWith, "Reference Class")
			So(output, ShouldContainSubstring, "True Positives")
			So(output, ShouldContainSubstring, "False Positives")
			So(output, ShouldContainSubstring, "True Negatives")
			So(output, ShouldContainSubstring, "Precision")
			So(output, ShouldContainSubstring, "Recall")
			So(output, ShouldContainSubstring, "F1 Score")
			So(output, ShouldContainSubstring, "------")
			So(output, ShouldContainSubstring, "Overall accuracy:")
		})

		Convey("Show Confusion Matrix", func() {
			output := ShowConfusionMatrix(confusionMat)
			So(output, ShouldStartWith, "Reference Class")
			So(output, ShouldContainSubstring, "---------------")
		})

		Convey("Get Confusion Matrix", func() {
			X, _ := base.ParseCSVToInstances("../examples/datasets/iris_headers.csv", true)
			Y, _ := base.ParseCSVToInstances("../examples/datasets/exam.csv", true)
			Convey("Nomarl ref and gen matrices", func() {
				C, _ := GetConfusionMatrix(X, X)
				ret := make(map[string]map[string]int)
				So(C, ShouldHaveSameTypeAs, ret)
			})
			Convey("Row count mismatch", func() {
				_, err := GetConfusionMatrix(X, Y)
				So(err.Error(), ShouldStartWith, "Row count mismatch:")
			})
		})
	})
}
<commit_msg>Fix variable name in convey<commit_after>package evaluation

import (
	"github.com/sjwhitworth/golearn/base"
	. "github.com/smartystreets/goconvey/convey"
	"testing"
)

func TestMetrics(t *testing.T) {
	Convey("Quantities derived from a confusion matrix", t, func() {
		confusionMat := make(ConfusionMatrix)
		confusionMat["a"] = make(map[string]int)
		confusionMat["b"] = make(map[string]int)
		confusionMat["a"]["a"] = 75
		confusionMat["a"]["b"] = 5
		confusionMat["b"]["a"] = 10
		confusionMat["b"]["b"] = 10

		Convey("True Positives", func() {
			So(GetTruePositives("a", confusionMat), ShouldAlmostEqual, 75, 1)
			So(GetTruePositives("b", confusionMat), ShouldAlmostEqual, 10, 1)
		})

		Convey("True Negatives", func() {
			So(GetTrueNegatives("a", confusionMat), ShouldAlmostEqual, 10, 1)
			So(GetTrueNegatives("b", confusionMat), ShouldAlmostEqual, 75, 1)
		})

		Convey("False Positives", func() {
			So(GetFalsePositives("a", confusionMat), ShouldAlmostEqual, 10, 1)
			So(GetFalsePositives("b", confusionMat), ShouldAlmostEqual, 5, 1)
		})

		Convey("False Negatives", func() {
			So(GetFalseNegatives("a", confusionMat), ShouldAlmostEqual, 5, 1)
			So(GetFalseNegatives("b", confusionMat), ShouldAlmostEqual, 10, 1)
		})

		Convey("Precision", func() {
			So(GetPrecision("a", confusionMat), ShouldAlmostEqual, 0.88, 0.01)
			So(GetPrecision("b", confusionMat), ShouldAlmostEqual, 0.666, 0.01)
		})

		Convey("Recall", func() {
			So(GetRecall("a", confusionMat), ShouldAlmostEqual, 0.94, 0.01)
			So(GetRecall("b", confusionMat), ShouldAlmostEqual, 0.50, 0.01)
		})

		Convey("MicroPrecision", func() {
			So(GetMicroPrecision(confusionMat), ShouldAlmostEqual, 0.85, 0.01)
		})

		Convey("MicroRecall", func() {
			So(GetMicroRecall(confusionMat), ShouldAlmostEqual, 0.85, 0.01)
		})

		Convey("MacroPrecision", func() {
			So(GetMacroPrecision(confusionMat), ShouldAlmostEqual, 0.775, 0.01)
		})

		Convey("MacroRecall", func() {
			So(GetMacroRecall(confusionMat), ShouldAlmostEqual, 0.719, 0.01)
		})

		Convey("F1Score", func() {
			So(GetF1Score("a", confusionMat), ShouldAlmostEqual, 0.91, 0.1)
			So(GetF1Score("b", confusionMat), ShouldAlmostEqual, 0.571, 0.01)
		})

		Convey("Accuracy", func() {
			So(GetAccuracy(confusionMat), ShouldAlmostEqual, 0.85, 0.1)
		})

		Convey("Get Summary", func() {
			output := GetSummary(confusionMat)
			So(output, ShouldStartWith, "Reference Class")
			So(output, ShouldContainSubstring, "True Positives")
			So(output, ShouldContainSubstring, "False Positives")
			So(output, ShouldContainSubstring, "True Negatives")
			So(output, ShouldContainSubstring, "Precision")
			So(output, ShouldContainSubstring, "Recall")
			So(output, ShouldContainSubstring, "F1 Score")
			So(output, ShouldContainSubstring, "------")
			So(output, ShouldContainSubstring, "Overall accuracy:")
		})

		Convey("Show Confusion Matrix", func() {
			output := ShowConfusionMatrix(confusionMat)
			So(output, ShouldStartWith, "Reference Class")
			So(output, ShouldContainSubstring, "---------------")
		})

		Convey("Get Confusion Matrix", func() {
			X, _ := base.ParseCSVToInstances("../examples/datasets/iris_headers.csv", true)
			Y, _ := base.ParseCSVToInstances("../examples/datasets/exam.csv", true)
			Convey("Nomarl ref and gen matrices", func() {
				out, _ := GetConfusionMatrix(X, X)
				ret := make(map[string]map[string]int)
				So(out, ShouldHaveSameTypeAs, ret)
			})
			Convey("Row count mismatch", func() {
				_, err := GetConfusionMatrix(X, Y)
				So(err.Error(), ShouldStartWith, "Row count mismatch:")
			})
		})
	})
}
<|endoftext|>


<commit_before>// Copyright 2016 The Ebiten Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package twenty48

import (
	"image/color"
)

var (
	backgroundColor = color.RGBA{0xfa, 0xf8, 0xef, 0xff}
	frameColor      = color.RGBA{0xbb, 0xad, 0xa0, 0xff}
)

func tileColor(value int) color.Color {
	switch value {
	case 2, 4:
		return color.RGBA{0x77, 0x6e, 0x65, 0xff}
	case 8, 16, 32, 64, 128, 256, 512, 1024, 2048:
		return color.RGBA{0xf9, 0xf6, 0xf2, 0xff}
	}
	panic("not reach")
}

func tileBackgroundColor(value int) color.Color {
	switch value {
	case 0:
		return color.NRGBA{0xee, 0xe4, 0xda, 0x59}
	case 2:
		return color.RGBA{0xee, 0xe4, 0xda, 0xff}
	case 4:
		return color.RGBA{0xed, 0xe0, 0xc8, 0xff}
	case 8:
		return color.RGBA{0xf2, 0xb1, 0x79, 0xff}
	case 16:
		return color.RGBA{0xf5, 0x95, 0x63, 0xff}
	case 32:
		return color.RGBA{0xf6, 0x7c, 0x5f, 0xff}
	case 64:
		return color.RGBA{0xf6, 0x5e, 0x3b, 0xff}
	case 128:
		return color.RGBA{0xed, 0xcf, 0x72, 0xff}
	case 256:
		return color.RGBA{0xed, 0xcc, 0x61, 0xff}
	case 512:
		return color.RGBA{0xed, 0xc8, 0x50, 0xff}
	case 1024:
		return color.RGBA{0xed, 0xc5, 0x3f, 0xff}
	case 2048:
		return color.RGBA{0xed, 0xc2, 0x2e, 0xff}
	}
	panic("not reach")
}
<commit_msg>examples/4096: Define colors for huge number tiles<commit_after>// Copyright 2016 The Ebiten Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package twenty48

import (
	"image/color"
)

var (
	backgroundColor = color.RGBA{0xfa, 0xf8, 0xef, 0xff}
	frameColor      = color.RGBA{0xbb, 0xad, 0xa0, 0xff}
)

func tileColor(value int) color.Color {
	switch value {
	case 2, 4:
		return color.RGBA{0x77, 0x6e, 0x65, 0xff}
	case 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536:
		return color.RGBA{0xf9, 0xf6, 0xf2, 0xff}
	}
	panic("not reach")
}

func tileBackgroundColor(value int) color.Color {
	switch value {
	case 0:
		return color.NRGBA{0xee, 0xe4, 0xda, 0x59}
	case 2:
		return color.RGBA{0xee, 0xe4, 0xda, 0xff}
	case 4:
		return color.RGBA{0xed, 0xe0, 0xc8, 0xff}
	case 8:
		return color.RGBA{0xf2, 0xb1, 0x79, 0xff}
	case 16:
		return color.RGBA{0xf5, 0x95, 0x63, 0xff}
	case 32:
		return color.RGBA{0xf6, 0x7c, 0x5f, 0xff}
	case 64:
		return color.RGBA{0xf6, 0x5e, 0x3b, 0xff}
	case 128:
		return color.RGBA{0xed, 0xcf, 0x72, 0xff}
	case 256:
		return color.RGBA{0xed, 0xcc, 0x61, 0xff}
	case 512:
		return color.RGBA{0xed, 0xc8, 0x50, 0xff}
	case 1024:
		return color.RGBA{0xed, 0xc5, 0x3f, 0xff}
	case 2048:
		return color.RGBA{0xed, 0xc2, 0x2e, 0xff}
	case 4096:
		return color.NRGBA{0xa3, 0x49, 0xa4, 0x7f}
	case 8192:
		return color.NRGBA{0xa3, 0x49, 0xa4, 0xb2}
	case 16384:
		return color.NRGBA{0xa3, 0x49, 0xa4, 0xcc}
	case 32768:
		return color.NRGBA{0xa3, 0x49, 0xa4, 0xe5}
	case 65536:
		return color.NRGBA{0xa3, 0x49, 0xa4, 0xff}
	}
	panic("not reach")
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"nowac/kegg"
	"strings"
)

type InputList struct {
	Input []string
}

type Selection struct {
	Selection []string
}

type Page struct {
	Title string
	Body  []byte
}

var defaultTemplatePaths = []string{
	"templates/_base.html",
	"templates/header.html",
	"templates/navbar.html",
	"templates/footer.html",
}

var emptyTemplatePath = []string{"templates/_empty_page.html",
	"templates/header.html",
}

var indexTemplatePath = "templates/index.html"
var aboutTemplatePath = "templates/about.html"
var demoTemplatePath = "templates/demo.html"
var demoVisualizationTemplatePath = "templates/visualization.html"

var indexTemplate = template.Must(template.ParseFiles(
	append(defaultTemplatePaths, indexTemplatePath)...,
))
var aboutTemplate = template.Must(template.ParseFiles(
	append(defaultTemplatePaths, aboutTemplatePath)...,
))
var demoTemplate = template.Must(template.ParseFiles(
	append(defaultTemplatePaths, demoTemplatePath)...,
))

var demoVisualizationTemplate = template.Must(template.ParseFiles(
	append(defaultTemplatePaths, demoVisualizationTemplatePath)...,
))

func renderTemplate(t *template.Template, w http.ResponseWriter,
	d interface{}) {

	// Cross domain requests in browser are a go go
	w.Header().Set("Access-Control-Allow-Origin", "*")

	// Applies template to dataobject d
	err := t.Execute(w, d)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func indexHandler(w http.ResponseWriter, r *http.Request) {
	renderTemplate(indexTemplate, w, nil)
}

func aboutHandler(w http.ResponseWriter, r *http.Request) {
	renderTemplate(aboutTemplate, w, nil)
}

const lenPath = len("/demo/")

func demoHandler(w http.ResponseWriter, r *http.Request) {
	// Get selected pathways (if any)
	selectedPathways := r.URL.Path[lenPath:]
	log.Print("title of page:", selectedPathways)

	// if user has selected pathways render a visualization
	if len(selectedPathways) > 1 {
		selection := Selection{parsePathwayInput(selectedPathways)}
		renderTemplate(demoVisualizationTemplate, w, selection)
		return
	}

	// if user has not selected any pathways, fetch
	// availible pathways from db and display them to the user
	pathways := kegg.GiveMeSomePathways()
	input := InputList{pathways}

	renderTemplate(demoTemplate, w, input)
}

func parsePathwayInput(input string) []string {
	// Remove any unwanted characters
	a := strings.Replace(input, "%3A", ":", -1)
	a = strings.Replace(a, "&", "", -1)
	a = strings.Replace(a, "=", "", -1)

	// Split into separate hsa:... strings
	b := strings.Split(a, "pathwaySelect")

	// Clear out first empty item
	b = b[1:len(b)]

	return b

}

func parseGeneInput(input string) []string {

	// Remove any unwanted characters
	a := strings.Replace(input, "%3A", ":", -1)
	a = strings.Replace(a, "&", "", -1)
	a = strings.Replace(a, "=", "", -1)

	// Split into separate hsa:... strings
	b := strings.Split(a, "geneSelect")

	// Clear out first empty item
	b = b[1:len(b)]

	return b

}

func main() {

	// cmd line flags
	var ip = flag.String("ip", "localhost", "ip to run on")
	var port = flag.String("port", ":8000", "port to run on")
	flag.Parse()

	address := *ip + *port

	http.HandleFunc("/", indexHandler)
	http.HandleFunc("/about", aboutHandler)
	http.HandleFunc("/demo/", demoHandler)

	// Handling requests for css files
	http.Handle("/css/", http.StripPrefix("/css/",
		http.FileServer(http.Dir("css"))))

	// Handling requests for js files
	http.Handle("/js/", http.StripPrefix("/js/",
		http.FileServer(http.Dir("js"))))

	// Handling requests for any public file
	http.Handle("/public/", http.StripPrefix("/public/",
		http.FileServer(http.Dir("public"))))

	// lib directory, d3 jquery and so on.
	http.Handle("/lib/", http.StripPrefix("/lib/",
		http.FileServer(http.Dir("lib"))))

	fmt.Println("Webserver started on", address)
	err := http.ListenAndServe(address, nil)
	if err != nil {
		log.Panic("Could not start webapp! ", err.Error())
	}

}
<commit_msg>github ref to kegg lib<commit_after>package main

import (
	"flag"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"strings"

	"github.com/fjukstad/kegg"
)

type InputList struct {
	Input []string
}

type Selection struct {
	Selection []string
}

type Page struct {
	Title string
	Body  []byte
}

var defaultTemplatePaths = []string{
	"templates/_base.html",
	"templates/header.html",
	"templates/navbar.html",
	"templates/footer.html",
}

var emptyTemplatePath = []string{"templates/_empty_page.html",
	"templates/header.html",
}

var indexTemplatePath = "templates/index.html"
var aboutTemplatePath = "templates/about.html"
var demoTemplatePath = "templates/demo.html"
var demoVisualizationTemplatePath = "templates/visualization.html"

var indexTemplate = template.Must(template.ParseFiles(
	append(defaultTemplatePaths, indexTemplatePath)...,
))
var aboutTemplate = template.Must(template.ParseFiles(
	append(defaultTemplatePaths, aboutTemplatePath)...,
))
var demoTemplate = template.Must(template.ParseFiles(
	append(defaultTemplatePaths, demoTemplatePath)...,
))

var demoVisualizationTemplate = template.Must(template.ParseFiles(
	append(defaultTemplatePaths, demoVisualizationTemplatePath)...,
))

func renderTemplate(t *template.Template, w http.ResponseWriter,
	d interface{}) {

	// Cross domain requests in browser are a go go
	w.Header().Set("Access-Control-Allow-Origin", "*")

	// Applies template to dataobject d
	err := t.Execute(w, d)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func indexHandler(w http.ResponseWriter, r *http.Request) {
	renderTemplate(indexTemplate, w, nil)
}

func aboutHandler(w http.ResponseWriter, r *http.Request) {
	renderTemplate(aboutTemplate, w, nil)
}

const lenPath = len("/demo/")

func demoHandler(w http.ResponseWriter, r *http.Request) {
	// Get selected pathways (if any)
	selectedPathways := r.URL.Path[lenPath:]
	log.Print("title of page:", selectedPathways)

	// if user has selected pathways render a visualization
	if len(selectedPathways) > 1 {
		selection := Selection{parsePathwayInput(selectedPathways)}
		renderTemplate(demoVisualizationTemplate, w, selection)
		return
	}

	// if user has not selected any pathways, fetch
	// availible pathways from db and display them to the user
	pathways := kegg.GiveMeSomePathways()
	input := InputList{pathways}

	renderTemplate(demoTemplate, w, input)
}

func parsePathwayInput(input string) []string {
	// Remove any unwanted characters
	a := strings.Replace(input, "%3A", ":", -1)
	a = strings.Replace(a, "&", "", -1)
	a = strings.Replace(a, "=", "", -1)

	// Split into separate hsa:... strings
	b := strings.Split(a, "pathwaySelect")

	// Clear out first empty item
	b = b[1:len(b)]

	return b

}

func parseGeneInput(input string) []string {

	// Remove any unwanted characters
	a := strings.Replace(input, "%3A", ":", -1)
	a = strings.Replace(a, "&", "", -1)
	a = strings.Replace(a, "=", "", -1)

	// Split into separate hsa:... strings
	b := strings.Split(a, "geneSelect")

	// Clear out first empty item
	b = b[1:len(b)]

	return b

}

func main() {

	// cmd line flags
	var ip = flag.String("ip", "localhost", "ip to run on")
	var port = flag.String("port", ":8000", "port to run on")
	flag.Parse()

	address := *ip + *port

	http.HandleFunc("/", indexHandler)
	http.HandleFunc("/about", aboutHandler)
	http.HandleFunc("/demo/", demoHandler)

	// Handling requests for css files
	http.Handle("/css/", http.StripPrefix("/css/",
		http.FileServer(http.Dir("css"))))

	// Handling requests for js files
	http.Handle("/js/", http.StripPrefix("/js/",
		http.FileServer(http.Dir("js"))))

	// Handling requests for any public file
	http.Handle("/public/", http.StripPrefix("/public/",
		http.FileServer(http.Dir("public"))))

	// lib directory, d3 jquery and so on.
	http.Handle("/lib/", http.StripPrefix("/lib/",
		http.FileServer(http.Dir("lib"))))

	fmt.Println("Webserver started on", address)
	err := http.ListenAndServe(address, nil)
	if err != nil {
		log.Panic("Could not start webapp! ", err.Error())
	}

}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Cisco and/or its affiliates.
//
// 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 resync

import (
	"sync"
	"time"

	"github.com/ligato/cn-infra/infra"
	"github.com/ligato/cn-infra/logging"
)

var (
	// SingleResyncAcceptTimeout defines timeout for accepting resync start.
	SingleResyncAcceptTimeout = time.Second * 1
	// SingleResyncAckTimeout defines timeout for resync ack.
	SingleResyncAckTimeout = time.Second * 10
)

// Plugin implements Plugin interface, therefore it can be loaded with other plugins.
type Plugin struct {
	Deps

	mu            sync.Mutex
	regOrder      []string
	registrations map[string]*registration
}

// Deps groups dependencies injected into the plugin so that they are
// logically separated from other plugin fields.
type Deps struct {
	infra.PluginName
	Log logging.PluginLogger
}

// Init initializes variables.
func (p *Plugin) Init() error {
	p.registrations = make(map[string]*registration)
	return nil
}

// Close TODO set flag that ignore errors => not start Resync while agent is stopping
// TODO kill existing Resync timeout while agent is stopping
func (p *Plugin) Close() error {
	//TODO close error report channel

	p.mu.Lock()
	defer p.mu.Unlock()

	p.registrations = make(map[string]*registration)

	return nil
}

// Register function is supposed to be called in Init() by all VPP Agent plugins.
// The plugins are supposed to load current state of their objects when newResync() is called.
// The actual CreateNewObjects(), DeleteObsoleteObjects() and ModifyExistingObjects() will be orchestrated
// to ensure their proper order. If an error occurs during Resync, then new Resync is planned.
func (p *Plugin) Register(resyncName string) Registration {
	p.mu.Lock()
	defer p.mu.Unlock()

	if _, found := p.registrations[resyncName]; found {
		p.Log.WithField("resyncName", resyncName).
			Panic("You are trying to register same resync twice")
		return nil
	}
	// ensure that resync is triggered in the same order as the plugins were registered
	p.regOrder = append(p.regOrder, resyncName)

	reg := newRegistration(resyncName, make(chan StatusEvent))
	p.registrations[resyncName] = reg

	return reg
}

// DoResync can be used to start resync procedure outside of after init
func (p *Plugin) DoResync() {
	p.startResync()
}

// Call callback on plugins to create/delete/modify objects.
func (p *Plugin) startResync() {
	if len(p.regOrder) == 0 {
		p.Log.Warnf("No registrations, skipping resync")
		return
	}
	p.Log.Infof("Starting resync for: %+v", p.regOrder)

	resyncStart := time.Now()

	for _, regName := range p.regOrder {
		if reg, found := p.registrations[regName]; found {
			t := time.Now()
			p.startSingleResync(regName, reg)

			took := time.Since(t).Round(time.Millisecond)
			p.Log.Debugf("finished resync for %v took %v", regName, took)
		}
	}

	p.Log.Infof("Resync done (took: %v)", time.Since(resyncStart).Round(time.Millisecond))

	// TODO check if there ReportError (if not than report) if error occurred even during Resync
}
func (p *Plugin) startSingleResync(resyncName string, reg *registration) {
	started := newStatusEvent(Started)

	select {
	case reg.statusChan <- started:
		// accept
	case <-time.After(SingleResyncAcceptTimeout):
		p.Log.WithField("regName", resyncName).Warn("Timeout of resync start!")
		return
	}

	select {
	case <-started.ReceiveAck():
		// ack
	case <-time.After(SingleResyncAckTimeout):
		p.Log.WithField("regName", resyncName).Warn("Timeout of resync ACK!")
	}
}
<commit_msg>Log number of resync subscribers<commit_after>// Copyright (c) 2017 Cisco and/or its affiliates.
//
// 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 resync

import (
	"strings"
	"sync"
	"time"

	"github.com/ligato/cn-infra/infra"
	"github.com/ligato/cn-infra/logging"
)

var (
	// SingleResyncAcceptTimeout defines timeout for accepting resync start.
	SingleResyncAcceptTimeout = time.Second * 1
	// SingleResyncAckTimeout defines timeout for resync ack.
	SingleResyncAckTimeout = time.Second * 10
)

// Plugin implements Plugin interface, therefore it can be loaded with other plugins.
type Plugin struct {
	Deps

	mu            sync.Mutex
	regOrder      []string
	registrations map[string]*registration
}

// Deps groups dependencies injected into the plugin so that they are
// logically separated from other plugin fields.
type Deps struct {
	infra.PluginName
	Log logging.PluginLogger
}

// Init initializes variables.
func (p *Plugin) Init() error {
	p.registrations = make(map[string]*registration)
	return nil
}

// Close TODO set flag that ignore errors => not start Resync while agent is stopping
// TODO kill existing Resync timeout while agent is stopping
func (p *Plugin) Close() error {
	//TODO close error report channel

	p.mu.Lock()
	defer p.mu.Unlock()

	p.registrations = make(map[string]*registration)

	return nil
}

// Register function is supposed to be called in Init() by all VPP Agent plugins.
// The plugins are supposed to load current state of their objects when newResync() is called.
// The actual CreateNewObjects(), DeleteObsoleteObjects() and ModifyExistingObjects() will be orchestrated
// to ensure their proper order. If an error occurs during Resync, then new Resync is planned.
func (p *Plugin) Register(resyncName string) Registration {
	p.mu.Lock()
	defer p.mu.Unlock()

	if _, found := p.registrations[resyncName]; found {
		p.Log.WithField("resyncName", resyncName).
			Panic("You are trying to register same resync twice")
		return nil
	}
	// ensure that resync is triggered in the same order as the plugins were registered
	p.regOrder = append(p.regOrder, resyncName)

	reg := newRegistration(resyncName, make(chan StatusEvent))
	p.registrations[resyncName] = reg

	return reg
}

// DoResync can be used to start resync procedure outside of after init
func (p *Plugin) DoResync() {
	p.startResync()
}

// Call callback on plugins to create/delete/modify objects.
func (p *Plugin) startResync() {
	if len(p.regOrder) == 0 {
		p.Log.Warnf("No registrations, skipping resync")
		return
	}

	subs := strings.Join(p.regOrder, ", ")
	p.Log.Infof("Resync starting for %d registrations (%v)", len(p.regOrder), subs)

	resyncStart := time.Now()

	for _, regName := range p.regOrder {
		if reg, found := p.registrations[regName]; found {
			t := time.Now()
			p.startSingleResync(regName, reg)

			took := time.Since(t).Round(time.Millisecond)
			p.Log.Debugf("finished resync for %v took %v", regName, took)
		}
	}

	p.Log.Infof("Resync done (took: %v)", time.Since(resyncStart).Round(time.Millisecond))

	// TODO check if there ReportError (if not than report) if error occurred even during Resync
}
func (p *Plugin) startSingleResync(resyncName string, reg *registration) {
	started := newStatusEvent(Started)

	select {
	case reg.statusChan <- started:
		// accept
	case <-time.After(SingleResyncAcceptTimeout):
		p.Log.WithField("regName", resyncName).Warn("Timeout of resync start!")
		return
	}

	select {
	case <-started.ReceiveAck():
		// ack
	case <-time.After(SingleResyncAckTimeout):
		p.Log.WithField("regName", resyncName).Warn("Timeout of resync ACK!")
	}
}
<|endoftext|>


<commit_before>package shared

import (
	"fmt"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/pkg/errors"
	"gopkg.in/robfig/cron.v2"

	"github.com/lxc/lxd/shared/units"
	"github.com/lxc/lxd/shared/validate"
)

type InstanceAction string

const (
	Stop     InstanceAction = "stop"
	Start    InstanceAction = "start"
	Restart  InstanceAction = "restart"
	Freeze   InstanceAction = "freeze"
	Unfreeze InstanceAction = "unfreeze"
)

// IsRootDiskDevice returns true if the given device representation is configured as root disk for
// a container. It typically get passed a specific entry of api.Instance.Devices.
func IsRootDiskDevice(device map[string]string) bool {
	// Root disk devices also need a non-empty "pool" property, but we can't check that here
	// because this function is used with clients talking to older servers where there was no
	// concept of a storage pool, and also it is used for migrating from old to new servers.
	// The validation of the non-empty "pool" property is done inside the disk device itself.
	if device["type"] == "disk" && device["path"] == "/" && device["source"] == "" {
		return true
	}

	return false
}

// GetRootDiskDevice returns the container device that is configured as root disk
func GetRootDiskDevice(devices map[string]map[string]string) (string, map[string]string, error) {
	var devName string
	var dev map[string]string

	for n, d := range devices {
		if IsRootDiskDevice(d) {
			if devName != "" {
				return "", nil, fmt.Errorf("More than one root device found")
			}

			devName = n
			dev = d
		}
	}

	if devName != "" {
		return devName, dev, nil
	}

	return "", nil, fmt.Errorf("No root device could be found")
}

// HugePageSizeKeys is a list of known hugepage size configuration keys.
var HugePageSizeKeys = [...]string{"limits.hugepages.64KB", "limits.hugepages.1MB", "limits.hugepages.2MB", "limits.hugepages.1GB"}

// HugePageSizeSuffix contains the list of known hugepage size suffixes.
var HugePageSizeSuffix = [...]string{"64KB", "1MB", "2MB", "1GB"}

// KnownInstanceConfigKeys maps all fully defined, well-known config keys
// to an appropriate checker function, which validates whether or not a
// given value is syntactically legal.
var KnownInstanceConfigKeys = map[string]func(value string) error{
	"boot.autostart":             validate.Optional(validate.IsBool),
	"boot.autostart.delay":       validate.Optional(validate.IsInt64),
	"boot.autostart.priority":    validate.Optional(validate.IsInt64),
	"boot.stop.priority":         validate.Optional(validate.IsInt64),
	"boot.host_shutdown_timeout": validate.Optional(validate.IsInt64),

	"limits.cpu": func(value string) error {
		if value == "" {
			return nil
		}

		// Validate the character set
		match, _ := regexp.MatchString("^[-,0-9]*$", value)
		if !match {
			return fmt.Errorf("Invalid CPU limit syntax")
		}

		// Validate first character
		if strings.HasPrefix(value, "-") || strings.HasPrefix(value, ",") {
			return fmt.Errorf("CPU limit can't start with a separator")
		}

		// Validate last character
		if strings.HasSuffix(value, "-") || strings.HasSuffix(value, ",") {
			return fmt.Errorf("CPU limit can't end with a separator")
		}

		return nil
	},
	"limits.cpu.allowance": func(value string) error {
		if value == "" {
			return nil
		}

		if strings.HasSuffix(value, "%") {
			// Percentage based allocation
			_, err := strconv.Atoi(strings.TrimSuffix(value, "%"))
			if err != nil {
				return err
			}

			return nil
		}

		// Time based allocation
		fields := strings.SplitN(value, "/", 2)
		if len(fields) != 2 {
			return fmt.Errorf("Invalid allowance: %s", value)
		}

		_, err := strconv.Atoi(strings.TrimSuffix(fields[0], "ms"))
		if err != nil {
			return err
		}

		_, err = strconv.Atoi(strings.TrimSuffix(fields[1], "ms"))
		if err != nil {
			return err
		}

		return nil
	},
	"limits.cpu.priority": validate.Optional(validate.IsPriority),

	"limits.disk.priority": validate.Optional(validate.IsPriority),

	"limits.hugepages.64KB": validate.Optional(validate.IsSize),
	"limits.hugepages.1MB":  validate.Optional(validate.IsSize),
	"limits.hugepages.2MB":  validate.Optional(validate.IsSize),
	"limits.hugepages.1GB":  validate.Optional(validate.IsSize),

	"limits.memory": func(value string) error {
		if value == "" {
			return nil
		}

		if strings.HasSuffix(value, "%") {
			_, err := strconv.ParseInt(strings.TrimSuffix(value, "%"), 10, 64)
			if err != nil {
				return err
			}

			return nil
		}

		_, err := units.ParseByteSizeString(value)
		if err != nil {
			return err
		}

		return nil
	},
	"limits.memory.enforce": func(value string) error {
		return validate.IsOneOf(value, []string{"soft", "hard"})
	},
	"limits.memory.swap":          validate.Optional(validate.IsBool),
	"limits.memory.swap.priority": validate.Optional(validate.IsPriority),
	"limits.memory.hugepages":     validate.Optional(validate.IsBool),

	"limits.network.priority": validate.Optional(validate.IsPriority),

	"limits.processes": validate.Optional(validate.IsInt64),

	"linux.kernel_modules": validate.IsAny,

	"migration.incremental.memory":            validate.Optional(validate.IsBool),
	"migration.incremental.memory.iterations": validate.Optional(validate.IsUint32),
	"migration.incremental.memory.goal":       validate.Optional(validate.IsUint32),

	"nvidia.runtime":             validate.Optional(validate.IsBool),
	"nvidia.driver.capabilities": validate.IsAny,
	"nvidia.require.cuda":        validate.IsAny,
	"nvidia.require.driver":      validate.IsAny,

	"security.nesting":       validate.Optional(validate.IsBool),
	"security.privileged":    validate.Optional(validate.IsBool),
	"security.devlxd":        validate.Optional(validate.IsBool),
	"security.devlxd.images": validate.Optional(validate.IsBool),

	"security.protection.delete": validate.Optional(validate.IsBool),
	"security.protection.shift":  validate.Optional(validate.IsBool),

	"security.idmap.base":     validate.Optional(validate.IsUint32),
	"security.idmap.isolated": validate.Optional(validate.IsBool),
	"security.idmap.size":     validate.Optional(validate.IsUint32),

	"security.secureboot": validate.Optional(validate.IsBool),

	"security.syscalls.allow":                   validate.IsAny,
	"security.syscalls.blacklist_default":       validate.Optional(validate.IsBool),
	"security.syscalls.blacklist_compat":        validate.Optional(validate.IsBool),
	"security.syscalls.blacklist":               validate.IsAny,
	"security.syscalls.deny_default":            validate.Optional(validate.IsBool),
	"security.syscalls.deny_compat":             validate.Optional(validate.IsBool),
	"security.syscalls.deny":                    validate.IsAny,
	"security.syscalls.intercept.bpf":           validate.Optional(validate.IsBool),
	"security.syscalls.intercept.bpf.devices":   validate.Optional(validate.IsBool),
	"security.syscalls.intercept.mknod":         validate.Optional(validate.IsBool),
	"security.syscalls.intercept.mount":         validate.Optional(validate.IsBool),
	"security.syscalls.intercept.mount.allowed": validate.IsAny,
	"security.syscalls.intercept.mount.fuse":    validate.IsAny,
	"security.syscalls.intercept.mount.shift":   validate.Optional(validate.IsBool),
	"security.syscalls.intercept.setxattr":      validate.Optional(validate.IsBool),
	"security.syscalls.whitelist":               validate.IsAny,

	"snapshots.schedule": func(value string) error {
		if value == "" {
			return nil
		}

		if len(strings.Split(value, " ")) != 5 {
			return fmt.Errorf("Schedule must be of the form: <minute> <hour> <day-of-month> <month> <day-of-week>")
		}

		_, err := cron.Parse(fmt.Sprintf("* %s", value))
		if err != nil {
			return errors.Wrap(err, "Error parsing schedule")
		}

		return nil
	},
	"snapshots.schedule.stopped": validate.Optional(validate.IsBool),
	"snapshots.pattern":          validate.IsAny,
	"snapshots.expiry": func(value string) error {
		// Validate expression
		_, err := GetSnapshotExpiry(time.Time{}, value)
		return err
	},

	// Caller is responsible for full validation of any raw.* value
	"raw.apparmor": validate.IsAny,
	"raw.idmap":    validate.IsAny,
	"raw.lxc":      validate.IsAny,
	"raw.qemu":     validate.IsAny,
	"raw.seccomp":  validate.IsAny,

	"volatile.apply_template":   validate.IsAny,
	"volatile.base_image":       validate.IsAny,
	"volatile.last_state.idmap": validate.IsAny,
	"volatile.last_state.power": validate.IsAny,
	"volatile.idmap.base":       validate.IsAny,
	"volatile.idmap.current":    validate.IsAny,
	"volatile.idmap.next":       validate.IsAny,
	"volatile.apply_quota":      validate.IsAny,
}

// ConfigKeyChecker returns a function that will check whether or not
// a provide value is valid for the associate config key.  Returns an
// error if the key is not known.  The checker function only performs
// syntactic checking of the value, semantic and usage checking must
// be done by the caller.  User defined keys are always considered to
// be valid, e.g. user.* and environment.* keys.
func ConfigKeyChecker(key string) (func(value string) error, error) {
	if f, ok := KnownInstanceConfigKeys[key]; ok {
		return f, nil
	}

	if strings.HasPrefix(key, "volatile.") {
		if strings.HasSuffix(key, ".hwaddr") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".name") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".host_name") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".mtu") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".created") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".id") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".vlan") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".spoofcheck") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".apply_quota") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, "vm.uuid") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".ceph_rbd") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".driver") {
			return validate.IsAny, nil
		}
	}

	if strings.HasPrefix(key, "environment.") {
		return validate.IsAny, nil
	}

	if strings.HasPrefix(key, "user.") {
		return validate.IsAny, nil
	}

	if strings.HasPrefix(key, "image.") {
		return validate.IsAny, nil
	}

	if strings.HasPrefix(key, "limits.kernel.") &&
		(len(key) > len("limits.kernel.")) {
		return validate.IsAny, nil
	}

	return nil, fmt.Errorf("Unknown configuration key: %s", key)
}

// InstanceGetParentAndSnapshotName returns the parent instance name, snapshot name,
// and whether it actually was a snapshot name.
func InstanceGetParentAndSnapshotName(name string) (string, string, bool) {
	fields := strings.SplitN(name, SnapshotDelimiter, 2)
	if len(fields) == 1 {
		return name, "", false
	}

	return fields[0], fields[1], true
}
<commit_msg>shared/instance: Adds volatile.uuid key to instance validation<commit_after>package shared

import (
	"fmt"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/pkg/errors"
	"gopkg.in/robfig/cron.v2"

	"github.com/lxc/lxd/shared/units"
	"github.com/lxc/lxd/shared/validate"
)

type InstanceAction string

const (
	Stop     InstanceAction = "stop"
	Start    InstanceAction = "start"
	Restart  InstanceAction = "restart"
	Freeze   InstanceAction = "freeze"
	Unfreeze InstanceAction = "unfreeze"
)

// IsRootDiskDevice returns true if the given device representation is configured as root disk for
// a container. It typically get passed a specific entry of api.Instance.Devices.
func IsRootDiskDevice(device map[string]string) bool {
	// Root disk devices also need a non-empty "pool" property, but we can't check that here
	// because this function is used with clients talking to older servers where there was no
	// concept of a storage pool, and also it is used for migrating from old to new servers.
	// The validation of the non-empty "pool" property is done inside the disk device itself.
	if device["type"] == "disk" && device["path"] == "/" && device["source"] == "" {
		return true
	}

	return false
}

// GetRootDiskDevice returns the container device that is configured as root disk
func GetRootDiskDevice(devices map[string]map[string]string) (string, map[string]string, error) {
	var devName string
	var dev map[string]string

	for n, d := range devices {
		if IsRootDiskDevice(d) {
			if devName != "" {
				return "", nil, fmt.Errorf("More than one root device found")
			}

			devName = n
			dev = d
		}
	}

	if devName != "" {
		return devName, dev, nil
	}

	return "", nil, fmt.Errorf("No root device could be found")
}

// HugePageSizeKeys is a list of known hugepage size configuration keys.
var HugePageSizeKeys = [...]string{"limits.hugepages.64KB", "limits.hugepages.1MB", "limits.hugepages.2MB", "limits.hugepages.1GB"}

// HugePageSizeSuffix contains the list of known hugepage size suffixes.
var HugePageSizeSuffix = [...]string{"64KB", "1MB", "2MB", "1GB"}

// KnownInstanceConfigKeys maps all fully defined, well-known config keys
// to an appropriate checker function, which validates whether or not a
// given value is syntactically legal.
var KnownInstanceConfigKeys = map[string]func(value string) error{
	"boot.autostart":             validate.Optional(validate.IsBool),
	"boot.autostart.delay":       validate.Optional(validate.IsInt64),
	"boot.autostart.priority":    validate.Optional(validate.IsInt64),
	"boot.stop.priority":         validate.Optional(validate.IsInt64),
	"boot.host_shutdown_timeout": validate.Optional(validate.IsInt64),

	"limits.cpu": func(value string) error {
		if value == "" {
			return nil
		}

		// Validate the character set
		match, _ := regexp.MatchString("^[-,0-9]*$", value)
		if !match {
			return fmt.Errorf("Invalid CPU limit syntax")
		}

		// Validate first character
		if strings.HasPrefix(value, "-") || strings.HasPrefix(value, ",") {
			return fmt.Errorf("CPU limit can't start with a separator")
		}

		// Validate last character
		if strings.HasSuffix(value, "-") || strings.HasSuffix(value, ",") {
			return fmt.Errorf("CPU limit can't end with a separator")
		}

		return nil
	},
	"limits.cpu.allowance": func(value string) error {
		if value == "" {
			return nil
		}

		if strings.HasSuffix(value, "%") {
			// Percentage based allocation
			_, err := strconv.Atoi(strings.TrimSuffix(value, "%"))
			if err != nil {
				return err
			}

			return nil
		}

		// Time based allocation
		fields := strings.SplitN(value, "/", 2)
		if len(fields) != 2 {
			return fmt.Errorf("Invalid allowance: %s", value)
		}

		_, err := strconv.Atoi(strings.TrimSuffix(fields[0], "ms"))
		if err != nil {
			return err
		}

		_, err = strconv.Atoi(strings.TrimSuffix(fields[1], "ms"))
		if err != nil {
			return err
		}

		return nil
	},
	"limits.cpu.priority": validate.Optional(validate.IsPriority),

	"limits.disk.priority": validate.Optional(validate.IsPriority),

	"limits.hugepages.64KB": validate.Optional(validate.IsSize),
	"limits.hugepages.1MB":  validate.Optional(validate.IsSize),
	"limits.hugepages.2MB":  validate.Optional(validate.IsSize),
	"limits.hugepages.1GB":  validate.Optional(validate.IsSize),

	"limits.memory": func(value string) error {
		if value == "" {
			return nil
		}

		if strings.HasSuffix(value, "%") {
			_, err := strconv.ParseInt(strings.TrimSuffix(value, "%"), 10, 64)
			if err != nil {
				return err
			}

			return nil
		}

		_, err := units.ParseByteSizeString(value)
		if err != nil {
			return err
		}

		return nil
	},
	"limits.memory.enforce": func(value string) error {
		return validate.IsOneOf(value, []string{"soft", "hard"})
	},
	"limits.memory.swap":          validate.Optional(validate.IsBool),
	"limits.memory.swap.priority": validate.Optional(validate.IsPriority),
	"limits.memory.hugepages":     validate.Optional(validate.IsBool),

	"limits.network.priority": validate.Optional(validate.IsPriority),

	"limits.processes": validate.Optional(validate.IsInt64),

	"linux.kernel_modules": validate.IsAny,

	"migration.incremental.memory":            validate.Optional(validate.IsBool),
	"migration.incremental.memory.iterations": validate.Optional(validate.IsUint32),
	"migration.incremental.memory.goal":       validate.Optional(validate.IsUint32),

	"nvidia.runtime":             validate.Optional(validate.IsBool),
	"nvidia.driver.capabilities": validate.IsAny,
	"nvidia.require.cuda":        validate.IsAny,
	"nvidia.require.driver":      validate.IsAny,

	"security.nesting":       validate.Optional(validate.IsBool),
	"security.privileged":    validate.Optional(validate.IsBool),
	"security.devlxd":        validate.Optional(validate.IsBool),
	"security.devlxd.images": validate.Optional(validate.IsBool),

	"security.protection.delete": validate.Optional(validate.IsBool),
	"security.protection.shift":  validate.Optional(validate.IsBool),

	"security.idmap.base":     validate.Optional(validate.IsUint32),
	"security.idmap.isolated": validate.Optional(validate.IsBool),
	"security.idmap.size":     validate.Optional(validate.IsUint32),

	"security.secureboot": validate.Optional(validate.IsBool),

	"security.syscalls.allow":                   validate.IsAny,
	"security.syscalls.blacklist_default":       validate.Optional(validate.IsBool),
	"security.syscalls.blacklist_compat":        validate.Optional(validate.IsBool),
	"security.syscalls.blacklist":               validate.IsAny,
	"security.syscalls.deny_default":            validate.Optional(validate.IsBool),
	"security.syscalls.deny_compat":             validate.Optional(validate.IsBool),
	"security.syscalls.deny":                    validate.IsAny,
	"security.syscalls.intercept.bpf":           validate.Optional(validate.IsBool),
	"security.syscalls.intercept.bpf.devices":   validate.Optional(validate.IsBool),
	"security.syscalls.intercept.mknod":         validate.Optional(validate.IsBool),
	"security.syscalls.intercept.mount":         validate.Optional(validate.IsBool),
	"security.syscalls.intercept.mount.allowed": validate.IsAny,
	"security.syscalls.intercept.mount.fuse":    validate.IsAny,
	"security.syscalls.intercept.mount.shift":   validate.Optional(validate.IsBool),
	"security.syscalls.intercept.setxattr":      validate.Optional(validate.IsBool),
	"security.syscalls.whitelist":               validate.IsAny,

	"snapshots.schedule": func(value string) error {
		if value == "" {
			return nil
		}

		if len(strings.Split(value, " ")) != 5 {
			return fmt.Errorf("Schedule must be of the form: <minute> <hour> <day-of-month> <month> <day-of-week>")
		}

		_, err := cron.Parse(fmt.Sprintf("* %s", value))
		if err != nil {
			return errors.Wrap(err, "Error parsing schedule")
		}

		return nil
	},
	"snapshots.schedule.stopped": validate.Optional(validate.IsBool),
	"snapshots.pattern":          validate.IsAny,
	"snapshots.expiry": func(value string) error {
		// Validate expression
		_, err := GetSnapshotExpiry(time.Time{}, value)
		return err
	},

	// Caller is responsible for full validation of any raw.* value
	"raw.apparmor": validate.IsAny,
	"raw.idmap":    validate.IsAny,
	"raw.lxc":      validate.IsAny,
	"raw.qemu":     validate.IsAny,
	"raw.seccomp":  validate.IsAny,

	"volatile.apply_template":   validate.IsAny,
	"volatile.base_image":       validate.IsAny,
	"volatile.last_state.idmap": validate.IsAny,
	"volatile.last_state.power": validate.IsAny,
	"volatile.idmap.base":       validate.IsAny,
	"volatile.idmap.current":    validate.IsAny,
	"volatile.idmap.next":       validate.IsAny,
	"volatile.apply_quota":      validate.IsAny,
	"volatile.uuid":             validate.Optional(validate.IsUUID),
}

// ConfigKeyChecker returns a function that will check whether or not
// a provide value is valid for the associate config key.  Returns an
// error if the key is not known.  The checker function only performs
// syntactic checking of the value, semantic and usage checking must
// be done by the caller.  User defined keys are always considered to
// be valid, e.g. user.* and environment.* keys.
func ConfigKeyChecker(key string) (func(value string) error, error) {
	if f, ok := KnownInstanceConfigKeys[key]; ok {
		return f, nil
	}

	if strings.HasPrefix(key, "volatile.") {
		if strings.HasSuffix(key, ".hwaddr") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".name") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".host_name") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".mtu") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".created") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".id") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".vlan") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".spoofcheck") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".apply_quota") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, "vm.uuid") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".ceph_rbd") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".driver") {
			return validate.IsAny, nil
		}
	}

	if strings.HasPrefix(key, "environment.") {
		return validate.IsAny, nil
	}

	if strings.HasPrefix(key, "user.") {
		return validate.IsAny, nil
	}

	if strings.HasPrefix(key, "image.") {
		return validate.IsAny, nil
	}

	if strings.HasPrefix(key, "limits.kernel.") &&
		(len(key) > len("limits.kernel.")) {
		return validate.IsAny, nil
	}

	return nil, fmt.Errorf("Unknown configuration key: %s", key)
}

// InstanceGetParentAndSnapshotName returns the parent instance name, snapshot name,
// and whether it actually was a snapshot name.
func InstanceGetParentAndSnapshotName(name string) (string, string, bool) {
	fields := strings.SplitN(name, SnapshotDelimiter, 2)
	if len(fields) == 1 {
		return name, "", false
	}

	return fields[0], fields[1], true
}
<|endoftext|>


<commit_before>package json

import (
	"github.com/opsidian/parsley/ast/interpreter"
	"github.com/opsidian/parsley/combinator"
	"github.com/opsidian/parsley/parser"
	"github.com/opsidian/parsley/text"
	"github.com/opsidian/parsley/text/terminal"
)

// NewParser returns with a new JSON parser
func NewParser() *parser.NamedFunc {
	var value parser.NamedFunc

	array := combinator.Seq("ARRAY", "array",
		terminal.Rune('['),
		combinator.SepBy(
			text.LeftTrim(&value, text.WsSpacesNl),
			text.LeftTrim(terminal.Rune(','), text.WsSpaces),
		).Bind(interpreter.Array()),
		text.LeftTrim(terminal.Rune(']'), text.WsSpacesNl),
	).Bind(interpreter.Select(1))

	keyValue := combinator.Seq("OBJ_KV", "key-value pair",
		terminal.String(false),
		text.LeftTrim(terminal.Rune(':'), text.WsSpaces),
		text.LeftTrim(&value, text.WsSpaces),
	)

	object := combinator.Seq("OBJ", "object",
		terminal.Rune('{'),
		combinator.SepBy(
			text.LeftTrim(keyValue, text.WsSpacesNl),
			text.LeftTrim(terminal.Rune(','), text.WsSpaces),
		).Bind(interpreter.Object()),
		text.LeftTrim(terminal.Rune('}'), text.WsSpacesNl),
	).Bind(interpreter.Select(1))

	value = *combinator.Choice("value",
		terminal.String(false),
		terminal.Float(),
		terminal.Integer(),
		array,
		object,
		terminal.Word("false", false),
		terminal.Word("true", true),
		terminal.Word("null", nil),
	)

	return text.Trim(&value)
}
<commit_msg>Allow to have a new line before a map's value in the example json parser<commit_after>package json

import (
	"github.com/opsidian/parsley/ast/interpreter"
	"github.com/opsidian/parsley/combinator"
	"github.com/opsidian/parsley/parser"
	"github.com/opsidian/parsley/text"
	"github.com/opsidian/parsley/text/terminal"
)

// NewParser returns with a new JSON parser
func NewParser() *parser.NamedFunc {
	var value parser.NamedFunc

	array := combinator.Seq("ARRAY", "array",
		terminal.Rune('['),
		combinator.SepBy(
			text.LeftTrim(&value, text.WsSpacesNl),
			text.LeftTrim(terminal.Rune(','), text.WsSpaces),
		).Bind(interpreter.Array()),
		text.LeftTrim(terminal.Rune(']'), text.WsSpacesNl),
	).Bind(interpreter.Select(1))

	keyValue := combinator.Seq("OBJ_KV", "key-value pair",
		terminal.String(false),
		text.LeftTrim(terminal.Rune(':'), text.WsSpaces),
		text.LeftTrim(&value, text.WsSpacesNl),
	)

	object := combinator.Seq("OBJ", "object",
		terminal.Rune('{'),
		combinator.SepBy(
			text.LeftTrim(keyValue, text.WsSpacesNl),
			text.LeftTrim(terminal.Rune(','), text.WsSpaces),
		).Bind(interpreter.Object()),
		text.LeftTrim(terminal.Rune('}'), text.WsSpacesNl),
	).Bind(interpreter.Select(1))

	value = *combinator.Choice("value",
		terminal.String(false),
		terminal.Float(),
		terminal.Integer(),
		array,
		object,
		terminal.Word("false", false),
		terminal.Word("true", true),
		terminal.Word("null", nil),
	)

	return text.Trim(&value)
}
<|endoftext|>


<commit_before>// Copyright 2016 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

package doc

import (
	"testing"

	"github.com/caixw/apidoc/app"
	"github.com/issue9/assert"
)

var synerr = &app.SyntaxError{}

func TestscanAPIExample(t *testing.T) {
	a := assert.New(t)

	// 正常测试
	code := ` xml
<root>
    <data>123</data>
</root>`
	matchCode := `<root>
    <data>123</data>
</root>`
	l := newLexer([]rune(code))
	a.NotNil(l)
	e, err := l.scanAPIExample()
	a.NotError(err).
		Equal(e.Type, "xml").
		Equal(e.Code, matchCode)

	code = ` xml <root>
    <data>123</data>
</root>
 @apiURL abc/test`
	matchCode = `<root>
    <data>123</data>
</root>`
	l = newLexer([]rune(code))
	a.NotNil(l)
	e, err = l.scanAPIExample()
	a.NotError(err).
		Equal(e.Type, "xml").
		Equal(len(e.Code), len(matchCode)).
		Equal(e.Code, matchCode)
}

func TestScanAPIParam(t *testing.T) {
	a := assert.New(t)

	// 正常语法测试
	l := newLexer([]rune("id int optional 用户 id号\n"))
	p, err := l.scanAPIParam("@apiQuery")
	a.NotError(err).NotNil(p)
	a.Equal(p.Name, "id").
		Equal(p.Type, "int").
		Equal(p.Summary, "optional 用户 id号")

	// 缺少参数
	l = newLexer([]rune("id int \n"))
	p, err = l.scanAPIParam("@apiQuery")
	a.ErrorType(err, synerr).Nil(p)

	// 缺少参数
	l = newLexer([]rune("id  \n"))
	p, err = l.scanAPIParam("@apiQuery")
	a.ErrorType(err, synerr).Nil(p)
}

func TestScanAPI(t *testing.T) {
	a := assert.New(t)
	d := &Doc{Apis: []*API{}}

	// 正常情况
	l := newLexer([]rune(" get test.com/api.json?k=1 summary summary\n api description\n@apiSuccess 200 OK"))

	a.NotError(l.scanAPI(d))
	api := d.Apis[0]
	a.Equal(api.Method, "get").
		Equal(api.URL, "test.com/api.json?k=1").
		Equal(api.Summary, "summary summary").
		Equal(api.Description, "api description")

	// 多行description
	l = newLexer([]rune(" post test.com/api.json?K=1  summary summary\n api \ndescription\n@apiError 400 summary"))
	a.NotError(l.scanAPI(d))
	api = d.Apis[1]
	a.Equal(api.URL, "test.com/api.json?K=1").
		Equal(api.Method, "post").
		Equal(api.Summary, "summary summary").
		Equal(api.Description, "api \ndescription")

	// 缺少description参数
	l = newLexer([]rune("get test.com/api.json summary summary \n@apiError 400 error"))
	a.NotError(l.scanAPI(d))
	api = d.Apis[2]
	a.Equal(api.Method, "get").
		Equal(api.URL, "test.com/api.json").
		Equal(api.Summary, "summary summary").
		Equal(api.Description, "")

	// 缺少description参数
	l = newLexer([]rune("get test.com/api.json summary summary\n \n@apiError 400 error"))
	a.NotError(l.scanAPI(d))
	api = d.Apis[3]
	a.Equal(api.Method, "get").
		Equal(api.URL, "test.com/api.json").
		Equal(api.Summary, "summary summary").
		Equal(api.Description, "")

	// 没有任何参数
	l = newLexer([]rune("  "))
	a.ErrorType(l.scanAPI(d), synerr)
}

func TestScanAPIDoc(t *testing.T) {
	a := assert.New(t)

	code := ` title of apidoc
@apiVersion 2.0.1
@apiBaseURL https://api.caixw.io
@apiLicense MIT https://opensource.org/licenses/MIT
@apiContent
line1
line2`

	l := newLexer([]rune(code))
	a.NotNil(l)
	doc := &Doc{}

	a.NotError(l.scanAPIDoc(doc))
	a.Equal(doc.Version, "2.0.1").
		Equal(doc.Title, "title of apidoc").
		Equal(doc.BaseURL, "https://api.caixw.io").
		Equal(doc.LicenseName, "MIT").
		Equal(doc.LicenseURL, "https://opensource.org/licenses/MIT").
		Equal(doc.Content, "\nline1\nline2")

		// 重复内容，报错
	code = `title of apidoc2
		@apiBaseURL http://api.caixw.io
line1
line2`
	l = newLexer([]rune(code))
	a.Error(l.scanAPIDoc(doc))

	// 检测各个都是空值的情况
	code = `2.9 title of apidoc
`
	l = newLexer([]rune(code))
	a.NotNil(l)
	doc = &Doc{}
	a.NotError(l.scanAPIDoc(doc))
	a.Equal(doc.Title, "2.9 title of apidoc").
		Equal(doc.Version, "").
		Equal(doc.BaseURL, "").
		Equal(doc.LicenseName, "").
		Equal(doc.LicenseURL, "")
}

func TestScanAPIRequest(t *testing.T) {
	a := assert.New(t)
	api := &API{}

	code := ` xml
 @apiHeader h1 v1
 @apiHeader h2 v2
@apiParam p1 int optional p1 summary
@apiParam p2 int p2 summary
@apiExample json
{
    p1:v1,
    p2:v2
}
@apiExample xml
<root>
    <p1>v1</p1>
    <p2>v2</p2>
</root>
`
	l := newLexer([]rune(code))
	a.NotError(l.scanAPIRequest(api))
	a.NotNil(api.Request)
	r := api.Request
	a.Equal(2, len(r.Headers)).
		Equal(r.Headers["h1"], "v1").
		Equal(r.Headers["h2"], "v2").
		Equal(r.Params[0].Name, "p1").
		Equal(r.Params[1].Summary, "p2 summary").
		Equal(r.Examples[0].Type, "json").
		Equal(r.Examples[1].Type, "xml").
		Equal(r.Examples[1].Code, `<root>
    <p1>v1</p1>
    <p2>v2</p2>
</root>`)

	code = ` xml
@apiHeader h1 v1
@apiParam p1 int p1 summary

@apiExample xml
<root>
    <p1>v1</p1>
</root>
@apiGroup abc
`
	matchCode := `<root>
    <p1>v1</p1>
</root>`
	l = newLexer([]rune(code))
	a.NotError(l.scanAPIRequest(api))
	a.NotNil(api.Request)
	r = api.Request
	a.Equal(1, len(r.Headers)).
		Equal(r.Headers["h1"], "v1").
		Equal(r.Params[0].Name, "p1").
		Equal(r.Examples[0].Type, "xml").
		Equal(r.Examples[0].Code, matchCode)
}

func TestScanResponse(t *testing.T) {
	a := assert.New(t)

	code := ` 200 json
@apiHeader h1 v1
@apiHeader h2 v2
@apiParam p1 int optional p1 summary
@apiParam p2 int p2 summary
@apiExample json
{
    p1:v1,
    p2:v2
}
@apiExample xml
<root>
    <p1>v1</p1>
    <p2>v2</p2>
</root>
`
	l := newLexer([]rune(code))
	resp, err := l.scanResponse("@apiError")
	a.NotError(err).NotNil(resp)
	a.Equal(resp.Code, "200").
		Equal(resp.Summary, "json").
		Equal(resp.Headers["h1"], "v1").
		Equal(resp.Headers["h2"], "v2").
		Equal(resp.Params[0].Name, "p1").
		Equal(resp.Params[1].Summary, "p2 summary").
		Equal(resp.Examples[0].Type, "json").
		Equal(resp.Examples[1].Type, "xml")

	code = ` 200 xml  status summary
 @apiHeader h1 v1
 @apiParam p1 int p1 summary

@apiExample xml
<root>
    <p1>v1</p1>
</root>
@apiError
`
	matchCode := `<root>
    <p1>v1</p1>
</root>`
	l = newLexer([]rune(code))
	resp, err = l.scanResponse("@apiError")
	a.NotError(err).NotNil(resp)
	a.Equal(resp.Code, "200").
		Equal(resp.Summary, "xml  status summary").
		Equal(resp.Headers["h1"], "v1").
		Equal(resp.Params[0].Name, "p1").
		Equal(resp.Examples[0].Code, matchCode)

	// 缺少必要的参数
	code = `
@apiSuccess g
`
	l = newLexer([]rune(code))
	resp, err = l.scanResponse("@apiError")
	a.Error(err).Nil(resp)
}

func TestDoc_Scan(t *testing.T) {
	a := assert.New(t)
	doc1 := New()

	code := `
@api get /baseurl/api/login api summary
api description 1
api description 2
@apiQuery q1 int q1 summary
@apiQuery q2 int q2 summary
@apiParam p1 int p1 summary
@apiParam p2 int p2 summary

@apiSuccess 200 json
@apiHeader h1 v1
@apiHeader h2 v2
@apiParam p1 int optional p1 summary
@apiParam p2 int p2 summary
@apiExample json
{
    p1:v1,
    p2:v2
}
@apiExample xml
<root>
    <p1>v1</p1>
    <p2>v2</p2>
</root>

@apiError 200 json
@apiHeader h1 v1
@apiHeader h2 v2
`
	err := doc1.Scan([]rune(code))
	a.NotError(err)
	d := doc1.Apis[0]

	a.Equal(d.URL, "/baseurl/api/login").
		Equal(d.Group, app.DefaultGroupName).
		Equal(d.Summary, "api summary").
		Equal(d.Description, "api description 1\napi description 2")

	a.Equal(2, len(d.Queries)).
		Equal(2, len(d.Params))

	q := d.Queries
	a.Equal(q[0].Name, "q1").Equal(q[0].Summary, "q1 summary")

	p := d.Params
	a.Equal(p[0].Name, "p1").Equal(p[0].Summary, "p1 summary")

	s := d.Success
	a.Equal(s.Code, "200").
		Equal(s.Summary, "json").
		Equal(s.Headers["h1"], "v1").
		Equal(s.Headers["h2"], "v2").
		Equal(s.Params[0].Name, "p1").
		Equal(s.Params[1].Summary, "p2 summary").
		Equal(s.Examples[0].Type, "json").
		Equal(s.Examples[1].Type, "xml")

	s = d.Error
	a.Equal(s.Code, "200")

	// 不包含api定义的代码块，将返回 nil 且不会有内容添加到 doc1.Apis
	code = `
Copyright 2015 by caixw, All rights reserved.
Use of this source code is governed by a MIT
license that can be found in the LICENSE file.
`
	l := len(doc1.Apis)
	err = doc1.Scan([]rune(code))
	a.NotError(err)
	a.Equal(l, len(doc1.Apis))

	// @apiGroup
	code = `
@api delete /admin/users/{id} delete users
@apiGroup
@apiParam id int user id
@apiError 400 error
`
	l = len(doc1.Apis)
	a.ErrorType(doc1.Scan([]rune(code)), synerr) // @apiGroup 少参数

	// @apiIgnore
	code = `
@api delete /admin/users/{id} delete users
@apiIgnore
@apiParam id int user id
@apiError 400 error
`
	l = len(doc1.Apis)
	err = doc1.Scan([]rune(code))
	a.NotError(err)
	a.Equal(l, len(doc1.Apis))

	// @apiIgnore 非正常标签，标签只能出现在行首
	code = `
@api delete /admin/users/{id} delete users
@apiGroup group
ab @apiIgnore
@apiParam id int user id
@apiSuccess 200 OK
`
	l = len(doc1.Apis)
	err = doc1.Scan([]rune(code))
	a.NotError(err)
	a.Equal(l+1, len(doc1.Apis))

	// @apiIgno 不认识的标签，会提示错误信息
	code = `
@api delete /admin/users/{id} delete users
@apiIgno
@apiGroup group
@apiParam id int user id
@apiSuccess 200 OK
`
	l = len(doc1.Apis)
	err = doc1.Scan([]rune(code))
	a.ErrorType(err, synerr)
}
<commit_msg>修正测试错误<commit_after>// Copyright 2016 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

package doc

import (
	"testing"

	"github.com/caixw/apidoc/app"
	"github.com/issue9/assert"
)

var synerr = &app.SyntaxError{}

func TestScanAPIExample(t *testing.T) {
	a := assert.New(t)

	// 正常测试
	code := ` xml
<root>
    <data>123</data>
</root>`
	matchCode := `<root>
    <data>123</data>
</root>`
	l := newLexer([]rune(code))
	a.NotNil(l)
	e, err := l.scanAPIExample()
	a.NotError(err).
		Equal(e.Type, "xml").
		Equal(e.Code, matchCode)

	code = ` xml <root>
    <data>123</data>
</root>
 @apiURL abc/test`
	matchCode = `<root>
    <data>123</data>
</root>`
	l = newLexer([]rune(code))
	a.NotNil(l)
	e, err = l.scanAPIExample()
	a.NotError(err).
		Equal(e.Type, "xml").
		Equal(len(e.Code), len(matchCode)).
		Equal(e.Code, matchCode)
}

func TestScanAPIParam(t *testing.T) {
	a := assert.New(t)

	// 正常语法测试
	l := newLexer([]rune("id int optional 用户 id号\n"))
	p, err := l.scanAPIParam("@apiQuery")
	a.NotError(err).NotNil(p)
	a.Equal(p.Name, "id").
		Equal(p.Type, "int").
		Equal(p.Summary, "optional 用户 id号")

	// 缺少参数
	l = newLexer([]rune("id int \n"))
	p, err = l.scanAPIParam("@apiQuery")
	a.ErrorType(err, synerr).Nil(p)

	// 缺少参数
	l = newLexer([]rune("id  \n"))
	p, err = l.scanAPIParam("@apiQuery")
	a.ErrorType(err, synerr).Nil(p)
}

func TestScanAPI(t *testing.T) {
	a := assert.New(t)
	d := &Doc{Apis: []*API{}}

	// 正常情况
	l := newLexer([]rune(" get test.com/api.json?k=1 summary summary\n api description\n@apiSuccess 200 OK"))

	a.NotError(l.scanAPI(d))
	api := d.Apis[0]
	a.Equal(api.Method, "get").
		Equal(api.URL, "test.com/api.json?k=1").
		Equal(api.Summary, "summary summary").
		Equal(api.Description, "api description")

	// 多行description
	l = newLexer([]rune(" post test.com/api.json?K=1  summary summary\n api \ndescription\n@apiSuccess 400 summary"))
	a.NotError(l.scanAPI(d))
	api = d.Apis[1]
	a.Equal(api.URL, "test.com/api.json?K=1").
		Equal(api.Method, "post").
		Equal(api.Summary, "summary summary").
		Equal(api.Description, "api \ndescription")

	// 缺少description参数
	l = newLexer([]rune("get test.com/api.json summary summary \n@apiSuccess 400 error"))
	a.NotError(l.scanAPI(d))
	api = d.Apis[2]
	a.Equal(api.Method, "get").
		Equal(api.URL, "test.com/api.json").
		Equal(api.Summary, "summary summary").
		Equal(api.Description, "")

	// 缺少description参数
	l = newLexer([]rune("get test.com/api.json summary summary\n \n@apiSuccess 400 error"))
	a.NotError(l.scanAPI(d))
	api = d.Apis[3]
	a.Equal(api.Method, "get").
		Equal(api.URL, "test.com/api.json").
		Equal(api.Summary, "summary summary").
		Equal(api.Description, "")

	// 没有任何参数
	l = newLexer([]rune("  "))
	a.ErrorType(l.scanAPI(d), synerr)
}

func TestScanAPIDoc(t *testing.T) {
	a := assert.New(t)

	code := ` title of apidoc
@apiVersion 2.0.1
@apiBaseURL https://api.caixw.io
@apiLicense MIT https://opensource.org/licenses/MIT
@apiContent
line1
line2`

	l := newLexer([]rune(code))
	a.NotNil(l)
	doc := &Doc{}

	a.NotError(l.scanAPIDoc(doc))
	a.Equal(doc.Version, "2.0.1").
		Equal(doc.Title, "title of apidoc").
		Equal(doc.BaseURL, "https://api.caixw.io").
		Equal(doc.LicenseName, "MIT").
		Equal(doc.LicenseURL, "https://opensource.org/licenses/MIT").
		Equal(doc.Content, "\nline1\nline2")

		// 重复内容，报错
	code = `title of apidoc2
		@apiBaseURL http://api.caixw.io
line1
line2`
	l = newLexer([]rune(code))
	a.Error(l.scanAPIDoc(doc))

	// 检测各个都是空值的情况
	code = `2.9 title of apidoc
`
	l = newLexer([]rune(code))
	a.NotNil(l)
	doc = &Doc{}
	a.NotError(l.scanAPIDoc(doc))
	a.Equal(doc.Title, "2.9 title of apidoc").
		Equal(doc.Version, "").
		Equal(doc.BaseURL, "").
		Equal(doc.LicenseName, "").
		Equal(doc.LicenseURL, "")
}

func TestScanAPIRequest(t *testing.T) {
	a := assert.New(t)
	api := &API{}

	code := ` xml
 @apiHeader h1 v1
 @apiHeader h2 v2
@apiParam p1 int optional p1 summary
@apiParam p2 int p2 summary
@apiExample json
{
    p1:v1,
    p2:v2
}
@apiExample xml
<root>
    <p1>v1</p1>
    <p2>v2</p2>
</root>
`
	l := newLexer([]rune(code))
	a.NotError(l.scanAPIRequest(api))
	a.NotNil(api.Request)
	r := api.Request
	a.Equal(2, len(r.Headers)).
		Equal(r.Headers["h1"], "v1").
		Equal(r.Headers["h2"], "v2").
		Equal(r.Params[0].Name, "p1").
		Equal(r.Params[1].Summary, "p2 summary").
		Equal(r.Examples[0].Type, "json").
		Equal(r.Examples[1].Type, "xml").
		Equal(r.Examples[1].Code, `<root>
    <p1>v1</p1>
    <p2>v2</p2>
</root>`)

	code = ` xml
@apiHeader h1 v1
@apiParam p1 int p1 summary

@apiExample xml
<root>
    <p1>v1</p1>
</root>
@apiGroup abc
`
	matchCode := `<root>
    <p1>v1</p1>
</root>`
	l = newLexer([]rune(code))
	a.NotError(l.scanAPIRequest(api))
	a.NotNil(api.Request)
	r = api.Request
	a.Equal(1, len(r.Headers)).
		Equal(r.Headers["h1"], "v1").
		Equal(r.Params[0].Name, "p1").
		Equal(r.Examples[0].Type, "xml").
		Equal(r.Examples[0].Code, matchCode)
}

func TestScanResponse(t *testing.T) {
	a := assert.New(t)

	code := ` 200 json
@apiHeader h1 v1
@apiHeader h2 v2
@apiParam p1 int optional p1 summary
@apiParam p2 int p2 summary
@apiExample json
{
    p1:v1,
    p2:v2
}
@apiExample xml
<root>
    <p1>v1</p1>
    <p2>v2</p2>
</root>
`
	l := newLexer([]rune(code))
	resp, err := l.scanResponse("@apiError")
	a.NotError(err).NotNil(resp)
	a.Equal(resp.Code, "200").
		Equal(resp.Summary, "json").
		Equal(resp.Headers["h1"], "v1").
		Equal(resp.Headers["h2"], "v2").
		Equal(resp.Params[0].Name, "p1").
		Equal(resp.Params[1].Summary, "p2 summary").
		Equal(resp.Examples[0].Type, "json").
		Equal(resp.Examples[1].Type, "xml")

	code = ` 200 xml  status summary
 @apiHeader h1 v1
 @apiParam p1 int p1 summary

@apiExample xml
<root>
    <p1>v1</p1>
</root>
@apiError
`
	matchCode := `<root>
    <p1>v1</p1>
</root>`
	l = newLexer([]rune(code))
	resp, err = l.scanResponse("@apiError")
	a.NotError(err).NotNil(resp)
	a.Equal(resp.Code, "200").
		Equal(resp.Summary, "xml  status summary").
		Equal(resp.Headers["h1"], "v1").
		Equal(resp.Params[0].Name, "p1").
		Equal(resp.Examples[0].Code, matchCode)

	// 缺少必要的参数
	code = `
@apiSuccess g
`
	l = newLexer([]rune(code))
	resp, err = l.scanResponse("@apiError")
	a.Error(err).Nil(resp)
}

func TestDoc_Scan(t *testing.T) {
	a := assert.New(t)
	doc1 := New()

	code := `
@api get /baseurl/api/login api summary
api description 1
api description 2
@apiQuery q1 int q1 summary
@apiQuery q2 int q2 summary
@apiParam p1 int p1 summary
@apiParam p2 int p2 summary

@apiSuccess 200 json
@apiHeader h1 v1
@apiHeader h2 v2
@apiParam p1 int optional p1 summary
@apiParam p2 int p2 summary
@apiExample json
{
    p1:v1,
    p2:v2
}
@apiExample xml
<root>
    <p1>v1</p1>
    <p2>v2</p2>
</root>

@apiError 200 json
@apiHeader h1 v1
@apiHeader h2 v2
`
	err := doc1.Scan([]rune(code))
	a.NotError(err)
	d := doc1.Apis[0]

	a.Equal(d.URL, "/baseurl/api/login").
		Equal(d.Group, app.DefaultGroupName).
		Equal(d.Summary, "api summary").
		Equal(d.Description, "api description 1\napi description 2")

	a.Equal(2, len(d.Queries)).
		Equal(2, len(d.Params))

	q := d.Queries
	a.Equal(q[0].Name, "q1").Equal(q[0].Summary, "q1 summary")

	p := d.Params
	a.Equal(p[0].Name, "p1").Equal(p[0].Summary, "p1 summary")

	s := d.Success
	a.Equal(s.Code, "200").
		Equal(s.Summary, "json").
		Equal(s.Headers["h1"], "v1").
		Equal(s.Headers["h2"], "v2").
		Equal(s.Params[0].Name, "p1").
		Equal(s.Params[1].Summary, "p2 summary").
		Equal(s.Examples[0].Type, "json").
		Equal(s.Examples[1].Type, "xml")

	s = d.Error
	a.Equal(s.Code, "200")

	// 不包含api定义的代码块，将返回 nil 且不会有内容添加到 doc1.Apis
	code = `
Copyright 2015 by caixw, All rights reserved.
Use of this source code is governed by a MIT
license that can be found in the LICENSE file.
`
	l := len(doc1.Apis)
	err = doc1.Scan([]rune(code))
	a.NotError(err)
	a.Equal(l, len(doc1.Apis))

	// @apiGroup
	code = `
@api delete /admin/users/{id} delete users
@apiGroup
@apiParam id int user id
@apiError 400 error
`
	l = len(doc1.Apis)
	a.ErrorType(doc1.Scan([]rune(code)), synerr) // @apiGroup 少参数

	// @apiIgnore
	code = `
@api delete /admin/users/{id} delete users
@apiIgnore
@apiParam id int user id
@apiError 400 error
`
	l = len(doc1.Apis)
	err = doc1.Scan([]rune(code))
	a.NotError(err)
	a.Equal(l, len(doc1.Apis))

	// @apiIgnore 非正常标签，标签只能出现在行首
	code = `
@api delete /admin/users/{id} delete users
@apiGroup group
ab @apiIgnore
@apiParam id int user id
@apiSuccess 200 OK
`
	l = len(doc1.Apis)
	err = doc1.Scan([]rune(code))
	a.NotError(err)
	a.Equal(l+1, len(doc1.Apis))

	// @apiIgno 不认识的标签，会提示错误信息
	code = `
@api delete /admin/users/{id} delete users
@apiIgno
@apiGroup group
@apiParam id int user id
@apiSuccess 200 OK
`
	l = len(doc1.Apis)
	err = doc1.Scan([]rune(code))
	a.ErrorType(err, synerr)
}
<|endoftext|>