<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package flushfs_test

import (
	"bufio"
	"encoding/hex"
	"fmt"
	"io"
	"os"
	"path"
	"runtime"
	"syscall"
	"testing"
	"unsafe"

	"golang.org/x/sys/unix"

	"github.com/jacobsa/bazilfuse"
	"github.com/jacobsa/fuse/fsutil"
	"github.com/jacobsa/fuse/samples"
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
)

func TestFlushFS(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

type flushFSTest struct {
	samples.SubprocessTest

	// Files to which mount_sample is writing reported flushes and fsyncs.
	flushes *os.File
	fsyncs  *os.File

	// File handles that are closed in TearDown if non-nil.
	f1 *os.File
	f2 *os.File
}

func (t *flushFSTest) setUp(
	ti *TestInfo,
	flushErr bazilfuse.Errno,
	fsyncErr bazilfuse.Errno) {
	var err error

	// Set up files to receive flush and fsync reports.
	t.flushes, err = fsutil.AnonymousFile("")
	AssertEq(nil, err)

	t.fsyncs, err = fsutil.AnonymousFile("")
	AssertEq(nil, err)

	// Set up test config.
	t.MountType = "flushfs"
	t.MountFlags = []string{
		"--flushfs.flush_error",
		fmt.Sprintf("%d", int(flushErr)),

		"--flushfs.fsync_error",
		fmt.Sprintf("%d", int(fsyncErr)),
	}

	t.MountFiles = map[string]*os.File{
		"flushfs.flushes_file": t.flushes,
		"flushfs.fsyncs_file":  t.fsyncs,
	}

	t.SubprocessTest.SetUp(ti)
}

func (t *flushFSTest) TearDown() {
	// Unlink reporting files.
	os.Remove(t.flushes.Name())
	os.Remove(t.fsyncs.Name())

	// Close reporting files.
	t.flushes.Close()
	t.fsyncs.Close()

	// Close test files if non-nil.
	if t.f1 != nil {
		ExpectEq(nil, t.f1.Close())
	}

	if t.f2 != nil {
		ExpectEq(nil, t.f2.Close())
	}

	// Finish tearing down.
	t.SubprocessTest.TearDown()
}

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

func readReports(f *os.File) (reports []string, err error) {
	// Seek the file to the start.
	_, err = f.Seek(0, 0)
	if err != nil {
		err = fmt.Errorf("Seek: %v", err)
		return
	}

	// We expect reports to end in a newline (including the final one).
	reader := bufio.NewReader(f)
	for {
		var record []byte
		record, err = reader.ReadBytes('\n')
		if err == io.EOF {
			if len(record) != 0 {
				err = fmt.Errorf("Unexpected record:\n%s", hex.Dump(record))
				return
			}

			err = nil
			return
		}

		if err != nil {
			err = fmt.Errorf("ReadBytes: %v", err)
			return
		}

		// Strip the newline.
		reports = append(reports, string(record[:len(record)-1]))
	}
}

// Return a copy of the current contents of t.flushes.
func (t *flushFSTest) getFlushes() (p []string) {
	var err error
	if p, err = readReports(t.flushes); err != nil {
		panic(err)
	}

	return
}

// Return a copy of the current contents of t.fsyncs.
func (t *flushFSTest) getFsyncs() (p []string) {
	var err error
	if p, err = readReports(t.fsyncs); err != nil {
		panic(err)
	}

	return
}

// Like syscall.Dup2, but correctly annotates the syscall as blocking. See here
// for more info: https://github.com/golang/go/issues/10202
func dup2(oldfd int, newfd int) (err error) {
	_, _, e1 := syscall.Syscall(
		syscall.SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)

	if e1 != 0 {
		err = e1
	}

	return
}

// Call msync(2) on a slice previously returned by mmap(2).
func msync(p []byte) (err error) {
	_, _, errno := unix.Syscall(
		unix.SYS_MMAP,
		uintptr(unsafe.Pointer(&p[0])),
		uintptr(len(p)),
		0)

	if errno != 0 {
		err = errno
		return
	}
<commit_msg>Oops, msync helper is broken.<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package flushfs_test

import (
	"bufio"
	"encoding/hex"
	"fmt"
	"io"
	"os"
	"path"
	"runtime"
	"syscall"
	"testing"
	"unsafe"

	"golang.org/x/sys/unix"

	"github.com/jacobsa/bazilfuse"
	"github.com/jacobsa/fuse/fsutil"
	"github.com/jacobsa/fuse/samples"
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
)

func TestFlushFS(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

type flushFSTest struct {
	samples.SubprocessTest

	// Files to which mount_sample is writing reported flushes and fsyncs.
	flushes *os.File
	fsyncs  *os.File

	// File handles that are closed in TearDown if non-nil.
	f1 *os.File
	f2 *os.File
}

func (t *flushFSTest) setUp(
	ti *TestInfo,
	flushErr bazilfuse.Errno,
	fsyncErr bazilfuse.Errno) {
	var err error

	// Set up files to receive flush and fsync reports.
	t.flushes, err = fsutil.AnonymousFile("")
	AssertEq(nil, err)

	t.fsyncs, err = fsutil.AnonymousFile("")
	AssertEq(nil, err)

	// Set up test config.
	t.MountType = "flushfs"
	t.MountFlags = []string{
		"--flushfs.flush_error",
		fmt.Sprintf("%d", int(flushErr)),

		"--flushfs.fsync_error",
		fmt.Sprintf("%d", int(fsyncErr)),
	}

	t.MountFiles = map[string]*os.File{
		"flushfs.flushes_file": t.flushes,
		"flushfs.fsyncs_file":  t.fsyncs,
	}

	t.SubprocessTest.SetUp(ti)
}

func (t *flushFSTest) TearDown() {
	// Unlink reporting files.
	os.Remove(t.flushes.Name())
	os.Remove(t.fsyncs.Name())

	// Close reporting files.
	t.flushes.Close()
	t.fsyncs.Close()

	// Close test files if non-nil.
	if t.f1 != nil {
		ExpectEq(nil, t.f1.Close())
	}

	if t.f2 != nil {
		ExpectEq(nil, t.f2.Close())
	}

	// Finish tearing down.
	t.SubprocessTest.TearDown()
}

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

func readReports(f *os.File) (reports []string, err error) {
	// Seek the file to the start.
	_, err = f.Seek(0, 0)
	if err != nil {
		err = fmt.Errorf("Seek: %v", err)
		return
	}

	// We expect reports to end in a newline (including the final one).
	reader := bufio.NewReader(f)
	for {
		var record []byte
		record, err = reader.ReadBytes('\n')
		if err == io.EOF {
			if len(record) != 0 {
				err = fmt.Errorf("Unexpected record:\n%s", hex.Dump(record))
				return
			}

			err = nil
			return
		}

		if err != nil {
			err = fmt.Errorf("ReadBytes: %v", err)
			return
		}

		// Strip the newline.
		reports = append(reports, string(record[:len(record)-1]))
	}
}

// Return a copy of the current contents of t.flushes.
func (t *flushFSTest) getFlushes() (p []string) {
	var err error
	if p, err = readReports(t.flushes); err != nil {
		panic(err)
	}

	return
}

// Return a copy of the current contents of t.fsyncs.
func (t *flushFSTest) getFsyncs() (p []string) {
	var err error
	if p, err = readReports(t.fsyncs); err != nil {
		panic(err)
	}

	return
}

// Like syscall.Dup2, but correctly annotates the syscall as blocking. See here
// for more info: https://github.com/golang/go/issues/10202
func dup2(oldfd int, newfd int) (err error) {
	_, _, e1 := syscall.Syscall(
		syscall.SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)

	if e1 != 0 {
		err = e1
	}

	return
}

// Call msync(2) on a slice previously returned by mmap(2).
func msync(p []byte) (err error) {
	_, _, errno := unix.Syscall(
		unix.SYS_MSYNC,
		uintptr(unsafe.Pointer(&p[0])),
		uintptr(len(p)),
		0)

	if errno != 0 {
		err = errno
		return
	}

{'fraction_non_alphanumeric': 0.20210377023992435, 'fraction_numerical': 0.00850963243115471, 'mean_word_length': 2.496694214876033, 'pattern_counts': {'":': 4, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4101074', 'n_tokens_mistral': 3225, 'n_tokens_neox': 2974, 'n_words': 830}