<commit_before>package GoSDK

import (
	"fmt"
	"strings"
)

const (
	_CODE_ADMIN_PREAMBLE    = "/admin/code/v/1"
	_CODE_ADMIN_PREAMBLE_V2 = "/codeadmin/v/2"
)

//Service is a helper struct for grouping facts about a code service
type Service struct {
	Name    string
	Code    string
	Version int
	Params  []string
	System  string
}

//CodeLog provides structure to the code log return value
type CodeLog struct {
	Log  string
	Time string
}

//GetServiceNames retrieves the service names for a particular system
func (d *DevClient) GetServiceNames(systemKey string) ([]string, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := get(d, _CODE_ADMIN_PREAMBLE+"/"+systemKey, nil, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Error getting services: %v", err)
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Error getting services: %v", resp.Body)
	}
	code := resp.Body.(map[string]interface{})["code"]
	sliceBody, isSlice := code.([]interface{})
	if !isSlice && code != nil {
		return nil, fmt.Errorf("Error getting services: server returned unexpected response")
	}
	services := make([]string, len(sliceBody))
	for i, service := range sliceBody {
		services[i] = service.(string)
	}
	return services, nil
}

//GetService returns information about a specified service
func (d *DevClient) GetService(systemKey, name string) (*Service, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := get(d, _CODE_PREAMBLE+"/"+systemKey+"/"+name, nil, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Error getting service: %v", err)
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Error getting service: %v", resp.Body)
	}
	mapBody := resp.Body.(map[string]interface{})
	paramsSlice := mapBody["params"].([]interface{})
	params := make([]string, len(paramsSlice))
	for i, param := range paramsSlice {
		params[i] = param.(string)
	}
	svc := &Service{
		Name:    name,
		System:  systemKey,
		Code:    mapBody["code"].(string),
		Version: int(mapBody["current_version"].(float64)),
		Params:  params,
	}
	return svc, nil
}

func (d *DevClient) GetServiceRaw(systemKey, name string) (map[string]interface{}, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := get(d, _CODE_PREAMBLE+"/"+systemKey+"/"+name, nil, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Error getting service: %v", err)
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Error getting service: %v", resp.Body)
	}
	mapBody := resp.Body.(map[string]interface{})
	/*
		paramsSlice := mapBody["params"].([]interface{})
		params := make([]string, len(paramsSlice))
		for i, param := range paramsSlice {
			params[i] = param.(string)
		}
	*/
	return mapBody, nil
}

//SetServiceEffectiveUser allows the developer to set the userid that a service executes under.
func (d *DevClient) SetServiceEffectiveUser(systemKey, name, userid string) error {
	creds, err := d.credentials()
	if err != nil {
		return err
	}
	resp, err := put(d, _CODE_ADMIN_PREAMBLE+"/"+systemKey+"/"+name, map[string]interface{}{
		"run_user": userid,
	}, creds, nil)
	if err != nil {
		return fmt.Errorf("Error updating service: %v\n", err)
	}
	if resp.StatusCode != 200 {
		return fmt.Errorf("Error updating service: %v\n", resp.Body)
	}
	return nil
}

//UpdateService facillitates changes to the service's code
func (d *DevClient) UpdateService(systemKey, name, code string, params []string) (map[string]interface{}, error) {
	extra := map[string]interface{}{"code": code, "name": name, "parameters": params}
	return d.updateService(systemKey, name, code, extra)
}

func (d *DevClient) UpdateServiceWithLibraries(systemKey, name, code, deps string, params []string) (map[string]interface{}, error) {
	extra := map[string]interface{}{"code": code, "name": name, "parameters": params, "dependencies": deps}
	return d.updateService(systemKey, name, code, extra)
}

//UpdateServiceWithBody updates a service code and any additional info passed in (parameters, execution_timeout, etc.)
func (d *DevClient) UpdateServiceWithBody(systemKey, name, code string, extra map[string]interface{}) (map[string]interface{}, error) {
	return d.updateService(systemKey, name, code, extra)
}

func (d *DevClient) updateService(sysKey, name, code string, extra map[string]interface{}) (map[string]interface{}, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	extra["code"] = code
	resp, err := put(d, _CODE_ADMIN_PREAMBLE+"/"+sysKey+"/"+name, extra, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Error updating service: %v\n", err)
	}
	body, ok := resp.Body.(map[string]interface{})
	if !ok {
		return nil, fmt.Errorf("Service not created. First create service...")
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Error updating service: %v\n", resp.Body)
	}
	return body, nil
}

//NewServiceWithLibraries creates a new service with the specified code, params, and libraries/dependencies.
//Parameters is a slice of strings of parameter names
func (d *DevClient) NewServiceWithLibraries(systemKey, name, code, deps string, params []string) error {
	extra := map[string]interface{}{"parameters": params, "dependencies": deps}
	return d.newService(systemKey, name, code, extra)
}

//NewService creates a new service with a new name, code and params
func (d *DevClient) NewService(systemKey, name, code string, params []string) error {
	extra := map[string]interface{}{"parameters": params}
	return d.newService(systemKey, name, code, extra)
}

//NewServiceWithBody creates a new service with a new name, code and any additional info passed in (parameters, execution_timeout, etc.)
func (d *DevClient) NewServiceWithBody(systemKey, name, code string, extra map[string]interface{}) error {
	return d.newService(systemKey, name, code, extra)
}

//EnableLogsForService activates logging for execution of a service
func (d *DevClient) EnableLogsForService(systemKey, name string) error {
	creds, err := d.credentials()
	if err != nil {
		return err
	}
	_, err = post(d, _CODE_ADMIN_PREAMBLE_V2+"/logs/"+systemKey+"/"+name, map[string]interface{}{"logging": "true"}, creds, nil)
	return err
}

//DisableLogsForService turns logging off for that service
func (d *DevClient) DisableLogsForService(systemKey, name string) error {
	creds, err := d.credentials()
	if err != nil {
		return err
	}
	_, err = post(d, _CODE_ADMIN_PREAMBLE_V2+"/logs/"+systemKey+"/"+name, map[string]interface{}{"logging": false}, creds, nil)
	return err
}

//AreServiceLogsEnabled allows the developer to query the state of logging
func (d *DevClient) AreServiceLogsEnabled(systemKey, name string) (bool, error) {
	creds, err := d.credentials()
	if err != nil {
		return false, err
	}
	resp, err := get(d, _CODE_ADMIN_PREAMBLE_V2+"/logs/"+systemKey+"/"+name+"/active", nil, creds, nil)
	if err != nil {
		return false, err
	}
	le := resp.Body.(map[string]interface{})["logging_enabled"]
	if le == nil {
		return false, fmt.Errorf("Improperly formatted json response")
	} else {
		return strings.ToLower(le.(string)) == "true", nil
	}
}

//GetLogsForService retrieves the logs for the service
func (d *DevClient) GetLogsForService(systemKey, name string) ([]CodeLog, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := get(d, _CODE_ADMIN_PREAMBLE_V2+"/logs/"+systemKey+"/"+name, nil, creds, nil)
	if err != nil {
		return nil, err
	}
	switch resp.Body.(type) {
	case string:
		return nil, fmt.Errorf("%s", resp.Body.(string))
	case []interface{}:
		r := resp.Body.([]map[string]interface{})
		outgoing := make([]CodeLog, len(r))
		for idx, v := range r {
			cl := genCodeLog(v)
			outgoing[idx] = cl
		}
		return outgoing, nil
	case []map[string]interface{}:
		r := resp.Body.([]map[string]interface{})
		outgoing := make([]CodeLog, len(r))
		for idx, v := range r {
			cl := genCodeLog(v)
			outgoing[idx] = cl
		}
		return outgoing, nil
	default:
		return nil, fmt.Errorf("Bad Return Value\n")
	}
}

func (d *DevClient) newService(systemKey, name, code string, extra map[string]interface{}) error {
	creds, err := d.credentials()
	if err != nil {
		return err
	}
	extra["code"] = code
	resp, err := post(d, _CODE_ADMIN_PREAMBLE+"/"+systemKey+"/"+name, extra, creds, nil)
	if err != nil {
		return fmt.Errorf("Error creating new service: %v", err)
	}
	if resp.StatusCode != 200 {
		return fmt.Errorf("Error creating new service: %v", resp.Body)
	}
	return nil
}

func (d *DevClient) DeleteService(systemKey, name string) error {
	creds, err := d.credentials()
	if err != nil {
		return err
	}
	resp, err := delete(d, _CODE_ADMIN_PREAMBLE+"/"+systemKey+"/"+name, nil, creds, nil)
	if err != nil {
		return fmt.Errorf("Error deleting service: %v", err)
	}
	if resp.StatusCode != 200 {
		return fmt.Errorf("Error deleting service: %v", resp.Body)
	}
	return nil
}

func (d *DevClient) GetFailedServices(systemKey string) ([]map[string]interface{}, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := get(d, "/codeadmin/failed/"+systemKey, nil, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Could not get failed services: %s", err)
	}
	body := resp.Body.(map[string]interface{})[systemKey].([]interface{})
	services := make([]map[string]interface{}, len(body))
	for i, b := range body {
		services[i] = b.(map[string]interface{})
	}
	return services, nil
}

func (d *DevClient) RetryFailedServices(systemKey string, ids []string) ([]string, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := post(d, "/codeadmin/failed/"+systemKey, map[string]interface{}{"id": ids}, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Could not retry failed service %s/%s: %s", systemKey, ids, err)
	}
	body := resp.Body.([]interface{})
	responses := make([]string, len(body))
	for i, b := range body {
		responses[i] = b.(string)
	}
	return responses, nil
}

func (d *DevClient) DeleteFailedServices(systemKey string, ids []string) ([]map[string]interface{}, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := deleteWithBody(d, "/codeadmin/failed/"+systemKey, map[string]interface{}{"id": ids}, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Could not delete failed services %s/%s: %s", systemKey, ids, err)
	}
	body := resp.Body.([]interface{})
	services := make([]map[string]interface{}, len(body))
	for i, b := range body {
		services[i] = b.(map[string]interface{})
	}
	return services, nil
}

func (d *DevClient) SetLongRunningServiceParams(systemKey, name string, autoRestart, autoBalance bool, concurrency int) error {
	creds, err := d.credentials()
	if err != nil {
		return err
	}
	params := map[string]interface{}{
		"execution_timeout": -1,
		"auto_restart":      autoRestart,
		"concurrency":       concurrency,
		"auto_balance":      autoBalance,
	}

	_, err = put(d, _CODE_ADMIN_PREAMBLE_V2+"/"+systemKey+"/"+name, params, creds, nil)
	return err
}

func genCodeLog(m map[string]interface{}) CodeLog {
	cl := CodeLog{}
	if tim, ext := m["service_execution_time"]; ext {
		t := tim.(string)
		cl.Time = t
	}
	if logg, ext := m["log"]; ext {
		l := logg.(string)
		cl.Log = l
	}
	return cl
}
<commit_msg>added code for service update with a map<commit_after>package GoSDK

import (
	"fmt"
	"strings"
)

const (
	_CODE_ADMIN_PREAMBLE    = "/admin/code/v/1"
	_CODE_ADMIN_PREAMBLE_V2 = "/codeadmin/v/2"
)

//Service is a helper struct for grouping facts about a code service
type Service struct {
	Name    string
	Code    string
	Version int
	Params  []string
	System  string
}

//CodeLog provides structure to the code log return value
type CodeLog struct {
	Log  string
	Time string
}

//GetServiceNames retrieves the service names for a particular system
func (d *DevClient) GetServiceNames(systemKey string) ([]string, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := get(d, _CODE_ADMIN_PREAMBLE+"/"+systemKey, nil, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Error getting services: %v", err)
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Error getting services: %v", resp.Body)
	}
	code := resp.Body.(map[string]interface{})["code"]
	sliceBody, isSlice := code.([]interface{})
	if !isSlice && code != nil {
		return nil, fmt.Errorf("Error getting services: server returned unexpected response")
	}
	services := make([]string, len(sliceBody))
	for i, service := range sliceBody {
		services[i] = service.(string)
	}
	return services, nil
}

