mikrotik-exporter/vendor/gopkg.in/routeros.v2/proto_test.go
2017-08-27 23:27:11 -04:00

451 lines
8.8 KiB
Go

package routeros_test
import (
"fmt"
"io"
"testing"
"gopkg.in/routeros.v2"
"gopkg.in/routeros.v2/proto"
)
func TestLogin(t *testing.T) {
c, s := newPair(t)
defer c.Close()
go func() {
defer s.Close()
s.readSentence(t, "/login @ []")
s.writeSentence(t, "!done", "=ret=abc123")
s.readSentence(t, "/login @ [{`name` `userTest`} {`response` `0021277bff9ac7caf06aa608e46616d47f`}]")
s.writeSentence(t, "!done")
}()
err := c.Login("userTest", "passTest")
if err != nil {
t.Fatal(err)
}
}
func TestLoginIncorrect(t *testing.T) {
c, s := newPair(t)
defer c.Close()
go func() {
defer s.Close()
s.readSentence(t, "/login @ []")
s.writeSentence(t, "!done", "=ret=abc123")
s.readSentence(t, "/login @ [{`name` `userTest`} {`response` `0021277bff9ac7caf06aa608e46616d47f`}]")
s.writeSentence(t, "!trap", "=message=incorrect login")
}()
err := c.Login("userTest", "passTest")
if err == nil {
t.Fatalf("Login succeeded; want error")
}
if err.Error() != "from RouterOS device: incorrect login" {
t.Fatal(err)
}
}
func TestLoginNoChallenge(t *testing.T) {
c, s := newPair(t)
defer c.Close()
go func() {
defer s.Close()
s.readSentence(t, "/login @ []")
s.writeSentence(t, "!done")
}()
err := c.Login("userTest", "passTest")
if err == nil {
t.Fatalf("Login succeeded; want error")
}
if err.Error() != "RouterOS: /login: no ret (challenge) received" {
t.Fatal(err)
}
}
func TestLoginInvalidChallenge(t *testing.T) {
c, s := newPair(t)
defer c.Close()
go func() {
defer s.Close()
s.readSentence(t, "/login @ []")
s.writeSentence(t, "!done", "=ret=Invalid Hex String")
}()
err := c.Login("userTest", "passTest")
if err == nil {
t.Fatalf("Login succeeded; want error")
}
if err.Error() != "RouterOS: /login: invalid ret (challenge) hex string received: encoding/hex: invalid byte: U+0049 'I'" {
t.Fatal(err)
}
}
func TestLoginEOF(t *testing.T) {
c, s := newPair(t)
defer c.Close()
s.Close()
err := c.Login("userTest", "passTest")
if err == nil {
t.Fatalf("Login succeeded; want error")
}
if err.Error() != "io: read/write on closed pipe" {
t.Fatal(err)
}
}
func TestCloseTwice(t *testing.T) {
c, s := newPair(t)
defer s.Close()
c.Close()
c.Close()
}
func TestAsyncTwice(t *testing.T) {
c, s := newPair(t)
defer c.Close()
defer s.Close()
c.Async()
errC := c.Async()
err := <-errC
want := "Async() has already been called"
if err.Error() != want {
t.Fatalf("Second Async()=%#q; want %#q", err, want)
}
err = <-errC
if err != nil {
t.Fatalf("Async() channel should be closed after error; got %#q", err)
}
}
func TestRun(t *testing.T) {
c, s := newPair(t)
defer c.Close()
go func() {
defer s.Close()
s.readSentence(t, "/ip/address @ []")
s.writeSentence(t, "!re", "=address=1.2.3.4/32")
s.writeSentence(t, "!done")
}()
sen, err := c.Run("/ip/address")
if err != nil {
t.Fatal(err)
}
want := "!re @ [{`address` `1.2.3.4/32`}]\n!done @ []"
if sen.String() != want {
t.Fatalf("/ip/address (%s); want (%s)", sen, want)
}
}
func TestRunWithListen(t *testing.T) {
c, s := newPair(t)
defer c.Close()
go func() {
defer s.Close()
s.readSentence(t, "/ip/address @l1 []")
s.writeSentence(t, "!re", ".tag=l1", "=address=1.2.3.4/32")
s.writeSentence(t, "!done", ".tag=l1")
}()
listen, err := c.Listen("/ip/address")
if err != nil {
t.Fatal(err)
}
sen := <-listen.Chan()
want := "!re @l1 [{`address` `1.2.3.4/32`}]"
if fmt.Sprintf("%s", sen) != want {
t.Fatalf("/ip/address (%s); want (%s)", sen, want)
}
sen = <-listen.Chan()
if sen != nil {
t.Fatalf("Listen() channel should be closed after EOF; got %#q", sen)
}
err = listen.Err()
if err != nil {
t.Fatal(err)
}
}
func TestRunAsync(t *testing.T) {
c, s := newPair(t)
defer c.Close()
c.Async()
go func() {
defer s.Close()
s.readSentence(t, "/ip/address @r1 []")
s.writeSentence(t, "!re", ".tag=r1", "=address=1.2.3.4/32")
s.writeSentence(t, "!done", ".tag=r1")
}()
sen, err := c.Run("/ip/address")
if err != nil {
t.Fatal(err)
}
want := "!re @r1 [{`address` `1.2.3.4/32`}]\n!done @r1 []"
if sen.String() != want {
t.Fatalf("/ip/address (%s); want (%s)", sen, want)
}
}
func TestRunEmptySentence(t *testing.T) {
c, s := newPair(t)
defer c.Close()
go func() {
defer s.Close()
s.readSentence(t, "/ip/address @ []")
s.writeSentence(t)
s.writeSentence(t, "!re", "=address=1.2.3.4/32")
s.writeSentence(t, "!done")
}()
sen, err := c.Run("/ip/address")
if err != nil {
t.Fatal(err)
}
want := "!re @ [{`address` `1.2.3.4/32`}]\n!done @ []"
if sen.String() != want {
t.Fatalf("/ip/address (%s); want (%s)", sen, want)
}
}
func TestRunEOF(t *testing.T) {
c, s := newPair(t)
defer c.Close()
go func() {
defer s.Close()
s.readSentence(t, "/ip/address @ []")
}()
_, err := c.Run("/ip/address")
if err == nil {
t.Fatalf("Run succeeded; want error")
}
if err != io.EOF {
t.Fatal(err)
}
}
func TestRunEOFAsync(t *testing.T) {
c, s := newPair(t)
defer c.Close()
c.Async()
go func() {
defer s.Close()
s.readSentence(t, "/ip/address @r1 []")
s.writeSentence(t, "!re", "=address=1.2.3.4/32")
}()
_, err := c.Run("/ip/address")
if err == nil {
t.Fatalf("Run succeeded; want error")
}
if err != io.EOF {
t.Fatal(err)
}
}
func TestRunInvalidSentence(t *testing.T) {
c, s := newPair(t)
defer c.Close()
go func() {
defer s.Close()
s.readSentence(t, "/ip/address @ []")
s.writeSentence(t, "!xxx")
}()
_, err := c.Run("/ip/address")
if err == nil {
t.Fatalf("Run succeeded; want error")
}
if err.Error() != "unknown RouterOS reply word: !xxx" {
t.Fatal(err)
}
}
func TestRunTrap(t *testing.T) {
c, s := newPair(t)
defer c.Close()
go func() {
defer s.Close()
s.readSentence(t, "/ip/address @ []")
s.writeSentence(t, "!trap", "=message=Some device error message")
}()
_, err := c.Run("/ip/address")
if err == nil {
t.Fatalf("Run succeeded; want error")
}
if err.Error() != "from RouterOS device: Some device error message" {
t.Fatal(err)
}
}
func TestRunMesagelessTrap(t *testing.T) {
c, s := newPair(t)
defer c.Close()
go func() {
defer s.Close()
s.readSentence(t, "/ip/address @ []")
s.writeSentence(t, "!trap", "=some=unknown key")
}()
_, err := c.Run("/ip/address")
if err == nil {
t.Fatalf("Run succeeded; want error")
}
if err.Error() != "from RouterOS device: unknown error: !trap @ [{`some` `unknown key`}]" {
t.Fatal(err)
}
}
func TestRunFatal(t *testing.T) {
c, s := newPair(t)
defer c.Close()
go func() {
defer s.Close()
s.readSentence(t, "/ip/address @ []")
s.writeSentence(t, "!fatal", "=message=Some device error message")
}()
_, err := c.Run("/ip/address")
if err == nil {
t.Fatalf("Run succeeded; want error")
}
if err.Error() != "from RouterOS device: Some device error message" {
t.Fatal(err)
}
}
func TestRunAfterClose(t *testing.T) {
c, s := newPair(t)
c.Close()
s.Close()
_, err := c.Run("/ip/address")
if err == nil {
t.Fatalf("Run succeeded; want error")
}
if err.Error() != "io: read/write on closed pipe" {
t.Fatal(err)
}
}
func TestListen(t *testing.T) {
c, s := newPair(t)
defer c.Close()
go func() {
defer s.Close()
s.readSentence(t, "/ip/address/listen @l1 []")
s.writeSentence(t, "!re", ".tag=l1", "=address=1.2.3.4/32")
s.readSentence(t, "/cancel @r2 [{`tag` `l1`}]")
s.writeSentence(t, "!trap", "=category=2", ".tag=l1")
s.writeSentence(t, "!done", "=tag=r2")
s.writeSentence(t, "!done", "=tag=l1")
}()
c.Queue = 1
listen, err := c.Listen("/ip/address/listen")
if err != nil {
t.Fatal(err)
}
reC := listen.Chan()
listen.Cancel()
sen := <-reC
want := "!re @l1 [{`address` `1.2.3.4/32`}]"
if fmt.Sprintf("%s", sen) != want {
t.Fatalf("/ip/address/listen (%s); want (%s)", sen, want)
}
sen = <-reC
if sen != nil {
t.Fatalf("Listen() channel should be closed after Close(); got %#q", sen)
}
err = listen.Err()
if err != nil {
t.Fatal(err)
}
}
type conn struct {
*io.PipeReader
*io.PipeWriter
}
func (c *conn) Close() error {
c.PipeReader.Close()
c.PipeWriter.Close()
return nil
}
func newPair(t *testing.T) (*routeros.Client, *fakeServer) {
ar, aw := io.Pipe()
br, bw := io.Pipe()
c, err := routeros.NewClient(&conn{ar, bw})
if err != nil {
t.Fatal(err)
}
s := &fakeServer{
proto.NewReader(br),
proto.NewWriter(aw),
&conn{br, aw},
}
return c, s
}
type fakeServer struct {
r proto.Reader
w proto.Writer
io.Closer
}
func (f *fakeServer) readSentence(t *testing.T, want string) {
sen, err := f.r.ReadSentence()
if err != nil {
t.Fatal(err)
}
if sen.String() != want {
t.Fatalf("Sentence (%s); want (%s)", sen.String(), want)
}
t.Logf("< %s\n", sen)
}
func (f *fakeServer) writeSentence(t *testing.T, sentence ...string) {
t.Logf("> %#q\n", sentence)
f.w.BeginSentence()
for _, word := range sentence {
f.w.WriteWord(word)
}
err := f.w.EndSentence()
if err != nil {
t.Fatal(err)
}
}