<commit_before>package irc

import (
	"bytes"
	"testing"
)

func s2b(s string) []byte {
	return []byte(s)
}

var messageTests = [...]*struct {
	rawMsg   string
	parsed   *Msg
	hostmask bool
	server   bool
}{
	{
		":syrk!kalt@millennium.stealth.net QUIT :Gone to have lunch",
		&Msg{cmd: s2b("QUIT"),
			trailing: s2b("Gone to have lunch"),
			name:     s2b("syrk"),
			user:     s2b("kalt"),
			host:     s2b("millennium.stealth.net"),
		},
		true,
		false,
	},
	{
		":Trillian SQUIT cm22.eng.umd.edu :Server out of control",
		&Msg{cmd: s2b("SQUIT"),
			trailing: s2b("Server out of control"),
			name:     s2b("Trillian"),
			user:     nil,
			host:     nil,
			params:   [][]byte{s2b("cm22.eng.umd.edu")},
		},
		false,
		true,
	},
	{
		":WiZ!jto@tolsun.oulu.fi PART #playzone :I lost",
		&Msg{cmd: s2b("PART"),
			trailing: s2b("I lost"),
			name:     s2b("WiZ"),
			user:     s2b("jto"),
			host:     s2b("tolsun.oulu.fi"),
			params:   [][]byte{s2b("#playzone")},
		},
		true,
		false,
	},
	{
		":WiZ!jto@tolsun.oulu.fi MODE #eu-opers -l",
		&Msg{cmd: s2b("MODE"),
			trailing: nil,
			name:     s2b("WiZ"),
			user:     s2b("jto"),
			host:     s2b("tolsun.oulu.fi"),
			params:   [][]byte{s2b("#eu-opers"), s2b("-l")},
		},
		true,
		false,
	},
	{
		"MODE &oulu +b *!*@*.edu +e *!*@*.bu.edu",
		&Msg{cmd: s2b("MODE"),
			trailing: nil,
			name:     nil,
			user:     nil,
			host:     nil,
			params: [][]byte{s2b("&oulu"),
				s2b("+b"),
				s2b("*!*@*.edu"),
				s2b("+e"),
				s2b("*!*@*.bu.edu"),
			},
		},
		false,
		true,
	},
	{
		"PRIVMSG #channel :Message with :colons!",
		&Msg{cmd: s2b("PRIVMSG"),
			trailing: s2b("Message with :colons!"),
			name:     nil,
			user:     nil,
			host:     nil,
			params:   [][]byte{s2b("#channel")},
		},
		false,
		true, // TODO PRIVMSG should not be server
	},
	{
		":irc.vives.lan 251 test :There are 2 users and 0 services on 1 servers",
		&Msg{cmd: s2b("251"),
			trailing: s2b("There are 2 users and 0 services on 1 servers"),
			name:     s2b("irc.vives.lan"),
			user:     nil,
			host:     nil,
			params:   [][]byte{s2b("test")},
		},
		false,
		true,
	},
	{
		":irc.vives.lan 376 test :End of MOTD command",
		&Msg{cmd: s2b("376"),
			trailing: s2b("End of MOTD command"),
			name:     s2b("irc.vives.lan"),
			user:     nil,
			host:     nil,
			params:   [][]byte{s2b("test")},
		},
		false,
		true,
	},
	{
		":irc.vives.lan 250 test :Highest connection count: 1 (1 connections received)",
		&Msg{cmd: s2b("250"),
			trailing: s2b("Highest connection count: 1 (1 connections received)"),
			name:     s2b("irc.vives.lan"),
			user:     nil,
			host:     nil,
			params:   [][]byte{s2b("test")},
		},
		false,
		true,
	},
	{
		":sorcix!~sorcix@sorcix.users.quakenet.org PRIVMSG #viveslan :\001ACTION is testing CTCP messages!\001",
		&Msg{cmd: s2b("PRIVMSG"),
			trailing: s2b("\001ACTION is testing CTCP messages!\001"),
			name:     s2b("sorcix"),
			user:     s2b("~sorcix"),
			host:     s2b("sorcix.users.quakenet.org"),
			params:   [][]byte{s2b("#viveslan")},
		},
		true,
		false,
	},
	{
		":sorcix!~sorcix@sorcix.users.quakenet.org NOTICE midnightfox :\001PONG 1234567890\001",
		&Msg{cmd: s2b("NOTICE"),
			trailing: s2b("\001PONG 1234567890\001"),
			name:     s2b("sorcix"),
			user:     s2b("~sorcix"),
			host:     s2b("sorcix.users.quakenet.org"),
			params:   [][]byte{s2b("#viveslan")},
		},
		true,
		false,
	},
	{
		":a!b@c QUIT",
		&Msg{cmd: s2b("QUIT"),
			trailing: nil,
			name:     s2b("a"),
			user:     s2b("b"),
			host:     s2b("c"),
			params:   [][]byte{},
		},
		true,
		false,
	},
	{
		":a!b PRIVMSG :message",
		&Msg{cmd: s2b("PRIVMSG"),
			trailing: s2b("message"),
			name:     s2b("a"),
			user:     s2b("b"),
			host:     nil,
			params:   [][]byte{},
		},
		false,
		false,
	},
	{
		":a@c NOTICE ::::Hey!",
		&Msg{cmd: s2b("NOTICE"),
			trailing: s2b(":::Hey!"),
			name:     s2b("a"),
			user:     nil,
			host:     s2b("c"),
			params:   [][]byte{},
		},
		false,
		false,
	},
}

func TestMsgCmd(t *testing.T) {
	for _, z := range messageTests {
		m, err := NewMsg(s2b(z.rawMsg))
		m.ParseAll()
		p := z.parsed
		if err != nil || !bytes.Equal(m.cmd, p.cmd) {
			t.Errorf("failed:%s\nparsed:%s", z.rawMsg, m.String())
		}
	}
}

func TestMsgPrefixName(t *testing.T) {
	for _, z := range messageTests {
		m, err := NewMsg(s2b(z.rawMsg))
		m.ParseAll()
		p := z.parsed
		if err != nil || !bytes.Equal(m.name, p.name) {
			t.Errorf("failed:%s\nparsed:%s\nm=%s p=%s", z.rawMsg, m.String(),
				m.name, p.name)
		}
	}
}

func TestMsgUser(t *testing.T) {
	for _, z := range messageTests {
		m, err := NewMsg(s2b(z.rawMsg))
		m.ParseAll()
		p := z.parsed
		if err != nil || !bytes.Equal(m.user, p.user) {
			t.Errorf("failed:%s\nparsed:%s", z.rawMsg, m.String())
		}
	}

}

