<commit_before>package server

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"math/rand"
	"net/http"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"github.com/gorilla/mux"
	"github.com/otoolep/raft"
	"github.com/otoolep/rqlite/command"
	"github.com/otoolep/rqlite/db"

	log "code.google.com/p/log4go"
)

type FailedSqlStmt struct {
	Sql   string `json:"sql"`
	Error string `json:"error"`
}

type StmtResponse struct {
	Time     string          `json:"time"`
	Failures []FailedSqlStmt `json:"failures"`
}

type QueryResponse struct {
	Time     string          `json:"time"`
	Failures []FailedSqlStmt `json:"failures"`
	Rows     db.RowResults   `json:"rows"`
}

// The raftd server is a combination of the Raft server and an HTTP
// server which acts as the transport.
type Server struct {
	name       string
	host       string
	port       int
	path       string
	router     *mux.Router
	raftServer raft.Server
	httpServer *http.Server
	database   *db.DB
	mutex      sync.RWMutex
}

// queryParam returns whether the given query param is set to true.
func queryParam(req *http.Request, param string) (bool, error) {
	err := req.ParseForm()
	if err != nil {
		return false, err
	}
	if _, ok := req.Form[param]; ok {
		return true, nil
	}
	return false, nil
}

// isPretty returns whether the HTTP response body should be pretty-printed.
func isPretty(req *http.Request) (bool, error) {
	return queryParam(req, "pretty")
}

// isTransaction returns whether the client requested an explicit
// transaction for the request.
func isTransaction(req *http.Request) (bool, error) {
	return queryParam(req, "transaction")
}

// Creates a new server.
func New(dataDir string, database *db.DB, host string, port int) *Server {
	s := &Server{
		host:     host,
		port:     port,
		path:     dataDir,
		database: database,
		router:   mux.NewRouter(),
	}

	// Read existing name or generate a new one.
	if b, err := ioutil.ReadFile(filepath.Join(dataDir, "name")); err == nil {
		s.name = string(b)
	} else {
		s.name = fmt.Sprintf("%07x", rand.Int())[0:7]
		if err = ioutil.WriteFile(filepath.Join(dataDir, "name"), []byte(s.name), 0644); err != nil {
			panic(err)
		}
	}

	return s
}

// Returns the connection string.
func (s *Server) connectionString() string {
	return fmt.Sprintf("http://%s:%d", s.host, s.port)
}

// Starts the server.
func (s *Server) ListenAndServe(leader string) error {
	var err error

	log.Info("Initializing Raft Server: %s", s.path)

	// Initialize and start Raft server.
	transporter := raft.NewHTTPTransporter("/raft", 200*time.Millisecond)
	s.raftServer, err = raft.NewServer(s.name, s.path, transporter, nil, s.database, "")
	if err != nil {
		log.Error("Failed to create new Raft server", err.Error())
		return err
	}
	transporter.Install(s.raftServer, s)
	s.raftServer.Start()

	if leader != "" {
		// Join to leader if specified.

		log.Info("Attempting to join leader at %s", leader)

		if !s.raftServer.IsLogEmpty() {
			log.Error("Cannot join with an existing log")
			return errors.New("Cannot join with an existing log")
		}
		if err := s.Join(leader); err != nil {
			log.Error("Failed to join leader", err.Error())
			return err
		}

	} else if s.raftServer.IsLogEmpty() {
		// Initialize the server by joining itself.

		log.Info("Initializing new cluster")

		_, err := s.raftServer.Do(&raft.DefaultJoinCommand{
			Name:             s.raftServer.Name(),
			ConnectionString: s.connectionString(),
		})
		if err != nil {
			log.Error("Failed to join to self", err.Error())
		}

	} else {
		log.Info("Recovered from log")
	}

	log.Info("Initializing HTTP server")

	// Initialize and start HTTP server.
	s.httpServer = &http.Server{
		Addr:    fmt.Sprintf(":%d", s.port),
		Handler: s.router,
	}

	s.router.HandleFunc("/db", s.readHandler).Methods("GET")
	s.router.HandleFunc("/db", s.writeHandler).Methods("POST")
	s.router.HandleFunc("/join", s.joinHandler).Methods("POST")

	log.Info("Listening at %s", s.connectionString())

	return s.httpServer.ListenAndServe()
}

// This is a hack around Gorilla mux not providing the correct net/http
// HandleFunc() interface.
func (s *Server) HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) {
	s.router.HandleFunc(pattern, handler)
}

// Joins to the leader of an existing cluster.
func (s *Server) Join(leader string) error {
	command := &raft.DefaultJoinCommand{
		Name:             s.raftServer.Name(),
		ConnectionString: s.connectionString(),
	}

	var b bytes.Buffer
	json.NewEncoder(&b).Encode(command)
	resp, err := http.Post(fmt.Sprintf("http://%s/join", leader), "application/json", &b)
	if err != nil {
		return err
	}
	resp.Body.Close()

	return nil
}

func (s *Server) joinHandler(w http.ResponseWriter, req *http.Request) {
	command := &raft.DefaultJoinCommand{}

	if err := json.NewDecoder(req.Body).Decode(&command); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if _, err := s.raftServer.Do(command); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func (s *Server) readHandler(w http.ResponseWriter, req *http.Request) {
	log.Trace("readHandler for URL: %s", req.URL)
	var failures = make([]FailedSqlStmt, 0)

	b, err := ioutil.ReadAll(req.Body)
	if err != nil {
		log.Trace("Bad HTTP request", err.Error())
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	stmt := string(b)
	startTime := time.Now()
	r, err := s.database.Query(stmt)
	if err != nil {
		log.Trace("Bad SQL statement", err.Error())
		failures = append(failures, FailedSqlStmt{stmt, err.Error()})
	}
	duration := time.Since(startTime)

	rr := QueryResponse{Time: duration.String(), Failures: failures, Rows: r}
	pretty, _ := isPretty(req)
	if pretty {
		b, err = json.MarshalIndent(rr, "", "    ")
	} else {
		b, err = json.Marshal(rr)
	}
	if err != nil {
		log.Trace("Failed to marshal JSON data", err.Error())
		http.Error(w, err.Error(), http.StatusBadRequest) // Internal error actually
	} else {
		w.Write([]byte(b))
	}
}

func (s *Server) writeHandler(w http.ResponseWriter, req *http.Request) {
	log.Trace("writeHandler for URL: %s", req.URL)

	var failures = make([]FailedSqlStmt, 0)
	var startTime time.Time

	// Read the value from the POST body.
	b, err := ioutil.ReadAll(req.Body)
	if err != nil {
		log.Trace("Bad HTTP request", err.Error())
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	stmts := strings.Split(string(b), "\n")
	if stmts[len(stmts)-1] == "" {
		stmts = stmts[:len(stmts)-1]
	}

	log.Trace("Execute statement contains %d commands", len(stmts))
	if len(stmts) == 0 {
		log.Trace("No database execute commands supplied")
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	startTime = time.Now()
	transaction, _ := isTransaction(req)
	if transaction {
		log.Trace("Transaction requested")
		_, err = s.raftServer.Do(command.NewTransactionExecuteCommandSet(stmts))
		if err != nil {
			failures = append(failures, FailedSqlStmt{stmts[0], err.Error()})
			log.Trace("Transaction failed: %s", err.Error())
		}
	} else {
		log.Trace("No transaction requested")
		for i := range stmts {
			_, err = s.raftServer.Do(command.NewExecuteCommand(stmts[i]))
			if err != nil {
				log.Trace("Execute statement %s failed: %s", stmts[i], err.Error())
				failures = append(failures, FailedSqlStmt{stmts[i], err.Error()})
			}
		}
	}
	duration := time.Since(startTime)

	wr := StmtResponse{Time: duration.String(), Failures: failures}
	pretty, _ := isPretty(req)
	if pretty {
		b, err = json.MarshalIndent(wr, "", "    ")
	} else {
		b, err = json.Marshal(wr)
	}
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest) // Internal error actually
	} else {
		w.Write([]byte(b))
	}
}
<commit_msg>Use correct error for internal failure<commit_after>package server

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"math/rand"
	"net/http"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"github.com/gorilla/mux"
	"github.com/otoolep/raft"
	"github.com/otoolep/rqlite/command"
	"github.com/otoolep/rqlite/db"

	log "code.google.com/p/log4go"
)

type FailedSqlStmt struct {
	Sql   string `json:"sql"`
	Error string `json:"error"`
}

type StmtResponse struct {
	Time     string          `json:"time"`
	Failures []FailedSqlStmt `json:"failures"`
}

type QueryResponse struct {
	Time     string          `json:"time"`
	Failures []FailedSqlStmt `json:"failures"`
	Rows     db.RowResults   `json:"rows"`
}

// The raftd server is a combination of the Raft server and an HTTP
// server which acts as the transport.
type Server struct {
	name       string
	host       string
	port       int
	path       string
	router     *mux.Router
	raftServer raft.Server
	httpServer *http.Server
	database   *db.DB
	mutex      sync.RWMutex
}

// queryParam returns whether the given query param is set to true.
func queryParam(req *http.Request, param string) (bool, error) {
	err := req.ParseForm()
	if err != nil {
		return false, err
	}
	if _, ok := req.Form[param]; ok {
		return true, nil
	}
	return false, nil
}

// isPretty returns whether the HTTP response body should be pretty-printed.
func isPretty(req *http.Request) (bool, error) {
	return queryParam(req, "pretty")
}

// isTransaction returns whether the client requested an explicit
// transaction for the request.
func isTransaction(req *http.Request) (bool, error) {
	return queryParam(req, "transaction")
}

// Creates a new server.
func New(dataDir string, database *db.DB, host string, port int) *Server {
	s := &Server{
		host:     host,
		port:     port,
		path:     dataDir,
		database: database,
		router:   mux.NewRouter(),
	}

	// Read existing name or generate a new one.
	if b, err := ioutil.ReadFile(filepath.Join(dataDir, "name")); err == nil {
		s.name = string(b)
	} else {
		s.name = fmt.Sprintf("%07x", rand.Int())[0:7]
		if err = ioutil.WriteFile(filepath.Join(dataDir, "name"), []byte(s.name), 0644); err != nil {
			panic(err)
		}
	}

	return s
}

// Returns the connection string.
func (s *Server) connectionString() string {
	return fmt.Sprintf("http://%s:%d", s.host, s.port)
}

// Starts the server.
func (s *Server) ListenAndServe(leader string) error {
	var err error

	log.Info("Initializing Raft Server: %s", s.path)

	// Initialize and start Raft server.
	transporter := raft.NewHTTPTransporter("/raft", 200*time.Millisecond)
	s.raftServer, err = raft.NewServer(s.name, s.path, transporter, nil, s.database, "")
	if err != nil {
		log.Error("Failed to create new Raft server", err.Error())
		return err
	}
	transporter.Install(s.raftServer, s)
	s.raftServer.Start()

	if leader != "" {
		// Join to leader if specified.

		log.Info("Attempting to join leader at %s", leader)

		if !s.raftServer.IsLogEmpty() {
			log.Error("Cannot join with an existing log")
			return errors.New("Cannot join with an existing log")
		}
		if err := s.Join(leader); err != nil {
			log.Error("Failed to join leader", err.Error())
			return err
		}

	} else if s.raftServer.IsLogEmpty() {
		// Initialize the server by joining itself.

		log.Info("Initializing new cluster")

		_, err := s.raftServer.Do(&raft.DefaultJoinCommand{
			Name:             s.raftServer.Name(),
			ConnectionString: s.connectionString(),
		})
		if err != nil {
			log.Error("Failed to join to self", err.Error())
		}

	} else {
		log.Info("Recovered from log")
	}

	log.Info("Initializing HTTP server")

	// Initialize and start HTTP server.
	s.httpServer = &http.Server{
		Addr:    fmt.Sprintf(":%d", s.port),
		Handler: s.router,
	}

	s.router.HandleFunc("/db", s.readHandler).Methods("GET")
	s.router.HandleFunc("/db", s.writeHandler).Methods("POST")
	s.router.HandleFunc("/join", s.joinHandler).Methods("POST")

	log.Info("Listening at %s", s.connectionString())

	return s.httpServer.ListenAndServe()
}

// This is a hack around Gorilla mux not providing the correct net/http
// HandleFunc() interface.
func (s *Server) HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) {
	s.router.HandleFunc(pattern, handler)
}

// Joins to the leader of an existing cluster.
func (s *Server) Join(leader string) error {
	command := &raft.DefaultJoinCommand{
		Name:             s.raftServer.Name(),
		ConnectionString: s.connectionString(),
	}

	var b bytes.Buffer
	json.NewEncoder(&b).Encode(command)
	resp, err := http.Post(fmt.Sprintf("http://%s/join", leader), "application/json", &b)
	if err != nil {
		return err
	}
	resp.Body.Close()

	return nil
}