//GetService returns information about a specified service
func (d *DevClient) GetService(systemKey, name string) (*Service, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := get(d, _CODE_PREAMBLE+"/"+systemKey+"/"+name, nil, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Error getting service: %v", err)
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Error getting service: %v", resp.Body)
	}
	mapBody := resp.Body.(map[string]interface{})
	paramsSlice := mapBody["params"].([]interface{})
	params := make([]string, len(paramsSlice))
	for i, param := range paramsSlice {
		params[i] = param.(string)
	}
	svc := &Service{
		Name:    name,
		System:  systemKey,
		Code:    mapBody["code"].(string),
		Version: int(mapBody["current_version"].(float64)),
		Params:  params,
	}
	return svc, nil
}

func (d *DevClient) GetServiceRaw(systemKey, name string) (map[string]interface{}, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := get(d, _CODE_PREAMBLE+"/"+systemKey+"/"+name, nil, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Error getting service: %v", err)
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Error getting service: %v", resp.Body)
	}
	mapBody := resp.Body.(map[string]interface{})
	/*
		paramsSlice := mapBody["params"].([]interface{})
		params := make([]string, len(paramsSlice))
		for i, param := range paramsSlice {
			params[i] = param.(string)
		}
	*/
	return mapBody, nil
}

//SetServiceEffectiveUser allows the developer to set the userid that a service executes under.
func (d *DevClient) SetServiceEffectiveUser(systemKey, name, userid string) error {
	creds, err := d.credentials()
	if err != nil {
		return err
	}
	resp, err := put(d, _CODE_ADMIN_PREAMBLE+"/"+systemKey+"/"+name, map[string]interface{}{
		"run_user": userid,
	}, creds, nil)
	if err != nil {
		return fmt.Errorf("Error updating service: %v\n", err)
	}
	if resp.StatusCode != 200 {
		return fmt.Errorf("Error updating service: %v\n", resp.Body)
	}
	return nil
}

//UpdateService facillitates changes to the service's code
func (d *DevClient) UpdateService(systemKey, name, code string, params []string) (map[string]interface{}, error) {
	extra := map[string]interface{}{"code": code, "name": name, "parameters": params}
	return d.updateService(systemKey, name, code, extra)
}

func (d *DevClient) UpdateServiceWithLibraries(systemKey, name, code, deps string, params []string) (map[string]interface{}, error) {
	extra := map[string]interface{}{"code": code, "name": name, "parameters": params, "dependencies": deps}
	return d.updateService(systemKey, name, code, extra)
}

//UpdateServiceWithBody updates a service code and any additional info passed in (parameters, execution_timeout, etc.)
func (d *DevClient) UpdateServiceWithBody(systemKey, name, code string, extra map[string]interface{}) (map[string]interface{}, error) {
	return d.updateService(systemKey, name, code, extra)
}

func (d *DevClient) updateService(sysKey, name, code string, extra map[string]interface{}) (map[string]interface{}, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	extra["code"] = code
	resp, err := put(d, _CODE_ADMIN_PREAMBLE+"/"+sysKey+"/"+name, extra, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Error updating service: %v\n", err)
	}
	body, ok := resp.Body.(map[string]interface{})
	if !ok {
		return nil, fmt.Errorf("Service not created. First create service...")
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Error updating service: %v\n", resp.Body)
	}
	return body, nil
}

//NewServiceWithLibraries creates a new service with the specified code, params, and libraries/dependencies.
//Parameters is a slice of strings of parameter names
func (d *DevClient) NewServiceWithLibraries(systemKey, name, code, deps string, params []string) error {
	extra := map[string]interface{}{"parameters": params, "dependencies": deps}
	return d.newService(systemKey, name, code, extra)
}

//NewService creates a new service with a new name, code and params
func (d *DevClient) NewService(systemKey, name, code string, params []string) error {
	extra := map[string]interface{}{"parameters": params}
	return d.newService(systemKey, name, code, extra)
}

//NewServiceWithBody creates a new service with a new name, code and any additional info passed in (parameters, execution_timeout, etc.)
func (d *DevClient) NewServiceWithBody(systemKey, name, code string, extra map[string]interface{}) error {
	return d.newService(systemKey, name, code, extra)
}

//EnableLogsForService activates logging for execution of a service
func (d *DevClient) EnableLogsForService(systemKey, name string) error {
	creds, err := d.credentials()
	if err != nil {
		return err
	}
	_, err = post(d, _CODE_ADMIN_PREAMBLE_V2+"/logs/"+systemKey+"/"+name, map[string]interface{}{"logging": "true"}, creds, nil)
	return err
}

func (d *DevClient) UpdateServiceWithMap(systemKey, name string, changes map[string]interface{}) (map[string]interface{}, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := put(d, _CODE_ADMIN_PREAMBLE+"/"+systemKey+"/"+name, changes, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Error updating service: %v\n", err)
	}
	body, ok := resp.Body.(map[string]interface{})
	if !ok {
		return nil, fmt.Errorf("Service not created. First create service...")
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Error updating service: %v\n", resp.Body)
	}
	return body, nil
}

//DisableLogsForService turns logging off for that service
func (d *DevClient) DisableLogsForService(systemKey, name string) error {
	creds, err := d.credentials()
	if err != nil {
		return err
	}
	_, err = post(d, _CODE_ADMIN_PREAMBLE_V2+"/logs/"+systemKey+"/"+name, map[string]interface{}{"logging": false}, creds, nil)
	return err
}

//AreServiceLogsEnabled allows the developer to query the state of logging
func (d *DevClient) AreServiceLogsEnabled(systemKey, name string) (bool, error) {
	creds, err := d.credentials()
	if err != nil {
		return false, err
	}
	resp, err := get(d, _CODE_ADMIN_PREAMBLE_V2+"/logs/"+systemKey+"/"+name+"/active", nil, creds, nil)
	if err != nil {
		return false, err
	}
	le := resp.Body.(map[string]interface{})["logging_enabled"]
	if le == nil {
		return false, fmt.Errorf("Improperly formatted json response")
	} else {
		return strings.ToLower(le.(string)) == "true", nil
	}
}

//GetLogsForService retrieves the logs for the service
func (d *DevClient) GetLogsForService(systemKey, name string) ([]CodeLog, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := get(d, _CODE_ADMIN_PREAMBLE_V2+"/logs/"+systemKey+"/"+name, nil, creds, nil)
	if err != nil {
		return nil, err
	}
	switch resp.Body.(type) {
	case string:
		return nil, fmt.Errorf("%s", resp.Body.(string))
	case []interface{}:
		r := resp.Body.([]map[string]interface{})
		outgoing := make([]CodeLog, len(r))
		for idx, v := range r {
			cl := genCodeLog(v)
			outgoing[idx] = cl
		}
		return outgoing, nil
	case []map[string]interface{}:
		r := resp.Body.([]map[string]interface{})
		outgoing := make([]CodeLog, len(r))
		for idx, v := range r {
			cl := genCodeLog(v)
			outgoing[idx] = cl
		}
		return outgoing, nil
	default:
		return nil, fmt.Errorf("Bad Return Value\n")
	}
}

func (d *DevClient) newService(systemKey, name, code string, extra map[string]interface{}) error {
	creds, err := d.credentials()
	if err != nil {
		return err
	}
	extra["code"] = code
	resp, err := post(d, _CODE_ADMIN_PREAMBLE+"/"+systemKey+"/"+name, extra, creds, nil)
	if err != nil {
		return fmt.Errorf("Error creating new service: %v", err)
	}
	if resp.StatusCode != 200 {
		return fmt.Errorf("Error creating new service: %v", resp.Body)
	}
	return nil
}

func (d *DevClient) DeleteService(systemKey, name string) error {
	creds, err := d.credentials()
	if err != nil {
		return err
	}
	resp, err := delete(d, _CODE_ADMIN_PREAMBLE+"/"+systemKey+"/"+name, nil, creds, nil)
	if err != nil {
		return fmt.Errorf("Error deleting service: %v", err)
	}
	if resp.StatusCode != 200 {
		return fmt.Errorf("Error deleting service: %v", resp.Body)
	}
	return nil
}

func (d *DevClient) GetFailedServices(systemKey string) ([]map[string]interface{}, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := get(d, "/codeadmin/failed/"+systemKey, nil, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Could not get failed services: %s", err)
	}
	body := resp.Body.(map[string]interface{})[systemKey].([]interface{})
	services := make([]map[string]interface{}, len(body))
	for i, b := range body {
		services[i] = b.(map[string]interface{})
	}
	return services, nil
}

func (d *DevClient) RetryFailedServices(systemKey string, ids []string) ([]string, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := post(d, "/codeadmin/failed/"+systemKey, map[string]interface{}{"id": ids}, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Could not retry failed service %s/%s: %s", systemKey, ids, err)
	}
	body := resp.Body.([]interface{})
	responses := make([]string, len(body))
	for i, b := range body {
		responses[i] = b.(string)
	}
	return responses, nil
}

func (d *DevClient) DeleteFailedServices(systemKey string, ids []string) ([]map[string]interface{}, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := deleteWithBody(d, "/codeadmin/failed/"+systemKey, map[string]interface{}{"id": ids}, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Could not delete failed services %s/%s: %s", systemKey, ids, err)
	}
	body := resp.Body.([]interface{})
	services := make([]map[string]interface{}, len(body))
	for i, b := range body {
		services[i] = b.(map[string]interface{})
	}
	return services, nil
}

func (d *DevClient) SetLongRunningServiceParams(systemKey, name string, autoRestart, autoBalance bool, concurrency int) error {
	creds, err := d.credentials()
	if err != nil {
		return err
	}
	params := map[string]interface{}{
		"execution_timeout": -1,
		"auto_restart":      autoRestart,
		"concurrency":       concurrency,
		"auto_balance":      autoBalance,
	}

	_, err = put(d, _CODE_ADMIN_PREAMBLE_V2+"/"+systemKey+"/"+name, params, creds, nil)
	return err
}

func genCodeLog(m map[string]interface{}) CodeLog {
	cl := CodeLog{}
	if tim, ext := m["service_execution_time"]; ext {
		t := tim.(string)
		cl.Time = t
	}
	if logg, ext := m["log"]; ext {
		l := logg.(string)
		cl.Log = l
	}
	return cl
}
<|endoftext|>


<commit_before>/**
 * Copyright 2015 Andrew Bates
 *
 * 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 gosh

import (
	"sort"
	"strings"
	"unicode"
)

type Completer struct {
	topLevelCommands CommandMap
}

func NewCompleter(commands CommandMap) *Completer {
	completer := &Completer{commands}
	return completer
}

func (completer Completer) Complete(line string) (c []string) {
	prefix := ""
	fields := strings.Fields(line)
	/* We need to make sure that there are empty fields
	 * in the event of a blank line, or a line that ends
	 * in a space.  Otherwise, there is nothing to attempt
	 * to match on below
	 */
	if len(fields) == 0 {
		fields = []string{""}
	} else if unicode.IsSpace(rune(line[len(line)-1])) {
		fields = append(fields, "")
	}

	commands := completer.topLevelCommands
	for _, field := range fields {
		completions := commands.getCompletions(field)
		for completion, command := range completions {
			/* If it is an exact match then
			 * continue to the next field
			 */
			if field == completion {
				prefix = prefix + completion + " "
				commands = command.SubCommands()
				break
			} else {
				c = append(c, prefix+completion)
			}
		}
	}
	sort.Strings(c)
	return
}
<commit_msg>Changes in support of TreeCommand<commit_after>/**
 * Copyright 2015 Andrew Bates
 *
 * 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 gosh

import (
	"sort"
	"strings"
	"unicode"
)

type Completer struct {
	topLevelCommands CommandMap
}

func NewCompleter(commands CommandMap) *Completer {
	completer := &Completer{commands}
	return completer
}

func (completer Completer) Complete(line string) (c []string) {
	prefix := ""
	fields := strings.Fields(line)
	/* We need to make sure that there are empty fields
	 * in the event of a blank line, or a line that ends
	 * in a space.  Otherwise, there is nothing to attempt
	 * to match on below
	 */
	if len(fields) == 0 {
		fields = []string{""}
	} else if unicode.IsSpace(rune(line[len(line)-1])) {
		fields = append(fields, "")
	}

	commands := completer.topLevelCommands
	for _, field := range fields {
		completions := commands.getCompletions(field)
		for completion, command := range completions {
			/* If it is an exact match then
			 * continue to the next field
			 */
			if field == completion {
				prefix = prefix + completion + " "
				if command, ok := command.(TreeCommand); ok {
					commands = command.SubCommands()
				} else {
					completions := command.Completions()
					commands = make(CommandMap, len(completions))
					for _, completion := range completions {
						commands[completion] = command
					}
				}
				break
			} else {
				c = append(c, prefix+completion)
			}
		}
	}
	sort.Strings(c)
	return
}
<|endoftext|>


