// This test is a copy&paste of `TestRmTouch` but swapping the rm, for truncation
func TestMvTouch(t *testing.T) {
	require := require.New(t)
	assert := assert.New(t)

	withTempFile(t, time.Millisecond*200, func(t *testing.T, filename string, file *os.File) error {
		follow, err := tailer.NewFile(filename)
		require.NoError(err, "Failed to create tailer.File")

		want := make([]byte, 100)
		for i := 0; i < 100; i++ {
			want[i] = byte(i)
		}

		t.Log("Want:", want)

		go func() {
			max := len(want)
			step := max / 10
			for i := 0; i < max; i += step {
				if i == max/2 {
					// CHANGES FROM `TestRmTouch` START HERE
					t.Log("Moving the old file out of the way", file)
					require.NoError(os.Rename(filename, filename+".old"), "Unable to rename the file")

					file, err = os.Create(filename)
					require.NoError(err, "failed to create new test file: %v", err)
					t.Log("File created again", file)
					// CHANGES FROM `TestRmTouch` STOP HERE
				}

				block := want[i : i+step]
				t.Logf("Writing block{%v} to file(%v)\n", block, file)
				file.Write(block)

				file.Sync()
				time.Sleep(time.Millisecond * time.Duration(step))
			}
			t.Log("Finished writing out all the bytes")
		}()

		got := make([]byte, len(want))
		_, err = io.ReadAtLeast(follow, got, 51)
		assert.NoError(err)

		t.Log("Got:", got)

		return nil
	})
}
// This test is a copy&paste of `TestRmTouch` but swapping the rm, for truncation
func TestTruncation(t *testing.T) {
	require := require.New(t)
	assert := assert.New(t)

	withTempFile(t, time.Millisecond*200, func(t *testing.T, filename string, file *os.File) error {
		follow, err := tailer.NewFile(filename)
		require.NoError(err, "Failed to create tailer.File")

		want := make([]byte, 100)
		for i := 0; i < 100; i++ {
			want[i] = byte(i)
		}

		t.Log("Want:", want)

		go func() {
			max := len(want)
			step := max / 10
			for i := 0; i < max; i += step {
				if i == max/2 {
					// CHANGES FROM `TestRmTouch` START HERE
					t.Log("truncating the file")
					file, err := os.OpenFile(filename, os.O_TRUNC, os.ModeTemporary)
					require.NoError(err, "unable to truncate file: %v", err)
					require.NoError(file.Close(), "failed to close the truncated file")
					t.Log("file truncated:", file)
					// CHANGES FROM `TestRmTouch` STOP HERE
				}

				block := want[i : i+step]
				t.Logf("Writing block{%v} to file(%v)\n", block, file)
				file.Write(block)

				file.Sync()
				time.Sleep(time.Millisecond * time.Duration(step))
			}
			t.Log("Finished writing out all the bytes")
		}()

		got := make([]byte, len(want))
		_, err = io.ReadAtLeast(follow, got, 51)
		assert.NoError(err)

		t.Log("Got:", got)

		return nil
	})
}
Beispiel #3
0
// Run for 50ms constantly trying to read from something that has nothing to read
// This is pretty much here to make sure we don't let our Reader "spin" i.e. return (0, nil)
func TestSpinningReader(t *testing.T) {
	require := require.New(t)
	assert := assert.New(t)

	withTempFile(t, time.Millisecond*150, func(t *testing.T, filename string, file *os.File) error {
		tail, err := tailer.NewFile(filename)
		require.NoError(err, "Failed to create tailer.File")

		// Touch the file repeatedly
		go func() {
			for _ = range time.Tick(time.Millisecond * 5) {
				t.Log("Touching the file")
				os.Chtimes(filename, time.Now(), time.Now())
			}
		}()

		// Read from the file as quickly as possible
		var readCount int
		go func() {
			buf := make([]byte, 1000)
			for stop := time.After(time.Millisecond * 50); ; {
				select {
				case <-stop:
					return
				default:
					t.Log("Read called")
					_, err := tail.Read(buf)
					assert.NoError(err, "read error: %v", err)
					t.Log("Read completed")
					readCount++
					if readCount > 5 {
						assert.Fail("Spinning on read")
					}
				}
			}
		}()

		// This sleep & the go func() of the code above is there because Read should deadlock the thread it is running in
		time.Sleep(time.Millisecond * 50)

		t.Logf("Reader read '%v' times", readCount)
		return nil
	})
}
Beispiel #4
0
// Can we do the most basic thing, can we follow writes to the file overtime
func TestCanFollowFile(t *testing.T) {
	require := require.New(t)
	assert := assert.New(t)

	withTempFile(t, time.Millisecond*200, func(t *testing.T, filename string, file *os.File) error {
		tail, err := tailer.NewFile(filename)
		require.NoError(err, "Failed to create tailer.File")

		go func() {
			for i := 0; i < 10; i++ {
				t.Logf("Writing: %v", i)
				file.Write([]byte{byte(i)})
				time.Sleep(time.Millisecond * 10)
			}
		}()

		t.Log("Preparing to read 10 bytes")
		_, err = io.ReadAtLeast(tail, make([]byte, 10), 10)
		t.Log("Read 10 bytes, err ->", err)
		assert.NoError(err, "Read shouldn't return an error here")
		return err
	})
}
Beispiel #5
0
// Make sure this adheres to a io.ReadCloser & check that reads after closes return (0, io.EOF)
func TestBasicImpl(t *testing.T) {
	require := require.New(t)
	assert := assert.New(t)

	var (
		tail io.ReadCloser
		n    int
		err  error
	)
	withTempFile(t, time.Millisecond*150, func(t *testing.T, filename string, file *os.File) error {
		tail, err = tailer.NewFile(filename)
		require.NoError(err, "Failed to create tailer.File")

		err = tail.Close()
		require.NoError(err, "Failed to close tailer.File")

		n, err = tail.Read(make([]byte, 1))

		assert.Equal(0, n, "Calls to Read after Close is called should return 0 bytes read")
		assert.Equal(io.EOF, err, "Calls to Read after Close is called should return io.EOF as their error")

		return nil
	})
}