func TestMsgHost(t *testing.T) {
	for _, z := range messageTests {
		m, err := NewMsg(s2b(z.rawMsg))
		m.ParseAll()
		p := z.parsed
		if err != nil || !bytes.Equal(m.host, p.host) {
			t.Errorf("failed:%s\nparsed:%s", z.rawMsg, m.String())
		}
	}
}
func TestMsgTrailing(t *testing.T) {
	for _, z := range messageTests {
		m, err := NewMsg(s2b(z.rawMsg))
		m.ParseAll()
		p := z.parsed
		if err != nil || !bytes.Equal(m.trailing, p.trailing) {
			t.Errorf("failed:%s\nparsed:%s", z.rawMsg, m.String())
		}
	}
}

func TestMsgParams(t *testing.T) {
	for _, z := range messageTests {
		m, err := NewMsg(s2b(z.rawMsg))
		m.ParseAll()
		p := z.parsed
		if err != nil {
			for i := 0; i < len(p.params); i++ {
				bytes.Equal(p.params[i], m.params[i])
			}
			t.Errorf("failed:%s\nparsed:%s", z.rawMsg, m.String())
		}
	}
}

func TestMsgServer(t *testing.T) {
	for _, z := range messageTests {
		m, err := NewMsg(s2b(z.rawMsg))
		m.ParseAll()
		if err != nil || m.IsServer() != z.server {
			t.Errorf("failed:%s\nparsed:%s", z.rawMsg, m.String())
		}
	}
}

func TestMsgHostMask(t *testing.T) {
	for _, z := range messageTests {
		m, err := NewMsg(s2b(z.rawMsg))
		m.ParseAll()
		if err != nil || m.IsHostMask() != z.hostmask {
			t.Errorf("failed:%s\nparsed:%s", z.rawMsg, m.String())
		}
	}
}
<commit_msg>update testcase<commit_after>package irc

import (
	"bytes"
	"testing"
)

func s2b(s string) []byte {
	return []byte(s)
}

var messageTests = [...]*struct {
	rawMsg   string
	parsed   *Msg
	hostmask bool
	server   bool
}{
	{
		":syrk!kalt@millennium.stealth.net QUIT :Gone to have lunch",
		&Msg{cmd: s2b("QUIT"),
			trailing: s2b("Gone to have lunch"),
			name:     s2b("syrk"),
			user:     s2b("kalt"),
			host:     s2b("millennium.stealth.net"),
		},
		true,
		false,
	},
	{
		":Trillian SQUIT cm22.eng.umd.edu :Server out of control",
		&Msg{cmd: s2b("SQUIT"),
			trailing: s2b("Server out of control"),
			name:     s2b("Trillian"),
			user:     nil,
			host:     nil,
			params:   [][]byte{s2b("cm22.eng.umd.edu")},
		},
		false,
		true,
	},
	{
		":WiZ!jto@tolsun.oulu.fi PART #playzone :I lost",
		&Msg{cmd: s2b("PART"),
			trailing: s2b("I lost"),
			name:     s2b("WiZ"),
			user:     s2b("jto"),
			host:     s2b("tolsun.oulu.fi"),
			params:   [][]byte{s2b("#playzone")},
		},
		true,
		false,
	},
	{
		":WiZ!jto@tolsun.oulu.fi MODE #eu-opers -l",
		&Msg{cmd: s2b("MODE"),
			trailing: nil,
			name:     s2b("WiZ"),
			user:     s2b("jto"),
			host:     s2b("tolsun.oulu.fi"),
			params:   [][]byte{s2b("#eu-opers"), s2b("-l")},
		},
		true,
		false,
	},
	{
		"MODE &oulu +b *!*@*.edu +e *!*@*.bu.edu",
		&Msg{cmd: s2b("MODE"),
			trailing: nil,
			name:     nil,
			user:     nil,
			host:     nil,
			params: [][]byte{s2b("&oulu"),
				s2b("+b"),
				s2b("*!*@*.edu"),
				s2b("+e"),
				s2b("*!*@*.bu.edu"),
			},
		},
		false,
		true,
	},
	{
		"PRIVMSG #channel :Message with :colons!",
		&Msg{cmd: s2b("PRIVMSG"),
			trailing: s2b("Message with :colons!"),
			name:     nil,
			user:     nil,
			host:     nil,
			params:   [][]byte{s2b("#channel")},
		},
		false,
		true, // TODO PRIVMSG should not be server
	},
	{
		":irc.vives.lan 251 test :There are 2 users and 0 services on 1 servers",
		&Msg{cmd: s2b("251"),
			trailing: s2b("There are 2 users and 0 services on 1 servers"),
			name:     s2b("irc.vives.lan"),
			user:     nil,
			host:     nil,
			params:   [][]byte{s2b("test")},
		},
		false,
		true,
	},
	{
		":irc.vives.lan 376 test :End of MOTD command",
		&Msg{cmd: s2b("376"),
			trailing: s2b("End of MOTD command"),
			name:     s2b("irc.vives.lan"),
			user:     nil,
			host:     nil,
			params:   [][]byte{s2b("test")},
		},
		false,
		true,
	},
	{
		":irc.vives.lan 250 test :Highest connection count: 1 (1 connections received)",
		&Msg{cmd: s2b("250"),
			trailing: s2b("Highest connection count: 1 (1 connections received)"),
			name:     s2b("irc.vives.lan"),
			user:     nil,
			host:     nil,
			params:   [][]byte{s2b("test")},
		},
		false,
		true,
	},
	{
		":sorcix!~sorcix@sorcix.users.quakenet.org PRIVMSG #viveslan :\001ACTION is testing CTCP messages!\001",
		&Msg{cmd: s2b("PRIVMSG"),
			trailing: s2b("\001ACTION is testing CTCP messages!\001"),
			name:     s2b("sorcix"),
			user:     s2b("~sorcix"),
			host:     s2b("sorcix.users.quakenet.org"),
			params:   [][]byte{s2b("#viveslan")},
		},
		true,
		false,
	},
	{
		":sorcix!~sorcix@sorcix.users.quakenet.org NOTICE midnightfox :\001PONG 1234567890\001",
		&Msg{cmd: s2b("NOTICE"),
			trailing: s2b("\001PONG 1234567890\001"),
			name:     s2b("sorcix"),
			user:     s2b("~sorcix"),
			host:     s2b("sorcix.users.quakenet.org"),
			params:   [][]byte{s2b("#viveslan")},
		},
		true,
		false,
	},
	{
		":a!b@c QUIT",
		&Msg{cmd: s2b("QUIT"),
			trailing: nil,
			name:     s2b("a"),
			user:     s2b("b"),
			host:     s2b("c"),
			params:   [][]byte{},
		},
		true,
		false,
	},
	{
		":a!b PRIVMSG :message",
		&Msg{cmd: s2b("PRIVMSG"),
			trailing: s2b("message"),
			name:     s2b("a"),
			user:     s2b("b"),
			host:     nil,
			params:   [][]byte{},
		},
		false,
		false,
	},
	{
		":a@c NOTICE ::::Hey!",
		&Msg{cmd: s2b("NOTICE"),
			trailing: s2b(":::Hey!"),
			name:     s2b("a"),
			user:     nil,
			host:     s2b("c"),
			params:   [][]byte{},
		},
		false,
		false,
	},
	{
		":nick PRIVMSG $@ :This message contains a\ttab!",
		&Msg{cmd: s2b("PRIVMSG"),
			trailing: s2b("This message contains a\ttab!"),
			name:     s2b("nick"),
			user:     nil,
			host:     nil,
			params:   [][]byte{s2b("$@")},
		},
		false,
		true, // TODO
	},
	{
		"TEST $@  param :Trailing",
		&Msg{cmd: s2b("TEST"),
			trailing: s2b("Trailing"),
			name:     nil,
			user:     nil,
			host:     nil,
			params:   [][]byte{s2b("$@"), s2b(""), s2b("param")},
		},
		false,
		false,
	},
}