<commit_before>package boardgame

import (
	"crypto/sha1"
	"errors"
	"fmt"
	"strconv"
)

//A Component represents a movable resource in the game. Cards, dice, meeples,
//resource tokens, etc are all components. Values is a struct that stores the
//specific values for the component. Components are the same across all games
//of this type. Component references should not be compared directly for
//equality, as sometimes different underlying objects will represent the same
//notional component (in order to satisfy both the Component and
//ComponentInstance interfaces simultaneously). Instead, use Equivalent() to
//test that two Components refer to the same conceptual Component.
type Component interface {
	Values() ComponentValues
	Deck() *Deck
	DeckIndex() int
	//Equivalent checks whether two components are equivalent--that is,
	//whether they represent the same index in the same deck.
	Equivalent(other Component) bool

	//Instance returns a ComponentInstance representing this component in the
	//given state.
	Instance(st State) ComponentInstance

	//ptr() is used for when the component itself is used as a key into
	//an index and equality is important.
	ptr() *component
}

//ComponentInstance is a specific instantiation of a component as it exists in
//the particular State it is associated with. ComponentInstances also
//implement all of the Component information, as a convenience you often need
//both bits of inforamation.  The downside of this is that two Component
//values can't be compared directly for equality because they may be different
//underlying objects and wrappers. If you want to see if two Components that
//might be from different states refer to the same underlying conceptual
//Component, use Equivalent(). However, ComponentInstances compared with
//another ComponentInstance for the same component in the same state will be
//equal.
type ComponentInstance interface {
	//ComponentInstances have all of the information of a base Component, as
	//often that's the information you most need.
	Component

	//ID returns a semi-stable ID for this component within this game and the
	//current state this component instance is associated with. Within this
	//game, it will only change when the shuffleCount for this component
	//changes. Across games the Id for the "same" component will be different,
	//in a way that cannot be guessed without access to game.SecretSalt. See
	//the package doc for more on semi-stable Ids for components, what they
	//can be used for, and when they do (and don't) change.
	ID() string
	//DynamicValues returns the Dynamic Values for this component in the state
	//this instance is associated with. A convenience so you don't have to go
	//find them within the DynamicComponentValues yourself.
	DynamicValues() SubState

	//State returns the State object that this ComponentInstance is affiliated
	//with.
	State() State

	//Mutable returns a mutable version of this component instance. It's sugar
	//for state.ContainingMutableComponent. You must pass in a Mutable version
	//of the state associated with this ComponentInstance to prove that you
	//have a mutable state.
	Mutable(state MutableState) (MutableComponentInstance, error)

	//mutable is only to be used to up-cast to mutablecomponentindex when you
	//know that's what it is as a quick convenience for use only within this package.
	mutable() MutableComponentInstance

	secretMoveCount() int
	movedSecretly()
}

//Note that a MutableComponentInstance doesn't actually guarantee that the
//component is in a mutable context at this moment, just that it was at some
//point on thie state (otherwise you couldn't have gotten a reference to it).
//In practice though, if a Component was ever in a mutable context in a given
//state, it must remain that way, because it can't be moved from a
//MutableStack to a non-Mutable stack.

//MutableComponentInstance is a component instance that's in a context that is
//mutable. You generally get these from a MutableStack that contains them. The
//instance contains many methods to move the component to other stacks or
//locations.
type MutableComponentInstance interface {
	ComponentInstance

	//MoveTo moves the specified component in its current stack to the
	//specified slot in the destination stack. The destination stack must be
	//different than the one the component's currently in--if you're moving
	//components within a stack, use SwapComponent. In destination, slotIndex
	//must point to a valid "slot" to put a component, such that after
	//insertion, using that index on the destination will return that
	//component. In defaults Stacks, slots are any index from 0 up to and
	//including stack.Len(), because the stack will grow to insert the
	//component between existing components if necessary. For SizedStacks,
	//slotIndex must point to a currently empty slot.
	//MoveTo{First,Last,Next}Slot methods are useful if you want to move to
	//those locations. If you want the precise location of the inserted
	//component to not be visible, see SecretMoveTo.
	MoveTo(other MutableStack, slotIndex int) error

	//SecretMoveTo is equivalent to MoveTo, but after the move the Ids of all
	//components in destination will be scrambled. SecretMoveTo is useful when
	//the destination stack will be sanitized with something like PolicyOrder,
	//but the precise location of this insertion should not be observable.
	//Read the package doc for more about when this is useful.
	SecretMoveTo(other MutableStack, slotIndex int) error

	//MoveToFirstSlot moves the component to the first valid slot in the other
	//stack. For default Stacks, this is always 0. For SizedStacks, this is
	//the first empty slot from the left.
	MoveToFirstSlot(other MutableStack) error

	//MoveToLastSlot moves the component to the last valid slot in the other
	//stack. For default Stacks, this is always Len(). For SizedStacks, this is
	//the first empty slot from the right.
	MoveToLastSlot(other MutableStack) error

	//MoveToNextSlot moves the component to the next valid slot in the other
	//stack where the component could be added without splicing. For default
	//stacks this is equivalent to MoveToLastSlot. For fixed size stacks this
	//is equivalent to MoveToFirstSlot.
	MoveToNextSlot(other MutableStack) error

	//SlideToFirstSlot takes the given component and moves it to the start of
	//the same stack, moving everything else up. It is equivalent to removing
	//the component, moving it to a temporary stack, and then moving it back
	//to the original stack with MoveToFirstSlot--but of course without
	//needing the extra scratch stack.
	SlideToFirstSlot() error

	//SlideToLastSlot takes the given component and moves it to the end of the
	//same stack, moving everything else down. It is equivalent to removing
	//the component, moving it to a temporary stack, and then moving it back
	//to the original stack with MoveToLastSlot--but of course without needing
	//the extra scratch stack.
	SlideToLastSlot() error
}

type component struct {
	values ComponentValues
	//The deck we're a part of.
	deck *Deck
	//The index we are in the deck we're in.
	deckIndex int
}

//componentInstance has value method receivers so two that are configured the
//same will test as equal even if they were created separately, and because we
//never need to mutate the values within--all of the mutable state is handled
//on the state object.
type componentInstance struct {
	*component
	statePtr *state
}

func (c *component) Values() ComponentValues {
	if c == nil {
		return nil
	}
	return c.values
}

func (c *component) Deck() *Deck {
	if c == nil {
		return nil
	}
	return c.deck
}

func (c *component) DeckIndex() int {
	if c == nil {
		return -1
	}
	return c.deckIndex
}

func (c *component) Equivalent(other Component) bool {
	if c == nil && other == nil {
		return true
	}
	if c.Deck().Name() != other.Deck().Name() {
		return false
	}
	return c.DeckIndex() == other.DeckIndex()
}

func (c *component) ptr() *component {
	return c
}

func (c *component) Instance(st State) ComponentInstance {

	var ptr *state

	if st != nil {
		ptr = st.(*state)
	}

	return componentInstance{
		c,
		ptr,
	}
}

//ComponentValues is the interface that the Values property of a Component
//must implement. BaseComponentValues is designed to be anonymously embedded
//in your component to implement the latter part of the interface. autoreader
//can be used to implement Reader.
type ComponentValues interface {
	Reader
	//ContainingComponent is the component that this ComponentValues is
	//embedded in. It should return the component that was passed to
	//SetContainingComponent.
	ContainingComponent() Component
	//SetContainingComponent is called to let the component values know what
	//its containing component is.
	SetContainingComponent(c Component)
}

//BaseComponentValues is an optional convenience struct designed to be
//embedded anoymously in your component values to implement
//ContainingComponent() and SetContainingComponent() automatically.
type BaseComponentValues struct {
	c Component
}

func (b *BaseComponentValues) ContainingComponent() Component {
	return b.c
}

func (b *BaseComponentValues) SetContainingComponent(c Component) {
	b.c = c
}

func (c componentInstance) ID() string {

	//Shadow components shouldn't get an Id
	if c.Equivalent(c.Deck().GenericComponent()) {
		return ""
	}

	//S should  never be nil in normal circumstances, but if it is, return an
	//obviously-special Id so it doesn't appear to be the actual Id for this
	//component.
	if c.statePtr == nil {
		return ""
	}

	input := "insecuredefaultinput"

	game := c.statePtr.game
	input = game.Id() + game.secretSalt

	input += c.Deck().Name() + strconv.Itoa(c.DeckIndex())

	//The id only ever changes when the item has moved secretly.
	input += strconv.Itoa(c.secretMoveCount())

	hash := sha1.Sum([]byte(input))

	return fmt.Sprintf("%x", hash)
}

//secretMoveCount returns the secret move count for this component in the
//given state.
func (c componentInstance) secretMoveCount() int {

	if c == c.Deck().GenericComponent() {
		return 0
	}

	if c.statePtr == nil {
		return 0
	}

	s := c.statePtr

	deckMoveCount, ok := s.secretMoveCount[c.Deck().Name()]

	//No components in that deck have been moved secretly, I guess.
	if !ok {
		return 0
	}

	if c.DeckIndex() >= len(deckMoveCount) {
		//TODO: warn?
		return 0
	}

	if c.DeckIndex() < 0 {
		//This should never happen
		return 0
	}

	return deckMoveCount[c.DeckIndex()]
}

//movedSecretly increments the secretMoveCount for this component.
func (c componentInstance) movedSecretly() {
	if c.Equivalent(c.Deck().GenericComponent()) {
		return
	}

	s := c.statePtr

	if s == nil {
		return
	}

	deckMoveCount, ok := s.secretMoveCount[c.Deck().Name()]

	//We must be the first component in this deck that has been secretly
	//moved. Create the whole int stack for this group.
	if !ok {
		//The zero-value will be fine
		deckMoveCount = make([]int, len(c.Deck().Components()))
		s.secretMoveCount[c.Deck().Name()] = deckMoveCount
	}

	if c.DeckIndex() >= len(deckMoveCount) {
		//TODO: warn?
		return
	}

	if c.DeckIndex() < 0 {
		//This should never happen
		return
	}

	deckMoveCount[c.DeckIndex()]++

}

func (c componentInstance) MoveTo(other MutableStack, slotIndex int) error {
	source, sourceIndex, err := c.statePtr.ContainingMutableStack(c)
	if err != nil {
		return errors.New("The source component was not in a mutable stack: " + err.Error())
	}
	return source.moveComponent(sourceIndex, other, slotIndex)
}

func (c componentInstance) SecretMoveTo(other MutableStack, slotIndex int) error {
	source, sourceIndex, err := c.statePtr.ContainingMutableStack(c)
	if err != nil {
		return errors.New("The source component was not in a mutable stack: " + err.Error())
	}
	return source.secretMoveComponent(sourceIndex, other, slotIndex)
}

