github.com/decred/politeia@v1.4.0/politeiad/backend/gitbe/journal_test.go (about)

     1  // Copyright (c) 2017-2020 The Decred developers
     2  // Use of this source code is governed by an ISC
     3  // license that can be found in the LICENSE file.
     4  
     5  package gitbe
     6  
     7  import (
     8  	"errors"
     9  	"fmt"
    10  	"io"
    11  	"os"
    12  	"path/filepath"
    13  	"testing"
    14  
    15  	"golang.org/x/sync/errgroup"
    16  )
    17  
    18  func testExact(j *Journal, filename string, count int) error {
    19  	// Test replay exact
    20  	err := j.Open(filename)
    21  	if err != nil {
    22  		return err
    23  	}
    24  	i := 0
    25  	for ; ; i++ {
    26  		err = j.Replay(filename, func(s string) error {
    27  			ss := fmt.Sprintf("%v", i)
    28  			if ss != s {
    29  				return fmt.Errorf("not equal: %v %v", ss, s)
    30  			}
    31  			return nil
    32  		})
    33  		if errors.Is(err, io.EOF) {
    34  			if i > count {
    35  				return fmt.Errorf("ran too many times")
    36  			}
    37  			break
    38  		} else if err != nil {
    39  			return err
    40  		}
    41  	}
    42  	if i != count {
    43  		return fmt.Errorf("invalid count: %v %v", i, count)
    44  	}
    45  
    46  	return nil
    47  }
    48  
    49  func TestJournalExact(t *testing.T) {
    50  	dir, err := os.MkdirTemp("", "journal")
    51  	t.Logf("TestJournalExact: %v", dir)
    52  	if err != nil {
    53  		t.Fatal(err)
    54  	}
    55  	j := NewJournal()
    56  
    57  	// Test journal
    58  	count := 1000
    59  	filename := filepath.Join(dir, "file1")
    60  	for i := 0; i < count; i++ {
    61  		err = j.Journal(filename, fmt.Sprintf("%v", i))
    62  		if err != nil {
    63  			t.Fatalf("%v: %v", i, err)
    64  		}
    65  	}
    66  
    67  	err = testExact(j, filename, count)
    68  	if err != nil {
    69  		t.Fatal(err)
    70  	}
    71  
    72  	err = j.Close(filename)
    73  	if err != nil {
    74  		t.Fatal(err)
    75  	}
    76  
    77  	os.RemoveAll(dir)
    78  }
    79  
    80  func TestJournalDoubleOpen(t *testing.T) {
    81  	dir, err := os.MkdirTemp("", "journal")
    82  	if err != nil {
    83  		t.Fatal(err)
    84  	}
    85  	t.Logf("TestJournalDoubleOpen: %v", dir)
    86  
    87  	j := NewJournal()
    88  	filename := filepath.Join(dir, "file1")
    89  	err = j.Journal(filename, "journal this")
    90  	if err != nil {
    91  		t.Fatal(err)
    92  	}
    93  
    94  	err = j.Open(filename)
    95  	if err != nil {
    96  		t.Fatal(err)
    97  	}
    98  
    99  	err = j.Open(filename)
   100  	if !errors.Is(err, ErrBusy) {
   101  		t.Fatal(err)
   102  	}
   103  
   104  	os.RemoveAll(dir)
   105  }
   106  
   107  func TestJournalDoubleClose(t *testing.T) {
   108  	dir, err := os.MkdirTemp("", "journal")
   109  	if err != nil {
   110  		t.Fatal(err)
   111  	}
   112  	t.Logf("TestJournalDoubleClose: %v", dir)
   113  
   114  	j := NewJournal()
   115  	filename := filepath.Join(dir, "file1")
   116  	err = j.Journal(filename, "journal this")
   117  	if err != nil {
   118  		t.Fatal(err)
   119  	}
   120  
   121  	err = j.Open(filename)
   122  	if err != nil {
   123  		t.Fatal(err)
   124  	}
   125  
   126  	err = j.Close(filename)
   127  	if err != nil {
   128  		t.Fatal(err)
   129  	}
   130  
   131  	err = j.Close(filename)
   132  	if !errors.Is(err, ErrNotFound) {
   133  		t.Fatal(err)
   134  	}
   135  
   136  	os.RemoveAll(dir)
   137  }
   138  
   139  func TestJournalConcurrent(t *testing.T) {
   140  	dir, err := os.MkdirTemp("", "journal")
   141  	t.Logf("TestJournalConcurrent: %v", dir)
   142  	if err != nil {
   143  		t.Fatal(err)
   144  	}
   145  
   146  	j := NewJournal()
   147  	// Test concurrent writes
   148  	files := 10
   149  	count := 1000
   150  	var eg errgroup.Group
   151  	for i := 0; i < files; i++ {
   152  		k := i
   153  		eg.Go(func() error {
   154  			filename := filepath.Join(dir, fmt.Sprintf("file%v", k))
   155  			for k := 0; k < count; k++ {
   156  				err := j.Journal(filename, fmt.Sprintf("%v", k))
   157  				if err != nil {
   158  					return err
   159  				}
   160  			}
   161  			return nil
   162  		})
   163  	}
   164  	if err := eg.Wait(); err != nil {
   165  		t.Fatal(err)
   166  	}
   167  
   168  	// Test concurrent reads
   169  	t.Logf("TestJournalConcurrent: reading back %v", dir)
   170  	for i := 0; i < files; i++ {
   171  		k := i
   172  		eg.Go(func() error {
   173  			filename := filepath.Join(dir, fmt.Sprintf("file%v", k))
   174  			return testExact(j, filename, count)
   175  		})
   176  	}
   177  	if err := eg.Wait(); err != nil {
   178  		t.Fatal(err)
   179  	}
   180  
   181  	// Close concurrent
   182  	t.Logf("TestJournalConcurrent: closing %v", dir)
   183  	for i := 0; i < files; i++ {
   184  		k := i
   185  		eg.Go(func() error {
   186  			filename := filepath.Join(dir, fmt.Sprintf("file%v", k))
   187  			return j.Close(filename)
   188  		})
   189  	}
   190  	if err := eg.Wait(); err != nil {
   191  		t.Fatal(err)
   192  	}
   193  
   194  	os.RemoveAll(dir)
   195  }
   196  
   197  func TestJournalConcurrentSame(t *testing.T) {
   198  	dir, err := os.MkdirTemp("", "journal")
   199  	t.Logf("TestJournalConcurrentSame: %v", dir)
   200  	if err != nil {
   201  		t.Fatal(err)
   202  	}
   203  
   204  	j := NewJournal()
   205  
   206  	count := 10000
   207  	check := make(map[int]struct{})
   208  	var eg errgroup.Group
   209  	filename := filepath.Join(dir, "file1")
   210  	for i := 0; i < count; i++ {
   211  		check[i] = struct{}{}
   212  		k := i
   213  		eg.Go(func() error {
   214  			return j.Journal(filename, fmt.Sprintf("%v", k))
   215  		})
   216  	}
   217  	if err := eg.Wait(); err != nil {
   218  		t.Fatal(err)
   219  	}
   220  
   221  	// Read back and make sure all entries exist
   222  	err = j.Open(filename)
   223  	if err != nil {
   224  		t.Fatal(err)
   225  	}
   226  
   227  	i := 0
   228  	for ; ; i++ {
   229  		err = j.Replay(filename, func(s string) error {
   230  			delete(check, i)
   231  			return nil
   232  		})
   233  		if errors.Is(err, io.EOF) {
   234  			if i > count {
   235  				t.Fatalf("ran too many times")
   236  			}
   237  			break
   238  		} else if err != nil {
   239  			t.Fatal(err)
   240  		}
   241  	}
   242  	if i != count {
   243  		t.Fatalf("invalid count: %v %v", i, count)
   244  	}
   245  	if len(check) != 0 {
   246  		t.Fatalf("len != 0")
   247  	}
   248  
   249  	os.RemoveAll(dir)
   250  }
   251  
   252  func TestJournalCopy(t *testing.T) {
   253  	dir, err := os.MkdirTemp("", "journal")
   254  	t.Logf("TestJournalConcurrentCopy: %v", dir)
   255  	if err != nil {
   256  		t.Fatal(err)
   257  	}
   258  
   259  	j := NewJournal()
   260  
   261  	// Test journal
   262  	count := 1000
   263  	filename := filepath.Join(dir, "file1")
   264  	for i := 0; i < count; i++ {
   265  		err = j.Journal(filename, fmt.Sprintf("%v", i))
   266  		if err != nil {
   267  			t.Fatalf("%v: %v", i, err)
   268  		}
   269  	}
   270  
   271  	err = testExact(j, filename, count)
   272  	if err != nil {
   273  		t.Fatal(err)
   274  	}
   275  
   276  	err = j.Close(filename)
   277  	if err != nil {
   278  		t.Fatal(err)
   279  	}
   280  
   281  	// Copy journal fail
   282  	destination := filepath.Join(dir, "") // Try to overwrite dir
   283  	err = j.Copy(filename, destination)
   284  	if err == nil {
   285  		t.Fatalf("Expected error")
   286  	}
   287  
   288  	// Copy journal fail 2
   289  	destination = filepath.Join(dir, "d", "..", "file1") // Try to overwrite same file
   290  	err = j.Copy(filename, destination)
   291  	if !errors.Is(err, ErrSameFile) {
   292  		t.Fatalf("Expected ErrSameFile")
   293  	}
   294  
   295  	// Copy journal
   296  	destination = filepath.Join(dir, "file2")
   297  	err = j.Copy(filename, destination)
   298  	if err != nil {
   299  		t.Fatal(err)
   300  	}
   301  
   302  	// Test Copy
   303  	err = testExact(j, destination, count)
   304  	if err != nil {
   305  		t.Fatal(err)
   306  	}
   307  
   308  	os.RemoveAll(dir)
   309  }