func TestMsgCmd(t *testing.T) {
	for _, z := range messageTests {
		m, err := NewMsg(s2b(z.rawMsg))
		m.ParseAll()
		p := z.parsed
		if err != nil || !bytes.Equal(m.cmd, p.cmd) {
			t.Errorf("failed:%s\nparsed:%s", z.rawMsg, m.String())
		}
	}
}

func TestMsgPrefixName(t *testing.T) {
	for _, z := range messageTests {
		m, err := NewMsg(s2b(z.rawMsg))
		m.ParseAll()
		p := z.parsed
		if err != nil || !bytes.Equal(m.name, p.name) {
			t.Errorf("failed:%s\nparsed:%s\nm=%s p=%s", z.rawMsg, m.String(),
				m.name, p.name)
		}
	}
}

func TestMsgUser(t *testing.T) {
	for _, z := range messageTests {
		m, err := NewMsg(s2b(z.rawMsg))
		m.ParseAll()
		p := z.parsed
		if err != nil || !bytes.Equal(m.user, p.user) {
			t.Errorf("failed:%s\nparsed:%s", z.rawMsg, m.String())
		}
	}

}

func TestMsgHost(t *testing.T) {
	for _, z := range messageTests {
		m, err := NewMsg(s2b(z.rawMsg))
		m.ParseAll()
		p := z.parsed
		if err != nil || !bytes.Equal(m.host, p.host) {
			t.Errorf("failed:%s\nparsed:%s", z.rawMsg, m.String())
		}
	}
}
func TestMsgTrailing(t *testing.T) {
	for _, z := range messageTests {
		m, err := NewMsg(s2b(z.rawMsg))
		m.ParseAll()
		p := z.parsed
		if err != nil || !bytes.Equal(m.trailing, p.trailing) {
			t.Errorf("failed:%s\nparsed:%s", z.rawMsg, m.String())
		}
	}
}

func TestMsgParams(t *testing.T) {
	for _, z := range messageTests {
		m, err := NewMsg(s2b(z.rawMsg))
		m.ParseAll()
		p := z.parsed
		if err != nil {
			for i := 0; i < len(p.params); i++ {
				bytes.Equal(p.params[i], m.params[i])
			}
			t.Errorf("failed:%s\nparsed:%s", z.rawMsg, m.String())
		}
	}
}

func TestMsgServer(t *testing.T) {
	for _, z := range messageTests {
		m, err := NewMsg(s2b(z.rawMsg))
		m.ParseAll()
		if err != nil || m.IsServer() != z.server {
			t.Errorf("failed:%s\nparsed:%s", z.rawMsg, m.String())
		}
	}
}