func (c componentInstance) MoveToFirstSlot(other MutableStack) error {
	source, sourceIndex, err := c.statePtr.ContainingMutableStack(c)
	if err != nil {
		return errors.New("The source component was not in a mutable stack: " + err.Error())
	}
	return source.moveComponent(sourceIndex, other, firstSlotIndex)
}

func (c componentInstance) MoveToLastSlot(other MutableStack) error {
	source, sourceIndex, err := c.statePtr.ContainingMutableStack(c)
	if err != nil {
		return errors.New("The source component was not in a mutable stack: " + err.Error())
	}
	return source.moveComponent(sourceIndex, other, lastSlotIndex)
}

func (c componentInstance) MoveToNextSlot(other MutableStack) error {
	source, sourceIndex, err := c.statePtr.ContainingMutableStack(c)
	if err != nil {
		return errors.New("The source component was not in a mutable stack: " + err.Error())
	}
	return source.moveComponent(sourceIndex, other, nextSlotIndex)
}

func (c componentInstance) SlideToFirstSlot() error {
	source, sourceIndex, err := c.statePtr.ContainingMutableStack(c)
	if err != nil {
		return errors.New("The source component was not in a mutable stack: " + err.Error())
	}
	return source.moveComponentToStart(sourceIndex)
}

func (c componentInstance) SlideToLastSlot() error {
	source, sourceIndex, err := c.statePtr.ContainingMutableStack(c)
	if err != nil {
		return errors.New("The source component was not in a mutable stack: " + err.Error())
	}
	return source.moveComponentToEnd(sourceIndex)
}

func (c componentInstance) Mutable(mState MutableState) (MutableComponentInstance, error) {
	if mState == nil {
		return nil, errors.New("Passed nil MutableState")
	}

	st := mState.(*state)

	if st != c.statePtr {
		return nil, errors.New("The MutableState passed did not match the state this componentinstance was originally from.")
	}

	stack, index, err := mState.ContainingMutableStack(c)

	if err != nil {
		return nil, err
	}

	return stack.MutableComponentAt(index), nil
}

func (c componentInstance) mutable() MutableComponentInstance {
	return c
}

func (c componentInstance) State() State {
	return c.statePtr
}

func (c componentInstance) DynamicValues() SubState {

	if c.statePtr == nil {
		return nil
	}

	dynamic := c.statePtr.DynamicComponentValues()

	values := dynamic[c.Deck().Name()]

	if values == nil {
		return nil
	}

	if len(values) <= c.DeckIndex() {
		return nil
	}

	if c.DeckIndex() < 0 {
		//TODO: is this the right beahvior now that we have auto-inflation?
		return c.Deck().Chest().Manager().Delegate().DynamicComponentValuesConstructor(c.Deck())
	}

	return values[c.DeckIndex()]
}
<commit_msg>Add Component.Generic() bool. Part of #613.<commit_after>package boardgame

import (
	"crypto/sha1"
	"errors"
	"fmt"
	"strconv"
)

//A Component represents a movable resource in the game. Cards, dice, meeples,
//resource tokens, etc are all components. Values is a struct that stores the
//specific values for the component. Components are the same across all games
//of this type. Component references should not be compared directly for
//equality, as sometimes different underlying objects will represent the same
//notional component (in order to satisfy both the Component and
//ComponentInstance interfaces simultaneously). Instead, use Equivalent() to
//test that two Components refer to the same conceptual Component.
type Component interface {
	Values() ComponentValues
	Deck() *Deck
	DeckIndex() int
	//Equivalent checks whether two components are equivalent--that is,
	//whether they represent the same index in the same deck.
	Equivalent(other Component) bool

	//Instance returns a ComponentInstance representing this component in the
	//given state.
	Instance(st State) ComponentInstance

	//Generic returns true if this Component is the generic component for this
	//deck. You might get this component if you ask for a component from a
	//sanitized stack. This method is a convenience method equivalent to
	//checking for equivalency to Deck().GenericComponent().
	Generic() bool

	//ptr() is used for when the component itself is used as a key into
	//an index and equality is important.
	ptr() *component
}

//ComponentInstance is a specific instantiation of a component as it exists in
//the particular State it is associated with. ComponentInstances also
//implement all of the Component information, as a convenience you often need
//both bits of inforamation.  The downside of this is that two Component
//values can't be compared directly for equality because they may be different
//underlying objects and wrappers. If you want to see if two Components that
//might be from different states refer to the same underlying conceptual
//Component, use Equivalent(). However, ComponentInstances compared with
//another ComponentInstance for the same component in the same state will be
//equal.
type ComponentInstance interface {
	//ComponentInstances have all of the information of a base Component, as
	//often that's the information you most need.
	Component

	//ID returns a semi-stable ID for this component within this game and the
	//current state this component instance is associated with. Within this
	//game, it will only change when the shuffleCount for this component
	//changes. Across games the Id for the "same" component will be different,
	//in a way that cannot be guessed without access to game.SecretSalt. See
	//the package doc for more on semi-stable Ids for components, what they
	//can be used for, and when they do (and don't) change.
	ID() string
	//DynamicValues returns the Dynamic Values for this component in the state
	//this instance is associated with. A convenience so you don't have to go
	//find them within the DynamicComponentValues yourself.
	DynamicValues() SubState

	//State returns the State object that this ComponentInstance is affiliated
	//with.
	State() State

	//Mutable returns a mutable version of this component instance. It's sugar
	//for state.ContainingMutableComponent. You must pass in a Mutable version
	//of the state associated with this ComponentInstance to prove that you
	//have a mutable state.
	Mutable(state MutableState) (MutableComponentInstance, error)

	//mutable is only to be used to up-cast to mutablecomponentindex when you
	//know that's what it is as a quick convenience for use only within this package.
	mutable() MutableComponentInstance

	secretMoveCount() int
	movedSecretly()
}

//Note that a MutableComponentInstance doesn't actually guarantee that the
//component is in a mutable context at this moment, just that it was at some
//point on thie state (otherwise you couldn't have gotten a reference to it).
//In practice though, if a Component was ever in a mutable context in a given
//state, it must remain that way, because it can't be moved from a
//MutableStack to a non-Mutable stack.

//MutableComponentInstance is a component instance that's in a context that is
//mutable. You generally get these from a MutableStack that contains them. The
//instance contains many methods to move the component to other stacks or
//locations.
type MutableComponentInstance interface {
	ComponentInstance

	//MoveTo moves the specified component in its current stack to the
	//specified slot in the destination stack. The destination stack must be
	//different than the one the component's currently in--if you're moving
	//components within a stack, use SwapComponent. In destination, slotIndex
	//must point to a valid "slot" to put a component, such that after
	//insertion, using that index on the destination will return that
	//component. In defaults Stacks, slots are any index from 0 up to and
	//including stack.Len(), because the stack will grow to insert the
	//component between existing components if necessary. For SizedStacks,
	//slotIndex must point to a currently empty slot.
	//MoveTo{First,Last,Next}Slot methods are useful if you want to move to
	//those locations. If you want the precise location of the inserted
	//component to not be visible, see SecretMoveTo.
	MoveTo(other MutableStack, slotIndex int) error

	//SecretMoveTo is equivalent to MoveTo, but after the move the Ids of all
	//components in destination will be scrambled. SecretMoveTo is useful when
	//the destination stack will be sanitized with something like PolicyOrder,
	//but the precise location of this insertion should not be observable.
	//Read the package doc for more about when this is useful.
	SecretMoveTo(other MutableStack, slotIndex int) error

	//MoveToFirstSlot moves the component to the first valid slot in the other
	//stack. For default Stacks, this is always 0. For SizedStacks, this is
	//the first empty slot from the left.
	MoveToFirstSlot(other MutableStack) error

	//MoveToLastSlot moves the component to the last valid slot in the other
	//stack. For default Stacks, this is always Len(). For SizedStacks, this is
	//the first empty slot from the right.
	MoveToLastSlot(other MutableStack) error

	//MoveToNextSlot moves the component to the next valid slot in the other
	//stack where the component could be added without splicing. For default
	//stacks this is equivalent to MoveToLastSlot. For fixed size stacks this
	//is equivalent to MoveToFirstSlot.
	MoveToNextSlot(other MutableStack) error

	//SlideToFirstSlot takes the given component and moves it to the start of
	//the same stack, moving everything else up. It is equivalent to removing
	//the component, moving it to a temporary stack, and then moving it back
	//to the original stack with MoveToFirstSlot--but of course without
	//needing the extra scratch stack.
	SlideToFirstSlot() error

	//SlideToLastSlot takes the given component and moves it to the end of the
	//same stack, moving everything else down. It is equivalent to removing
	//the component, moving it to a temporary stack, and then moving it back
	//to the original stack with MoveToLastSlot--but of course without needing
	//the extra scratch stack.
	SlideToLastSlot() error
}

type component struct {
	values ComponentValues
	//The deck we're a part of.
	deck *Deck
	//The index we are in the deck we're in.
	deckIndex int
}

//componentInstance has value method receivers so two that are configured the
//same will test as equal even if they were created separately, and because we
//never need to mutate the values within--all of the mutable state is handled
//on the state object.
type componentInstance struct {
	*component
	statePtr *state
}

func (c *component) Values() ComponentValues {
	if c == nil {
		return nil
	}
	return c.values
}

func (c *component) Deck() *Deck {
	if c == nil {
		return nil
	}
	return c.deck
}

func (c *component) DeckIndex() int {
	if c == nil {
		return -1
	}
	return c.deckIndex
}

func (c *component) Generic() bool {
	if c == nil {
		return false
	}
	return c.Equivalent(c.Deck().GenericComponent())
}

func (c *component) Equivalent(other Component) bool {
	if c == nil && other == nil {
		return true
	}
	if c.Deck().Name() != other.Deck().Name() {
		return false
	}
	return c.DeckIndex() == other.DeckIndex()
}

func (c *component) ptr() *component {
	return c
}

func (c *component) Instance(st State) ComponentInstance {

	var ptr *state

	if st != nil {
		ptr = st.(*state)
	}

	return componentInstance{
		c,
		ptr,
	}
}

//ComponentValues is the interface that the Values property of a Component
//must implement. BaseComponentValues is designed to be anonymously embedded
//in your component to implement the latter part of the interface. autoreader
//can be used to implement Reader.
type ComponentValues interface {
	Reader
	//ContainingComponent is the component that this ComponentValues is
	//embedded in. It should return the component that was passed to
	//SetContainingComponent.
	ContainingComponent() Component
	//SetContainingComponent is called to let the component values know what
	//its containing component is.
	SetContainingComponent(c Component)
}

//BaseComponentValues is an optional convenience struct designed to be
//embedded anoymously in your component values to implement
//ContainingComponent() and SetContainingComponent() automatically.
type BaseComponentValues struct {
	c Component
}

func (b *BaseComponentValues) ContainingComponent() Component {
	return b.c
}

func (b *BaseComponentValues) SetContainingComponent(c Component) {
	b.c = c
}

func (c componentInstance) ID() string {

	//Shadow components shouldn't get an Id
	if c.Equivalent(c.Deck().GenericComponent()) {
		return ""
	}

	//S should  never be nil in normal circumstances, but if it is, return an
	//obviously-special Id so it doesn't appear to be the actual Id for this
	//component.
	if c.statePtr == nil {
		return ""
	}

	input := "insecuredefaultinput"

	game := c.statePtr.game
	input = game.Id() + game.secretSalt

	input += c.Deck().Name() + strconv.Itoa(c.DeckIndex())

	//The id only ever changes when the item has moved secretly.
	input += strconv.Itoa(c.secretMoveCount())

	hash := sha1.Sum([]byte(input))

	return fmt.Sprintf("%x", hash)
}

