<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 fstesting

import (
	"errors"
	"io"
	"io/ioutil"
	"log"
	"math"
	"math/rand"
	"os"
	"os/user"
	"strconv"
	"strings"
	"time"

	"github.com/googlecloudplatform/gcsfuse/fs"
	"github.com/googlecloudplatform/gcsfuse/timeutil"
	"github.com/jacobsa/fuse"
	"github.com/jacobsa/gcloud/gcs"
	"github.com/jacobsa/gcloud/gcs/gcsutil"
	"github.com/jacobsa/oglematchers"
	"github.com/jacobsa/ogletest"
	"golang.org/x/net/context"
)

// A struct that can be embedded to inherit common file system test behaviors.
type fsTest struct {
	ctx    context.Context
	clock  timeutil.Clock
	bucket gcs.Bucket
	mfs    *fuse.MountedFileSystem

	// Files to close when tearing down. Nil entries are skipped.
	f1 *os.File
	f2 *os.File
}

var _ fsTestInterface = &fsTest{}

func (t *fsTest) setUpFSTest(cfg FSTestConfig) {
	t.ctx = context.Background()
	t.clock = cfg.ServerConfig.Clock
	t.bucket = cfg.ServerConfig.Bucket

	// Set up a temporary directory for mounting.
	mountPoint, err := ioutil.TempDir("", "fs_test")
	if err != nil {
		panic("ioutil.TempDir: " + err.Error())
	}

	// Create a file system server.
	server, err := fs.NewServer(&cfg.ServerConfig)
	if err != nil {
		panic("NewServer: " + err.Error())
	}

	// Mount the file system.
	t.mfs, err = fuse.Mount(mountPoint, server, &fuse.MountConfig{})
	if err != nil {
		panic("Mount: " + err.Error())
	}
}

func (t *fsTest) tearDownFsTest() {
	// Close any files we opened.
	if t.f1 != nil {
		ogletest.ExpectEq(nil, t.f1.Close())
	}

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

	// Unmount the file system. Try again on "resource busy" errors.
	delay := 10 * time.Millisecond
	for {
		err := fuse.Unmount(t.mfs.Dir())
		if err == nil {
			break
		}

		if strings.Contains(err.Error(), "resource busy") {
			log.Println("Resource busy error while unmounting; trying again")
			time.Sleep(delay)
			delay = time.Duration(1.3 * float64(delay))
			continue
		}

		panic("MountedFileSystem.Unmount: " + err.Error())
	}

	if err := t.mfs.Join(t.ctx); err != nil {
		panic("MountedFileSystem.Join: " + err.Error())
	}
}

func (t *fsTest) createWithContents(name string, contents string) error {
	return t.createObjects(map[string]string{name: contents})
}

func (t *fsTest) createObjects(in map[string]string) error {
	err := gcsutil.CreateObjects(t.ctx, t.bucket, in)
	return err<commit_msg>Don't forget to unlink the mount point.<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 fstesting

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"math"
	"math/rand"
	"os"
	"os/user"
	"strconv"
	"strings"
	"time"

	"github.com/googlecloudplatform/gcsfuse/fs"
	"github.com/googlecloudplatform/gcsfuse/timeutil"
	"github.com/jacobsa/fuse"
	"github.com/jacobsa/gcloud/gcs"
	"github.com/jacobsa/gcloud/gcs/gcsutil"
	"github.com/jacobsa/oglematchers"
	"github.com/jacobsa/ogletest"
	"golang.org/x/net/context"
)

// A struct that can be embedded to inherit common file system test behaviors.
type fsTest struct {
	ctx    context.Context
	clock  timeutil.Clock
	bucket gcs.Bucket
	mfs    *fuse.MountedFileSystem
	Dir    string

	// Files to close when tearing down. Nil entries are skipped.
	f1 *os.File
	f2 *os.File
}

var _ fsTestInterface = &fsTest{}

func (t *fsTest) setUpFSTest(cfg FSTestConfig) {
	var err error

	t.ctx = context.Background()
	t.clock = cfg.ServerConfig.Clock
	t.bucket = cfg.ServerConfig.Bucket

	// Set up a temporary directory for mounting.
	t.Dir, err = ioutil.TempDir("", "fs_test")
	if err != nil {
		panic("ioutil.TempDir: " + err.Error())
	}

	// Create a file system server.
	server, err := fs.NewServer(&cfg.ServerConfig)
	if err != nil {
		panic("NewServer: " + err.Error())
	}

	// Mount the file system.
	t.mfs, err = fuse.Mount(t.Dir, server, &fuse.MountConfig{})
	if err != nil {
		panic("Mount: " + err.Error())
	}
}

func (t *fsTest) tearDownFsTest() {
	var err error

	// Close any files we opened.
	if t.f1 != nil {
		ogletest.ExpectEq(nil, t.f1.Close())
	}

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

	// Unmount the file system. Try again on "resource busy" errors.
	delay := 10 * time.Millisecond
	for {
		err := fuse.Unmount(t.mfs.Dir())
		if err == nil {
			break
		}

		if strings.Contains(err.Error(), "resource busy") {
			log.Println("Resource busy error while unmounting; trying again")
			time.Sleep(delay)
			delay = time.Duration(1.3 * float64(delay))
			continue
		}

		panic("MountedFileSystem.Unmount: " + err.Error())
	}

	if err := t.mfs.Join(t.ctx); err != nil {
		panic("MountedFileSystem.Join: " + err.Error())
	}

	// Unlink the mount point.
	if err = os.Remove(t.Dir); err != nil {
		err = fmt.Errorf("Unlinking mount point: %v", err)
		return
	}
}

func (t *fsTest) createWithContents(name string, contents string) error {
	return t.createObjects(map[string]string{name: contents})
}

func (t *fsTest) createObjects(in map[string]string) error {
	err := gcsutil.CreateObjects(t.ctx, t.bucket, in)
	return err
{'fraction_non_alphanumeric': 0.13581652569941444, 'fraction_numerical': 0.006506180871828237, 'mean_word_length': 3.5683506686478457, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, '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': '476064', 'n_tokens_mistral': 2282, 'n_tokens_neox': 2158, 'n_words': 610}