func TestMsgHostMask(t *testing.T) {
	for _, z := range messageTests {
		m, err := NewMsg(s2b(z.rawMsg))
		m.ParseAll()
		if err != nil || m.IsHostMask() != z.hostmask {
			t.Errorf("failed:%s\nparsed:%s", z.rawMsg, m.String())
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"net/http"
	"net/url"
	"os"
	"time"
	"log"

	"github.com/jmcvetta/napping"
	"bytes"
)

type Configuration struct {
	LogFilePath string
	Interval    int
	DebugMode   bool
	TraceMode   bool
	LogStashUrl string
	LgLogin     string // logstash login
	LgPassword  string // logstash password
	NatsUrls    []string
}
type NatsNodeTopInfo struct {
	Varz  Varz
	Connz Connz
}
type Cluster struct {
	Addr         string
	Cluster_port int
}
type Varz struct {
	Server_id         string
	Host              string
	Addr              string
	Http_host         string
	Cluster           Cluster
	Start             string
	Now               time.Time
	Uptime            string
	Mem               float32
	Cpu               float32
	Connections       int
	Total_connections int
	Routes            int
	Remotes           int
	In_msgs           int
	Out_msgs          int
	In_bytes          int
	Out_bytes         int
	In_msgs_sec       int
	Out_msgs_sec      int
	In_bytes_sec      int
	Out_bytes_sec     int
	Slow_consumers    int
	Subscriptions     int
}
type Connection struct {
	Сid           int
	Ip            string
	Port          int
	Start         string
	Last_activity string
	Uptime        string
	Pending_bytes int
	In_msgs       int
	Out_msgs      int
	In_bytes      int
	Out_bytes     int
}
type Connz struct {
	Now             string
	Num_connections int
	Total           int
	Offset          int
	Limit           int
	Connections     []Connection
}
type PrevInOutValues struct {
	In_msgs   int
	Out_msgs  int
	In_bytes  int
	Out_bytes int

	Now       time.Time
}
type InOutPerSec struct {
	In_msgs_sec   int
	Out_msgs_sec  int
	In_bytes_sec  int
	Out_bytes_sec int
}

var prev_vals map[string]*PrevInOutValues = make(map[string]*PrevInOutValues)

func main() {

	config := Configuration{}

	configPathCL := flag.String("c", "", "path to config file")
	logFilePathCL := flag.String("l", "", "path to log file")
	isDebugCL := flag.Bool("d", false, "DEBUG mode")
	isTraceCL := flag.Bool("t", false, "TRACE mode")

	setFlag(flag.CommandLine)
	flag.Parse()

	config = readConfig(*configPathCL)

	isDebug := config.DebugMode
	isTrace := config.TraceMode

	if *isDebugCL {
		isDebug = *isDebugCL
	}

	if *isTraceCL {
		isTrace = *isTraceCL
	}

	setLogOutput(config, *logFilePathCL)

	httpClient := http.Client{}
	httpClient.Timeout = time.Duration(300) * time.Millisecond
	sessionToNats := napping.Session{Client: &httpClient}
	sessionToLogstash := napping.Session{Userinfo: url.UserPassword(config.LgLogin, config.LgPassword)}

	e := HttpError{}

	log.Printf("NATS-ELK forwarder started\n")
	log.Printf("Interval of requests: %d ms\n", config.Interval)

	for true {

		for _, url := range config.NatsUrls {

			varz := Varz{}
			connzs := Connz{}
			natsNodeTopInfo := NatsNodeTopInfo{}

			varzUrl := url + "/varz"
			connzUrl := url + "/connz"

			varzResponse, err := sessionToNats.Get(varzUrl, nil, &varz, &e)

			if err != nil {
				log.Printf("%v\n", err)
				continue
			}

			connzResponse, err := sessionToNats.Get(connzUrl, nil, &connzs, &e)

			if err != nil {
				log.Printf("%v\n", err)
				continue
			}

			if varzResponse.Status() == 200 && connzResponse.Status() == 200 {

				if isDebug {
					log.Printf("Get data from nats node (%v) - Success\n", url)
				}

				perSecValues := getPerSecValues(url, varz)

				varz.In_bytes_sec = perSecValues.In_bytes_sec
				varz.Out_bytes_sec = perSecValues.Out_bytes_sec
				varz.In_msgs_sec = perSecValues.In_msgs_sec
				varz.Out_msgs_sec = perSecValues.Out_msgs_sec

				varz.Mem = varz.Mem / 1024 / 1024 // to MB
				natsNodeTopInfo.Varz = varz
				natsNodeTopInfo.Connz = connzs

				if isTrace {
					printPrettyJson(natsNodeTopInfo)
				}

				logstashResponse, err := sessionToLogstash.Post(config.LogStashUrl, natsNodeTopInfo, nil, &e)

				if err != nil {
					log.Printf("Sending to logstash -> Error: ")
					log.Printf("%v\n", err)
					continue
				}
				if logstashResponse.Status() == 200 && isDebug {
					log.Printf("Sending to logstash (%v): Success\n", config.LogStashUrl)
				}
			}
		}
		time.Sleep(time.Duration(config.Interval) * time.Millisecond)
	}
}
func getPerSecValues(url string, varz Varz) InOutPerSec {
	inOutPerSec := InOutPerSec{}

	if prev_vals[url] == nil {

		prev_vals[url] = &PrevInOutValues{}

		prev_vals[url].In_bytes = varz.In_bytes
		prev_vals[url].Out_bytes = varz.Out_bytes
		prev_vals[url].In_msgs = varz.In_msgs
		prev_vals[url].Out_msgs = varz.Out_msgs
		prev_vals[url].Now = varz.Now

		return InOutPerSec{}
	}

	// calculate
	in_bytes_delta := varz.In_bytes - prev_vals[url].In_bytes
	out_bytes_delta := varz.Out_bytes - prev_vals[url].Out_bytes

	in_msgs_delta := varz.In_msgs - prev_vals[url].In_msgs
	out_msgs_delta := varz.Out_msgs - prev_vals[url].Out_msgs

	sec := varz.Now.Second() - prev_vals[url].Now.Second()

	inOutPerSec.In_bytes_sec = in_bytes_delta / sec
	inOutPerSec.Out_bytes_sec = out_bytes_delta / sec
	inOutPerSec.In_msgs_sec = in_msgs_delta / sec
	inOutPerSec.Out_msgs_sec = out_msgs_delta / sec

	// save prev.values
	prev_vals[url].In_bytes = varz.In_bytes
	prev_vals[url].Out_bytes = varz.Out_bytes
	prev_vals[url].In_msgs = varz.In_msgs
	prev_vals[url].Out_msgs = varz.Out_msgs
	prev_vals[url].Now = varz.Now

	// return result
	return inOutPerSec
}
func readConfig(filepath string) Configuration {

	file, _ := os.Open(filepath)
	decoder := json.NewDecoder(file)
	configuration := Configuration{}
	err := decoder.Decode(&configuration)

	if err != nil {
		log.Println("error:", err)
	}

	return configuration
}

type HttpError struct {
	Message string
	Errors  []struct {
		Resource string
		Field    string
		Code     string
	}
}

func setFlag(flag *flag.FlagSet) {
	flag.Usage = func() {
		showHelp()
	}
}
func showHelp() {
	fmt.Println(`
Usage: CLI Template [OPTIONS]
Options:
    -c, --config     Path to config file.
    -l, --log        Path to log file.
    -d, --debug      DEBUG mode.
    -t, --trace      TRACE mode.
    -h, --help       prints this help info.
    `)
}
func setLogOutput(config Configuration, logFilePathCL string) {

	if len(config.LogFilePath) > 0 || len(logFilePathCL) > 0 {

		logFilePath := ""

		if len(config.LogFilePath) > 0 {
			logFilePath = config.LogFilePath
		}
		if len(logFilePathCL) > 0 {
			logFilePath = logFilePathCL
		}

		file, err := os.OpenFile(logFilePath, os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666)

		if err != nil {
			log.Fatalf("error opening file: %v", err)
		}

		log.SetOutput(file)
	}
}
func printPrettyJson(info NatsNodeTopInfo){
	var prettyJSON bytes.Buffer

	body, err := json.Marshal(info)

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

	error := json.Indent(&prettyJSON, body, "", "\t")
	if error != nil {
		log.Println("JSON parse error: ", error)
		return
	}

	log.Println(string(prettyJSON.Bytes()))
}
<commit_msg>added support for log file rolling<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"os"
	"time"

	"github.com/jmcvetta/napping"
	"github.com/natefinch/lumberjack"
)

type Configuration struct {
	LogFilePath string
	Interval    int
	DebugMode   bool
	TraceMode   bool
	LogStashUrl string
	LgLogin     string // logstash login
	LgPassword  string // logstash password
	NatsUrls    []string
}
type NatsMetric struct {
	Varz  Varz
	Connz Connz
}
type Cluster struct {
	Addr         string
	Cluster_port int
}
type Varz struct {
	Server_id         string
	Host              string
	Addr              string
	Http_host         string
	Cluster           Cluster
	Start             string
	Now               time.Time
	Uptime            string
	Mem               float32
	Cpu               float32
	Connections       int
	Total_connections int
	Routes            int
	Remotes           int
	In_msgs           int
	Out_msgs          int
	In_bytes          int
	Out_bytes         int
	In_msgs_sec       int
	Out_msgs_sec      int
	In_bytes_sec      int
	Out_bytes_sec     int
	Slow_consumers    int
	Subscriptions     int
}
type Connection struct {
	Сid           int
	Ip            string
	Port          int
	Start         string
	Last_activity string
	Uptime        string
	Pending_bytes int
	In_msgs       int
	Out_msgs      int
	In_bytes      int
	Out_bytes     int
}
type Connz struct {
	Now             string
	Num_connections int
	Total           int
	Offset          int
	Limit           int
	Connections     []Connection
}
type PrevInOutValues struct {
	In_msgs   int
	Out_msgs  int
	In_bytes  int
	Out_bytes int

	Now time.Time
}
type InOutPerSec struct {
	In_msgs_sec   int
	Out_msgs_sec  int
	In_bytes_sec  int
	Out_bytes_sec int
}

var prev_vals map[string]*PrevInOutValues = make(map[string]*PrevInOutValues)

func main() {

	config := Configuration{}

	configPathCL := flag.String("c", "", "path to config file")
	logFilePathCL := flag.String("l", "", "path to log file")
	isDebugCL := flag.Bool("d", false, "DEBUG mode")
	isTraceCL := flag.Bool("t", false, "TRACE mode")

	setFlag(flag.CommandLine)
	flag.Parse()

	config = readConfig(*configPathCL)

	isDebug := config.DebugMode
	isTrace := config.TraceMode

	if *isDebugCL {
		isDebug = *isDebugCL
	}

	if *isTraceCL {
		isTrace = *isTraceCL
	}

	setLogOutput(config, *logFilePathCL)

	httpClient := http.Client{}
	httpClient.Timeout = time.Duration(300) * time.Millisecond
	sessionToNats := napping.Session{Client: &httpClient}
	sessionToLogstash := napping.Session{Userinfo: url.UserPassword(config.LgLogin, config.LgPassword)}

	e := HttpError{}

	log.Printf("NATS-ELK forwarder started\n")
	log.Printf("Interval of requests: %d ms\n", config.Interval)

	for true {

		for _, url := range config.NatsUrls {

			varz := Varz{}
			connzs := Connz{}
			natsNodeTopInfo := NatsMetric{}

			varzUrl := url + "/varz"
			connzUrl := url + "/connz"

			varzResponse, err := sessionToNats.Get(varzUrl, nil, &varz, &e)

			if err != nil {
				log.Printf("%v\n", err)
				continue
			}

			connzResponse, err := sessionToNats.Get(connzUrl, nil, &connzs, &e)

			if err != nil {
				log.Printf("%v\n", err)
				continue
			}

			if varzResponse.Status() == 200 && connzResponse.Status() == 200 {

				if isDebug {
					log.Printf("Get data from nats node (%v) - Success\n", url)
				}

				perSecValues := getPerSecValues(url, varz)

				varz.In_bytes_sec = perSecValues.In_bytes_sec
				varz.Out_bytes_sec = perSecValues.Out_bytes_sec
				varz.In_msgs_sec = perSecValues.In_msgs_sec
				varz.Out_msgs_sec = perSecValues.Out_msgs_sec

				varz.Mem = varz.Mem / 1024 / 1024 // to MB
				natsNodeTopInfo.Varz = varz
				natsNodeTopInfo.Connz = connzs

				if isTrace {
					printPrettyJson(natsNodeTopInfo)
				}

				logstashResponse, err := sessionToLogstash.Post(config.LogStashUrl, natsNodeTopInfo, nil, &e)

				if err != nil {
					log.Printf("Sending to logstash -> Error: ")
					log.Printf("%v\n", err)
					continue
				}
				if logstashResponse.Status() == 200 && isDebug {
					log.Printf("Sending to logstash (%v): Success\n", config.LogStashUrl)
				}
			}
		}
		time.Sleep(time.Duration(config.Interval) * time.Millisecond)
	}
}
func getPerSecValues(url string, varz Varz) InOutPerSec {
	inOutPerSec := InOutPerSec{}

	if prev_vals[url] == nil {

		prev_vals[url] = &PrevInOutValues{}

		prev_vals[url].In_bytes = varz.In_bytes
		prev_vals[url].Out_bytes = varz.Out_bytes
		prev_vals[url].In_msgs = varz.In_msgs
		prev_vals[url].Out_msgs = varz.Out_msgs
		prev_vals[url].Now = varz.Now

		return InOutPerSec{}
	}

	// calculate
	in_bytes_delta := varz.In_bytes - prev_vals[url].In_bytes
	out_bytes_delta := varz.Out_bytes - prev_vals[url].Out_bytes

	in_msgs_delta := varz.In_msgs - prev_vals[url].In_msgs
	out_msgs_delta := varz.Out_msgs - prev_vals[url].Out_msgs

	sec := varz.Now.Second() - prev_vals[url].Now.Second()

	inOutPerSec.In_bytes_sec = in_bytes_delta / sec
	inOutPerSec.Out_bytes_sec = out_bytes_delta / sec
	inOutPerSec.In_msgs_sec = in_msgs_delta / sec
	inOutPerSec.Out_msgs_sec = out_msgs_delta / sec

	// save prev.values
	prev_vals[url].In_bytes = varz.In_bytes
	prev_vals[url].Out_bytes = varz.Out_bytes
	prev_vals[url].In_msgs = varz.In_msgs
	prev_vals[url].Out_msgs = varz.Out_msgs
	prev_vals[url].Now = varz.Now

	// return result
	return inOutPerSec
}
func readConfig(filepath string) Configuration {

	file, _ := os.Open(filepath)
	decoder := json.NewDecoder(file)
	configuration := Configuration{}
	err := decoder.Decode(&configuration)

	if err != nil {
		log.Println("error:", err)
	}

	return configuration
}

type HttpError struct {
	Message string
	Errors  []struct {
		Resource string
		Field    string
		Code     string
	}
}

func setFlag(flag *flag.FlagSet) {
	flag.Usage = func() {
		showHelp()
	}
}
func showHelp() {
	fmt.Println(`
Usage: CLI Template [OPTIONS]
Options:
    -c, --config     Path to config file.
    -l, --log        Path to log file.
    -d, --debug      DEBUG mode.
    -t, --trace      TRACE mode.
    -h, --help       prints this help info.
    `)
}
func setLogOutput(config Configuration, logFilePathCL string) {

	if len(config.LogFilePath) > 0 || len(logFilePathCL) > 0 {

		logFilePath := ""

		if len(config.LogFilePath) > 0 {
			logFilePath = config.LogFilePath
		}
		if len(logFilePathCL) > 0 {
			logFilePath = logFilePathCL
		}

		log.SetOutput(&lumberjack.Logger{
			Filename:   logFilePath,
			MaxSize:    500, // megabytes
			MaxBackups: 3,
			MaxAge:     28, //days
		})
	}
}
func printPrettyJson(info NatsMetric) {
	var prettyJSON bytes.Buffer

	body, err := json.Marshal(info)

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

	error := json.Indent(&prettyJSON, body, "", "\t")
	if error != nil {
		log.Println("JSON parse error: ", error)
		return
	}

	log.Println(string(prettyJSON.Bytes()))
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"testing"

	"github.com/ParsePlatform/parse-cli/parsecli"
	"github.com/facebookgo/ensure"
	"github.com/facebookgo/parse"
)

func newNewCmdHarness(t testing.TB) (*parsecli.Harness, *newCmd) {
	h := parsecli.NewHarness(t)
	h.MakeEmptyRoot()
	return h, &newCmd{}
}

func TestCloudCodeHelpMessage(t *testing.T) {
	t.Parallel()
	h := parsecli.NewHarness(t)
	defer h.Stop()

	n := &newCmd{}
	msg := n.cloudCodeHelpMessage(h.Env, &parsecli.App{ApplicationID: "a", MasterKey: "m"})
	ensure.StringContains(t,
		msg,
		fmt.Sprintf(
			`Your Cloud Code has been created at %s.

This includes a "Hello world" cloud function, so once you deploy,
you can test that it works, with`,
			h.Env.Root,
		),
	)
}

func TestGetCloudCodeDir(t *testing.T) {
	t.Parallel()
	h := parsecli.NewHarness(t)
	h.MakeEmptyRoot()
	defer h.Stop()

	n := &newCmd{}
	h.Env.In = ioutil.NopCloser(strings.NewReader("\n"))
	name, err := n.getCloudCodeDir(h.Env, "myapp", true)
	ensure.Nil(t, err)
	ensure.StringContains(t, h.Out.String(), "Now it's time to set up some Cloud Code")
	ensure.DeepEqual(t, name, "myapp")

	h.Out.Reset()
	h.Env.In = ioutil.NopCloser(strings.NewReader("otherApp\n"))
	name, err = n.getCloudCodeDir(h.Env, "myapp", true)
	ensure.Nil(t, err)
	ensure.StringContains(t, h.Out.String(), "Now it's time to set up some Cloud Code")
	ensure.DeepEqual(t, name, "otherApp")

	_, err = os.Create(filepath.Join(h.Env.Root, "otherApp"))
	ensure.Nil(t, err)
	h.Out.Reset()
	h.Env.In = ioutil.NopCloser(strings.NewReader("otherApp\n"))
	name, err = n.getCloudCodeDir(h.Env, "myapp", true)
	ensure.Err(t, err, regexp.MustCompile("already exists"))
	ensure.StringContains(t, h.Out.String(), "Now it's time to set up some Cloud Code")

	ensure.Nil(t, os.MkdirAll(filepath.Join(h.Env.Root, "myapp", "config"), 0755))
	_, err = os.Create(filepath.Join(h.Env.Root, "myapp", "config", "global.json"))
	ensure.Nil(t, err)
	h.Out.Reset()
	h.Env.In = ioutil.NopCloser(strings.NewReader("\n"))
	name, err = n.getCloudCodeDir(h.Env, "myapp", true)
	ensure.Err(t, err, regexp.MustCompile("you already have Cloud Code"))
	ensure.Nil(t, os.Remove(filepath.Join(h.Env.Root, "myapp", "config", "global.json")))

	h.Out.Reset()
	h.Env.In = ioutil.NopCloser(strings.NewReader("\n"))
	name, err = n.getCloudCodeDir(h.Env, "myapp", false)
	ensure.Nil(t, err)
	ensure.StringContains(t, h.Out.String(), "folder where we can download the latest")
}

func TestNewCmdDirs(t *testing.T) {
	t.Parallel()

	h, _ := newNewCmdHarness(t)
	defer h.Stop()

	ensure.Nil(t, parsecli.CloneSampleCloudCode(h.Env, true))

	var err error

	for _, newProjectFile := range parsecli.NewProjectFiles {
		_, err = os.Stat(filepath.Join(h.Env.Root, newProjectFile.Dirname))
		ensure.Nil(t, err)
	}
}

func TestNewCmdContent(t *testing.T) {
	t.Parallel()

	h, _ := newNewCmdHarness(t)
	defer h.Stop()

	ensure.Nil(t, parsecli.CloneSampleCloudCode(h.Env, true))

	for _, newProjectFile := range parsecli.NewProjectFiles {
		content, err := ioutil.ReadFile(
			filepath.Join(h.Env.Root, newProjectFile.Dirname, newProjectFile.Filename),
		)
		ensure.Nil(t, err)
		ensure.DeepEqual(t, string(content), newProjectFile.Content)
	}

	content, err := ioutil.ReadFile(filepath.Join(h.Env.Root, parsecli.ParseProject))
	ensure.Nil(t, err)
	ensure.DeepEqual(t,
		string(content),
		fmt.Sprintf(
			`{
  "project_type" : %d,
  "parse": {"jssdk":""}
}`,
			parsecli.ParseFormat,
		),
	)

	content, err = ioutil.ReadFile(filepath.Join(h.Env.Root, parsecli.ParseLocal))
	ensure.Nil(t, err)
	ensure.DeepEqual(t, string(content), "{}")

}

func TestCurlCommand(t *testing.T) {
	t.Parallel()
	h := parsecli.NewHarness(t)
	defer h.Stop()

	n := &newCmd{}
	command := n.curlCommand(h.Env, &parsecli.App{ApplicationID: "AppID", RestKey: "RestKey"})
	ensure.DeepEqual(t,
		command,
		`curl -X POST \
 -H "X-Parse-Application-Id: AppID" \
 -H "X-Parse-REST-API-Key: RestKey" \
 -H "Content-Type: application/json" \
 -d '{}' \
 https://api.parse.com/1/functions/hello
`)
}

func TestCreateNewAppNoCode(t *testing.T) {
	t.Parallel()
	h, _ := parsecli.NewAppHarness(t)
	defer h.Stop()

	h.Env.In = ioutil.NopCloser(strings.NewReader("email\npassword"))
	n := &newCmd{noCode: true, createNewApp: true, parseAppName: "yolo"}
	ensure.Nil(t, n.run(h.Env))
	ensure.StringContains(t, h.Out.String(), "Successfully created")
}

func TestSelectNewAppNoCode(t *testing.T) {
	t.Parallel()
	h, _ := parsecli.NewAppHarness(t)
	defer h.Stop()

	h.Env.In = ioutil.NopCloser(strings.NewReader("email\npassword\n"))
	n := &newCmd{noCode: true, parseAppName: "A"}
	ensure.Nil(t, n.run(h.Env))
	ensure.StringContains(t, h.Out.String(), "Successfully selected")
}

func TestShouldCreateNewApp(t *testing.T) {
	t.Parallel()
	h := parsecli.NewHarness(t)
	defer h.Stop()

	n := &newCmd{}

	h.Env.In = ioutil.NopCloser(strings.NewReader("new"))
	decision, err := n.promptCreateNewApp(h.Env, false)
	ensure.Nil(t, err)
	ensure.DeepEqual(t, decision, "new")

	h.Env.In = ioutil.NopCloser(strings.NewReader("existing"))
	decision, err = n.promptCreateNewApp(h.Env, false)
	ensure.Nil(t, err)
	ensure.DeepEqual(t, decision, "existing")

	h.Env.In = ioutil.NopCloser(strings.NewReader("other"))
	_, err = n.promptCreateNewApp(h.Env, false)
	ensure.Err(t, err, regexp.MustCompile("are the only valid options"))

	decision, err = n.promptCreateNewApp(h.Env, true)
	ensure.Nil(t, err)
	ensure.DeepEqual(t, decision, "existing")

	n.createNewApp = true
	decision, err = n.promptCreateNewApp(h.Env, true)
	ensure.Nil(t, err)
	ensure.DeepEqual(t, decision, "new")
}

func TestSetupAndConfigure(t *testing.T) {
	t.Parallel()
	h := parsecli.NewHarness(t)
	h.MakeEmptyRoot()
	defer h.Stop()

	n := &newCmd{}
	h.Env.Type = parsecli.ParseFormat
	h.Env.In = ioutil.NopCloser(strings.NewReader("\n"))
	code, err := n.setupSample(h.Env, "myapp", &parsecli.ParseAppConfig{ApplicationID: "a"}, true, false)
	ensure.Nil(t, err)
	ensure.True(t, code)

	type jsSDKVersion struct {
		JS []string `json:"js"`
	}
	ht := parsecli.TransportFunc(func(r *http.Request) (*http.Response, error) {
		ensure.DeepEqual(t, r.URL.Path, "/1/jsVersions")
		rows := jsSDKVersion{JS: []string{"1.5.0", "1.6.0"}}
		return &http.Response{
			StatusCode: http.StatusOK,
			Body:       ioutil.NopCloser(strings.NewReader(jsonStr(t, rows))),
		}, nil
	})
	h.Env.ParseAPIClient = &parsecli.ParseAPIClient{APIClient: &parse.Client{Transport: ht}}
	err = n.configureSample(
		&addCmd{MakeDefault: true},
		"yolo",
		(&parsecli.ParseAppConfig{ApplicationID: "a"}).WithInternalMasterKey("m"),
		nil,
		h.Env,
	)
	ensure.Nil(t, err)
}
<commit_msg>fix test break due to existing dir<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"testing"

	"github.com/ParsePlatform/parse-cli/parsecli"
	"github.com/facebookgo/ensure"
	"github.com/facebookgo/parse"
)

