Skip to content

Commit

Permalink
app mock
Browse files Browse the repository at this point in the history
  • Loading branch information
ivcosla committed Aug 1, 2019
1 parent 8aa55a1 commit fb139da
Show file tree
Hide file tree
Showing 6 changed files with 205 additions and 0 deletions.
34 changes: 34 additions & 0 deletions cmd/therealssh-cli/commands/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"net"
"net/rpc"
"os"
"os/exec"
"os/signal"
"os/user"
"strings"
Expand Down Expand Up @@ -145,3 +146,36 @@ func Execute() {
log.Fatal(err)
}
}

func runInPTY() error {
c := exec.Command("sh")
ptmx, err := pty.Start(c)

// Make sure to close the pty at the end.
defer func() { _ = ptmx.Close() }() // Best effort.

// Handle pty size.
ch := make(chan os.Signal, 1)
signal.Notify(ch, syscall.SIGWINCH)
go func() {
for range ch {
if err := pty.InheritSize(os.Stdin, ptmx); err != nil {
log.Printf("error resizing pty: %s", err)
}
}
}()
ch <- syscall.SIGWINCH // Initial resize.

// Set stdin in raw mode.
oldState, err := terminal.MakeRaw(int(os.Stdin.Fd()))
if err != nil {
panic(err)
}
defer func() { _ = terminal.Restore(int(os.Stdin.Fd()), oldState) }() // Best effort.

// Copy stdin to the pty and the pty to stdout.
go func() { _, _ = io.Copy(ptmx, os.Stdin) }()
_, _ = io.Copy(os.Stdout, ptmx)

return nil
}
2 changes: 2 additions & 0 deletions internal/therealssh/channel.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ func (sshCh *SSHChannel) Serve() error {
err = sshCh.Shell()
case RequestExec:
err = sshCh.Start(string(data[1:]))
//case RequestExecWithoutShell:

case RequestWindowChange:
cols := binary.BigEndian.Uint32(data[1:])
rows := binary.BigEndian.Uint32(data[5:])
Expand Down
1 change: 1 addition & 0 deletions internal/therealssh/channel_pty_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ func TestChannelServe(t *testing.T) {
assert.Equal(t, CmdChannelResponse, buf[0])
assert.Equal(t, ResponseConfirm, buf[5])


require.NotNil(t, ch.session)

ch.msgCh <- []byte{byte(RequestShell)}
Expand Down
150 changes: 150 additions & 0 deletions internal/therealssh/pty_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
package therealssh

import (
"errors"
"fmt"
"github.com/creack/pty"
"github.com/skycoin/dmsg/cipher"
"github.com/skycoin/skywire/pkg/app"
"github.com/skycoin/skywire/pkg/routing"
"github.com/stretchr/testify/require"
"io/ioutil"
"net"
"os/exec"
"testing"
)

func runInPTY(command string) ([]byte, error) {
c := exec.Command(command)
ptmx, err := pty.Start(c)
if err != nil {
return nil, err
}

// Make sure to close the pty at the end.
defer func() { _ = ptmx.Close() }() // Best effort.

// as stated in https://github.com/creack/pty/issues/21#issuecomment-513069505 we can ignore this error
res, _ := ioutil.ReadAll(ptmx) // nolint: err
return res, nil
}

func runInRemote(t *testing.T, pk cipher.PubKey) ([]byte, error) {
in, out := net.Pipe()
ch := OpenChannel(1, routing.Addr{PubKey: pk, Port: Port}, in)

errCh := make(chan error)
go func() {
errCh <- ch.Send(CmdChannelOpen, []byte("foo"))
}()

server := NewServer(MockAuthorizer{})
go func(){
err := server.Serve(out)
require.NoError(t, err)
}()

type data struct {
res []byte
err error
}
resCh := make(chan data)
go func() {
res, err := ch.Request(RequestExec, []byte("ls"))
resCh <- data{res, err}
}()

d := <- resCh
require.NoError(t, d.err)
fmt.Println(d.res)
return d.res, d.err
}

func TestRunInPTY(t *testing.T) {
serverPK, _ := cipher.GenerateKeyPair()
//clientPK, _ := cipher.GenerateKeyPair()

clientConn, serverConn := net.Pipe()

serverApp := createDefaultServerApp(t, serverConn)
clientApp := createDefaultClientApp(t, clientConn)


// server.Serve
server := NewServer(MockAuthorizer{})
go func() {
conn, err := serverApp.Accept()
require.NoError(t, err)

require.NoError(t, server.Serve(conn))
}()

// client
_, client, err := NewClient(":9999", clientApp)
require.NoError(t, err)

go func() {
conn, err := clientApp.Dial(routing.Addr{PubKey: serverPK, Port: 2})
require.NoError(t, err)

require.NoError(t, client.serveConn(conn))
}()

_, ch, err := client.OpenChannel(serverPK)
require.NoError(t, err)
res, err := ch.Request(RequestExec, []byte("ls"))
require.NoError(t, err)
fmt.Println(res)

require.NoError(t, serverApp.Close())
require.NoError(t, clientApp.Close())
require.NoError(t, server.Close())
require.NoError(t, client.Close())
}

func createDefaultServerApp(t *testing.T, conn net.Conn) *app.App {
sshApp := app.NewAppMock(conn)

go func() {
f := func(f app.Frame, p []byte) (interface{}, error) {
if f == app.FrameCreateLoop {
return &routing.Addr{PubKey: lpk, Port: 2}, nil
}

if f == app.FrameClose {
go func() { dataCh <- p }()
return nil, nil
}

return nil, errors.New("unexpected frame")
}
}()

return sshApp
}

func createDefaultClientApp(t *testing.T, conn net.Conn) *app.App {
sshApp := app.NewAppMock(conn)
go func() {
f := func(f app.Frame, p []byte) (interface{}, error) {
if f == app.FrameCreateLoop {
return &routing.Addr{PubKey: lpk, Port: 2}, nil
}

if f == app.FrameClose {
return nil, nil
}

return nil, errors.New("unexpected frame")
}
serveErrCh <- proto.Serve(f)
}()

return sshApp
}

type MockAuthorizer struct {}

func (MockAuthorizer) Authorize(pk cipher.PubKey) error {
return nil
}
2 changes: 2 additions & 0 deletions internal/therealssh/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ const (
RequestShell
// RequestExec represents request for new process.
RequestExec
// RequestExec without shell, for use in integration testing.
// RequestExecWithoutShell
// RequestWindowChange represents request for PTY size change.
RequestWindowChange
)
Expand Down
16 changes: 16 additions & 0 deletions pkg/app/testing.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package app

import (
"github.com/skycoin/skywire/pkg/routing"
"io"
"net"
)

func NewAppMock(conn net.Conn) *App {
app := &App{proto: NewProtocol(conn), acceptChan: make(chan [2]routing.Addr),
doneChan: make(chan struct{}),
conns: make(map[routing.Loop]io.ReadWriteCloser)}
go app.handleProto()

return app
}

0 comments on commit fb139da

Please sign in to comment.