//secretMoveCount returns the secret move count for this component in the
//given state.
func (c componentInstance) secretMoveCount() int {

	if c == c.Deck().GenericComponent() {
		return 0
	}

	if c.statePtr == nil {
		return 0
	}

	s := c.statePtr

	deckMoveCount, ok := s.secretMoveCount[c.Deck().Name()]

	//No components in that deck have been moved secretly, I guess.
	if !ok {
		return 0
	}

	if c.DeckIndex() >= len(deckMoveCount) {
		//TODO: warn?
		return 0
	}

	if c.DeckIndex() < 0 {
		//This should never happen
		return 0
	}

	return deckMoveCount[c.DeckIndex()]
}

//movedSecretly increments the secretMoveCount for this component.
func (c componentInstance) movedSecretly() {
	if c.Equivalent(c.Deck().GenericComponent()) {
		return
	}

	s := c.statePtr

	if s == nil {
		return
	}

	deckMoveCount, ok := s.secretMoveCount[c.Deck().Name()]

	//We must be the first component in this deck that has been secretly
	//moved. Create the whole int stack for this group.
	if !ok {
		//The zero-value will be fine
		deckMoveCount = make([]int, len(c.Deck().Components()))
		s.secretMoveCount[c.Deck().Name()] = deckMoveCount
	}

	if c.DeckIndex() >= len(deckMoveCount) {
		//TODO: warn?
		return
	}

	if c.DeckIndex() < 0 {
		//This should never happen
		return
	}

	deckMoveCount[c.DeckIndex()]++

}

func (c componentInstance) MoveTo(other MutableStack, slotIndex int) error {
	source, sourceIndex, err := c.statePtr.ContainingMutableStack(c)
	if err != nil {
		return errors.New("The source component was not in a mutable stack: " + err.Error())
	}
	return source.moveComponent(sourceIndex, other, slotIndex)
}

func (c componentInstance) SecretMoveTo(other MutableStack, slotIndex int) error {
	source, sourceIndex, err := c.statePtr.ContainingMutableStack(c)
	if err != nil {
		return errors.New("The source component was not in a mutable stack: " + err.Error())
	}
	return source.secretMoveComponent(sourceIndex, other, slotIndex)
}

func (c componentInstance) MoveToFirstSlot(other MutableStack) error {
	source, sourceIndex, err := c.statePtr.ContainingMutableStack(c)
	if err != nil {
		return errors.New("The source component was not in a mutable stack: " + err.Error())
	}
	return source.moveComponent(sourceIndex, other, firstSlotIndex)
}

func (c componentInstance) MoveToLastSlot(other MutableStack) error {
	source, sourceIndex, err := c.statePtr.ContainingMutableStack(c)
	if err != nil {
		return errors.New("The source component was not in a mutable stack: " + err.Error())
	}
	return source.moveComponent(sourceIndex, other, lastSlotIndex)
}

func (c componentInstance) MoveToNextSlot(other MutableStack) error {
	source, sourceIndex, err := c.statePtr.ContainingMutableStack(c)
	if err != nil {
		return errors.New("The source component was not in a mutable stack: " + err.Error())
	}
	return source.moveComponent(sourceIndex, other, nextSlotIndex)
}

func (c componentInstance) SlideToFirstSlot() error {
	source, sourceIndex, err := c.statePtr.ContainingMutableStack(c)
	if err != nil {
		return errors.New("The source component was not in a mutable stack: " + err.Error())
	}
	return source.moveComponentToStart(sourceIndex)
}

func (c componentInstance) SlideToLastSlot() error {
	source, sourceIndex, err := c.statePtr.ContainingMutableStack(c)
	if err != nil {
		return errors.New("The source component was not in a mutable stack: " + err.Error())
	}
	return source.moveComponentToEnd(sourceIndex)
}

func (c componentInstance) Mutable(mState MutableState) (MutableComponentInstance, error) {
	if mState == nil {
		return nil, errors.New("Passed nil MutableState")
	}

	st := mState.(*state)

	if st != c.statePtr {
		return nil, errors.New("The MutableState passed did not match the state this componentinstance was originally from.")
	}

	stack, index, err := mState.ContainingMutableStack(c)

	if err != nil {
		return nil, err
	}

	return stack.MutableComponentAt(index), nil
}

func (c componentInstance) mutable() MutableComponentInstance {
	return c
}

func (c componentInstance) State() State {
	return c.statePtr
}

func (c componentInstance) DynamicValues() SubState {

	if c.statePtr == nil {
		return nil
	}

	dynamic := c.statePtr.DynamicComponentValues()

	values := dynamic[c.Deck().Name()]

	if values == nil {
		return nil
	}

	if len(values) <= c.DeckIndex() {
		return nil
	}

	if c.DeckIndex() < 0 {
		//TODO: is this the right beahvior now that we have auto-inflation?
		return c.Deck().Chest().Manager().Delegate().DynamicComponentValuesConstructor(c.Deck())
	}

	return values[c.DeckIndex()]
}
<|endoftext|>


<commit_before>package main

import (
  "path"
  "os"
  "fmt"
  "sync"
  //"io/ioutil"
  "log"
)

func ensureDirExists(fullpath string) (err error) {
  err = os.MkdirAll(path.Dir(fullpath), os.ModeDir)
  return err
}

func cleanupEmptyDirs(root string) error {
  return nil
}

type PackageInstaller struct {
  backups map[string]string
  installDir string
  packageDir string
  backupsDir string
}

func (pi *PackageInstaller) installPackage(filesProvider UpdateFilesProvider) error {
  _ = pi.removeFiles(filesProvider.FilesToRemove())
  return nil
}

func (pi *PackageInstaller) backupFile(relpath string) error {
  oldpath := path.Join(pi.installDir, relpath)
  backupPath := fmt.Sprintf("%v.bak", relpath)

  newpath := path.Join(pi.backupsDir, backupPath)
  ensureDirExists(newpath)

  err := os.Rename(oldpath, newpath)
  if err == nil {
    pi.backups[relpath] = newpath
  }

  return err
}

func (pi *PackageInstaller) restoreBackups() {
  log.Printf("Restoring %v backups", len(pi.backups))

  var wg sync.WaitGroup

  for relpath, backuppath := range pi.backups {
    wg.Add(1)

    go func() {
      defer wg.Done()

      oldpath := path.Join(pi.installDir, relpath)
      err := os.Rename(backuppath, oldpath)

      if err != nil {
        log.Println(err)
      }
    }()
  }

  wg.Wait()
}

func (pi *PackageInstaller) removeBackups() {
  log.Printf("Removing %v backups", len(pi.backups))

  var wg sync.WaitGroup

  for _, backuppath := range pi.backups {
    wg.Add(1)

    go func() {
      defer wg.Done()

      err := os.Remove(backuppath)
      if err != nil {
        log.Println(err)
      }
    }()
  }

  wg.Wait()
}

func (pi *PackageInstaller) removeFiles(files []*UpdateFileInfo) error {
  log.Printf("Removing %v files", len(files))

  var wg sync.WaitGroup
  errc := make(chan error)
  done := make(chan bool)

  for _, fi := range files {
    wg.Add(1)

    go func() {
      defer wg.Done()

      select {
      case <-done: return
      default:
      }

      fullpath := path.Join(pi.installDir, fi.Filepath)

      err := pi.backupFile(fullpath)

      if err == nil {
        err = os.Remove(fullpath)
      }

      if err != nil {
        log.Printf("Removing file %v failed", fi)
        log.Println(err)
        errc <- err
        close(done)
      }
    }()
  }

  go func() {
    errc <- nil
  }()

  wg.Wait()

  if err := <-errc; err != nil {
    return err
  }

  return nil
}

func (pi *PackageInstaller) updateFiles(files []*UpdateFileInfo) error {
  log.Printf("Updating %v files", len(files))

  var wg sync.WaitGroup
  errc := make(chan error)
  done := make(chan bool)

  for _, fi := range files {
    wg.Add(1)

    go func() {
      defer wg.Done()

      select {
      case <-done: return
      default:
      }

      oldpath := path.Join(pi.installDir, fi.Filepath)

      err := pi.backupFile(oldpath)

      if err == nil {
        newpath := path.Join(pi.packageDir, fi.Filepath)
        err = os.Rename(newpath, oldpath)
      }

      if err != nil {
        log.Printf("Updating file %v failed", fi)
        log.Println(err)
        errc <- err
        close(done)
      }
    }()
  }

  go func() {
    errc <- nil
  }()

  wg.Wait()

  if err := <-errc; err != nil {
    return err
  }

  return nil
}

func (pi *PackageInstaller) addFiles(files []*UpdateFileInfo) error {
  log.Printf("Adding %v files", len(files))

  var wg sync.WaitGroup
  errc := make(chan error)
  done := make(chan bool)

  for _, fi := range files {
    wg.Add(1)

    go func() {
      defer wg.Done()

      select {
      case <-done: return
      default:
      }

      oldpath := path.Join(pi.installDir, fi.Filepath)

      newpath := path.Join(pi.packageDir, fi.Filepath)
      err := os.Rename(newpath, oldpath)

      if err != nil {
        log.Printf("Adding file %v failed", fi)
        log.Println(err)
        errc <- err
        close(done)
      }
    }()
  }

  go func() {
    errc <- nil
  }()

  wg.Wait()

  if err := <-errc; err != nil {
    return err
  }

  return nil
}

func (pi *PackageInstaller) removeFilesToAdd(files []*UpdateFileInfo) {
  var wg sync.WaitGroup

  for _, fi := range files {
    wg.Add(1)

    go func() {
      defer wg.Done()

      fullpath := path.Join(pi.installDir, fi.Filepath)
      err := os.Remove(fullpath)
      if err != nil {
        log.Println(err)
      }
    }()
  }

  wg.Wait()
}
<commit_msg>Added cleanup dirs routine<commit_after>package main

import (
  "path"
  "os"
  "fmt"
  "sync"
  "log"
  "sort"
  "io/ioutil"
)

type PackageInstaller struct {
  backups map[string]string
  installDir string
  packageDir string
  backupsDir string
}

func (pi *PackageInstaller) installPackage(filesProvider UpdateFilesProvider) error {
  _ = pi.removeFiles(filesProvider.FilesToRemove())
  return nil
}

func (pi *PackageInstaller) backupFile(relpath string) error {
  oldpath := path.Join(pi.installDir, relpath)
  backupPath := fmt.Sprintf("%v.bak", relpath)

  newpath := path.Join(pi.backupsDir, backupPath)
  ensureDirExists(newpath)

  err := os.Rename(oldpath, newpath)
  if err == nil {
    pi.backups[relpath] = newpath
  }

  return err
}

func (pi *PackageInstaller) restoreBackups() {
  log.Printf("Restoring %v backups", len(pi.backups))

  var wg sync.WaitGroup

  for relpath, backuppath := range pi.backups {
    wg.Add(1)

    go func() {
      defer wg.Done()

      oldpath := path.Join(pi.installDir, relpath)
      err := os.Rename(backuppath, oldpath)

      if err != nil {
        log.Println(err)
      }
    }()
  }

  wg.Wait()
}

func (pi *PackageInstaller) removeBackups() {
  log.Printf("Removing %v backups", len(pi.backups))

  var wg sync.WaitGroup

  for _, backuppath := range pi.backups {
    wg.Add(1)

    go func() {
      defer wg.Done()

      err := os.Remove(backuppath)
      if err != nil {
        log.Println(err)
      }
    }()
  }

  wg.Wait()
}

func (pi *PackageInstaller) removeFiles(files []*UpdateFileInfo) error {
  log.Printf("Removing %v files", len(files))

  var wg sync.WaitGroup
  errc := make(chan error)
  done := make(chan bool)

  for _, fi := range files {
    wg.Add(1)

    go func() {
      defer wg.Done()

      select {
      case <-done: return
      default:
      }

      fullpath := path.Join(pi.installDir, fi.Filepath)

      err := pi.backupFile(fullpath)

      if err == nil {
        err = os.Remove(fullpath)
      }

      if err != nil {
        log.Printf("Removing file %v failed", fi)
        log.Println(err)
        errc <- err
        close(done)
      }
    }()
  }

  go func() {
    errc <- nil
  }()

  wg.Wait()

  if err := <-errc; err != nil {
    return err
  }

  return nil
}