func newNewCmdHarness(t testing.TB) (*parsecli.Harness, *newCmd) {
	h := parsecli.NewHarness(t)
	h.MakeEmptyRoot()
	return h, &newCmd{}
}

func TestCloudCodeHelpMessage(t *testing.T) {
	t.Parallel()
	h := parsecli.NewHarness(t)
	defer h.Stop()

	n := &newCmd{}
	msg := n.cloudCodeHelpMessage(h.Env, &parsecli.App{ApplicationID: "a", MasterKey: "m"})
	ensure.StringContains(t,
		msg,
		fmt.Sprintf(
			`Your Cloud Code has been created at %s.

This includes a "Hello world" cloud function, so once you deploy,
you can test that it works, with`,
			h.Env.Root,
		),
	)
}

func TestGetCloudCodeDir(t *testing.T) {
	t.Parallel()
	h := parsecli.NewHarness(t)
	h.MakeEmptyRoot()
	defer h.Stop()

	n := &newCmd{}
	h.Env.In = ioutil.NopCloser(strings.NewReader("\n"))
	name, err := n.getCloudCodeDir(h.Env, "myapp", true)
	ensure.Nil(t, err)
	ensure.StringContains(t, h.Out.String(), "Now it's time to set up some Cloud Code")
	ensure.DeepEqual(t, name, "myapp")

	h.Out.Reset()
	h.Env.In = ioutil.NopCloser(strings.NewReader("otherApp\n"))
	name, err = n.getCloudCodeDir(h.Env, "myapp", true)
	ensure.Nil(t, err)
	ensure.StringContains(t, h.Out.String(), "Now it's time to set up some Cloud Code")
	ensure.DeepEqual(t, name, "otherApp")

	_, err = os.Create(filepath.Join(h.Env.Root, "otherApp"))
	ensure.Nil(t, err)
	h.Out.Reset()
	h.Env.In = ioutil.NopCloser(strings.NewReader("otherApp\n"))
	name, err = n.getCloudCodeDir(h.Env, "myapp", true)
	ensure.Err(t, err, regexp.MustCompile("already exists"))
	ensure.StringContains(t, h.Out.String(), "Now it's time to set up some Cloud Code")

	ensure.Nil(t, os.MkdirAll(filepath.Join(h.Env.Root, "myapp", "config"), 0755))
	_, err = os.Create(filepath.Join(h.Env.Root, "myapp", "config", "global.json"))
	ensure.Nil(t, err)
	h.Out.Reset()
	h.Env.In = ioutil.NopCloser(strings.NewReader("\n"))
	name, err = n.getCloudCodeDir(h.Env, "myapp", true)
	ensure.Err(t, err, regexp.MustCompile("you already have Cloud Code"))
	ensure.Nil(t, os.Remove(filepath.Join(h.Env.Root, "myapp", "config", "global.json")))

	h.Out.Reset()
	h.Env.In = ioutil.NopCloser(strings.NewReader("\n"))
	name, err = n.getCloudCodeDir(h.Env, "myapp", false)
	ensure.Err(t, err, regexp.MustCompile("a directory named: \"myapp\" already exists"))
}

