Moved integration tests and other minor fixes

This commit is contained in:
Chad Retz 2018-05-16 10:26:11 -05:00
parent 0e8472626c
commit db2d028c4a
15 changed files with 204 additions and 119 deletions

View File

@ -120,7 +120,6 @@ func (c *Conn) EventWait(
ctx context.Context, events []EventCode, predicate func(Event) (bool, error),
) (Event, error) {
eventCh := make(chan Event, 10)
defer close(eventCh)
if err := c.AddEventListener(eventCh, events...); err != nil {
return nil, err
}
@ -131,6 +130,8 @@ func (c *Conn) EventWait(
go func() { errCh <- c.HandleEvents(eventCtx) }()
for {
select {
case <-eventCtx.Done():
return nil, eventCtx.Err()
case err := <-errCh:
return nil, err
case event := <-eventCh:

View File

@ -1,40 +0,0 @@
package controltest
/*
func TestEvents(t *testing.T) {
SkipIfNotRunningSpecifically(t)
ctx, conn := NewTestContextAuthenticated(t)
defer ctx.CloseConnected(conn)
// Turn on event handler
eventCtx, cancelFn := context.WithCancel(ctx)
defer cancelFn()
go func() { ctx.Require.Equal(context.Canceled, conn.HandleEvents(eventCtx)) }()
// Enable all events and hold on to which ones were seen
allEvents := control.EventCodes()
seenEvents := map[control.EventCode]struct{}{}
ch := make(chan control.Event, 1000)
ctx.Require.NoError(conn.AddEventListener(ch, allEvents...))
// Turn on the network
ctx.Require.NoError(conn.SetConf(control.NewKeyVal("DisableNetwork", "0")))
MainLoop:
for {
select {
case e := <-ch:
// Remove the event listener if it was seen
if _, ok := seenEvents[e.Code()]; !ok {
ctx.Debugf("Got event: %v", e.Code())
seenEvents[e.Code()] = struct{}{}
ctx.Require.NoError(conn.RemoveEventListener(ch, e.Code()))
}
case <-time.After(3 * time.Second):
ctx.Debugf("3 seconds passed")
break MainLoop
}
}
// Check that each event was sent at least once
for _, event := range allEvents {
_, ok := seenEvents[event]
ctx.Debugf("Event %v seen? %v", event, ok)
}
}
*/

View File

@ -1,10 +0,0 @@
package controltest
/*
func TestGetHiddenServiceDescriptorAsync(t *testing.T) {
ctx, conn := NewTestContextAuthenticated(t)
defer ctx.CloseConnected(conn)
t.Skip("TODO")
}
*/

View File

@ -1,62 +0,0 @@
package controltest
import (
"context"
"flag"
"os"
"testing"
"github.com/cretz/bine/tor"
"github.com/stretchr/testify/require"
)
func SkipIfNotRunningSpecifically(t *testing.T) {
if f := flag.Lookup("test.run"); f == nil || f.Value == nil || f.Value.String() != t.Name() {
t.Skip("Only runs if -run specifies this test exactly")
}
}
type TestContext struct {
context.Context
*testing.T
*tor.Tor
Require *require.Assertions
}
var torExePath string
func init() {
flag.StringVar(&torExePath, "tor.path", "tor", "The TOR exe path")
flag.Parse()
}
func NewTestContext(t *testing.T, conf *tor.StartConf) *TestContext {
// Build start conf
if conf == nil {
conf = &tor.StartConf{}
}
conf.ExePath = torExePath
if f := flag.Lookup("test.v"); f != nil && f.Value != nil && f.Value.String() == "true" {
conf.DebugWriter = os.Stdout
} else {
conf.ExtraArgs = append(conf.ExtraArgs, "--quiet")
}
ret := &TestContext{Context: context.Background(), T: t, Require: require.New(t)}
// Start tor
var err error
if ret.Tor, err = tor.Start(ret.Context, conf); err != nil {
defer ret.Close()
t.Fatal(err)
}
return ret
}
func (t *TestContext) Close() {
if err := t.Tor.Close(); err != nil {
if t.Failed() {
t.Logf("Failure on close: %v", err)
} else {
t.Errorf("Failure on close: %v", err)
}
}
}

View File

@ -1,2 +0,0 @@
// Package controltest contains the integration tests for package control.
package controltest

95
tests/context_test.go Normal file
View File

@ -0,0 +1,95 @@
package tests
import (
"context"
"flag"
"os"
"testing"
"time"
"github.com/cretz/bine/tor"
"github.com/stretchr/testify/require"
)
var torExePath string
var torVerbose bool
var torIncludeNetworkTests bool
var globalEnabledNetworkContext *TestContext
func TestMain(m *testing.M) {
flag.StringVar(&torExePath, "tor.path", "tor", "The Tor exe path")
flag.BoolVar(&torVerbose, "tor.verbose", false, "Show verbose test info")
flag.BoolVar(&torIncludeNetworkTests, "tor.network", false, "Include network tests")
flag.Parse()
exitCode := m.Run()
if globalEnabledNetworkContext != nil {
globalEnabledNetworkContext.CloseTorOnClose = true
globalEnabledNetworkContext.Close()
}
os.Exit(exitCode)
}
func SkipIfExcludingNetworkTests(t *testing.T) {
if !torIncludeNetworkTests {
t.Skip("Only runs if -tor.network is set")
}
}
func GlobalEnabledNetworkContext(t *testing.T) *TestContext {
SkipIfExcludingNetworkTests(t)
if globalEnabledNetworkContext == nil {
ctx := NewTestContext(t, nil)
ctx.CloseTorOnClose = false
// 45 second wait for enable network
enableCtx, enableCancel := context.WithTimeout(ctx, 45*time.Second)
defer enableCancel()
ctx.Require.NoError(ctx.EnableNetwork(enableCtx, true))
globalEnabledNetworkContext = ctx
} else {
globalEnabledNetworkContext.T = t
globalEnabledNetworkContext.Require = require.New(t)
}
return globalEnabledNetworkContext
}
type TestContext struct {
context.Context
*testing.T
*tor.Tor
Require *require.Assertions
CloseTorOnClose bool
}
func NewTestContext(t *testing.T, conf *tor.StartConf) *TestContext {
// Build start conf
if conf == nil {
conf = &tor.StartConf{}
}
conf.ExePath = torExePath
if torVerbose {
conf.DebugWriter = os.Stdout
conf.NoHush = true
} else {
conf.ExtraArgs = append(conf.ExtraArgs, "--quiet")
}
ret := &TestContext{Context: context.Background(), T: t, Require: require.New(t), CloseTorOnClose: true}
// Start tor
var err error
if ret.Tor, err = tor.Start(ret.Context, conf); err != nil {
defer ret.Close()
t.Fatal(err)
}
return ret
}
func (t *TestContext) Close() {
if t.CloseTorOnClose {
if err := t.Tor.Close(); err != nil {
if t.Failed() {
t.Logf("Failure on close: %v", err)
} else {
t.Errorf("Failure on close: %v", err)
}
}
}
}

View File

@ -1,4 +1,4 @@
package controltest
package tests
import (
"testing"

View File

@ -1,4 +1,4 @@
package controltest
package tests
import (
"io/ioutil"

View File

@ -0,0 +1,3 @@
package tests
// TODO: test several event parsers

View File

@ -1,4 +1,4 @@
package controltest
package tests
import "testing"

View File

@ -1,4 +1,4 @@
package controltest
package tests
import (
"strings"

2
tests/doc.go Normal file
View File

@ -0,0 +1,2 @@
// Package tests contains integration tests.
package tests

44
tests/tor_dialer_test.go Normal file
View File

@ -0,0 +1,44 @@
package tests
import (
"context"
"encoding/json"
"io/ioutil"
"net/http"
"testing"
"time"
"golang.org/x/net/context/ctxhttp"
)
func TestDialerSimpleHTTP(t *testing.T) {
ctx := GlobalEnabledNetworkContext(t)
httpClient := httpClient(ctx)
// IsTor check
byts := httpGet(ctx, httpClient, "https://check.torproject.org/api/ip")
jsn := map[string]interface{}{}
ctx.Require.NoError(json.Unmarshal(byts, &jsn))
ctx.Require.True(jsn["IsTor"].(bool))
}
func httpClient(ctx *TestContext) *http.Client {
// 15 seconds max to dial
dialCtx, dialCancel := context.WithTimeout(ctx, 15*time.Second)
defer dialCancel()
// Make connection
dialer, err := ctx.Dialer(dialCtx, nil)
ctx.Require.NoError(err)
return &http.Client{Transport: &http.Transport{DialContext: dialer.DialContext}}
}
func httpGet(ctx *TestContext, client *http.Client, url string) []byte {
// We'll give it 30 seconds to respond
callCtx, callCancel := context.WithTimeout(ctx, 30*time.Second)
defer callCancel()
resp, err := ctxhttp.Get(callCtx, client, url)
ctx.Require.NoError(err)
defer resp.Body.Close()
respBytes, err := ioutil.ReadAll(resp.Body)
ctx.Require.NoError(err)
return respBytes
}

46
tests/tor_listen_test.go Normal file
View File

@ -0,0 +1,46 @@
package tests
import (
"context"
"net/http"
"testing"
"time"
"github.com/cretz/bine/tor"
)
func TestListenSimpleHTTPV2(t *testing.T) {
ctx := GlobalEnabledNetworkContext(t)
// Create an onion service to listen on random port but show as 80
conf := &tor.ListenConf{RemotePorts: []int{80}}
client, server, onion := startHTTPServer(ctx, conf, "/test", func(w http.ResponseWriter, r *http.Request) {
_, err := w.Write([]byte("Test Content"))
ctx.Require.NoError(err)
})
defer server.Shutdown(ctx)
// Call /test
byts := httpGet(ctx, client, "http://"+onion.ID+".onion/test")
ctx.Require.Equal("Test Content", string(byts))
}
// Only have to shutdown the HTTP server
func startHTTPServer(
ctx *TestContext,
listenConf *tor.ListenConf,
handlePattern string,
handler func(http.ResponseWriter, *http.Request),
) (*http.Client, *http.Server, *tor.OnionService) {
httpClient := httpClient(ctx)
// Wait at most a few minutes for the entire test
listenCtx, listenCancel := context.WithTimeout(context.Background(), 4*time.Minute)
defer listenCancel()
// Create an onion service to listen on random port but show as 80
onion, err := ctx.Listen(listenCtx, listenConf)
ctx.Require.NoError(err)
// Make HTTP server
mux := http.NewServeMux()
mux.HandleFunc(handlePattern, handler)
httpServer := &http.Server{Handler: mux}
go func() { ctx.Require.Equal(http.ErrServerClosed, httpServer.Serve(onion)) }()
return httpClient, httpServer, onion
}

View File

@ -102,6 +102,11 @@ type StartConf struct {
// NoHush if true does not set --hush. By default --hush is set.
NoHush bool
// NoAutoSocksPort if true does not set "--SocksPort auto" as is done by
// default. This means the caller could set their own or just let it
// default to 9050.
NoAutoSocksPort bool
}
// Start a Tor instance and connect to it. If ctx is nil, context.Background()
@ -175,6 +180,9 @@ func (t *Tor) startProcess(ctx context.Context, conf *StartConf) error {
if !conf.NoHush {
args = append(args, "--hush")
}
if !conf.NoAutoSocksPort {
args = append(args, "--SocksPort", "auto")
}
// If there is no Torrc file, create a blank temp one
torrcFileName := conf.TorrcFile
if torrcFileName == "" {