<commit_before>package rpc

import (
	"bufio"
	"cgl.tideland.biz/asserts"
	"github.com/mitchellh/packer/packer"
	"io"
	"net/rpc"
	"testing"
	"time"
)

type testCommunicator struct {
	startCalled bool
	startCmd    *packer.RemoteCmd

	uploadCalled bool
	uploadPath   string
	uploadData   string

	downloadCalled bool
	downloadPath   string
}

func (t *testCommunicator) Start(cmd *packer.RemoteCmd) error {
	t.startCalled = true
	t.startCmd = cmd
	return nil
}

func (t *testCommunicator) Upload(path string, reader io.Reader) (err error) {
	t.uploadCalled = true
	t.uploadPath = path
	t.uploadData, err = bufio.NewReader(reader).ReadString('\n')
	return
}

func (t *testCommunicator) Download(path string, writer io.Writer) error {
	t.downloadCalled = true
	t.downloadPath = path
	writer.Write([]byte("download\n"))

	return nil
}

func TestCommunicatorRPC(t *testing.T) {
	assert := asserts.NewTestingAsserts(t, true)

	// Create the interface to test
	c := new(testCommunicator)

	// Start the server
	server := rpc.NewServer()
	RegisterCommunicator(server, c)
	address := serveSingleConn(server)

	// Create the client over RPC and run some methods to verify it works
	client, err := rpc.Dial("tcp", address)
	assert.Nil(err, "should be able to connect")
	remote := Communicator(client)

	// The remote command we'll use
	stdin_r, stdin_w := io.Pipe()
	stdout_r, stdout_w := io.Pipe()
	stderr_r, stderr_w := io.Pipe()

	var cmd packer.RemoteCmd
	cmd.Command = "foo"
	cmd.Stdin = stdin_r
	cmd.Stdout = stdout_w
	cmd.Stderr = stderr_w

	// Test Start
	err = remote.Start(&cmd)
	assert.Nil(err, "should not have an error")

	// Test that we can read from stdout
	c.startCmd.Stdout.Write([]byte("outfoo\n"))
	bufOut := bufio.NewReader(stdout_r)
	data, err := bufOut.ReadString('\n')
	assert.Nil(err, "should have no problem reading stdout")
	assert.Equal(data, "outfoo\n", "should be correct stdout")

	// Test that we can read from stderr
	c.startCmd.Stderr.Write([]byte("errfoo\n"))
	bufErr := bufio.NewReader(stderr_r)
	data, err = bufErr.ReadString('\n')
	assert.Nil(err, "should have no problem reading stderr")
	assert.Equal(data, "errfoo\n", "should be correct stderr")

	// Test that we can write to stdin
	stdin_w.Write([]byte("infoo\n"))
	bufIn := bufio.NewReader(c.startCmd.Stdin)
	data, err = bufIn.ReadString('\n')
	assert.Nil(err, "should have no problem reading stdin")
	assert.Equal(data, "infoo\n", "should be correct stdin")

	// Test that we can get the exit status properly
	c.startCmd.SetExited(42)

	for i := 0; i < 5; i++ {
		if cmd.Exited {
			assert.Equal(cmd.ExitStatus, 42, "should have proper exit status")
			break
		}

		time.Sleep(50 * time.Millisecond)
	}

	assert.True(cmd.Exited, "should have exited")

	// Test that we can upload things
	uploadR, uploadW := io.Pipe()
	go uploadW.Write([]byte("uploadfoo\n"))
	err = remote.Upload("foo", uploadR)
	assert.Nil(err, "should not error")
	assert.True(c.uploadCalled, "should be called")
	assert.Equal(c.uploadPath, "foo", "should be correct path")
	assert.Equal(c.uploadData, "uploadfoo\n", "should have the proper data")

	// Test that we can download things
	downloadR, downloadW := io.Pipe()
	downloadDone := make(chan bool)
	var downloadData string
	var downloadErr error

	go func() {
		bufDownR := bufio.NewReader(downloadR)
		downloadData, downloadErr = bufDownR.ReadString('\n')
		downloadDone <- true
	}()<commit_msg>packer/rpc: get rid of data races in tests<commit_after>package rpc

import (
	"bufio"
	"cgl.tideland.biz/asserts"
	"github.com/mitchellh/packer/packer"
	"io"
	"net/rpc"
	"testing"
	"time"
)

type testCommunicator struct {
	startCalled bool
	startCmd    *packer.RemoteCmd

	uploadCalled bool
	uploadPath   string
	uploadData   string

	downloadCalled bool
	downloadPath   string
}

func (t *testCommunicator) Start(cmd *packer.RemoteCmd) error {
	t.startCalled = true
	t.startCmd = cmd
	return nil
}

func (t *testCommunicator) Upload(path string, reader io.Reader) (err error) {
	t.uploadCalled = true
	t.uploadPath = path
	t.uploadData, err = bufio.NewReader(reader).ReadString('\n')
	return
}

func (t *testCommunicator) Download(path string, writer io.Writer) error {
	t.downloadCalled = true
	t.downloadPath = path
	writer.Write([]byte("download\n"))

	return nil
}

func TestCommunicatorRPC(t *testing.T) {
	assert := asserts.NewTestingAsserts(t, true)

	// Create the interface to test
	c := new(testCommunicator)

	// Start the server
	server := rpc.NewServer()
	RegisterCommunicator(server, c)
	address := serveSingleConn(server)

	// Create the client over RPC and run some methods to verify it works
	client, err := rpc.Dial("tcp", address)
	assert.Nil(err, "should be able to connect")
	remote := Communicator(client)

	// The remote command we'll use
	stdin_r, stdin_w := io.Pipe()
	stdout_r, stdout_w := io.Pipe()
	stderr_r, stderr_w := io.Pipe()

	var cmd packer.RemoteCmd
	cmd.Command = "foo"
	cmd.Stdin = stdin_r
	cmd.Stdout = stdout_w
	cmd.Stderr = stderr_w

	// Test Start
	err = remote.Start(&cmd)
	assert.Nil(err, "should not have an error")

	// Test that we can read from stdout
	c.startCmd.Stdout.Write([]byte("outfoo\n"))
	bufOut := bufio.NewReader(stdout_r)
	data, err := bufOut.ReadString('\n')
	assert.Nil(err, "should have no problem reading stdout")
	assert.Equal(data, "outfoo\n", "should be correct stdout")

	// Test that we can read from stderr
	c.startCmd.Stderr.Write([]byte("errfoo\n"))
	bufErr := bufio.NewReader(stderr_r)
	data, err = bufErr.ReadString('\n')
	assert.Nil(err, "should have no problem reading stderr")
	assert.Equal(data, "errfoo\n", "should be correct stderr")

	// Test that we can write to stdin
	stdin_w.Write([]byte("infoo\n"))
	bufIn := bufio.NewReader(c.startCmd.Stdin)
	data, err = bufIn.ReadString('\n')
	assert.Nil(err, "should have no problem reading stdin")
	assert.Equal(data, "infoo\n", "should be correct stdin")

	// Test that we can get the exit status properly
	c.startCmd.SetExited(42)

	for i := 0; i < 5; i++ {
		cmd.Lock()
		exited := cmd.Exited
		cmd.Unlock()
		if exited {
			assert.Equal(cmd.ExitStatus, 42, "should have proper exit status")
			break
		}

		time.Sleep(50 * time.Millisecond)
	}

	assert.True(cmd.Exited, "should have exited")

	// Test that we can upload things
	uploadR, uploadW := io.Pipe()
	go uploadW.Write([]byte("uploadfoo\n"))
	err = remote.Upload("foo", uploadR)
	assert.Nil(err, "should not error")
	assert.True(c.uploadCalled, "should be called")
	assert.Equal(c.uploadPath, "foo", "should be correct path")
	assert.Equal(c.uploadData, "uploadfoo\n", "should have the proper data")

	// Test that we can download things
	downloadR, downloadW := io.Pipe()
	downloadDone := make(chan bool)
	var downloadData string
	var downloadErr error

	go func() {
		bufDownR := bufio.NewReader(downloadR)
		downloadData, downloadErr = bufDownR.ReadString('\n')
		downloadDone <- true
	}()
{'fraction_non_alphanumeric': 0.13248111563044743, 'fraction_numerical': 0.002324230098779779, 'mean_word_length': 4.255725190839694, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 32, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7035405', 'n_tokens_mistral': 2514, 'n_tokens_neox': 2437, 'n_words': 661}