func (s *Server) joinHandler(w http.ResponseWriter, req *http.Request) {
	command := &raft.DefaultJoinCommand{}

	if err := json.NewDecoder(req.Body).Decode(&command); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if _, err := s.raftServer.Do(command); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func (s *Server) readHandler(w http.ResponseWriter, req *http.Request) {
	log.Trace("readHandler for URL: %s", req.URL)
	var failures = make([]FailedSqlStmt, 0)

	b, err := ioutil.ReadAll(req.Body)
	if err != nil {
		log.Trace("Bad HTTP request", err.Error())
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	stmt := string(b)
	startTime := time.Now()
	r, err := s.database.Query(stmt)
	if err != nil {
		log.Trace("Bad SQL statement", err.Error())
		failures = append(failures, FailedSqlStmt{stmt, err.Error()})
	}
	duration := time.Since(startTime)

	rr := QueryResponse{Time: duration.String(), Failures: failures, Rows: r}
	pretty, _ := isPretty(req)
	if pretty {
		b, err = json.MarshalIndent(rr, "", "    ")
	} else {
		b, err = json.Marshal(rr)
	}
	if err != nil {
		log.Trace("Failed to marshal JSON data", err.Error())
		http.Error(w, err.Error(), http.StatusBadRequest) // Internal error actually
	} else {
		w.Write([]byte(b))
	}
}

func (s *Server) writeHandler(w http.ResponseWriter, req *http.Request) {
	log.Trace("writeHandler for URL: %s", req.URL)

	var failures = make([]FailedSqlStmt, 0)
	var startTime time.Time

	// Read the value from the POST body.
	b, err := ioutil.ReadAll(req.Body)
	if err != nil {
		log.Trace("Bad HTTP request", err.Error())
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	stmts := strings.Split(string(b), "\n")
	if stmts[len(stmts)-1] == "" {
		stmts = stmts[:len(stmts)-1]
	}

	log.Trace("Execute statement contains %d commands", len(stmts))
	if len(stmts) == 0 {
		log.Trace("No database execute commands supplied")
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	startTime = time.Now()
	transaction, _ := isTransaction(req)
	if transaction {
		log.Trace("Transaction requested")
		_, err = s.raftServer.Do(command.NewTransactionExecuteCommandSet(stmts))
		if err != nil {
			failures = append(failures, FailedSqlStmt{stmts[0], err.Error()})
			log.Trace("Transaction failed: %s", err.Error())
		}
	} else {
		log.Trace("No transaction requested")
		for i := range stmts {
			_, err = s.raftServer.Do(command.NewExecuteCommand(stmts[i]))
			if err != nil {
				log.Trace("Execute statement %s failed: %s", stmts[i], err.Error())
				failures = append(failures, FailedSqlStmt{stmts[i], err.Error()})
			}
		}
	}
	duration := time.Since(startTime)

	wr := StmtResponse{Time: duration.String(), Failures: failures}
	pretty, _ := isPretty(req)
	if pretty {
		b, err = json.MarshalIndent(wr, "", "    ")
	} else {
		b, err = json.Marshal(wr)
	}
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	} else {
		w.Write([]byte(b))
	}
}
<|endoftext|>


<commit_before>package server

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"math/rand"
	"net/http"
	"path"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"github.com/gorilla/mux"
	"github.com/otoolep/raft"
	"github.com/otoolep/rqlite/command"
	"github.com/otoolep/rqlite/db"

	log "code.google.com/p/log4go"
)

// queryParam returns whether the given query param is set to true.
func queryParam(req *http.Request, param string) (bool, error) {
	err := req.ParseForm()
	if err != nil {
		return false, err
	}
	if _, ok := req.Form[param]; ok {
		return true, nil
	}
	return false, nil
}

// isPretty returns whether the HTTP response body should be pretty-printed.
func isPretty(req *http.Request) (bool, error) {
	return queryParam(req, "pretty")
}

// isTransaction returns whether the client requested an explicit
// transaction for the request.
func isTransaction(req *http.Request) (bool, error) {
	return queryParam(req, "transaction")
}

// The raftd server is a combination of the Raft server and an HTTP
// server which acts as the transport.
type Server struct {
	name       string
	host       string
	port       int
	path       string
	router     *mux.Router
	raftServer raft.Server
	httpServer *http.Server
	db         *db.DB
	mutex      sync.RWMutex
}

// Creates a new server.
func New(dataDir string, dbfile string, host string, port int) *Server {
	s := &Server{
		host:   host,
		port:   port,
		path:   dataDir,
		db:     db.New(path.Join(dataDir, dbfile)),
		router: mux.NewRouter(),
	}

	// Read existing name or generate a new one.
	if b, err := ioutil.ReadFile(filepath.Join(dataDir, "name")); err == nil {
		s.name = string(b)
	} else {
		s.name = fmt.Sprintf("%07x", rand.Int())[0:7]
		if err = ioutil.WriteFile(filepath.Join(dataDir, "name"), []byte(s.name), 0644); err != nil {
			panic(err)
		}
	}

	return s
}

// Returns the connection string.
func (s *Server) connectionString() string {
	return fmt.Sprintf("http://%s:%d", s.host, s.port)
}

// Starts the server.
func (s *Server) ListenAndServe(leader string) error {
	var err error

	log.Info("Initializing Raft Server: %s", s.path)

	// Initialize and start Raft server.
	transporter := raft.NewHTTPTransporter("/raft", 200*time.Millisecond)
	s.raftServer, err = raft.NewServer(s.name, s.path, transporter, nil, s.db, "")
	if err != nil {
		log.Error("Failed to create new Raft server", err.Error())
		return err
	}
	transporter.Install(s.raftServer, s)
	s.raftServer.Start()

	if leader != "" {
		// Join to leader if specified.

		log.Info("Attempting to join leader:", leader)

		if !s.raftServer.IsLogEmpty() {
			log.Error("Cannot join with an existing log")
			return errors.New("Cannot join with an existing log")
		}
		if err := s.Join(leader); err != nil {
			log.Error("Failed to join leader", err.Error())
			return err
		}

	} else if s.raftServer.IsLogEmpty() {
		// Initialize the server by joining itself.

		log.Info("Initializing new cluster")

		_, err := s.raftServer.Do(&raft.DefaultJoinCommand{
			Name:             s.raftServer.Name(),
			ConnectionString: s.connectionString(),
		})
		if err != nil {
			log.Error("Failed to join to self", err.Error())
		}

	} else {
		log.Info("Recovered from log")
	}

	log.Info("Initializing HTTP server")

	// Initialize and start HTTP server.
	s.httpServer = &http.Server{
		Addr:    fmt.Sprintf(":%d", s.port),
		Handler: s.router,
	}

	s.router.HandleFunc("/db", s.readHandler).Methods("GET")
	s.router.HandleFunc("/db", s.writeHandler).Methods("POST")
	s.router.HandleFunc("/join", s.joinHandler).Methods("POST")

	log.Info("Listening at %s", s.connectionString())

	return s.httpServer.ListenAndServe()
}

// This is a hack around Gorilla mux not providing the correct net/http
// HandleFunc() interface.
func (s *Server) HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) {
	s.router.HandleFunc(pattern, handler)
}

// Joins to the leader of an existing cluster.
func (s *Server) Join(leader string) error {
	command := &raft.DefaultJoinCommand{
		Name:             s.raftServer.Name(),
		ConnectionString: s.connectionString(),
	}

	var b bytes.Buffer
	json.NewEncoder(&b).Encode(command)
	resp, err := http.Post(fmt.Sprintf("http://%s/join", leader), "application/json", &b)
	if err != nil {
		return err
	}
	resp.Body.Close()

	return nil
}

func (s *Server) joinHandler(w http.ResponseWriter, req *http.Request) {
	command := &raft.DefaultJoinCommand{}

	if err := json.NewDecoder(req.Body).Decode(&command); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if _, err := s.raftServer.Do(command); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func (s *Server) readHandler(w http.ResponseWriter, req *http.Request) {
	log.Debug("readHandler for URL: %s", req.URL)
	b, err := ioutil.ReadAll(req.Body)
	if err != nil {
		log.Debug("Bad HTTP request", err.Error())
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	r, err := s.db.Query(string(b))
	if err != nil {
		log.Debug("Bad HTTP request", err.Error())
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}

	pretty, _ := isPretty(req)
	if pretty {
		b, err = json.MarshalIndent(r, "", "    ")
	} else {
		b, err = json.Marshal(r)
	}
	if err != nil {
		log.Debug("Failed to marshal JSON data", err.Error())
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.Write([]byte(b))
}

func (s *Server) writeHandler(w http.ResponseWriter, req *http.Request) {
	log.Debug("writeHandler for URL: %s", req.URL)
	// Read the value from the POST body.
	b, err := ioutil.ReadAll(req.Body)
	if err != nil {
		log.Debug("Bad HTTP request", err.Error())
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	stmts := strings.Split(string(b), "\n")

	// Execute the command against the Raft server.
	switch {
	case len(stmts) == 0:
		log.Debug("No database execute commands supplied")
		w.WriteHeader(http.StatusBadRequest)
		return
	case len(stmts) == 1:
		_, err = s.raftServer.Do(command.NewWriteCommand(stmts[0]))
	case len(stmts) > 1:
		transaction, _ := isTransaction(req)
		if transaction {
			log.Debug("Transaction requested")
			_, err = s.raftServer.Do(command.NewTransactionWriteCommandSet(stmts))
		} else {
			log.Debug("No transaction requested")
			// Do each individually, returning JSON respoonse
		}
	}
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
	}
}
<commit_msg>Check if last stamement is empty<commit_after>package server

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"math/rand"
	"net/http"
	"path"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"github.com/gorilla/mux"
	"github.com/otoolep/raft"
	"github.com/otoolep/rqlite/command"
	"github.com/otoolep/rqlite/db"

	log "code.google.com/p/log4go"
)

// queryParam returns whether the given query param is set to true.
func queryParam(req *http.Request, param string) (bool, error) {
	err := req.ParseForm()
	if err != nil {
		return false, err
	}
	if _, ok := req.Form[param]; ok {
		return true, nil
	}
	return false, nil
}

// isPretty returns whether the HTTP response body should be pretty-printed.
func isPretty(req *http.Request) (bool, error) {
	return queryParam(req, "pretty")
}

// isTransaction returns whether the client requested an explicit
// transaction for the request.
func isTransaction(req *http.Request) (bool, error) {
	return queryParam(req, "transaction")
}

// The raftd server is a combination of the Raft server and an HTTP
// server which acts as the transport.
type Server struct {
	name       string
	host       string
	port       int
	path       string
	router     *mux.Router
	raftServer raft.Server
	httpServer *http.Server
	db         *db.DB
	mutex      sync.RWMutex
}

// Creates a new server.
func New(dataDir string, dbfile string, host string, port int) *Server {
	s := &Server{
		host:   host,
		port:   port,
		path:   dataDir,
		db:     db.New(path.Join(dataDir, dbfile)),
		router: mux.NewRouter(),
	}

	// Read existing name or generate a new one.
	if b, err := ioutil.ReadFile(filepath.Join(dataDir, "name")); err == nil {
		s.name = string(b)
	} else {
		s.name = fmt.Sprintf("%07x", rand.Int())[0:7]
		if err = ioutil.WriteFile(filepath.Join(dataDir, "name"), []byte(s.name), 0644); err != nil {
			panic(err)
		}
	}

	return s
}

// Returns the connection string.
func (s *Server) connectionString() string {
	return fmt.Sprintf("http://%s:%d", s.host, s.port)
}

// Starts the server.
func (s *Server) ListenAndServe(leader string) error {
	var err error

	log.Info("Initializing Raft Server: %s", s.path)

	// Initialize and start Raft server.
	transporter := raft.NewHTTPTransporter("/raft", 200*time.Millisecond)
	s.raftServer, err = raft.NewServer(s.name, s.path, transporter, nil, s.db, "")
	if err != nil {
		log.Error("Failed to create new Raft server", err.Error())
		return err
	}
	transporter.Install(s.raftServer, s)
	s.raftServer.Start()

	if leader != "" {
		// Join to leader if specified.

		log.Info("Attempting to join leader:", leader)

		if !s.raftServer.IsLogEmpty() {
			log.Error("Cannot join with an existing log")
			return errors.New("Cannot join with an existing log")
		}
		if err := s.Join(leader); err != nil {
			log.Error("Failed to join leader", err.Error())
			return err
		}

	} else if s.raftServer.IsLogEmpty() {
		// Initialize the server by joining itself.

		log.Info("Initializing new cluster")

		_, err := s.raftServer.Do(&raft.DefaultJoinCommand{
			Name:             s.raftServer.Name(),
			ConnectionString: s.connectionString(),
		})
		if err != nil {
			log.Error("Failed to join to self", err.Error())
		}

	} else {
		log.Info("Recovered from log")
	}

	log.Info("Initializing HTTP server")

	// Initialize and start HTTP server.
	s.httpServer = &http.Server{
		Addr:    fmt.Sprintf(":%d", s.port),
		Handler: s.router,
	}

	s.router.HandleFunc("/db", s.readHandler).Methods("GET")
	s.router.HandleFunc("/db", s.writeHandler).Methods("POST")
	s.router.HandleFunc("/join", s.joinHandler).Methods("POST")

	log.Info("Listening at %s", s.connectionString())

	return s.httpServer.ListenAndServe()
}

// This is a hack around Gorilla mux not providing the correct net/http
// HandleFunc() interface.
func (s *Server) HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) {
	s.router.HandleFunc(pattern, handler)
}

// Joins to the leader of an existing cluster.
func (s *Server) Join(leader string) error {
	command := &raft.DefaultJoinCommand{
		Name:             s.raftServer.Name(),
		ConnectionString: s.connectionString(),
	}

	var b bytes.Buffer
	json.NewEncoder(&b).Encode(command)
	resp, err := http.Post(fmt.Sprintf("http://%s/join", leader), "application/json", &b)
	if err != nil {
		return err
	}
	resp.Body.Close()

	return nil
}

func (s *Server) joinHandler(w http.ResponseWriter, req *http.Request) {
	command := &raft.DefaultJoinCommand{}

	if err := json.NewDecoder(req.Body).Decode(&command); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if _, err := s.raftServer.Do(command); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func (s *Server) readHandler(w http.ResponseWriter, req *http.Request) {
	log.Debug("readHandler for URL: %s", req.URL)
	b, err := ioutil.ReadAll(req.Body)
	if err != nil {
		log.Debug("Bad HTTP request", err.Error())
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	r, err := s.db.Query(string(b))
	if err != nil {
		log.Debug("Bad HTTP request", err.Error())
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}

	pretty, _ := isPretty(req)
	if pretty {
		b, err = json.MarshalIndent(r, "", "    ")
	} else {
		b, err = json.Marshal(r)
	}
	if err != nil {
		log.Debug("Failed to marshal JSON data", err.Error())
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.Write([]byte(b))
}

func (s *Server) writeHandler(w http.ResponseWriter, req *http.Request) {
	log.Debug("writeHandler for URL: %s", req.URL)
	// Read the value from the POST body.
	b, err := ioutil.ReadAll(req.Body)
	if err != nil {
		log.Debug("Bad HTTP request", err.Error())
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	stmts := strings.Split(string(b), "\n")
	if stmts[len(stmts)-1] == "" {
		stmts = stmts[:len(stmts)-1]
	}

	// Execute the command against the Raft server.
	switch {
	case len(stmts) == 0:
		log.Debug("No database execute commands supplied")
		w.WriteHeader(http.StatusBadRequest)
		return
	case len(stmts) == 1:
		_, err = s.raftServer.Do(command.NewWriteCommand(stmts[0]))
	case len(stmts) > 1:
		transaction, _ := isTransaction(req)
		if transaction {
			log.Debug("Transaction requested")
			_, err = s.raftServer.Do(command.NewTransactionWriteCommandSet(stmts))
		} else {
			log.Debug("No transaction requested")
			// Do each individually, returning JSON respoonse
		}
	}
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The TensorFlow Authors. All Rights Reserved.

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 tensorflow

import (
	"fmt"
	"testing"

	tfpb "github.com/tensorflow/tensorflow/tensorflow/go/genop/internal/proto/github.com/tensorflow/tensorflow/tensorflow/go/core"
)

func TestSignatureFromProto(t *testing.T) {
	got := signatureDefFromProto(&tfpb.SignatureDef{
		Inputs: map[string]*tfpb.TensorInfo{
			"input_1": &tfpb.TensorInfo{
				Encoding: &tfpb.TensorInfo_Name{
					Name: "tensor_1",
				},
				Dtype: tfpb.DataType_DT_INT8,
				TensorShape: &tfpb.TensorShapeProto{
					Dim: []*tfpb.TensorShapeProto_Dim{
						{Size: 1},
						{Size: 2},
						{Size: 3},
					},
				},
			},
			"input_2": &tfpb.TensorInfo{
				Encoding: &tfpb.TensorInfo_Name{
					Name: "tensor_2",
				},
				Dtype: tfpb.DataType_DT_FLOAT,
				TensorShape: &tfpb.TensorShapeProto{
					Dim: []*tfpb.TensorShapeProto_Dim{
						{Size: 4},
						{Size: 5},
						{Size: 6},
					},
				},
			},
		},
		Outputs: map[string]*tfpb.TensorInfo{
			"output_1": &tfpb.TensorInfo{
				Encoding: &tfpb.TensorInfo_Name{
					Name: "tensor_3",
				},
				Dtype: tfpb.DataType_DT_STRING,
				TensorShape: &tfpb.TensorShapeProto{
					Dim: []*tfpb.TensorShapeProto_Dim{
						{Size: 1},
						{Size: 2},
						{Size: 3},
					},
				},
			},
			"output_2": &tfpb.TensorInfo{
				Encoding: &tfpb.TensorInfo_Name{
					Name: "tensor_4",
				},
				Dtype: tfpb.DataType_DT_BOOL,
				TensorShape: &tfpb.TensorShapeProto{
					Dim: []*tfpb.TensorShapeProto_Dim{
						{Size: 4},
						{Size: 5},
						{Size: 6},
					},
				},
			},
		},
		MethodName: "method",
	})

	want := Signature{
		Inputs: map[string]TensorInfo{
			"input_1": TensorInfo{
				Name:  "tensor_1",
				DType: Int8,
				Shape: MakeShape(1, 2, 3),
			},
			"input_2": TensorInfo{
				Name:  "tensor_2",
				DType: Float,
				Shape: MakeShape(4, 5, 6),
			},
		},
		Outputs: map[string]TensorInfo{
			"output_1": TensorInfo{
				Name:  "tensor_3",
				DType: String,
				Shape: MakeShape(1, 2, 3),
			},
			"output_2": TensorInfo{
				Name:  "tensor_4",
				DType: Bool,
				Shape: MakeShape(4, 5, 6),
			},
		},
		MethodName: "method",
	}

	for k, input := range want.Inputs {
		diff, err := diffTensorInfos(got.Inputs[k], input)
		if err != nil {
			t.Fatalf("Signature.Inputs[%s]: unable to diff TensorInfos: %v", k, err)
		}
		if diff != "" {
			t.Errorf("Signature.Inputs[%s] diff:\n%s", k, diff)
		}
	}

	for k, output := range want.Outputs {
		diff, err := diffTensorInfos(got.Outputs[k], output)
		if err != nil {
			t.Fatalf("Signature.Outputs[%s]: unable to diff TensorInfos: %v", k, err)
		}
		if diff != "" {
			t.Errorf("Signature.Outputs[%s] diff:\n%s", k, diff)
		}
	}

	if got.MethodName != want.MethodName {
		t.Errorf("Signature.MethodName: got %q, want %q", got.MethodName, want.MethodName)
	}
}

func TestTensorInfoFromProto(t *testing.T) {
	got := tensorInfoFromProto(&tfpb.TensorInfo{
		Encoding: &tfpb.TensorInfo_Name{
			Name: "tensor",
		},
		Dtype: tfpb.DataType_DT_INT8,
		TensorShape: &tfpb.TensorShapeProto{
			Dim: []*tfpb.TensorShapeProto_Dim{
				{Size: 1},
				{Size: 2},
				{Size: 3},
			},
		},
	})
	want := TensorInfo{
		Name:  "tensor",
		DType: Int8,
		Shape: MakeShape(1, 2, 3),
	}

	diff, err := diffTensorInfos(got, want)
	if err != nil {
		t.Fatalf("Unable to diff TensorInfos: %v", err)
	}
	if diff != "" {
		t.Errorf("tensorInfoFromProto produced a diff (got -> want): %s", diff)
	}
}

func diffTensorInfos(a, b TensorInfo) (string, error) {
	diff := ""
	if a.Name != b.Name {
		diff += fmt.Sprintf("Name: %q -> %q\n", a.Name, b.Name)
	}
	if a.DType != b.DType {
		diff += fmt.Sprintf("DType: %v -> %v\n", a.DType, b.DType)
	}

	aShape, err := a.Shape.ToSlice()
	if err != nil {
		return "", err
	}
	bShape, err := b.Shape.ToSlice()
	if err != nil {
		return "", err
	}
	shapeLen := len(aShape)
	if len(bShape) > shapeLen {
		shapeLen = len(bShape)
	}
	for i := 0; i < shapeLen; i++ {
		if i >= len(aShape) {
			diff += fmt.Sprintf("+Shape[%d]: %d\n", i, bShape[i])
			continue
		}
		if i >= len(bShape) {
			diff += fmt.Sprintf("-Shape[%d]: %d\n", i, aShape[i])
			continue
		}
		if aShape[i] != bShape[i] {
			diff += fmt.Sprintf("Shape[%d]: %d -> %d\n", i, aShape[i], bShape[i])
		}
	}

	return diff, nil
}
<commit_msg>Remove tensorflow/core/framework/ protos from tensorflow/core:protos_all_go_proto. Users should now depend on the tensorflow/core/framework:*_go_proto targets directly.<commit_after>/*
Copyright 2019 The TensorFlow Authors. All Rights Reserved.

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 tensorflow

import (
	"fmt"
	"testing"

	tspb "github.com/tensorflow/tensorflow/tensorflow/go/genop/internal/proto/github.com/tensorflow/tensorflow/tensorflow/go/core/framework/tensor_shape_go_proto"
	typb "github.com/tensorflow/tensorflow/tensorflow/go/genop/internal/proto/github.com/tensorflow/tensorflow/tensorflow/go/core/framework/types_go_proto"
	tfpb "github.com/tensorflow/tensorflow/tensorflow/go/genop/internal/proto/github.com/tensorflow/tensorflow/tensorflow/go/core"
)

func TestSignatureFromProto(t *testing.T) {
	got := signatureDefFromProto(&tfpb.SignatureDef{
		Inputs: map[string]*tfpb.TensorInfo{
			"input_1": &tfpb.TensorInfo{
				Encoding: &tfpb.TensorInfo_Name{
					Name: "tensor_1",
				},
				Dtype: typb.DataType_DT_INT8,
				TensorShape: &tspb.TensorShapeProto{
					Dim: []*tspb.TensorShapeProto_Dim{
						{Size: 1},
						{Size: 2},
						{Size: 3},
					},
				},
			},
			"input_2": &tfpb.TensorInfo{
				Encoding: &tfpb.TensorInfo_Name{
					Name: "tensor_2",
				},
				Dtype: typb.DataType_DT_FLOAT,
				TensorShape: &tspb.TensorShapeProto{
					Dim: []*tspb.TensorShapeProto_Dim{
						{Size: 4},
						{Size: 5},
						{Size: 6},
					},
				},
			},
		},
		Outputs: map[string]*tfpb.TensorInfo{
			"output_1": &tfpb.TensorInfo{
				Encoding: &tfpb.TensorInfo_Name{
					Name: "tensor_3",
				},
				Dtype: typb.DataType_DT_STRING,
				TensorShape: &tspb.TensorShapeProto{
					Dim: []*tspb.TensorShapeProto_Dim{
						{Size: 1},
						{Size: 2},
						{Size: 3},
					},
				},
			},
			"output_2": &tfpb.TensorInfo{
				Encoding: &tfpb.TensorInfo_Name{
					Name: "tensor_4",
				},
				Dtype: typb.DataType_DT_BOOL,
				TensorShape: &tspb.TensorShapeProto{
					Dim: []*tspb.TensorShapeProto_Dim{
						{Size: 4},
						{Size: 5},
						{Size: 6},
					},
				},
			},
		},
		MethodName: "method",
	})

	want := Signature{
		Inputs: map[string]TensorInfo{
			"input_1": TensorInfo{
				Name:  "tensor_1",
				DType: Int8,
				Shape: MakeShape(1, 2, 3),
			},
			"input_2": TensorInfo{
				Name:  "tensor_2",
				DType: Float,
				Shape: MakeShape(4, 5, 6),
			},
		},
		Outputs: map[string]TensorInfo{
			"output_1": TensorInfo{
				Name:  "tensor_3",
				DType: String,
				Shape: MakeShape(1, 2, 3),
			},
			"output_2": TensorInfo{
				Name:  "tensor_4",
				DType: Bool,
				Shape: MakeShape(4, 5, 6),
			},
		},
		MethodName: "method",
	}

	for k, input := range want.Inputs {
		diff, err := diffTensorInfos(got.Inputs[k], input)
		if err != nil {
			t.Fatalf("Signature.Inputs[%s]: unable to diff TensorInfos: %v", k, err)
		}
		if diff != "" {
			t.Errorf("Signature.Inputs[%s] diff:\n%s", k, diff)
		}
	}

	for k, output := range want.Outputs {
		diff, err := diffTensorInfos(got.Outputs[k], output)
		if err != nil {
			t.Fatalf("Signature.Outputs[%s]: unable to diff TensorInfos: %v", k, err)
		}
		if diff != "" {
			t.Errorf("Signature.Outputs[%s] diff:\n%s", k, diff)
		}
	}

	if got.MethodName != want.MethodName {
		t.Errorf("Signature.MethodName: got %q, want %q", got.MethodName, want.MethodName)
	}
}

func TestTensorInfoFromProto(t *testing.T) {
	got := tensorInfoFromProto(&tfpb.TensorInfo{
		Encoding: &tfpb.TensorInfo_Name{
			Name: "tensor",
		},
		Dtype: typb.DataType_DT_INT8,
		TensorShape: &tspb.TensorShapeProto{
			Dim: []*tspb.TensorShapeProto_Dim{
				{Size: 1},
				{Size: 2},
				{Size: 3},
			},
		},
	})
	want := TensorInfo{
		Name:  "tensor",
		DType: Int8,
		Shape: MakeShape(1, 2, 3),
	}

	diff, err := diffTensorInfos(got, want)
	if err != nil {
		t.Fatalf("Unable to diff TensorInfos: %v", err)
	}
	if diff != "" {
		t.Errorf("tensorInfoFromProto produced a diff (got -> want): %s", diff)
	}
}

func diffTensorInfos(a, b TensorInfo) (string, error) {
	diff := ""
	if a.Name != b.Name {
		diff += fmt.Sprintf("Name: %q -> %q\n", a.Name, b.Name)
	}
	if a.DType != b.DType {
		diff += fmt.Sprintf("DType: %v -> %v\n", a.DType, b.DType)
	}

	aShape, err := a.Shape.ToSlice()
	if err != nil {
		return "", err
	}
	bShape, err := b.Shape.ToSlice()
	if err != nil {
		return "", err
	}
	shapeLen := len(aShape)
	if len(bShape) > shapeLen {
		shapeLen = len(bShape)
	}
	for i := 0; i < shapeLen; i++ {
		if i >= len(aShape) {
			diff += fmt.Sprintf("+Shape[%d]: %d\n", i, bShape[i])
			continue
		}
		if i >= len(bShape) {
			diff += fmt.Sprintf("-Shape[%d]: %d\n", i, aShape[i])
			continue
		}
		if aShape[i] != bShape[i] {
			diff += fmt.Sprintf("Shape[%d]: %d -> %d\n", i, aShape[i], bShape[i])
		}
	}

	return diff, nil
}
<|endoftext|>


<commit_before>package framework

import (
	"flag"
	"fmt"
	"time"

	"github.com/coreos-inc/vault-operator/pkg/util/k8sutil"

	"github.com/Sirupsen/logrus"
	eopK8sutil "github.com/coreos/etcd-operator/pkg/util/k8sutil"
	"k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/clientcmd"
)

var (
	// The global framework variable used by all e2e tests
	Global       *Framework
	operatorName = "vault-operator"
)

// Framework struct contains the various clients and other information needed to run the e2e tests
type Framework struct {
	KubeClient kubernetes.Interface
	Namespace  string
	vopImage   string
}

// Setup initializes the Global framework by initializing necessary clients and creating the vault operator
func Setup() error {
	kubeconfig := flag.String("kubeconfig", "", "kube config path, e.g. $HOME/.kube/config")
	vopImage := flag.String("operator-image", "", "operator image, e.g. quay.io/coreos/vault-operator-dev:latest")
	ns := flag.String("namespace", "", "e2e test namespace")
	flag.Parse()

	config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
	if err != nil {
		return err
	}
	cli, err := kubernetes.NewForConfig(config)
	if err != nil {
		return err
	}

	// TODO: need a CR client to CRUD the vault CR later

	Global = &Framework{
		KubeClient: cli,
		Namespace:  *ns,
		vopImage:   *vopImage,
	}

	return Global.setup()
}

// Teardown removes the vault-operator deployment and waits for its termination
func Teardown() error {
	err := Global.KubeClient.CoreV1().Pods(Global.Namespace).Delete(operatorName, k8sutil.CascadeDeleteBackground())
	if err != nil {
		return fmt.Errorf("failed to delete pod: %v", err)
	}
	Global = nil
	logrus.Info("e2e teardown successfully")
	return nil
}

func (f *Framework) setup() error {
	if err := f.createVaultOperatorPod(); err != nil {
		return fmt.Errorf("failed to setup vault operator: %v", err)
	}
	logrus.Info("e2e setup successfully")
	return nil
}

func (f *Framework) createVaultOperatorPod() error {
	pod := &v1.Pod{
		ObjectMeta: metav1.ObjectMeta{
			Name:      operatorName,
			Namespace: f.Namespace,
			Labels:    podLabelForOperator(operatorName),
		},
		Spec: v1.PodSpec{
			Containers: []v1.Container{{
				Name:            operatorName,
				Image:           f.vopImage,
				ImagePullPolicy: v1.PullAlways,
				Env: []v1.EnvVar{
					{
						Name:      "MY_POD_NAMESPACE",
						ValueFrom: &v1.EnvVarSource{FieldRef: &v1.ObjectFieldSelector{FieldPath: "metadata.namespace"}},
					},
					{
						Name:      "MY_POD_NAME",
						ValueFrom: &v1.EnvVarSource{FieldRef: &v1.ObjectFieldSelector{FieldPath: "metadata.name"}},
					},
				},
			}},
			ImagePullSecrets: []v1.LocalObjectReference{{
				Name: "coreos-pull-secret",
			}},
		},
	}

	// Create and wait for pod phase to become running
	// TODO: Replace with operator pod actually becoming ready once the vault-operator supports a readiness probe
	_, err := eopK8sutil.CreateAndWaitPod(f.KubeClient, f.Namespace, pod, 60*time.Second)
	if err != nil {
		return err
	}
	if err != nil {
		return fmt.Errorf("failed to create pod: %v", err)
	}
	return nil
}

func podLabelForOperator(name string) map[string]string {
	return map[string]string{"name": name}
}
<commit_msg>e2e: never restart operator pod in test<commit_after>package framework

import (
	"flag"
	"fmt"
	"time"

	"github.com/coreos-inc/vault-operator/pkg/util/k8sutil"

	"github.com/Sirupsen/logrus"
	eopK8sutil "github.com/coreos/etcd-operator/pkg/util/k8sutil"
	"k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/clientcmd"
)

var (
	// The global framework variable used by all e2e tests
	Global       *Framework
	operatorName = "vault-operator"
)

// Framework struct contains the various clients and other information needed to run the e2e tests
type Framework struct {
	KubeClient kubernetes.Interface
	Namespace  string
	vopImage   string
}

// Setup initializes the Global framework by initializing necessary clients and creating the vault operator
func Setup() error {
	kubeconfig := flag.String("kubeconfig", "", "kube config path, e.g. $HOME/.kube/config")
	vopImage := flag.String("operator-image", "", "operator image, e.g. quay.io/coreos/vault-operator-dev:latest")
	ns := flag.String("namespace", "", "e2e test namespace")
	flag.Parse()

	config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
	if err != nil {
		return err
	}
	cli, err := kubernetes.NewForConfig(config)
	if err != nil {
		return err
	}

	// TODO: need a CR client to CRUD the vault CR later

	Global = &Framework{
		KubeClient: cli,
		Namespace:  *ns,
		vopImage:   *vopImage,
	}

	return Global.setup()
}

// Teardown removes the vault-operator deployment and waits for its termination
func Teardown() error {
	err := Global.KubeClient.CoreV1().Pods(Global.Namespace).Delete(operatorName, k8sutil.CascadeDeleteBackground())
	if err != nil {
		return fmt.Errorf("failed to delete pod: %v", err)
	}
	Global = nil
	logrus.Info("e2e teardown successfully")
	return nil
}

func (f *Framework) setup() error {
	if err := f.createVaultOperatorPod(); err != nil {
		return fmt.Errorf("failed to setup vault operator: %v", err)
	}
	logrus.Info("e2e setup successfully")
	return nil
}

func (f *Framework) createVaultOperatorPod() error {
	pod := &v1.Pod{
		ObjectMeta: metav1.ObjectMeta{
			Name:      operatorName,
			Namespace: f.Namespace,
			Labels:    podLabelForOperator(operatorName),
		},
		Spec: v1.PodSpec{
			RestartPolicy: v1.RestartPolicyNever,
			Containers: []v1.Container{{
				Name:            operatorName,
				Image:           f.vopImage,
				ImagePullPolicy: v1.PullAlways,
				Env: []v1.EnvVar{
					{
						Name:      "MY_POD_NAMESPACE",
						ValueFrom: &v1.EnvVarSource{FieldRef: &v1.ObjectFieldSelector{FieldPath: "metadata.namespace"}},
					},
					{
						Name:      "MY_POD_NAME",
						ValueFrom: &v1.EnvVarSource{FieldRef: &v1.ObjectFieldSelector{FieldPath: "metadata.name"}},
					},
				},
			}},
			ImagePullSecrets: []v1.LocalObjectReference{{
				Name: "coreos-pull-secret",
			}},
		},
	}

	// Create and wait for pod phase to become running
	// TODO: Replace with operator pod actually becoming ready once the vault-operator supports a readiness probe
	_, err := eopK8sutil.CreateAndWaitPod(f.KubeClient, f.Namespace, pod, 60*time.Second)
	if err != nil {
		return err
	}
	if err != nil {
		return fmt.Errorf("failed to create pod: %v", err)
	}
	return nil
}

func podLabelForOperator(name string) map[string]string {
	return map[string]string{"name": name}
}
<|endoftext|>


<commit_before>package images

import (
	"context"
	"strings"

	"github.com/MakeNowJust/heredoc"
	g "github.com/onsi/ginkgo"
	o "github.com/onsi/gomega"

	kapi "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	imageapi "github.com/openshift/api/image/v1"
	imageclientset "github.com/openshift/client-go/image/clientset/versioned"
	exutil "github.com/openshift/origin/test/extended/util"
)

var _ = g.Describe("[sig-imageregistry][Feature:ImageExtract] Image extract", func() {
	defer g.GinkgoRecover()

	var oc *exutil.CLI
	var ns string

	g.AfterEach(func() {
		if g.CurrentGinkgoTestDescription().Failed && len(ns) > 0 {
			exutil.DumpPodLogsStartingWithInNamespace("", ns, oc)
		}
	})

	oc = exutil.NewCLI("image-extract")

	g.It("should extract content from an image", func() {
		is, err := oc.ImageClient().ImageV1().ImageStreams("openshift").Get(context.Background(), "php", metav1.GetOptions{})
		o.Expect(err).NotTo(o.HaveOccurred())
		o.Expect(is.Status.DockerImageRepository).NotTo(o.BeEmpty(), "registry not yet configured?")
		registry := strings.Split(is.Status.DockerImageRepository, "/")[0]

		ns = oc.Namespace()
		cli := oc.KubeFramework().PodClient()
		client := imageclientset.NewForConfigOrDie(oc.UserConfig()).ImageV1()

		_, err = client.ImageStreamImports(ns).Create(context.Background(), &imageapi.ImageStreamImport{
			ObjectMeta: metav1.ObjectMeta{
				Name: "1",
			},
			Spec: imageapi.ImageStreamImportSpec{
				Import: true,
				Images: []imageapi.ImageImportSpec{
					{
						From: kapi.ObjectReference{Kind: "DockerImage", Name: "busybox:latest"},
						To:   &kapi.LocalObjectReference{Name: "busybox"},
					},
					{
						From: kapi.ObjectReference{Kind: "DockerImage", Name: "mysql:latest"},
						To:   &kapi.LocalObjectReference{Name: "mysql"},
					},
				},
			},
		}, metav1.CreateOptions{})
		o.Expect(err).ToNot(o.HaveOccurred())

		// busyboxLayers := isi.Status.Images[0].Image.DockerImageLayers
		// busyboxLen := len(busyboxLayers)
		// mysqlLayers := isi.Status.Images[1].Image.DockerImageLayers
		// mysqlLen := len(mysqlLayers)

		pod := cli.Create(cliPodWithPullSecret(oc, heredoc.Docf(`
			set -x

			# command exits if directory doesn't exist
			! oc image extract --insecure %[2]s/%[1]s/1:busybox --path=/:/tmp/doesnotexist
			# command exits if directory isn't empty
			! oc image extract --insecure %[2]s/%[1]s/1:busybox --path=/:/

			# extract busybox to a directory, verify the contents
			mkdir -p /tmp/test
			oc image extract --insecure %[2]s/%[1]s/1:busybox --path=/:/tmp/test
			[ -d /tmp/test/etc ] && [ -d /tmp/test/bin ]
			[ -f /tmp/test/etc/passwd ] && grep root /tmp/test/etc/passwd

			# extract multiple individual files
			mkdir -p /tmp/test2
			oc image extract --insecure %[2]s/%[1]s/1:busybox --path=/etc/shadow:/tmp/test2 --path=/etc/localtime:/tmp/test2
			[ -f /tmp/test2/shadow ] && [ -f /tmp/test2/localtime ]

			# extract a single file to the current directory
			mkdir -p /tmp/test3
			cd /tmp/test3
			oc image extract --insecure %[2]s/%[1]s/1:busybox --file=/etc/shadow
			[ -f /tmp/test3/shadow ]
		`, ns, registry)))
		cli.WaitForSuccess(pod.Name, podStartupTimeout)
	})
})
<commit_msg>Image extract tests should check results of ImageStreamImport<commit_after>package images

import (
	"context"
	"fmt"
	"strings"

	"github.com/MakeNowJust/heredoc"
	g "github.com/onsi/ginkgo"
	o "github.com/onsi/gomega"

	kapi "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	imageapi "github.com/openshift/api/image/v1"
	imageclientset "github.com/openshift/client-go/image/clientset/versioned"
	exutil "github.com/openshift/origin/test/extended/util"
)

var _ = g.Describe("[sig-imageregistry][Feature:ImageExtract] Image extract", func() {
	defer g.GinkgoRecover()

	var oc *exutil.CLI
	var ns string

	g.AfterEach(func() {
		if g.CurrentGinkgoTestDescription().Failed && len(ns) > 0 {
			exutil.DumpPodLogsStartingWithInNamespace("", ns, oc)
		}
	})

	oc = exutil.NewCLI("image-extract")

	g.It("should extract content from an image", func() {
		is, err := oc.ImageClient().ImageV1().ImageStreams("openshift").Get(context.Background(), "php", metav1.GetOptions{})
		o.Expect(err).NotTo(o.HaveOccurred())
		o.Expect(is.Status.DockerImageRepository).NotTo(o.BeEmpty(), "registry not yet configured?")
		registry := strings.Split(is.Status.DockerImageRepository, "/")[0]

		ns = oc.Namespace()
		cli := oc.KubeFramework().PodClient()
		client := imageclientset.NewForConfigOrDie(oc.UserConfig()).ImageV1()

		isi, err := client.ImageStreamImports(ns).Create(context.Background(), &imageapi.ImageStreamImport{
			ObjectMeta: metav1.ObjectMeta{
				Name: "1",
			},
			Spec: imageapi.ImageStreamImportSpec{
				Import: true,
				Images: []imageapi.ImageImportSpec{
					{
						From: kapi.ObjectReference{Kind: "DockerImage", Name: "busybox:latest"},
						To:   &kapi.LocalObjectReference{Name: "busybox"},
					},
					{
						From: kapi.ObjectReference{Kind: "DockerImage", Name: "mysql:latest"},
						To:   &kapi.LocalObjectReference{Name: "mysql"},
					},
				},
			},
		}, metav1.CreateOptions{})
		o.Expect(err).ToNot(o.HaveOccurred())

		for i, img := range isi.Status.Images {
			o.Expect(img.Status.Status).To(o.Equal("Success"), fmt.Sprintf("imagestreamimport status for spec.image[%d] (message: %s)", i, img.Status.Message))
		}

		// busyboxLayers := isi.Status.Images[0].Image.DockerImageLayers
		// busyboxLen := len(busyboxLayers)
		// mysqlLayers := isi.Status.Images[1].Image.DockerImageLayers
		// mysqlLen := len(mysqlLayers)

		pod := cli.Create(cliPodWithPullSecret(oc, heredoc.Docf(`
			set -x

			# command exits if directory doesn't exist
			! oc image extract --insecure %[2]s/%[1]s/1:busybox --path=/:/tmp/doesnotexist
			# command exits if directory isn't empty
			! oc image extract --insecure %[2]s/%[1]s/1:busybox --path=/:/

			# extract busybox to a directory, verify the contents
			mkdir -p /tmp/test
			oc image extract --insecure %[2]s/%[1]s/1:busybox --path=/:/tmp/test
			[ -d /tmp/test/etc ] && [ -d /tmp/test/bin ]
			[ -f /tmp/test/etc/passwd ] && grep root /tmp/test/etc/passwd

			# extract multiple individual files
			mkdir -p /tmp/test2
			oc image extract --insecure %[2]s/%[1]s/1:busybox --path=/etc/shadow:/tmp/test2 --path=/etc/localtime:/tmp/test2
			[ -f /tmp/test2/shadow ] && [ -f /tmp/test2/localtime ]

			# extract a single file to the current directory
			mkdir -p /tmp/test3
			cd /tmp/test3
			oc image extract --insecure %[2]s/%[1]s/1:busybox --file=/etc/shadow
			[ -f /tmp/test3/shadow ]
		`, ns, registry)))
		cli.WaitForSuccess(pod.Name, podStartupTimeout)
	})
})
<|endoftext|>


<commit_before>// +build integration

/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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 integration

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"os/exec"
	"path"
	"strings"
	"testing"
	"time"

	core "k8s.io/api/core/v1"
	storage "k8s.io/api/storage/v1"
	"k8s.io/minikube/pkg/util/retry"
)

func validatePersistentVolumeClaim(ctx context.Context, t *testing.T, profile string) {
	defer PostMortemLogs(t, profile)

	ctx, cancel := context.WithTimeout(ctx, Minutes(10))
	defer cancel()

	if _, err := PodWait(ctx, t, profile, "kube-system", "integration-test=storage-provisioner", Minutes(4)); err != nil {
		t.Fatalf("failed waiting for storage-provisioner: %v", err)
	}

	checkStorageClass := func() error {
		rr, err := Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "get", "storageclass", "-o=json"))
		if err != nil {
			return err
		}
		scl := storage.StorageClassList{}
		if err := json.NewDecoder(bytes.NewReader(rr.Stdout.Bytes())).Decode(&scl); err != nil {
			return err
		}
		if len(scl.Items) == 0 {
			return fmt.Errorf("no storageclass yet")
		}
		return nil
	}

	// Ensure the addon-manager has created the StorageClass before creating a claim, otherwise it won't be bound
	if err := retry.Expo(checkStorageClass, time.Millisecond*500, Seconds(100)); err != nil {
		t.Errorf("failed to check for storage class: %v", err)
	}

	// Now create a testpvc
	rr, err := Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "apply", "-f", path.Join(*testdataDir, "storage-provisioner", "pvc.yaml")))
	if err != nil {
		t.Fatalf("kubectl apply pvc.yaml failed: args %q: %v", rr.Command(), err)
	}

	// make sure the pvc is Bound
	checkStoragePhase := func() error {
		rr, err := Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "get", "pvc", "myclaim", "-o=json"))
		if err != nil {
			return err
		}
		pvc := core.PersistentVolumeClaim{}
		if err := json.NewDecoder(bytes.NewReader(rr.Stdout.Bytes())).Decode(&pvc); err != nil {
			return err
		}
		// The test passes if the volume claim gets bound.
		if pvc.Status.Phase == "Bound" {
			return nil
		}
		return fmt.Errorf("testpvc phase = %q, want %q (msg=%+v)", pvc.Status.Phase, "Bound", pvc)
	}

	if err := retry.Expo(checkStoragePhase, 2*time.Second, Minutes(4)); err != nil {
		t.Fatalf("failed to check storage phase: %v", err)
	}

	//	create a test pod that will mount the persistent volume
	createPVTestPod(t, ctx, profile)

	// write to the persistent volume
	podName := "sp-pod"
	rr, err = Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "exec", podName, "--", "touch", "/tmp/mount/foo"))
	if err != nil {
		t.Fatalf("creating file in pv: args %q: %v", rr.Command(), err)
	}

	// kill the pod
	rr, err = Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "delete", "-f", path.Join(*testdataDir, "storage-provisioner", "pod.yaml")))
	if err != nil {
		t.Fatalf("kubectl delete pod.yaml failed: args %q: %v", rr.Command(), err)
	}
	// recreate the pod
	createPVTestPod(t, ctx, profile)

	// make sure the file we previously wrote to the persistent volume is still there
	rr, err = Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "exec", podName, "--", "ls", "/tmp/mount"))
	if err != nil {
		t.Fatalf("creating file in pv: args %q: %v", rr.Command(), err)
	}
	if !strings.Contains(rr.Output(), "foo") {
		t.Fatalf("expected file foo to persist in pvc, instead got [%v] as files in pv", rr.Output())
	}
}

func createPVTestPod(t *testing.T, ctx context.Context, profile string) {
	// Deploy a pod that will mount the PV
	rr, err := Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "apply", "-f", path.Join(*testdataDir, "storage-provisioner", "pod.yaml")))
	if err != nil {
		t.Fatalf("kubectl apply pvc.yaml failed: args %q: %v", rr.Command(), err)
	}
	// wait for pod to be running
	if _, err := PodWait(ctx, t, profile, "default", "test=storage-provisioner", Minutes(1)); err != nil {
		t.Fatalf("failed waiting for pod: %v", err)
	}
}
<commit_msg>fix lint<commit_after>// +build integration

/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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 integration

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"os/exec"
	"path"
	"strings"
	"testing"
	"time"

	core "k8s.io/api/core/v1"
	storage "k8s.io/api/storage/v1"
	"k8s.io/minikube/pkg/util/retry"
)

func validatePersistentVolumeClaim(ctx context.Context, t *testing.T, profile string) {
	defer PostMortemLogs(t, profile)

	ctx, cancel := context.WithTimeout(ctx, Minutes(10))
	defer cancel()

	if _, err := PodWait(ctx, t, profile, "kube-system", "integration-test=storage-provisioner", Minutes(4)); err != nil {
		t.Fatalf("failed waiting for storage-provisioner: %v", err)
	}

	checkStorageClass := func() error {
		rr, err := Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "get", "storageclass", "-o=json"))
		if err != nil {
			return err
		}
		scl := storage.StorageClassList{}
		if err := json.NewDecoder(bytes.NewReader(rr.Stdout.Bytes())).Decode(&scl); err != nil {
			return err
		}
		if len(scl.Items) == 0 {
			return fmt.Errorf("no storageclass yet")
		}
		return nil
	}

	// Ensure the addon-manager has created the StorageClass before creating a claim, otherwise it won't be bound
	if err := retry.Expo(checkStorageClass, time.Millisecond*500, Seconds(100)); err != nil {
		t.Errorf("failed to check for storage class: %v", err)
	}

	// Now create a testpvc
	rr, err := Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "apply", "-f", path.Join(*testdataDir, "storage-provisioner", "pvc.yaml")))
	if err != nil {
		t.Fatalf("kubectl apply pvc.yaml failed: args %q: %v", rr.Command(), err)
	}

	// make sure the pvc is Bound
	checkStoragePhase := func() error {
		rr, err := Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "get", "pvc", "myclaim", "-o=json"))
		if err != nil {
			return err
		}
		pvc := core.PersistentVolumeClaim{}
		if err := json.NewDecoder(bytes.NewReader(rr.Stdout.Bytes())).Decode(&pvc); err != nil {
			return err
		}
		// The test passes if the volume claim gets bound.
		if pvc.Status.Phase == "Bound" {
			return nil
		}
		return fmt.Errorf("testpvc phase = %q, want %q (msg=%+v)", pvc.Status.Phase, "Bound", pvc)
	}

	if err := retry.Expo(checkStoragePhase, 2*time.Second, Minutes(4)); err != nil {
		t.Fatalf("failed to check storage phase: %v", err)
	}

	//	create a test pod that will mount the persistent volume
	createPVTestPod(ctx, t, profile)

	// write to the persistent volume
	podName := "sp-pod"
	rr, err = Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "exec", podName, "--", "touch", "/tmp/mount/foo"))
	if err != nil {
		t.Fatalf("creating file in pv: args %q: %v", rr.Command(), err)
	}

	// kill the pod
	rr, err = Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "delete", "-f", path.Join(*testdataDir, "storage-provisioner", "pod.yaml")))
	if err != nil {
		t.Fatalf("kubectl delete pod.yaml failed: args %q: %v", rr.Command(), err)
	}
	// recreate the pod
	createPVTestPod(ctx, t, profile)

	// make sure the file we previously wrote to the persistent volume is still there
	rr, err = Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "exec", podName, "--", "ls", "/tmp/mount"))
	if err != nil {
		t.Fatalf("creating file in pv: args %q: %v", rr.Command(), err)
	}
	if !strings.Contains(rr.Output(), "foo") {
		t.Fatalf("expected file foo to persist in pvc, instead got [%v] as files in pv", rr.Output())
	}
}

func createPVTestPod(ctx context.Context, t *testing.T, profile string) {
	// Deploy a pod that will mount the PV
	rr, err := Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "apply", "-f", path.Join(*testdataDir, "storage-provisioner", "pod.yaml")))
	if err != nil {
		t.Fatalf("kubectl apply pvc.yaml failed: args %q: %v", rr.Command(), err)
	}
	// wait for pod to be running
	if _, err := PodWait(ctx, t, profile, "default", "test=storage-provisioner", Minutes(1)); err != nil {
		t.Fatalf("failed waiting for pod: %v", err)
	}
}
<|endoftext|>


<commit_before>package wbrules

import (
	"time"
	"testing"
	"github.com/stretchr/testify/assert"
	wbgo "github.com/contactless/wbgo"
)

var baseRuleTestTime = time.Date(2015, 2, 27, 19, 33, 17, 0, time.UTC)

func makeTime(d time.Duration) time.Time {
	return baseRuleTestTime.Add(d)
}

type fakeTimer struct {
	t *testing.T
	name string
	c chan time.Time
	d time.Duration
	periodic bool
	active bool
	rec *wbgo.Recorder
}

func (timer *fakeTimer) GetChannel() <-chan time.Time {
	return timer.c
}

func (timer *fakeTimer) fire(t time.Time) {
	timer.rec.Rec("timer.fire(): %s", timer.name)
	assert.True(timer.t, timer.active)
	timer.c <- t
	if !timer.periodic {
		timer.active = false
	}
}

func (timer *fakeTimer) Stop() {
	// note that we don't close timer here,
	// mimicking the behavior of real timers and tickers
	timer.active = false
	timer.rec.Rec("timer.Stop(): %s", timer.name)
}

type ruleFixture struct {
	cellFixture
	engine *RuleEngine
	timers map[string]*fakeTimer
}

func NewRuleFixture(t *testing.T) *ruleFixture {
	fixture := &ruleFixture{
		*NewCellFixture(t),
		nil,
		make(map[string]*fakeTimer),
	}
	fixture.engine = NewRuleEngine(fixture.model)
	fixture.engine.SetTimerFunc(fixture.newFakeTimer)
	fixture.engine.SetLogFunc(func (message string) {
		fixture.broker.Rec("[rule] %s", message)
	})
	assert.Equal(t, nil, fixture.engine.LoadScript("testrules.js"))
	fixture.driver.Start()
	fixture.publish("/devices/somedev/meta/name", "SomeDev", "")
	fixture.publish("/devices/somedev/controls/sw/meta/type", "switch", "sw")
	fixture.publish("/devices/somedev/controls/sw", "0", "sw")
	fixture.publish("/devices/somedev/controls/temp/meta/type", "temperature", "temp")
	fixture.publish("/devices/somedev/controls/temp", "19", "temp")
	return fixture
}

func (fixture *ruleFixture) newFakeTimer(name string, d time.Duration, periodic bool) Timer {
	timer := &fakeTimer{
		t: fixture.t,
		name: name,
		c: make(chan time.Time),
		d: d,
		periodic: periodic,
		active: true,
		rec: &fixture.broker.Recorder,
	}
	fixture.timers[name] = timer
	fixture.broker.Rec("newFakeTimer(): %s, %d, %v", name, d / time.Millisecond, periodic)
	return timer
}

func (fixture *ruleFixture) Verify(logs... string) {
	fixture.broker.Verify(logs...)
}

func (fixture *ruleFixture) VerifyUnordered(logs... string) {
	fixture.broker.VerifyUnordered(logs...)
}

func (fixture *ruleFixture) SetCellValue(device, cellName string, value interface{}) {
	fixture.driver.CallSync(func () {
		fixture.model.EnsureDevice(device).EnsureCell(cellName).SetValue(value)
	})
	actualCellName := <- fixture.cellChange
	assert.Equal(fixture.t, cellName, actualCellName)
}

func TestDeviceDefinition(t *testing.T) {
	fixture := NewRuleFixture(t)
	defer fixture.tearDown()
	fixture.Verify(
		"driver -> /devices/stabSettings/meta/name: [Stabilization Settings] (QoS 1, retained)",
		"driver -> /devices/stabSettings/controls/enabled/meta/type: [switch] (QoS 1, retained)",
		"driver -> /devices/stabSettings/controls/enabled/meta/order: [1] (QoS 1, retained)",
		"driver -> /devices/stabSettings/controls/enabled: [0] (QoS 1, retained)",
		"Subscribe -- driver: /devices/stabSettings/controls/enabled/on",
		"driver -> /devices/stabSettings/controls/highThreshold/meta/type: [range] (QoS 1, retained)",
		"driver -> /devices/stabSettings/controls/highThreshold/meta/order: [2] (QoS 1, retained)",
		"driver -> /devices/stabSettings/controls/highThreshold/meta/max: [50] (QoS 1, retained)",
		"driver -> /devices/stabSettings/controls/highThreshold: [22] (QoS 1, retained)",
		"Subscribe -- driver: /devices/stabSettings/controls/highThreshold/on",
		"driver -> /devices/stabSettings/controls/lowThreshold/meta/type: [range] (QoS 1, retained)",
		"driver -> /devices/stabSettings/controls/lowThreshold/meta/order: [3] (QoS 1, retained)",
		"driver -> /devices/stabSettings/controls/lowThreshold/meta/max: [40] (QoS 1, retained)",
		"driver -> /devices/stabSettings/controls/lowThreshold: [20] (QoS 1, retained)",
		"Subscribe -- driver: /devices/stabSettings/controls/lowThreshold/on",
		"Subscribe -- driver: /devices/+/meta/name",
		"Subscribe -- driver: /devices/+/controls/+",
		"Subscribe -- driver: /devices/+/controls/+/meta/type",
		"Subscribe -- driver: /devices/+/controls/+/meta/max",
		"tst -> /devices/somedev/meta/name: [SomeDev] (QoS 1, retained)",
		"tst -> /devices/somedev/controls/sw/meta/type: [switch] (QoS 1, retained)",
		"tst -> /devices/somedev/controls/sw: [0] (QoS 1, retained)",
		"tst -> /devices/somedev/controls/temp/meta/type: [temperature] (QoS 1, retained)",
		"tst -> /devices/somedev/controls/temp: [19] (QoS 1, retained)",
	)
}

func TestRules(t *testing.T) {
	fixture := NewRuleFixture(t)
	defer fixture.tearDown()
	fixture.broker.SkipTill("tst -> /devices/somedev/controls/temp: [19] (QoS 1, retained)")
	fixture.engine.Start() // FIXME: should auto-start
	t.Log("QQQQQQQQQQQQQQ")

	fixture.SetCellValue("stabSettings", "enabled", true)
	fixture.Verify(
		"driver -> /devices/stabSettings/controls/enabled: [1] (QoS 1, retained)",
		"[rule] heaterOn fired",
 		"driver -> /devices/somedev/controls/sw/on: [1] (QoS 1)",
	)
	t.Log("RRRRR0")
	fixture.expectCellChange("sw")
	t.Log("RRRRR1")

	fixture.publish("/devices/somedev/controls/temp", "21", "temp")
	fixture.Verify(
		"tst -> /devices/somedev/controls/temp: [21] (QoS 1, retained)",
	)

	fixture.publish("/devices/somedev/controls/temp", "22", "temp", "sw")
	fixture.Verify(
		"tst -> /devices/somedev/controls/temp: [22] (QoS 1, retained)",
		"[rule] heaterOff fired",
 		"driver -> /devices/somedev/controls/sw/on: [0] (QoS 1)",
	)

	fixture.publish("/devices/somedev/controls/temp", "18", "temp", "sw")
	fixture.Verify(
		"tst -> /devices/somedev/controls/temp: [18] (QoS 1, retained)",
		"[rule] heaterOn fired",
 		"driver -> /devices/somedev/controls/sw/on: [1] (QoS 1)",
	)

	// edge-triggered rule doesn't fire
	fixture.publish("/devices/somedev/controls/temp", "19", "temp")
	fixture.Verify(
		"tst -> /devices/somedev/controls/temp: [19] (QoS 1, retained)",
	)

	fixture.SetCellValue("stabSettings", "enabled", false)
	fixture.Verify(
		"driver -> /devices/stabSettings/controls/enabled: [0] (QoS 1, retained)",
		"[rule] heaterOff fired",
 		"driver -> /devices/somedev/controls/sw/on: [0] (QoS 1)",
	)
	fixture.expectCellChange("sw")

	fixture.publish("/devices/somedev/controls/foobar", "1", "foobar")
	fixture.publish("/devices/somedev/controls/foobar/meta/type", "text", "foobar")
	fixture.Verify(
		"tst -> /devices/somedev/controls/foobar: [1] (QoS 1, retained)",
		"tst -> /devices/somedev/controls/foobar/meta/type: [text] (QoS 1, retained)",
		"[rule] initiallyIncompleteLevelTriggered fired",
	)

	// level-triggered rule fires again here
	fixture.publish("/devices/somedev/controls/foobar", "2", "foobar")
	fixture.Verify(
		"tst -> /devices/somedev/controls/foobar: [2] (QoS 1, retained)",
		"[rule] initiallyIncompleteLevelTriggered fired",
	)
}

func TestTimers(t *testing.T) {
	fixture := NewRuleFixture(t)
	defer fixture.tearDown()
	fixture.broker.SkipTill("tst -> /devices/somedev/controls/temp: [19] (QoS 1, retained)")
	fixture.engine.Start() // FIXME: should auto-start

	fixture.publish("/devices/somedev/controls/foo", "t", "foo")
	fixture.publish("/devices/somedev/controls/foo/meta/type", "text", "foo")
	fixture.Verify(
		"tst -> /devices/somedev/controls/foo: [t] (QoS 1, retained)",
		"tst -> /devices/somedev/controls/foo/meta/type: [text] (QoS 1, retained)",
		"newFakeTimer(): sometimer, 500, false",
	)

	fixture.publish("/devices/somedev/controls/foo", "-", "foo")
	fixture.Verify(
		"tst -> /devices/somedev/controls/foo: [-] (QoS 1, retained)",
		"timer.Stop(): sometimer",
	)

	fixture.publish("/devices/somedev/controls/foo", "t", "foo")
	fixture.Verify(
		"tst -> /devices/somedev/controls/foo: [t] (QoS 1, retained)",
		"newFakeTimer(): sometimer, 500, false",
	)

	fixture.timers["sometimer"].fire(makeTime(500 * time.Millisecond))
	fixture.Verify(
		"timer.fire(): sometimer",
		"[rule] timer fired",
	)

	fixture.publish("/devices/somedev/controls/foo", "p", "foo")
	fixture.Verify(
		"tst -> /devices/somedev/controls/foo: [p] (QoS 1, retained)",
		"newFakeTimer(): sometimer, 500, true",
	)

	for i := 1; i < 4; i++ {
		targetTime := makeTime(time.Duration(500 * i) * time.Millisecond)
		fixture.timers["sometimer"].fire(targetTime)
		fixture.Verify(
			"timer.fire(): sometimer",
			"[rule] timer fired",
		)
	}

	fixture.publish("/devices/somedev/controls/foo", "t", "foo")
	fixture.Verify(
		"tst -> /devices/somedev/controls/foo: [t] (QoS 1, retained)",
	)
	fixture.VerifyUnordered(
		"timer.Stop(): sometimer",
		"newFakeTimer(): sometimer, 500, false",
	)

	fixture.timers["sometimer"].fire(makeTime(5 * 500 * time.Millisecond))
	fixture.Verify(
		"timer.fire(): sometimer",
		"[rule] timer fired",
	)
}

// TBD: metadata (like, meta["devname"]["controlName"])
// TBD: proper data path:
// http://stackoverflow.com/questions/18537257/golang-how-to-get-the-directory-of-the-currently-running-file
// https://github.com/kardianos/osext
// TBD: test bad device/rule defs
// TBD: traceback
// TBD: if rule *did* change anything (SetValue had an effect), re-run rules
//      and do so till no values are changed
// TBD: don't hang upon bad Verify() list
//      (deadlock detection fails due to duktape)
// TBD: should use separate recorder for the fixture, not abuse the fake broker
<commit_msg>Minor rule test cleanup.<commit_after>package wbrules

import (
	"time"
	"testing"
	"github.com/stretchr/testify/assert"
	wbgo "github.com/contactless/wbgo"
)

var baseRuleTestTime = time.Date(2015, 2, 27, 19, 33, 17, 0, time.UTC)

func makeTime(d time.Duration) time.Time {
	return baseRuleTestTime.Add(d)
}

type fakeTimer struct {
	t *testing.T
	name string
	c chan time.Time
	d time.Duration
	periodic bool
	active bool
	rec *wbgo.Recorder
}

func (timer *fakeTimer) GetChannel() <-chan time.Time {
	return timer.c
}

func (timer *fakeTimer) fire(t time.Time) {
	timer.rec.Rec("timer.fire(): %s", timer.name)
	assert.True(timer.t, timer.active)
	timer.c <- t
	if !timer.periodic {
		timer.active = false
	}
}

func (timer *fakeTimer) Stop() {
	// note that we don't close timer here,
	// mimicking the behavior of real timers and tickers
	timer.active = false
	timer.rec.Rec("timer.Stop(): %s", timer.name)
}

type ruleFixture struct {
	cellFixture
	engine *RuleEngine
	timers map[string]*fakeTimer
}

func NewRuleFixture(t *testing.T) *ruleFixture {
	fixture := &ruleFixture{
		*NewCellFixture(t),
		nil,
		make(map[string]*fakeTimer),
	}
	fixture.engine = NewRuleEngine(fixture.model)
	fixture.engine.SetTimerFunc(fixture.newFakeTimer)
	fixture.engine.SetLogFunc(func (message string) {
		fixture.broker.Rec("[rule] %s", message)
	})
	assert.Equal(t, nil, fixture.engine.LoadScript("testrules.js"))
	fixture.driver.Start()
	fixture.publish("/devices/somedev/meta/name", "SomeDev", "")
	fixture.publish("/devices/somedev/controls/sw/meta/type", "switch", "sw")
	fixture.publish("/devices/somedev/controls/sw", "0", "sw")
	fixture.publish("/devices/somedev/controls/temp/meta/type", "temperature", "temp")
	fixture.publish("/devices/somedev/controls/temp", "19", "temp")
	return fixture
}

func NewRuleFixtureSkippingDefs(t *testing.T) (fixture *ruleFixture) {
	fixture = NewRuleFixture(t)
	fixture.broker.SkipTill("tst -> /devices/somedev/controls/temp: [19] (QoS 1, retained)")
	fixture.engine.Start() // FIXME: should auto-start
	return
}

func (fixture *ruleFixture) newFakeTimer(name string, d time.Duration, periodic bool) Timer {
	timer := &fakeTimer{
		t: fixture.t,
		name: name,
		c: make(chan time.Time),
		d: d,
		periodic: periodic,
		active: true,
		rec: &fixture.broker.Recorder,
	}
	fixture.timers[name] = timer
	fixture.broker.Rec("newFakeTimer(): %s, %d, %v", name, d / time.Millisecond, periodic)
	return timer
}

func (fixture *ruleFixture) Verify(logs... string) {
	fixture.broker.Verify(logs...)
}

func (fixture *ruleFixture) VerifyUnordered(logs... string) {
	fixture.broker.VerifyUnordered(logs...)
}

func (fixture *ruleFixture) SetCellValue(device, cellName string, value interface{}) {
	fixture.driver.CallSync(func () {
		fixture.model.EnsureDevice(device).EnsureCell(cellName).SetValue(value)
	})
	actualCellName := <- fixture.cellChange
	assert.Equal(fixture.t, cellName, actualCellName)
}

func TestDeviceDefinition(t *testing.T) {
	fixture := NewRuleFixture(t)
	defer fixture.tearDown()
	fixture.Verify(
		"driver -> /devices/stabSettings/meta/name: [Stabilization Settings] (QoS 1, retained)",
		"driver -> /devices/stabSettings/controls/enabled/meta/type: [switch] (QoS 1, retained)",
		"driver -> /devices/stabSettings/controls/enabled/meta/order: [1] (QoS 1, retained)",
		"driver -> /devices/stabSettings/controls/enabled: [0] (QoS 1, retained)",
		"Subscribe -- driver: /devices/stabSettings/controls/enabled/on",
		"driver -> /devices/stabSettings/controls/highThreshold/meta/type: [range] (QoS 1, retained)",
		"driver -> /devices/stabSettings/controls/highThreshold/meta/order: [2] (QoS 1, retained)",
		"driver -> /devices/stabSettings/controls/highThreshold/meta/max: [50] (QoS 1, retained)",
		"driver -> /devices/stabSettings/controls/highThreshold: [22] (QoS 1, retained)",
		"Subscribe -- driver: /devices/stabSettings/controls/highThreshold/on",
		"driver -> /devices/stabSettings/controls/lowThreshold/meta/type: [range] (QoS 1, retained)",
		"driver -> /devices/stabSettings/controls/lowThreshold/meta/order: [3] (QoS 1, retained)",
		"driver -> /devices/stabSettings/controls/lowThreshold/meta/max: [40] (QoS 1, retained)",
		"driver -> /devices/stabSettings/controls/lowThreshold: [20] (QoS 1, retained)",
		"Subscribe -- driver: /devices/stabSettings/controls/lowThreshold/on",
		"Subscribe -- driver: /devices/+/meta/name",
		"Subscribe -- driver: /devices/+/controls/+",
		"Subscribe -- driver: /devices/+/controls/+/meta/type",
		"Subscribe -- driver: /devices/+/controls/+/meta/max",
		"tst -> /devices/somedev/meta/name: [SomeDev] (QoS 1, retained)",
		"tst -> /devices/somedev/controls/sw/meta/type: [switch] (QoS 1, retained)",
		"tst -> /devices/somedev/controls/sw: [0] (QoS 1, retained)",
		"tst -> /devices/somedev/controls/temp/meta/type: [temperature] (QoS 1, retained)",
		"tst -> /devices/somedev/controls/temp: [19] (QoS 1, retained)",
	)
}

func TestRules(t *testing.T) {
	fixture := NewRuleFixtureSkippingDefs(t)
	defer fixture.tearDown()

	fixture.SetCellValue("stabSettings", "enabled", true)
	fixture.Verify(
		"driver -> /devices/stabSettings/controls/enabled: [1] (QoS 1, retained)",
		"[rule] heaterOn fired",
 		"driver -> /devices/somedev/controls/sw/on: [1] (QoS 1)",
	)
	fixture.expectCellChange("sw")

	fixture.publish("/devices/somedev/controls/temp", "21", "temp")
	fixture.Verify(
		"tst -> /devices/somedev/controls/temp: [21] (QoS 1, retained)",
	)

	fixture.publish("/devices/somedev/controls/temp", "22", "temp", "sw")
	fixture.Verify(
		"tst -> /devices/somedev/controls/temp: [22] (QoS 1, retained)",
		"[rule] heaterOff fired",
 		"driver -> /devices/somedev/controls/sw/on: [0] (QoS 1)",
	)

	fixture.publish("/devices/somedev/controls/temp", "18", "temp", "sw")
	fixture.Verify(
		"tst -> /devices/somedev/controls/temp: [18] (QoS 1, retained)",
		"[rule] heaterOn fired",
 		"driver -> /devices/somedev/controls/sw/on: [1] (QoS 1)",
	)

	// edge-triggered rule doesn't fire
	fixture.publish("/devices/somedev/controls/temp", "19", "temp")
	fixture.Verify(
		"tst -> /devices/somedev/controls/temp: [19] (QoS 1, retained)",
	)

	fixture.SetCellValue("stabSettings", "enabled", false)
	fixture.Verify(
		"driver -> /devices/stabSettings/controls/enabled: [0] (QoS 1, retained)",
		"[rule] heaterOff fired",
 		"driver -> /devices/somedev/controls/sw/on: [0] (QoS 1)",
	)
	fixture.expectCellChange("sw")

	fixture.publish("/devices/somedev/controls/foobar", "1", "foobar")
	fixture.publish("/devices/somedev/controls/foobar/meta/type", "text", "foobar")
	fixture.Verify(
		"tst -> /devices/somedev/controls/foobar: [1] (QoS 1, retained)",
		"tst -> /devices/somedev/controls/foobar/meta/type: [text] (QoS 1, retained)",
		"[rule] initiallyIncompleteLevelTriggered fired",
	)

	// level-triggered rule fires again here
	fixture.publish("/devices/somedev/controls/foobar", "2", "foobar")
	fixture.Verify(
		"tst -> /devices/somedev/controls/foobar: [2] (QoS 1, retained)",
		"[rule] initiallyIncompleteLevelTriggered fired",
	)
}

func TestTimers(t *testing.T) {
	fixture := NewRuleFixtureSkippingDefs(t)
	defer fixture.tearDown()

	fixture.publish("/devices/somedev/controls/foo", "t", "foo")
	fixture.publish("/devices/somedev/controls/foo/meta/type", "text", "foo")
	fixture.Verify(
		"tst -> /devices/somedev/controls/foo: [t] (QoS 1, retained)",
		"tst -> /devices/somedev/controls/foo/meta/type: [text] (QoS 1, retained)",
		"newFakeTimer(): sometimer, 500, false",
	)

	fixture.publish("/devices/somedev/controls/foo", "-", "foo")
	fixture.Verify(
		"tst -> /devices/somedev/controls/foo: [-] (QoS 1, retained)",
		"timer.Stop(): sometimer",
	)

	fixture.publish("/devices/somedev/controls/foo", "t", "foo")
	fixture.Verify(
		"tst -> /devices/somedev/controls/foo: [t] (QoS 1, retained)",
		"newFakeTimer(): sometimer, 500, false",
	)

	fixture.timers["sometimer"].fire(makeTime(500 * time.Millisecond))
	fixture.Verify(
		"timer.fire(): sometimer",
		"[rule] timer fired",
	)

	fixture.publish("/devices/somedev/controls/foo", "p", "foo")
	fixture.Verify(
		"tst -> /devices/somedev/controls/foo: [p] (QoS 1, retained)",
		"newFakeTimer(): sometimer, 500, true",
	)

	for i := 1; i < 4; i++ {
		targetTime := makeTime(time.Duration(500 * i) * time.Millisecond)
		fixture.timers["sometimer"].fire(targetTime)
		fixture.Verify(
			"timer.fire(): sometimer",
			"[rule] timer fired",
		)
	}

	fixture.publish("/devices/somedev/controls/foo", "t", "foo")
	fixture.Verify(
		"tst -> /devices/somedev/controls/foo: [t] (QoS 1, retained)",
	)
	fixture.VerifyUnordered(
		"timer.Stop(): sometimer",
		"newFakeTimer(): sometimer, 500, false",
	)

	fixture.timers["sometimer"].fire(makeTime(5 * 500 * time.Millisecond))
	fixture.Verify(
		"timer.fire(): sometimer",
		"[rule] timer fired",
	)
}

// TBD: metadata (like, meta["devname"]["controlName"])
// TBD: proper data path:
// http://stackoverflow.com/questions/18537257/golang-how-to-get-the-directory-of-the-currently-running-file
// https://github.com/kardianos/osext
// TBD: test bad device/rule defs
// TBD: traceback
// TBD: if rule *did* change anything (SetValue had an effect), re-run rules
//      and do so till no values are changed
// TBD: don't hang upon bad Verify() list
//      (deadlock detection fails due to duktape)
// TBD: should use separate recorder for the fixture, not abuse the fake broker
<|endoftext|>


<commit_before>package typescriptify

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"reflect"
	"strings"
	"time"
)

type TypeScriptify struct {
	Prefix           string
	Suffix           string
	Indent           string
	CreateFromMethod bool
	BackupExtension  string // If empty no backup

	golangTypes []reflect.Type
	types       map[reflect.Kind]string

	// throwaway, used when converting
	alreadyConverted map[reflect.Type]bool
}

func New() *TypeScriptify {
	result := new(TypeScriptify)
	result.Indent = "\t"
	result.BackupExtension = "backup"

	types := make(map[reflect.Kind]string)

	types[reflect.Bool] = "boolean"

	types[reflect.Int] = "number"
	types[reflect.Int8] = "number"
	types[reflect.Int16] = "number"
	types[reflect.Int32] = "number"
	types[reflect.Int64] = "number"
	types[reflect.Uint] = "number"
	types[reflect.Uint8] = "number"
	types[reflect.Uint16] = "number"
	types[reflect.Uint32] = "number"
	types[reflect.Uint64] = "number"
	types[reflect.Float32] = "number"
	types[reflect.Float64] = "number"

	types[reflect.String] = "string"

	result.types = types

	return result
}

func (this *TypeScriptify) Add(obj interface{}) {
	this.AddType(reflect.TypeOf(obj))
}

func (this *TypeScriptify) AddType(typeOf reflect.Type) {
	this.golangTypes = append(this.golangTypes, typeOf)
}

func (this *TypeScriptify) Convert(customCode map[string]string) (string, error) {
	this.alreadyConverted = make(map[reflect.Type]bool)

	result := ""
	for _, typeof := range this.golangTypes {
		typeScriptCode, err := this.convertType(typeof, customCode)
		if err != nil {
			return "", err
		}
		result += "\n" + strings.Trim(typeScriptCode, " "+this.Indent+"\r\n")
	}
	return result, nil
}

func loadCustomCode(fileName string) (map[string]string, error) {
	result := make(map[string]string)
	f, err := os.Open(fileName)
	if err != nil {
		if os.IsNotExist(err) {
			return result, nil
		}
		return result, err
	}
	defer f.Close()

	bytes, err := ioutil.ReadAll(f)
	if err != nil {
		return result, err
	}

	var currentName string
	var currentValue string
	lines := strings.Split(string(bytes), "\n")
	for _, line := range lines {
		trimmedLine := strings.TrimSpace(line)
		if strings.HasPrefix(trimmedLine, "//[") && strings.HasSuffix(trimmedLine, ":]") {
			currentName = strings.Replace(strings.Replace(trimmedLine, "//[", "", -1), ":]", "", -1)
			currentValue = ""
		} else if trimmedLine == "//[end]" {
			result[currentName] = strings.TrimRight(currentValue, " \t\r\n")
			currentName = ""
			currentValue = ""
		} else if len(currentName) > 0 {
			currentValue += line + "\n"
		}
	}

	return result, nil
}

func (this TypeScriptify) backup(fileName string) error {
	fileIn, err := os.Open(fileName)
	if err != nil {
		return err
	}
	defer fileIn.Close()

	bytes, err := ioutil.ReadAll(fileIn)
	if err != nil {
		return err
	}

	fileOut, err := os.Create(fmt.Sprintf("%s-%s.%s", fileName, time.Now().Format("2006-01-02T15:04:05.99"), this.BackupExtension))
	if err != nil {
		return err
	}
	defer fileOut.Close()

	_, err = fileOut.Write(bytes)
	if err != nil {
		return err
	}

	return nil
}

func (this TypeScriptify) ConvertToFile(fileName string) error {
	if len(this.BackupExtension) > 0 {
		err := this.backup(fileName)
		if err != nil {
			return err
		}
	}

	customCode, err := loadCustomCode(fileName)
	if err != nil {
		return err
	}

	f, err := os.Create(fileName)
	if err != nil {
		return err
	}
	defer f.Close()

	converted, err := this.Convert(customCode)
	if err != nil {
		return err
	}

	f.WriteString("/* Do not change, this code is generated from Golang structs */\n\n")
	f.WriteString(converted)
	if err != nil {
		return err
	}

	return nil
}

func (this *TypeScriptify) convertType(typeOf reflect.Type, customCode map[string]string) (string, error) {
	if _, found := this.alreadyConverted[typeOf]; found { // Already converted
		return "", nil
	}

	entityName := fmt.Sprintf("%s%s%s", this.Prefix, this.Suffix, typeOf.Name())
	result := fmt.Sprintf("class %s {\n", entityName)
	builder := typeScriptClassBuilder{
		types:  this.types,
		indent: this.Indent,
	}

	for i := 0; i < typeOf.NumField(); i++ {
		val := typeOf.Field(i)
		//fmt.Println("kind=", val.Type.Kind().String())
		jsonTag := val.Tag.Get("json")
		jsonFieldName := ""
		if len(jsonTag) > 0 {
			jsonTagParts := strings.Split(jsonTag, ",")
			if len(jsonTagParts) > 0 {
				jsonFieldName = strings.Trim(jsonTagParts[0], this.Indent)
			}
		}
		if len(jsonFieldName) > 0 && jsonFieldName != "-" {
			var err error
			if val.Type.Kind() == reflect.Struct { // Struct:
				typeScriptChunk, err := this.convertType(val.Type, customCode)
				if err != nil {
					return "", err
				}
				result = typeScriptChunk + "\n" + result
				builder.AddStructField(jsonFieldName, val.Type.Name())
			} else if val.Type.Kind() == reflect.Slice { // Slice:
				if val.Type.Elem().Kind() == reflect.Struct { // Slice of structs:
					typeScriptChunk, err := this.convertType(val.Type.Elem(), customCode)
					if err != nil {
						return "", err
					}
					result = typeScriptChunk + "\n" + result
					builder.AddArrayOfStructsField(jsonFieldName, val.Type.Elem().Name())
				} else { // Slice of simple fields:
					err = builder.AddSimpleArrayField(jsonFieldName, val.Type.Elem().Name(), val.Type.Elem().Kind())
				}
			} else { // Simple field:
				err = builder.AddSimpleField(jsonFieldName, val.Type.Name(), val.Type.Kind())
			}
			if err != nil {
				return "", err
			}
		}
	}

	result += builder.fields
	if this.CreateFromMethod {
		result += fmt.Sprintf("\n%sstatic createFrom(source: any) {\n", this.Indent)
		result += fmt.Sprintf("%s%svar result = new %s();\n", this.Indent, this.Indent, entityName)
		result += builder.createFromMethodBody
		result += fmt.Sprintf("%s%sreturn result;\n", this.Indent, this.Indent)
		result += fmt.Sprintf("%s}\n\n", this.Indent)
	}

	if customCode != nil {
		code := customCode[entityName]
		result += this.Indent + "//[" + entityName + ":]\n" + code + "\n\n" + this.Indent + "//[end]\n"
	}

	result += "}"

	this.alreadyConverted[typeOf] = true

	return result, nil
}

type typeScriptClassBuilder struct {
	types                map[reflect.Kind]string
	indent               string
	fields               string
	createFromMethodBody string
}

func (this *typeScriptClassBuilder) AddSimpleArrayField(fieldName, fieldType string, kind reflect.Kind) error {
	if typeScriptType, ok := this.types[kind]; ok {
		if len(fieldName) > 0 {
			this.fields += fmt.Sprintf("%s%s: %s[];\n", this.indent, fieldName, typeScriptType)
			this.createFromMethodBody += fmt.Sprintf("%s%sresult.%s = source[\"%s\"];\n", this.indent, this.indent, fieldName, fieldName)
			return nil
		}
	}
	return errors.New(fmt.Sprintf("Cannot find type for %s (%s/%s)", kind.String(), fieldName, fieldType))
}

func (this *typeScriptClassBuilder) AddSimpleField(fieldName, fieldType string, kind reflect.Kind) error {
	if typeScriptType, ok := this.types[kind]; ok {
		if len(fieldName) > 0 {
			this.fields += fmt.Sprintf("%s%s: %s;\n", this.indent, fieldName, typeScriptType)
			this.createFromMethodBody += fmt.Sprintf("%s%sresult.%s = source[\"%s\"];\n", this.indent, this.indent, fieldName, fieldName)
			return nil
		}
	}
	return errors.New("Cannot find type for " + fieldType)
}

func (this *typeScriptClassBuilder) AddStructField(fieldName, fieldType string) {
	this.fields += fmt.Sprintf("%s%s: %s;\n", this.indent, fieldName, fieldType)
	this.createFromMethodBody += fmt.Sprintf("%s%sresult.%s = source[\"%s\"] ? %s.createFrom(source[\"%s\"]) : null;\n", this.indent, this.indent, fieldName, fieldName, fieldType, fieldName)
}

func (this *typeScriptClassBuilder) AddArrayOfStructsField(fieldName, fieldType string) {
	this.fields += fmt.Sprintf("%s%s: %s[];\n", this.indent, fieldName, fieldType)
	this.createFromMethodBody += fmt.Sprintf("%s%sresult.%s = source[\"%s\"] ? source[\"%s\"].map(function(element) { return %s.createFrom(element); }) : null;\n", this.indent, this.indent, fieldName, fieldName, fieldName, fieldType)
}
<commit_msg>Ignore if no previous backup exists<commit_after>package typescriptify

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"reflect"
	"strings"
	"time"
)

type TypeScriptify struct {
	Prefix           string
	Suffix           string
	Indent           string
	CreateFromMethod bool
	BackupExtension  string // If empty no backup

	golangTypes []reflect.Type
	types       map[reflect.Kind]string

	// throwaway, used when converting
	alreadyConverted map[reflect.Type]bool
}

func New() *TypeScriptify {
	result := new(TypeScriptify)
	result.Indent = "\t"
	result.BackupExtension = "backup"

	types := make(map[reflect.Kind]string)

	types[reflect.Bool] = "boolean"

	types[reflect.Int] = "number"
	types[reflect.Int8] = "number"
	types[reflect.Int16] = "number"
	types[reflect.Int32] = "number"
	types[reflect.Int64] = "number"
	types[reflect.Uint] = "number"
	types[reflect.Uint8] = "number"
	types[reflect.Uint16] = "number"
	types[reflect.Uint32] = "number"
	types[reflect.Uint64] = "number"
	types[reflect.Float32] = "number"
	types[reflect.Float64] = "number"

	types[reflect.String] = "string"

	result.types = types

	return result
}

func (this *TypeScriptify) Add(obj interface{}) {
	this.AddType(reflect.TypeOf(obj))
}

func (this *TypeScriptify) AddType(typeOf reflect.Type) {
	this.golangTypes = append(this.golangTypes, typeOf)
}

func (this *TypeScriptify) Convert(customCode map[string]string) (string, error) {
	this.alreadyConverted = make(map[reflect.Type]bool)

	result := ""
	for _, typeof := range this.golangTypes {
		typeScriptCode, err := this.convertType(typeof, customCode)
		if err != nil {
			return "", err
		}
		result += "\n" + strings.Trim(typeScriptCode, " "+this.Indent+"\r\n")
	}
	return result, nil
}

func loadCustomCode(fileName string) (map[string]string, error) {
	result := make(map[string]string)
	f, err := os.Open(fileName)
	if err != nil {
		if os.IsNotExist(err) {
			return result, nil
		}
		return result, err
	}
	defer f.Close()

	bytes, err := ioutil.ReadAll(f)
	if err != nil {
		return result, err
	}

	var currentName string
	var currentValue string
	lines := strings.Split(string(bytes), "\n")
	for _, line := range lines {
		trimmedLine := strings.TrimSpace(line)
		if strings.HasPrefix(trimmedLine, "//[") && strings.HasSuffix(trimmedLine, ":]") {
			currentName = strings.Replace(strings.Replace(trimmedLine, "//[", "", -1), ":]", "", -1)
			currentValue = ""
		} else if trimmedLine == "//[end]" {
			result[currentName] = strings.TrimRight(currentValue, " \t\r\n")
			currentName = ""
			currentValue = ""
		} else if len(currentName) > 0 {
			currentValue += line + "\n"
		}
	}

	return result, nil
}

func (this TypeScriptify) backup(fileName string) error {
	fileIn, err := os.Open(fileName)
	if err != nil {
		if !os.IsNotExist(err) {
			return err
		}
		// No neet to backup, just return:
		return nil
	}
	defer fileIn.Close()

	bytes, err := ioutil.ReadAll(fileIn)
	if err != nil {
		return err
	}

	fileOut, err := os.Create(fmt.Sprintf("%s-%s.%s", fileName, time.Now().Format("2006-01-02T15:04:05.99"), this.BackupExtension))
	if err != nil {
		return err
	}
	defer fileOut.Close()

	_, err = fileOut.Write(bytes)
	if err != nil {
		return err
	}

	return nil
}

func (this TypeScriptify) ConvertToFile(fileName string) error {
	if len(this.BackupExtension) > 0 {
		err := this.backup(fileName)
		if err != nil {
			return err
		}
	}

	customCode, err := loadCustomCode(fileName)
	if err != nil {
		return err
	}

	f, err := os.Create(fileName)
	if err != nil {
		return err
	}
	defer f.Close()

	converted, err := this.Convert(customCode)
	if err != nil {
		return err
	}

	f.WriteString("/* Do not change, this code is generated from Golang structs */\n\n")
	f.WriteString(converted)
	if err != nil {
		return err
	}

	return nil
}

func (this *TypeScriptify) convertType(typeOf reflect.Type, customCode map[string]string) (string, error) {
	if _, found := this.alreadyConverted[typeOf]; found { // Already converted
		return "", nil
	}

	entityName := fmt.Sprintf("%s%s%s", this.Prefix, this.Suffix, typeOf.Name())
	result := fmt.Sprintf("class %s {\n", entityName)
	builder := typeScriptClassBuilder{
		types:  this.types,
		indent: this.Indent,
	}

	for i := 0; i < typeOf.NumField(); i++ {
		val := typeOf.Field(i)
		//fmt.Println("kind=", val.Type.Kind().String())
		jsonTag := val.Tag.Get("json")
		jsonFieldName := ""
		if len(jsonTag) > 0 {
			jsonTagParts := strings.Split(jsonTag, ",")
			if len(jsonTagParts) > 0 {
				jsonFieldName = strings.Trim(jsonTagParts[0], this.Indent)
			}
		}
		if len(jsonFieldName) > 0 && jsonFieldName != "-" {
			var err error
			if val.Type.Kind() == reflect.Struct { // Struct:
				typeScriptChunk, err := this.convertType(val.Type, customCode)
				if err != nil {
					return "", err
				}
				result = typeScriptChunk + "\n" + result
				builder.AddStructField(jsonFieldName, val.Type.Name())
			} else if val.Type.Kind() == reflect.Slice { // Slice:
				if val.Type.Elem().Kind() == reflect.Struct { // Slice of structs:
					typeScriptChunk, err := this.convertType(val.Type.Elem(), customCode)
					if err != nil {
						return "", err
					}
					result = typeScriptChunk + "\n" + result
					builder.AddArrayOfStructsField(jsonFieldName, val.Type.Elem().Name())
				} else { // Slice of simple fields:
					err = builder.AddSimpleArrayField(jsonFieldName, val.Type.Elem().Name(), val.Type.Elem().Kind())
				}
			} else { // Simple field:
				err = builder.AddSimpleField(jsonFieldName, val.Type.Name(), val.Type.Kind())
			}
			if err != nil {
				return "", err
			}
		}
	}

	result += builder.fields
	if this.CreateFromMethod {
		result += fmt.Sprintf("\n%sstatic createFrom(source: any) {\n", this.Indent)
		result += fmt.Sprintf("%s%svar result = new %s();\n", this.Indent, this.Indent, entityName)
		result += builder.createFromMethodBody
		result += fmt.Sprintf("%s%sreturn result;\n", this.Indent, this.Indent)
		result += fmt.Sprintf("%s}\n\n", this.Indent)
	}

	if customCode != nil {
		code := customCode[entityName]
		result += this.Indent + "//[" + entityName + ":]\n" + code + "\n\n" + this.Indent + "//[end]\n"
	}

	result += "}"

	this.alreadyConverted[typeOf] = true

	return result, nil
}

type typeScriptClassBuilder struct {
	types                map[reflect.Kind]string
	indent               string
	fields               string
	createFromMethodBody string
}

func (this *typeScriptClassBuilder) AddSimpleArrayField(fieldName, fieldType string, kind reflect.Kind) error {
	if typeScriptType, ok := this.types[kind]; ok {
		if len(fieldName) > 0 {
			this.fields += fmt.Sprintf("%s%s: %s[];\n", this.indent, fieldName, typeScriptType)
			this.createFromMethodBody += fmt.Sprintf("%s%sresult.%s = source[\"%s\"];\n", this.indent, this.indent, fieldName, fieldName)
			return nil
		}
	}
	return errors.New(fmt.Sprintf("Cannot find type for %s (%s/%s)", kind.String(), fieldName, fieldType))
}

func (this *typeScriptClassBuilder) AddSimpleField(fieldName, fieldType string, kind reflect.Kind) error {
	if typeScriptType, ok := this.types[kind]; ok {
		if len(fieldName) > 0 {
			this.fields += fmt.Sprintf("%s%s: %s;\n", this.indent, fieldName, typeScriptType)
			this.createFromMethodBody += fmt.Sprintf("%s%sresult.%s = source[\"%s\"];\n", this.indent, this.indent, fieldName, fieldName)
			return nil
		}
	}
	return errors.New("Cannot find type for " + fieldType)
}

func (this *typeScriptClassBuilder) AddStructField(fieldName, fieldType string) {
	this.fields += fmt.Sprintf("%s%s: %s;\n", this.indent, fieldName, fieldType)
	this.createFromMethodBody += fmt.Sprintf("%s%sresult.%s = source[\"%s\"] ? %s.createFrom(source[\"%s\"]) : null;\n", this.indent, this.indent, fieldName, fieldName, fieldType, fieldName)
}

func (this *typeScriptClassBuilder) AddArrayOfStructsField(fieldName, fieldType string) {
	this.fields += fmt.Sprintf("%s%s: %s[];\n", this.indent, fieldName, fieldType)
	this.createFromMethodBody += fmt.Sprintf("%s%sresult.%s = source[\"%s\"] ? source[\"%s\"].map(function(element) { return %s.createFrom(element); }) : null;\n", this.indent, this.indent, fieldName, fieldName, fieldName, fieldType)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
)

func average(xs []float64) float64 {
	var total float64 = 0.0
	for _, value := range xs {
		total += value
	}
	return total / float64(len(xs))
}

func factorial(x uint) uint {
	if x == 0 {
		return 1
	}
	return x * factorial(x-1)
}

func main() {
	//	array := []float64{1, 2, 3, 4, 5}
	//	fmt.Println(average(array))
	fmt.Println("Enter your Number: ")
	var input uint
	fmt.Scanf("%d", &input)
	fmt.Println("Your Result :", factorial(input))
}

//Variadic functions wrote func Myfunc(args ...int) int {}
<commit_msg>func factorial<commit_after>package main

import (
	"fmt"
)

func average(xs []float64) float64 {
	var total float64 = 0.0
	for _, value := range xs {
		total += value
	}
	return total / float64(len(xs))
}

func factorial(x uint) uint {
	if x == 0 {
		return 1
	}
	return x * factorial(x-1)
}

func main() {
	//	array := []float64{1, 2, 3, 4, 5}
	//	fmt.Println(average(array))
	fmt.Println("Enter your Number: ")
	var input uint
	fmt.Scanf("%d", &input)
	fmt.Println("Your Result :", factorial(input))
}

//Variadic functions wrote func Myfunc(args ...int) int {}
// function calling functon called functional programming
<|endoftext|>