func TestNewCmdDirs(t *testing.T) {
	t.Parallel()

	h, _ := newNewCmdHarness(t)
	defer h.Stop()

	ensure.Nil(t, parsecli.CloneSampleCloudCode(h.Env, true))

	var err error

	for _, newProjectFile := range parsecli.NewProjectFiles {
		_, err = os.Stat(filepath.Join(h.Env.Root, newProjectFile.Dirname))
		ensure.Nil(t, err)
	}
}

func TestNewCmdContent(t *testing.T) {
	t.Parallel()

	h, _ := newNewCmdHarness(t)
	defer h.Stop()

	ensure.Nil(t, parsecli.CloneSampleCloudCode(h.Env, true))

	for _, newProjectFile := range parsecli.NewProjectFiles {
		content, err := ioutil.ReadFile(
			filepath.Join(h.Env.Root, newProjectFile.Dirname, newProjectFile.Filename),
		)
		ensure.Nil(t, err)
		ensure.DeepEqual(t, string(content), newProjectFile.Content)
	}

	content, err := ioutil.ReadFile(filepath.Join(h.Env.Root, parsecli.ParseProject))
	ensure.Nil(t, err)
	ensure.DeepEqual(t,
		string(content),
		fmt.Sprintf(
			`{
  "project_type" : %d,
  "parse": {"jssdk":""}
}`,
			parsecli.ParseFormat,
		),
	)

	content, err = ioutil.ReadFile(filepath.Join(h.Env.Root, parsecli.ParseLocal))
	ensure.Nil(t, err)
	ensure.DeepEqual(t, string(content), "{}")

}