func (pi *PackageInstaller) updateFiles(files []*UpdateFileInfo) error {
  log.Printf("Updating %v files", len(files))

  var wg sync.WaitGroup
  errc := make(chan error)
  done := make(chan bool)

  for _, fi := range files {
    wg.Add(1)

    go func() {
      defer wg.Done()

      select {
      case <-done: return
      default:
      }

      oldpath := path.Join(pi.installDir, fi.Filepath)

      err := pi.backupFile(oldpath)

      if err == nil {
        newpath := path.Join(pi.packageDir, fi.Filepath)
        err = os.Rename(newpath, oldpath)
      }

      if err != nil {
        log.Printf("Updating file %v failed", fi)
        log.Println(err)
        errc <- err
        close(done)
      }
    }()
  }

  go func() {
    errc <- nil
  }()

  wg.Wait()

  if err := <-errc; err != nil {
    return err
  }

  return nil
}

func (pi *PackageInstaller) addFiles(files []*UpdateFileInfo) error {
  log.Printf("Adding %v files", len(files))

  var wg sync.WaitGroup
  errc := make(chan error)
  done := make(chan bool)

  for _, fi := range files {
    wg.Add(1)

    go func() {
      defer wg.Done()

      select {
      case <-done: return
      default:
      }

      oldpath := path.Join(pi.installDir, fi.Filepath)

      newpath := path.Join(pi.packageDir, fi.Filepath)
      err := os.Rename(newpath, oldpath)

      if err != nil {
        log.Printf("Adding file %v failed", fi)
        log.Println(err)
        errc <- err
        close(done)
      }
    }()
  }

  go func() {
    errc <- nil
  }()

  wg.Wait()

  if err := <-errc; err != nil {
    return err
  }

  return nil
}

func (pi *PackageInstaller) removeFilesToAdd(files []*UpdateFileInfo) {
  var wg sync.WaitGroup

  for _, fi := range files {
    wg.Add(1)

    go func() {
      defer wg.Done()

      fullpath := path.Join(pi.installDir, fi.Filepath)
      err := os.Remove(fullpath)
      if err != nil {
        log.Println(err)
      }
    }()
  }

  wg.Wait()
}

func ensureDirExists(fullpath string) (err error) {
  err = os.MkdirAll(path.Dir(fullpath), os.ModeDir)
  return err
}

type ByLength []string

func (s ByLength) Len() int {
    return len(s)
}
func (s ByLength) Swap(i, j int) {
    s[i], s[j] = s[j], s[i]
}
func (s ByLength) Less(i, j int) bool {
    return len(s[i]) > len(s[j])
}

func cleanupEmptyDirs(root string) error {
  c := make(chan string)

  go func() {
    var wg sync.WaitGroup
    err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
      if err != nil {
        return err
      }

      if info.Mode().IsDir() {
        wg.Add(1)
        go func() {
          c <- path
          wg.Done()
        }()
      }

      return nil
    })

    go func() {
      wg.Wait()
      close(c)
    }()
  }()

  dirs := make([]string)
  for path := range c {
    dirs = append(dirs, c)
  }

  removeEmptyDirs(dirs)
}

func removeEmptyDirs(dirs []string) {
  sort.Sort(ByLength(dirs))

  for _, dirpath := range dirs {
    entries, err := ioutil.ReadDir(dirpath)
    if err != nil { continue }

    if len(entries) == 0 {
      log.Printf("Removing empty dir %v", dirpath)

      err = os.Remove(dirpath)
      if err != nil {
        log.Prinln(err)
      }
    }
  }
}
<|endoftext|>


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

package main

import (
	"bytes"
	"encoding/json"
	"github.com/01org/ciao/payloads"
	"github.com/01org/ciao/ssntp"
	"io/ioutil"
	"net/http"
	"net/url"
	"reflect"
	"testing"
	"time"
)

func testHTTPRequest(t *testing.T, method string, URL string, expectedResponse int, data []byte) []byte {
	req, err := http.NewRequest(method, URL, bytes.NewBuffer(data))
	req.Header.Set("X-Auth-Token", "imavalidtoken")
	if data != nil {
		req.Header.Set("Content-Type", "application/json")
	}

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		t.Fatal(err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != expectedResponse {
		var msg string

		body, err := ioutil.ReadAll(resp.Body)
		if err == nil {
			msg = string(body)
		}

		t.Fatalf("expected: %d, got: %d, msg: %s", expectedResponse, resp.StatusCode, msg)
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		t.Fatal(err)
	}

	return body
}

func testCreateServer(t *testing.T, n int) payloads.ComputeServers {
	tenant, err := context.ds.GetTenant(computeTestUser)
	if err != nil {
		t.Fatal(err)
	}

	// get a valid workload ID
	wls, err := context.ds.GetWorkloads()
	if err != nil {
		t.Fatal(err)
	}

	if len(wls) == 0 {
		t.Fatal("No valid workloads")
	}

	url := computeURL + "/v2.1/" + tenant.ID + "/servers"

	var server payloads.ComputeCreateServer
	server.Server.MaxInstances = n
	server.Server.Workload = wls[0].ID

	b, err := json.Marshal(server)
	if err != nil {
		t.Fatal(err)
	}

	body := testHTTPRequest(t, "POST", url, http.StatusAccepted, b)

	var servers payloads.ComputeServers

	err = json.Unmarshal(body, &servers)
	if err != nil {
		t.Fatal(err)
	}

	if servers.TotalServers != n {
		t.Fatal("Not enough servers returned")
	}

	return servers
}

func testListServerDetailsTenant(t *testing.T, tenantID string) payloads.ComputeServers {
	url := computeURL + "/v2.1/" + tenantID + "/servers/detail"

	body := testHTTPRequest(t, "GET", url, http.StatusOK, nil)

	var s payloads.ComputeServers
	err := json.Unmarshal(body, &s)
	if err != nil {
		t.Fatal(err)
	}

	return s
}

func TestCreateSingleServer(t *testing.T) {
	_ = testCreateServer(t, 1)
}

func TestListServerDetailsTenant(t *testing.T) {
	tenant, err := context.ds.GetTenant(computeTestUser)
	if err != nil {
		t.Fatal(err)
	}

	servers := testCreateServer(t, 1)
	if servers.TotalServers != 1 {
		t.Fatal(err)
	}

	s := testListServerDetailsTenant(t, tenant.ID)

	if s.TotalServers < 1 {
		t.Fatal("Not enough servers returned")
	}
}

func TestListServerDetailsWorkload(t *testing.T) {
	// get a valid workload ID
	wls, err := context.ds.GetWorkloads()
	if err != nil {
		t.Fatal(err)
	}

	if len(wls) == 0 {
		t.Fatal("No valid workloads")
	}

	servers := testCreateServer(t, 10)
	if servers.TotalServers != 10 {
		t.Fatal("failed to create enough servers")
	}

	url := computeURL + "/v2.1/flavors/" + wls[0].ID + "/servers/detail"

	body := testHTTPRequest(t, "GET", url, http.StatusOK, nil)

	var s payloads.ComputeServers
	err = json.Unmarshal(body, &s)
	if err != nil {
		t.Fatal(err)
	}

	if s.TotalServers < 10 {
		t.Fatal("Did not return correct number of servers")
	}
}

func TestShowServerDetails(t *testing.T) {
	tenant, err := context.ds.GetTenant(computeTestUser)
	if err != nil {
		t.Fatal(err)
	}

	tURL := computeURL + "/v2.1/" + tenant.ID + "/servers/"

	servers := testCreateServer(t, 1)
	if servers.TotalServers != 1 {
		t.Fatal(err)
	}

	s := testListServerDetailsTenant(t, tenant.ID)

	if s.TotalServers < 1 {
		t.Fatal("Not enough servers returned")
	}

	for _, s1 := range s.Servers {
		url := tURL + s1.ID

		body := testHTTPRequest(t, "GET", url, http.StatusOK, nil)

		var s2 payloads.ComputeServer
		err = json.Unmarshal(body, &s2)
		if err != nil {
			t.Fatal(err)
		}

		if reflect.DeepEqual(s1, s2.Server) == false {
			t.Fatal("Server details not correct")
		}
	}
}

func TestDeleteServer(t *testing.T) {
	tenant, err := context.ds.GetTenant(computeTestUser)
	if err != nil {
		t.Fatal(err)
	}

	// instances have to be assigned to a node to be deleted
	client := newTestClient(0, ssntp.AGENT)
	defer client.ssntp.Close()

	tURL := computeURL + "/v2.1/" + tenant.ID + "/servers/"

	servers := testCreateServer(t, 10)
	if servers.TotalServers != 10 {
		t.Fatal(err)
	}

	time.Sleep(2 * time.Second)

	client.sendStats()

	s := testListServerDetailsTenant(t, tenant.ID)

	if s.TotalServers < 1 {
		t.Fatal("Not enough servers returned")
	}

	for _, s1 := range s.Servers {
		url := tURL + s1.ID
		if s1.HostID != "" {
			_ = testHTTPRequest(t, "DELETE", url, http.StatusAccepted, nil)
		} else {
			_ = testHTTPRequest(t, "DELETE", url, http.StatusInternalServerError, nil)
		}

	}
}

func TestServersActionStart(t *testing.T) {
	tenant, err := context.ds.GetTenant(computeTestUser)
	if err != nil {
		t.Fatal(err)
	}

	url := computeURL + "/v2.1/" + tenant.ID + "/servers/action"

	client := newTestClient(0, ssntp.AGENT)
	defer client.ssntp.Close()

	servers := testCreateServer(t, 1)
	if servers.TotalServers != 1 {
		t.Fatal(err)
	}

	time.Sleep(2 * time.Second)

	client.sendStats()

	time.Sleep(1 * time.Second)

	err = context.stopInstance(servers.Servers[0].ID)
	if err != nil {
		t.Fatal(err)
	}

	time.Sleep(1 * time.Second)
	client.sendStats()

	var ids []string
	ids = append(ids, servers.Servers[0].ID)

	cmd := payloads.CiaoServersAction{
		Action:    "os-start",
		ServerIDs: ids,
	}

	b, err := json.Marshal(cmd)
	if err != nil {
		t.Fatal(err)
	}

	_ = testHTTPRequest(t, "POST", url, http.StatusAccepted, b)
}

func TestServersActionStop(t *testing.T) {
	tenant, err := context.ds.GetTenant(computeTestUser)
	if err != nil {
		t.Fatal(err)
	}

	url := computeURL + "/v2.1/" + tenant.ID + "/servers/action"

	client := newTestClient(0, ssntp.AGENT)
	defer client.ssntp.Close()

	servers := testCreateServer(t, 1)
	if servers.TotalServers != 1 {
		t.Fatal(err)
	}

	time.Sleep(2 * time.Second)

	client.sendStats()

	time.Sleep(1 * time.Second)

	var ids []string
	ids = append(ids, servers.Servers[0].ID)

	cmd := payloads.CiaoServersAction{
		Action:    "os-stop",
		ServerIDs: ids,
	}

	b, err := json.Marshal(cmd)
	if err != nil {
		t.Fatal(err)
	}

	_ = testHTTPRequest(t, "POST", url, http.StatusAccepted, b)
}

func TestListFlavors(t *testing.T) {
	tenant, err := context.ds.GetTenant(computeTestUser)
	if err != nil {
		t.Fatal(err)
	}

	url := computeURL + "/v2.1/" + tenant.ID + "/flavors"

	wls, err := context.ds.GetWorkloads()
	if err != nil {
		t.Fatal(err)
	}

	body := testHTTPRequest(t, "GET", url, http.StatusOK, nil)

	var flavors payloads.ComputeFlavors
	err = json.Unmarshal(body, &flavors)
	if err != nil {
		t.Fatal(err)
	}

	if len(flavors.Flavors) != len(wls) {
		t.Fatal("Incorrect number of flavors returned")
	}

	var matched int

	for _, f := range flavors.Flavors {
		for _, w := range wls {
			if w.ID == f.ID && w.Description == f.Name {
				matched++
			}
		}
	}

	if matched != len(wls) {
		t.Fatal("Flavor information didn't match workload information")
	}
}

func TestShowFlavorDetails(t *testing.T) {
	tenant, err := context.ds.GetTenant(computeTestUser)
	if err != nil {
		t.Fatal(err)
	}

	tURL := computeURL + "/v2.1/" + tenant.ID + "/flavors/"

	wls, err := context.ds.GetWorkloads()
	if err != nil {
		t.Fatal(err)
	}

	for _, w := range wls {
		details := payloads.FlavorDetails{
			OsFlavorAccessIsPublic: true,
			ID:   w.ID,
			Disk: w.ImageID,
			Name: w.Description,
		}

		defaults := w.Defaults
		for r := range defaults {
			switch defaults[r].Type {
			case payloads.VCPUs:
				details.Vcpus = defaults[r].Value
			case payloads.MemMB:
				details.RAM = defaults[r].Value
			}
		}

		url := tURL + w.ID
		body := testHTTPRequest(t, "GET", url, http.StatusOK, nil)

		var f payloads.ComputeFlavorDetails

		err = json.Unmarshal(body, &f)
		if err != nil {
			t.Fatal(err)
		}

		if reflect.DeepEqual(details, f.Flavor) == false {
			t.Fatal("Flavor details not correct")
		}
	}
}

func TestListTenantResources(t *testing.T) {
	var usage payloads.CiaoUsageHistory

	endTime := time.Now()
	startTime := endTime.Add(-15 * time.Minute)

	tenant, err := context.ds.GetTenant(computeTestUser)
	if err != nil {
		t.Fatal(err)
	}

	tURL := computeURL + "/v2.1/" + tenant.ID + "/resources?"

	usage.Usages, err = context.ds.GetTenantUsage(tenant.ID, startTime, endTime)
	if err != nil {
		t.Fatal(err)
	}

	v := url.Values{}
	v.Add("start_date", startTime.Format(time.RFC3339))
	v.Add("end_date", endTime.Format(time.RFC3339))

	tURL += v.Encode()

	body := testHTTPRequest(t, "GET", tURL, http.StatusOK, nil)

	var result payloads.CiaoUsageHistory

	err = json.Unmarshal(body, &result)
	if err != nil {
		t.Fatal(err)
	}

	if reflect.DeepEqual(usage, result) == false {
		t.Fatal("Tenant usage not correct")
	}
}
<commit_msg>ciao-controller: compute_test: add unit test for listTenantQuotas<commit_after>// Copyright (c) 2016 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"bytes"
	"encoding/json"
	"github.com/01org/ciao/payloads"
	"github.com/01org/ciao/ssntp"
	"io/ioutil"
	"net/http"
	"net/url"
	"reflect"
	"testing"
	"time"
)

