go.etcd.io/etcd@v3.3.27+incompatible/pkg/fileutil/purge_test.go (about)

     1  // Copyright 2015 The etcd Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package fileutil
    16  
    17  import (
    18  	"fmt"
    19  	"io/ioutil"
    20  	"os"
    21  	"path/filepath"
    22  	"reflect"
    23  	"testing"
    24  	"time"
    25  )
    26  
    27  func TestPurgeFile(t *testing.T) {
    28  	dir, err := ioutil.TempDir("", "purgefile")
    29  	if err != nil {
    30  		t.Fatal(err)
    31  	}
    32  	defer os.RemoveAll(dir)
    33  
    34  	// minimal file set
    35  	for i := 0; i < 3; i++ {
    36  		f, ferr := os.Create(filepath.Join(dir, fmt.Sprintf("%d.test", i)))
    37  		if ferr != nil {
    38  			t.Fatal(err)
    39  		}
    40  		f.Close()
    41  	}
    42  
    43  	stop, purgec := make(chan struct{}), make(chan string, 10)
    44  
    45  	// keep 3 most recent files
    46  	errch := purgeFile(dir, "test", 3, time.Millisecond, stop, purgec, nil)
    47  	select {
    48  	case f := <-purgec:
    49  		t.Errorf("unexpected purge on %q", f)
    50  	case <-time.After(10 * time.Millisecond):
    51  	}
    52  
    53  	// rest of the files
    54  	for i := 4; i < 10; i++ {
    55  		go func(n int) {
    56  			f, ferr := os.Create(filepath.Join(dir, fmt.Sprintf("%d.test", n)))
    57  			if ferr != nil {
    58  				t.Fatal(err)
    59  			}
    60  			f.Close()
    61  		}(i)
    62  	}
    63  
    64  	// watch files purge away
    65  	for i := 4; i < 10; i++ {
    66  		select {
    67  		case <-purgec:
    68  		case <-time.After(time.Second):
    69  			t.Errorf("purge took too long")
    70  		}
    71  	}
    72  
    73  	fnames, rerr := ReadDir(dir)
    74  	if rerr != nil {
    75  		t.Fatal(rerr)
    76  	}
    77  	wnames := []string{"7.test", "8.test", "9.test"}
    78  	if !reflect.DeepEqual(fnames, wnames) {
    79  		t.Errorf("filenames = %v, want %v", fnames, wnames)
    80  	}
    81  
    82  	// no error should be reported from purge routine
    83  	select {
    84  	case f := <-purgec:
    85  		t.Errorf("unexpected purge on %q", f)
    86  	case err := <-errch:
    87  		t.Errorf("unexpected purge error %v", err)
    88  	case <-time.After(10 * time.Millisecond):
    89  	}
    90  	close(stop)
    91  }
    92  
    93  func TestPurgeFileHoldingLockFile(t *testing.T) {
    94  	dir, err := ioutil.TempDir("", "purgefile")
    95  	if err != nil {
    96  		t.Fatal(err)
    97  	}
    98  	defer os.RemoveAll(dir)
    99  
   100  	for i := 0; i < 10; i++ {
   101  		var f *os.File
   102  		f, err = os.Create(filepath.Join(dir, fmt.Sprintf("%d.test", i)))
   103  		if err != nil {
   104  			t.Fatal(err)
   105  		}
   106  		f.Close()
   107  	}
   108  
   109  	// create a purge barrier at 5
   110  	p := filepath.Join(dir, fmt.Sprintf("%d.test", 5))
   111  	l, err := LockFile(p, os.O_WRONLY, PrivateFileMode)
   112  	if err != nil {
   113  		t.Fatal(err)
   114  	}
   115  
   116  	stop, purgec := make(chan struct{}), make(chan string, 10)
   117  	errch := purgeFile(dir, "test", 3, time.Millisecond, stop, purgec, nil)
   118  
   119  	for i := 0; i < 5; i++ {
   120  		select {
   121  		case <-purgec:
   122  		case <-time.After(time.Second):
   123  			t.Fatalf("purge took too long")
   124  		}
   125  	}
   126  
   127  	fnames, rerr := ReadDir(dir)
   128  	if rerr != nil {
   129  		t.Fatal(rerr)
   130  	}
   131  
   132  	wnames := []string{"5.test", "6.test", "7.test", "8.test", "9.test"}
   133  	if !reflect.DeepEqual(fnames, wnames) {
   134  		t.Errorf("filenames = %v, want %v", fnames, wnames)
   135  	}
   136  
   137  	select {
   138  	case s := <-purgec:
   139  		t.Errorf("unexpected purge %q", s)
   140  	case err = <-errch:
   141  		t.Errorf("unexpected purge error %v", err)
   142  	case <-time.After(10 * time.Millisecond):
   143  	}
   144  
   145  	// remove the purge barrier
   146  	if err = l.Close(); err != nil {
   147  		t.Fatal(err)
   148  	}
   149  
   150  	// wait for rest of purges (5, 6)
   151  	for i := 0; i < 2; i++ {
   152  		select {
   153  		case <-purgec:
   154  		case <-time.After(time.Second):
   155  			t.Fatalf("purge took too long")
   156  		}
   157  	}
   158  
   159  	fnames, rerr = ReadDir(dir)
   160  	if rerr != nil {
   161  		t.Fatal(rerr)
   162  	}
   163  	wnames = []string{"7.test", "8.test", "9.test"}
   164  	if !reflect.DeepEqual(fnames, wnames) {
   165  		t.Errorf("filenames = %v, want %v", fnames, wnames)
   166  	}
   167  
   168  	select {
   169  	case f := <-purgec:
   170  		t.Errorf("unexpected purge on %q", f)
   171  	case err := <-errch:
   172  		t.Errorf("unexpected purge error %v", err)
   173  	case <-time.After(10 * time.Millisecond):
   174  	}
   175  
   176  	close(stop)
   177  }