func TestCurlCommand(t *testing.T) {
	t.Parallel()
	h := parsecli.NewHarness(t)
	defer h.Stop()

	n := &newCmd{}
	command := n.curlCommand(h.Env, &parsecli.App{ApplicationID: "AppID", RestKey: "RestKey"})
	ensure.DeepEqual(t,
		command,
		`curl -X POST \
 -H "X-Parse-Application-Id: AppID" \
 -H "X-Parse-REST-API-Key: RestKey" \
 -H "Content-Type: application/json" \
 -d '{}' \
 https://api.parse.com/1/functions/hello
`)
}

func TestCreateNewAppNoCode(t *testing.T) {
	t.Parallel()
	h, _ := parsecli.NewAppHarness(t)
	defer h.Stop()

	h.Env.In = ioutil.NopCloser(strings.NewReader("email\npassword"))
	n := &newCmd{noCode: true, createNewApp: true, parseAppName: "yolo"}
	ensure.Nil(t, n.run(h.Env))
	ensure.StringContains(t, h.Out.String(), "Successfully created")
}

func TestSelectNewAppNoCode(t *testing.T) {
	t.Parallel()
	h, _ := parsecli.NewAppHarness(t)
	defer h.Stop()

	h.Env.In = ioutil.NopCloser(strings.NewReader("email\npassword\n"))
	n := &newCmd{noCode: true, parseAppName: "A"}
	ensure.Nil(t, n.run(h.Env))
	ensure.StringContains(t, h.Out.String(), "Successfully selected")
}