func testHTTPRequest(t *testing.T, method string, URL string, expectedResponse int, data []byte) []byte {
	req, err := http.NewRequest(method, URL, bytes.NewBuffer(data))
	req.Header.Set("X-Auth-Token", "imavalidtoken")
	if data != nil {
		req.Header.Set("Content-Type", "application/json")
	}

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		t.Fatal(err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != expectedResponse {
		var msg string

		body, err := ioutil.ReadAll(resp.Body)
		if err == nil {
			msg = string(body)
		}

		t.Fatalf("expected: %d, got: %d, msg: %s", expectedResponse, resp.StatusCode, msg)
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		t.Fatal(err)
	}

	return body
}

func testCreateServer(t *testing.T, n int) payloads.ComputeServers {
	tenant, err := context.ds.GetTenant(computeTestUser)
	if err != nil {
		t.Fatal(err)
	}

	// get a valid workload ID
	wls, err := context.ds.GetWorkloads()
	if err != nil {
		t.Fatal(err)
	}

	if len(wls) == 0 {
		t.Fatal("No valid workloads")
	}

	url := computeURL + "/v2.1/" + tenant.ID + "/servers"

	var server payloads.ComputeCreateServer
	server.Server.MaxInstances = n
	server.Server.Workload = wls[0].ID

	b, err := json.Marshal(server)
	if err != nil {
		t.Fatal(err)
	}

	body := testHTTPRequest(t, "POST", url, http.StatusAccepted, b)

	var servers payloads.ComputeServers

	err = json.Unmarshal(body, &servers)
	if err != nil {
		t.Fatal(err)
	}

	if servers.TotalServers != n {
		t.Fatal("Not enough servers returned")
	}

	return servers
}

func testListServerDetailsTenant(t *testing.T, tenantID string) payloads.ComputeServers {
	url := computeURL + "/v2.1/" + tenantID + "/servers/detail"

	body := testHTTPRequest(t, "GET", url, http.StatusOK, nil)

	var s payloads.ComputeServers
	err := json.Unmarshal(body, &s)
	if err != nil {
		t.Fatal(err)
	}

	return s
}

func TestCreateSingleServer(t *testing.T) {
	_ = testCreateServer(t, 1)
}

func TestListServerDetailsTenant(t *testing.T) {
	tenant, err := context.ds.GetTenant(computeTestUser)
	if err != nil {
		t.Fatal(err)
	}

	servers := testCreateServer(t, 1)
	if servers.TotalServers != 1 {
		t.Fatal(err)
	}

	s := testListServerDetailsTenant(t, tenant.ID)

	if s.TotalServers < 1 {
		t.Fatal("Not enough servers returned")
	}
}

func TestListServerDetailsWorkload(t *testing.T) {
	// get a valid workload ID
	wls, err := context.ds.GetWorkloads()
	if err != nil {
		t.Fatal(err)
	}

	if len(wls) == 0 {
		t.Fatal("No valid workloads")
	}

	servers := testCreateServer(t, 10)
	if servers.TotalServers != 10 {
		t.Fatal("failed to create enough servers")
	}

	url := computeURL + "/v2.1/flavors/" + wls[0].ID + "/servers/detail"

	body := testHTTPRequest(t, "GET", url, http.StatusOK, nil)

	var s payloads.ComputeServers
	err = json.Unmarshal(body, &s)
	if err != nil {
		t.Fatal(err)
	}

	if s.TotalServers < 10 {
		t.Fatal("Did not return correct number of servers")
	}
}

func TestShowServerDetails(t *testing.T) {
	tenant, err := context.ds.GetTenant(computeTestUser)
	if err != nil {
		t.Fatal(err)
	}

	tURL := computeURL + "/v2.1/" + tenant.ID + "/servers/"

	servers := testCreateServer(t, 1)
	if servers.TotalServers != 1 {
		t.Fatal(err)
	}

	s := testListServerDetailsTenant(t, tenant.ID)

	if s.TotalServers < 1 {
		t.Fatal("Not enough servers returned")
	}

	for _, s1 := range s.Servers {
		url := tURL + s1.ID

		body := testHTTPRequest(t, "GET", url, http.StatusOK, nil)

		var s2 payloads.ComputeServer
		err = json.Unmarshal(body, &s2)
		if err != nil {
			t.Fatal(err)
		}

		if reflect.DeepEqual(s1, s2.Server) == false {
			t.Fatal("Server details not correct")
		}
	}
}

func TestDeleteServer(t *testing.T) {
	tenant, err := context.ds.GetTenant(computeTestUser)
	if err != nil {
		t.Fatal(err)
	}

	// instances have to be assigned to a node to be deleted
	client := newTestClient(0, ssntp.AGENT)
	defer client.ssntp.Close()

	tURL := computeURL + "/v2.1/" + tenant.ID + "/servers/"

	servers := testCreateServer(t, 10)
	if servers.TotalServers != 10 {
		t.Fatal(err)
	}

	time.Sleep(2 * time.Second)

	client.sendStats()

	s := testListServerDetailsTenant(t, tenant.ID)

	if s.TotalServers < 1 {
		t.Fatal("Not enough servers returned")
	}

	for _, s1 := range s.Servers {
		url := tURL + s1.ID
		if s1.HostID != "" {
			_ = testHTTPRequest(t, "DELETE", url, http.StatusAccepted, nil)
		} else {
			_ = testHTTPRequest(t, "DELETE", url, http.StatusInternalServerError, nil)
		}

	}
}

func TestServersActionStart(t *testing.T) {
	tenant, err := context.ds.GetTenant(computeTestUser)
	if err != nil {
		t.Fatal(err)
	}

	url := computeURL + "/v2.1/" + tenant.ID + "/servers/action"

	client := newTestClient(0, ssntp.AGENT)
	defer client.ssntp.Close()

	servers := testCreateServer(t, 1)
	if servers.TotalServers != 1 {
		t.Fatal(err)
	}

	time.Sleep(2 * time.Second)

	client.sendStats()

	time.Sleep(1 * time.Second)

	err = context.stopInstance(servers.Servers[0].ID)
	if err != nil {
		t.Fatal(err)
	}

	time.Sleep(1 * time.Second)
	client.sendStats()

	var ids []string
	ids = append(ids, servers.Servers[0].ID)

	cmd := payloads.CiaoServersAction{
		Action:    "os-start",
		ServerIDs: ids,
	}

	b, err := json.Marshal(cmd)
	if err != nil {
		t.Fatal(err)
	}

	_ = testHTTPRequest(t, "POST", url, http.StatusAccepted, b)
}

func TestServersActionStop(t *testing.T) {
	tenant, err := context.ds.GetTenant(computeTestUser)
	if err != nil {
		t.Fatal(err)
	}

	url := computeURL + "/v2.1/" + tenant.ID + "/servers/action"

	client := newTestClient(0, ssntp.AGENT)
	defer client.ssntp.Close()

	servers := testCreateServer(t, 1)
	if servers.TotalServers != 1 {
		t.Fatal(err)
	}

	time.Sleep(2 * time.Second)

	client.sendStats()

	time.Sleep(1 * time.Second)

	var ids []string
	ids = append(ids, servers.Servers[0].ID)

	cmd := payloads.CiaoServersAction{
		Action:    "os-stop",
		ServerIDs: ids,
	}

	b, err := json.Marshal(cmd)
	if err != nil {
		t.Fatal(err)
	}

	_ = testHTTPRequest(t, "POST", url, http.StatusAccepted, b)
}

func TestListFlavors(t *testing.T) {
	tenant, err := context.ds.GetTenant(computeTestUser)
	if err != nil {
		t.Fatal(err)
	}

	url := computeURL + "/v2.1/" + tenant.ID + "/flavors"

	wls, err := context.ds.GetWorkloads()
	if err != nil {
		t.Fatal(err)
	}

	body := testHTTPRequest(t, "GET", url, http.StatusOK, nil)

	var flavors payloads.ComputeFlavors
	err = json.Unmarshal(body, &flavors)
	if err != nil {
		t.Fatal(err)
	}

	if len(flavors.Flavors) != len(wls) {
		t.Fatal("Incorrect number of flavors returned")
	}

	var matched int

	for _, f := range flavors.Flavors {
		for _, w := range wls {
			if w.ID == f.ID && w.Description == f.Name {
				matched++
			}
		}
	}

	if matched != len(wls) {
		t.Fatal("Flavor information didn't match workload information")
	}
}

func TestShowFlavorDetails(t *testing.T) {
	tenant, err := context.ds.GetTenant(computeTestUser)
	if err != nil {
		t.Fatal(err)
	}

	tURL := computeURL + "/v2.1/" + tenant.ID + "/flavors/"

	wls, err := context.ds.GetWorkloads()
	if err != nil {
		t.Fatal(err)
	}

	for _, w := range wls {
		details := payloads.FlavorDetails{
			OsFlavorAccessIsPublic: true,
			ID:   w.ID,
			Disk: w.ImageID,
			Name: w.Description,
		}

		defaults := w.Defaults
		for r := range defaults {
			switch defaults[r].Type {
			case payloads.VCPUs:
				details.Vcpus = defaults[r].Value
			case payloads.MemMB:
				details.RAM = defaults[r].Value
			}
		}

		url := tURL + w.ID
		body := testHTTPRequest(t, "GET", url, http.StatusOK, nil)

		var f payloads.ComputeFlavorDetails

		err = json.Unmarshal(body, &f)
		if err != nil {
			t.Fatal(err)
		}

		if reflect.DeepEqual(details, f.Flavor) == false {
			t.Fatal("Flavor details not correct")
		}
	}
}

func TestListTenantResources(t *testing.T) {
	var usage payloads.CiaoUsageHistory

	endTime := time.Now()
	startTime := endTime.Add(-15 * time.Minute)

	tenant, err := context.ds.GetTenant(computeTestUser)
	if err != nil {
		t.Fatal(err)
	}

	tURL := computeURL + "/v2.1/" + tenant.ID + "/resources?"

	usage.Usages, err = context.ds.GetTenantUsage(tenant.ID, startTime, endTime)
	if err != nil {
		t.Fatal(err)
	}

	v := url.Values{}
	v.Add("start_date", startTime.Format(time.RFC3339))
	v.Add("end_date", endTime.Format(time.RFC3339))

	tURL += v.Encode()

	body := testHTTPRequest(t, "GET", tURL, http.StatusOK, nil)

	var result payloads.CiaoUsageHistory

	err = json.Unmarshal(body, &result)
	if err != nil {
		t.Fatal(err)
	}

	if reflect.DeepEqual(usage, result) == false {
		t.Fatal("Tenant usage not correct")
	}
}

func TestListTenantQuotas(t *testing.T) {
	tenant, err := context.ds.GetTenant(computeTestUser)
	if err != nil {
		t.Fatal(err)
	}

	url := computeURL + "/v2.1/" + tenant.ID + "/quotas"

	var expected payloads.CiaoTenantResources

	for _, resource := range tenant.Resources {
		switch resource.Rtype {
		case instances:
			expected.InstanceLimit = resource.Limit
			expected.InstanceUsage = resource.Usage

		case vcpu:
			expected.VCPULimit = resource.Limit
			expected.VCPUUsage = resource.Usage

		case memory:
			expected.MemLimit = resource.Limit
			expected.MemUsage = resource.Usage

		case disk:
			expected.DiskLimit = resource.Limit
			expected.DiskUsage = resource.Usage
		}
	}

	expected.ID = tenant.ID

	body := testHTTPRequest(t, "GET", url, http.StatusOK, nil)

	var result payloads.CiaoTenantResources

	err = json.Unmarshal(body, &result)
	if err != nil {
		t.Fatal(err)
	}

	expected.Timestamp = result.Timestamp

	if reflect.DeepEqual(expected, result) == false {
		t.Fatal("Tenant quotas not correct")
	}
}
<|endoftext|>


<commit_before>package database

import (
	"database/sql"

	"github.com/wlMalk/gorator/database/query"
)

var ErrNoRows = sql.ErrNoRows

type Runner interface {
	Queryer
	QueryRower
	Execer
}

type Driver interface {
	Runner
	Close() error
	Ping() error
	Prepare(string) (*sql.Stmt, error)
	SetMaxIdleConns(int)
	SetMaxOpenConns(int)
}

type Transaction interface {
	Runner
	Rollback() error
	Commit() error
	Prepare(string) (*sql.Stmt, error)
	Stmt(*sql.Stmt) *sql.Stmt
}

type Model interface {
}

type Slice interface {
}

type Queryer interface {
	QueryQ(query.Query) (Rower, error)
	Query(string, ...interface{}) (Rower, error)
}

type QueryRower interface {
	QueryRowQ(query.Query) (Rower, error)
	QueryRow(string, ...interface{}) (Rower, error)
}

type Execer interface {
	ExecQ(query.Query) (Result, error)
	Exec(string, ...interface{}) (Result, error)
}

type Scanner interface {
	Scan(...interface{}) error
}

type Rower interface {
	Scanner
	Next() bool
	Columns() ([]string, error)
	Close() error
}

type Result interface {
	sql.Result
	// InsertIds() ([]interface{}, error)
}

type Tabler interface {
	Driver
	Name() string
	Columns(string) string
}

type Table struct {
	name    string
	schema  string
	columns map[string]string
}

func (t *Table) SetName(name string) {
	if t.name == "" {
		t.name = name
	}
}

func (t *Table) SetSchema(schema string) {
	if t.schema == "" {
		t.schema = schema
	}
}

func (t *Table) SetColumns(columns map[string]string) {
	if t.columns == nil || len(t.columns) == 0 {
		t.columns = columns
	}
}

func (t *Table) Name() string {
	return t.name
}

func (t *Table) Column(a string) string {
	return t.columns[a]
}

func (t *Table) Columns(a ...string) []string {
	var b []string

	for _, c := range a {
		b = append(b, t.columns[c])
	}

	return b
}

type DB struct {
	*sql.DB
	name string
}

type Tx struct {
	*sql.Tx
}

func New() *DB {
	return &DB{}
}

func (db *DB) SetName(name string) {
	db.name = name
}

func (db *DB) Begin() (Transaction, error) {
	xtx, err := db.DB.Begin()
	if err != nil {
		return nil, err
	}
	return &Tx{xtx}, err
}

func (db *DB) Query(query string, args ...interface{}) (Rower, error) {
	return db.DB.Query(query, args...)
}

func (db *DB) QueryRow(query string, args ...interface{}) (Rower, error) {
	return db.DB.Query(query, args...)
}

func (db *DB) Exec(query string, args ...interface{}) (Result, error) {
	return db.DB.Exec(query, args...)
}

func (tx *Tx) Query(query string, args ...interface{}) (Rower, error) {
	return tx.Tx.Query(query, args...)
}

func (tx *Tx) QueryRow(query string, args ...interface{}) (Rower, error) {
	return tx.Tx.Query(query, args...)
}

func (tx *Tx) Exec(query string, args ...interface{}) (Result, error) {
	return tx.Tx.Exec(query, args...)
}

func (db *DB) QueryQ(q query.Query) (Rower, error) {
	str, args, err := q.ToSql()
	if err != nil {
		return nil, err
	}
	return db.DB.Query(str, args...)
}

func (db *DB) QueryRowQ(q query.Query) (Rower, error) {
	str, args, err := q.ToSql()
	if err != nil {
		return nil, err
	}
	return db.DB.Query(str, args...)
}

func (db *DB) ExecQ(q query.Query) (Result, error) {
	str, args, err := q.ToSql()
	if err != nil {
		return nil, err
	}
	return db.DB.Exec(str, args...)
}

func (tx *Tx) QueryQ(q query.Query) (Rower, error) {
	str, args, err := q.ToSql()
	if err != nil {
		return nil, err
	}
	return tx.Tx.Query(str, args...)
}

func (tx *Tx) QueryRowQ(q query.Query) (Rower, error) {
	str, args, err := q.ToSql()
	if err != nil {
		return nil, err
	}
	return tx.Tx.Query(str, args...)
}

func (tx *Tx) ExecQ(q query.Query) (Result, error) {
	str, args, err := q.ToSql()
	if err != nil {
		return nil, err
	}
	return tx.Tx.Exec(str, args...)
}
<commit_msg>Changes to table struct<commit_after>package database

import (
	"database/sql"

	"github.com/wlMalk/gorator/database/query"
)

var ErrNoRows = sql.ErrNoRows

type Runner interface {
	Queryer
	QueryRower
	Execer
}

type Driver interface {
	Runner
	Close() error
	Ping() error
	Prepare(string) (*sql.Stmt, error)
	SetMaxIdleConns(int)
	SetMaxOpenConns(int)
}

type Transaction interface {
	Runner
	Rollback() error
	Commit() error
	Prepare(string) (*sql.Stmt, error)
	Stmt(*sql.Stmt) *sql.Stmt
}

type Model interface {
}

type Slice interface {
}

type Queryer interface {
	QueryQ(query.Query) (Rower, error)
	Query(string, ...interface{}) (Rower, error)
}

type QueryRower interface {
	QueryRowQ(query.Query) (Rower, error)
	QueryRow(string, ...interface{}) (Rower, error)
}

type Execer interface {
	ExecQ(query.Query) (Result, error)
	Exec(string, ...interface{}) (Result, error)
}

type Scanner interface {
	Scan(...interface{}) error
}

type Rower interface {
	Scanner
	Next() bool
	Columns() ([]string, error)
	Close() error
}

type Result interface {
	sql.Result
	// InsertIds() ([]interface{}, error)
}

type Tabler interface {
	Driver
	Name() string
	Columns(string) string
}

type Table struct {
	name    string
	schema  string
	columns map[string]string
}

func (t *Table) SetName(name string) {
	if t.name == "" {
		t.name = name
	}
}

func (t *Table) SetSchema(schema string) {
	if t.schema == "" {
		t.schema = schema
	}
}

func (t *Table) SetColumns(columns map[string]string) {
	if t.columns == nil || len(t.columns) == 0 {
		t.columns = columns
	}
}

func (t *Table) Name() string {
	return t.name
}

func (t *Table) Column(a string) string {
	return t.columns[a]
}

func (t *Table) Columns(a ...string) []string {
	var b []string

	for _, c := range a {
		nc, ok := t.columns[c]
		if ok {
			b = append(b, nc)
		} else {
			b = append(b, c)
		}
	}

	return b
}

type DB struct {
	*sql.DB
	name string
}

type Tx struct {
	*sql.Tx
}

func New() *DB {
	return &DB{}
}

func (db *DB) SetName(name string) {
	db.name = name
}

func (db *DB) Begin() (Transaction, error) {
	xtx, err := db.DB.Begin()
	if err != nil {
		return nil, err
	}
	return &Tx{xtx}, err
}

func (db *DB) Query(query string, args ...interface{}) (Rower, error) {
	return db.DB.Query(query, args...)
}

func (db *DB) QueryRow(query string, args ...interface{}) (Rower, error) {
	return db.DB.Query(query, args...)
}

func (db *DB) Exec(query string, args ...interface{}) (Result, error) {
	return db.DB.Exec(query, args...)
}

func (tx *Tx) Query(query string, args ...interface{}) (Rower, error) {
	return tx.Tx.Query(query, args...)
}

func (tx *Tx) QueryRow(query string, args ...interface{}) (Rower, error) {
	return tx.Tx.Query(query, args...)
}

func (tx *Tx) Exec(query string, args ...interface{}) (Result, error) {
	return tx.Tx.Exec(query, args...)
}

func (db *DB) QueryQ(q query.Query) (Rower, error) {
	str, args, err := q.ToSql()
	if err != nil {
		return nil, err
	}
	return db.DB.Query(str, args...)
}

func (db *DB) QueryRowQ(q query.Query) (Rower, error) {
	str, args, err := q.ToSql()
	if err != nil {
		return nil, err
	}
	return db.DB.Query(str, args...)
}

func (db *DB) ExecQ(q query.Query) (Result, error) {
	str, args, err := q.ToSql()
	if err != nil {
		return nil, err
	}
	return db.DB.Exec(str, args...)
}

func (tx *Tx) QueryQ(q query.Query) (Rower, error) {
	str, args, err := q.ToSql()
	if err != nil {
		return nil, err
	}
	return tx.Tx.Query(str, args...)
}

func (tx *Tx) QueryRowQ(q query.Query) (Rower, error) {
	str, args, err := q.ToSql()
	if err != nil {
		return nil, err
	}
	return tx.Tx.Query(str, args...)
}

func (tx *Tx) ExecQ(q query.Query) (Result, error) {
	str, args, err := q.ToSql()
	if err != nil {
		return nil, err
	}
	return tx.Tx.Exec(str, args...)
}
<|endoftext|>