func TestShouldCreateNewApp(t *testing.T) {
	t.Parallel()
	h := parsecli.NewHarness(t)
	defer h.Stop()

	n := &newCmd{}

	h.Env.In = ioutil.NopCloser(strings.NewReader("new"))
	decision, err := n.promptCreateNewApp(h.Env, false)
	ensure.Nil(t, err)
	ensure.DeepEqual(t, decision, "new")

	h.Env.In = ioutil.NopCloser(strings.NewReader("existing"))
	decision, err = n.promptCreateNewApp(h.Env, false)
	ensure.Nil(t, err)
	ensure.DeepEqual(t, decision, "existing")

	h.Env.In = ioutil.NopCloser(strings.NewReader("other"))
	_, err = n.promptCreateNewApp(h.Env, false)
	ensure.Err(t, err, regexp.MustCompile("are the only valid options"))

	decision, err = n.promptCreateNewApp(h.Env, true)
	ensure.Nil(t, err)
	ensure.DeepEqual(t, decision, "existing")

	n.createNewApp = true
	decision, err = n.promptCreateNewApp(h.Env, true)
	ensure.Nil(t, err)
	ensure.DeepEqual(t, decision, "new")
}

func TestSetupAndConfigure(t *testing.T) {
	t.Parallel()
	h := parsecli.NewHarness(t)
	h.MakeEmptyRoot()
	defer h.Stop()

	n := &newCmd{}
	h.Env.Type = parsecli.ParseFormat
	h.Env.In = ioutil.NopCloser(strings.NewReader("\n"))
	code, err := n.setupSample(h.Env, "myapp", &parsecli.ParseAppConfig{ApplicationID: "a"}, true, false)
	ensure.Nil(t, err)
	ensure.True(t, code)

	type jsSDKVersion struct {
		JS []string `json:"js"`
	}
	ht := parsecli.TransportFunc(func(r *http.Request) (*http.Response, error) {
		ensure.DeepEqual(t, r.URL.Path, "/1/jsVersions")
		rows := jsSDKVersion{JS: []string{"1.5.0", "1.6.0"}}
		return &http.Response{
			StatusCode: http.StatusOK,
			Body:       ioutil.NopCloser(strings.NewReader(jsonStr(t, rows))),
		}, nil
	})
	h.Env.ParseAPIClient = &parsecli.ParseAPIClient{APIClient: &parse.Client{Transport: ht}}
	err = n.configureSample(
		&addCmd{MakeDefault: true},
		"yolo",
		(&parsecli.ParseAppConfig{ApplicationID: "a"}).WithInternalMasterKey("m"),
		nil,
		h.Env,
	)
	ensure.Nil(t, err)
}
<|endoftext|>


<commit_before>package html2data

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/cookiejar"
	"os"

	"github.com/PuerkitoBio/goquery"
)

func getHTMLPage(url string) *http.Response {
	cookie, _ := cookiejar.New(nil)
	client := &http.Client{
		Jar: cookie,
	}

	response, err := client.Get(url)

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

	return response
}

// GetData - extract data by CSS selectors from URL or HTML page
func GetData(url string, selectors map[string]string) (result map[string][]string) {
	var err error
	var doc *goquery.Document
	result = map[string][]string{}

	stat, _ := os.Stdin.Stat()
	if url == "-" || (stat.Mode()&os.ModeCharDevice) == 0 {
		stdinReader := bufio.NewReader(os.Stdin)
		doc, err = goquery.NewDocumentFromReader(stdinReader)
	} else {
		httpResponse := getHTMLPage(url)
		doc, err = goquery.NewDocumentFromReader(httpResponse.Body)
	}

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

	for name, selector := range selectors {
		texts := []string{}
		doc.Find(selector).Each(func(i int, selection *goquery.Selection) {
			texts = append(texts, selection.Text())
		})
		result[name] = texts
	}

	return result
}
<commit_msg>Fixed compile<commit_after>package html2data

import (
	"bufio"
	"log"
	"net/http"
	"net/http/cookiejar"
	"os"

	"github.com/PuerkitoBio/goquery"
)

func getHTMLPage(url string) *http.Response {
	cookie, _ := cookiejar.New(nil)
	client := &http.Client{
		Jar: cookie,
	}

	response, err := client.Get(url)

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

	return response
}

// GetData - extract data by CSS selectors from URL or HTML page
func GetData(url string, selectors map[string]string) (result map[string][]string) {
	var err error
	var doc *goquery.Document
	result = map[string][]string{}

	stat, _ := os.Stdin.Stat()
	if url == "-" || (stat.Mode()&os.ModeCharDevice) == 0 {
		stdinReader := bufio.NewReader(os.Stdin)
		doc, err = goquery.NewDocumentFromReader(stdinReader)
	} else {
		httpResponse := getHTMLPage(url)
		doc, err = goquery.NewDocumentFromReader(httpResponse.Body)
	}

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

	for name, selector := range selectors {
		texts := []string{}
		doc.Find(selector).Each(func(i int, selection *goquery.Selection) {
			texts = append(texts, selection.Text())
		})
		result[name] = texts
	}

	return result
}
<|endoftext|>