github.com/rohankumardubey/proxyfs@v0.0.0-20210108201508-653efa9ab00e/inode/coalesce_test.go (about)

     1  package inode
     2  
     3  import (
     4  	"testing"
     5  	"time"
     6  
     7  	"github.com/stretchr/testify/assert"
     8  	"github.com/swiftstack/ProxyFS/blunder"
     9  )
    10  
    11  // NB: test setup and such is in api_test.go (look for TestMain function)
    12  
    13  func TestCoalesce(t *testing.T) {
    14  	testSetup(t, false)
    15  
    16  	// We're going to take some files:
    17  	//
    18  	// d1/file1a   (contents "abcd")
    19  	// d1/file1b   (contents "efgh")
    20  	// d2/file2a   (contents "ijkl")
    21  	// d2/file2b   (contents "mnop")
    22  	// d2/file2c   (contents "\0\0st\0\0")
    23  	//
    24  	// and coalesce them into a single file:
    25  	//
    26  	// d1/combined (contents "abcdefghijklmnop\0\0st\0\0")
    27  	//
    28  	// This will also unlink the constituent files from their directories.
    29  
    30  	assert := assert.New(t)
    31  	vh, err := FetchVolumeHandle("TestVolume")
    32  	if !assert.Nil(err) {
    33  		return
    34  	}
    35  
    36  	d1InodeNumber, err := vh.CreateDir(PosixModePerm, 0, 0)
    37  	if !assert.Nil(err) {
    38  		return
    39  	}
    40  	err = vh.Link(RootDirInodeNumber, "d1", d1InodeNumber, false)
    41  	if !assert.Nil(err) {
    42  		return
    43  	}
    44  
    45  	d2InodeNumber, err := vh.CreateDir(PosixModePerm, 0, 0)
    46  	if !assert.Nil(err) {
    47  		return
    48  	}
    49  	err = vh.Link(RootDirInodeNumber, "d2", d2InodeNumber, false)
    50  	if !assert.Nil(err) {
    51  		return
    52  	}
    53  
    54  	file1aInodeNumber, err := vh.CreateFile(PosixModePerm, 0, 0)
    55  	if !assert.Nil(err) {
    56  		return
    57  	}
    58  	err = vh.Write(file1aInodeNumber, 0, []byte("abcd"), nil)
    59  	if !assert.Nil(err) {
    60  		return
    61  	}
    62  	err = vh.Link(d1InodeNumber, "file1a", file1aInodeNumber, false)
    63  	if !assert.Nil(err) {
    64  		return
    65  	}
    66  
    67  	file1bInodeNumber, err := vh.CreateFile(PosixModePerm, 0, 0)
    68  	if !assert.Nil(err) {
    69  		return
    70  	}
    71  	err = vh.Write(file1bInodeNumber, 0, []byte("efgh"), nil)
    72  	if !assert.Nil(err) {
    73  		return
    74  	}
    75  	err = vh.Link(d1InodeNumber, "file1b", file1bInodeNumber, false)
    76  	if !assert.Nil(err) {
    77  		return
    78  	}
    79  
    80  	file2aInodeNumber, err := vh.CreateFile(PosixModePerm, 0, 0)
    81  	if !assert.Nil(err) {
    82  		return
    83  	}
    84  	err = vh.Write(file2aInodeNumber, 0, []byte("ijkl"), nil)
    85  	if !assert.Nil(err) {
    86  		return
    87  	}
    88  	err = vh.Link(d2InodeNumber, "file2a", file2aInodeNumber, false)
    89  	if !assert.Nil(err) {
    90  		return
    91  	}
    92  
    93  	file2bInodeNumber, err := vh.CreateFile(PosixModePerm, 0, 0)
    94  	if !assert.Nil(err) {
    95  		return
    96  	}
    97  	err = vh.Write(file2bInodeNumber, 0, []byte("mnop"), nil)
    98  	if !assert.Nil(err) {
    99  		return
   100  	}
   101  	err = vh.Link(d2InodeNumber, "file2b", file2bInodeNumber, false)
   102  	if !assert.Nil(err) {
   103  		return
   104  	}
   105  
   106  	// Note that this one is sparse: the first 2 bytes are 0, then we have "st", then 2 more 0s
   107  	file2cInodeNumber, err := vh.CreateFile(PosixModePerm, 0, 0)
   108  	if !assert.Nil(err) {
   109  		return
   110  	}
   111  	err = vh.Write(file2cInodeNumber, 2, []byte("st"), nil)
   112  	if !assert.Nil(err) {
   113  		return
   114  	}
   115  	err = vh.Link(d2InodeNumber, "file2c", file2cInodeNumber, false)
   116  	if !assert.Nil(err) {
   117  		return
   118  	}
   119  	err = vh.SetSize(file2cInodeNumber, 6)
   120  	if !assert.Nil(err) {
   121  		return
   122  	}
   123  
   124  	// Now create destination file
   125  	combinedInodeNumber, err := vh.CreateFile(PosixModePerm, 0, 0)
   126  	if !assert.Nil(err) {
   127  		return
   128  	}
   129  	err = vh.Link(d1InodeNumber, "combined", combinedInodeNumber, false)
   130  	if !assert.Nil(err) {
   131  		return
   132  	}
   133  
   134  	// test setup's done; now we can coalesce things
   135  	elements := make([]*CoalesceElement, 0, 5)
   136  	elements = append(elements, &CoalesceElement{
   137  		ContainingDirectoryInodeNumber: d1InodeNumber,
   138  		ElementInodeNumber:             file1aInodeNumber,
   139  		ElementName:                    "file1a"})
   140  	elements = append(elements, &CoalesceElement{
   141  		ContainingDirectoryInodeNumber: d1InodeNumber,
   142  		ElementInodeNumber:             file1bInodeNumber,
   143  		ElementName:                    "file1b"})
   144  	elements = append(elements, &CoalesceElement{
   145  		ContainingDirectoryInodeNumber: d2InodeNumber,
   146  		ElementInodeNumber:             file2aInodeNumber,
   147  		ElementName:                    "file2a"})
   148  	elements = append(elements, &CoalesceElement{
   149  		ContainingDirectoryInodeNumber: d2InodeNumber,
   150  		ElementInodeNumber:             file2bInodeNumber,
   151  		ElementName:                    "file2b"})
   152  	elements = append(elements, &CoalesceElement{
   153  		ContainingDirectoryInodeNumber: d2InodeNumber,
   154  		ElementInodeNumber:             file2cInodeNumber,
   155  		ElementName:                    "file2c"})
   156  
   157  	newMetaData := []byte("The quick brown fox jumped over the lazy dog.")
   158  
   159  	// Coalesce the above 5 files and metadata into d1/combined
   160  	startTime := time.Now()
   161  	attrChangeTime, modificationTime, numWrites, fileSize, err := vh.Coalesce(
   162  		combinedInodeNumber, "MetaDataStream", newMetaData, elements)
   163  	if !assert.Nil(err) {
   164  		return
   165  	}
   166  	assert.Equal(uint64(22), fileSize)
   167  	assert.Equal(uint64(5), numWrites)
   168  	assert.Equal(attrChangeTime, modificationTime)
   169  	assert.True(attrChangeTime.After(startTime))
   170  
   171  	// The new file has the contents of the old files combined
   172  	contents, err := vh.Read(combinedInodeNumber, 0, 22, nil)
   173  	if !assert.Nil(err) {
   174  		return
   175  	}
   176  	assert.Equal([]byte("abcdefghijklmnop\x00\x00st\x00\x00"), contents)
   177  
   178  	// The old files have ceased to be
   179  	_, err = vh.Lookup(d1InodeNumber, "file1a")
   180  	assert.True(blunder.Is(err, blunder.NotFoundError))
   181  	_, err = vh.Lookup(d1InodeNumber, "file1b")
   182  	assert.True(blunder.Is(err, blunder.NotFoundError))
   183  	_, err = vh.Lookup(d2InodeNumber, "file2a")
   184  	assert.True(blunder.Is(err, blunder.NotFoundError))
   185  	_, err = vh.Lookup(d2InodeNumber, "file2b")
   186  	assert.True(blunder.Is(err, blunder.NotFoundError))
   187  	_, err = vh.Lookup(d2InodeNumber, "file2c")
   188  	assert.True(blunder.Is(err, blunder.NotFoundError))
   189  
   190  	// The new file is linked in at the right spot
   191  	foundInodeNumber, err := vh.Lookup(d1InodeNumber, "combined")
   192  	if !assert.Nil(err) {
   193  		return
   194  	}
   195  	assert.Equal(combinedInodeNumber, foundInodeNumber)
   196  
   197  	// Verify the new file has the new metadata
   198  	buf, err := vh.GetStream(combinedInodeNumber, "MetaDataStream")
   199  	if assert.Nil(err) {
   200  		assert.Equal(buf, newMetaData)
   201  	}
   202  
   203  	testTeardown(t)
   204  }
   205  
   206  func TestCoalesceDir(t *testing.T) {
   207  	testSetup(t, false)
   208  
   209  	// We're going to take some files:
   210  	//
   211  	// d1/file1a   (contents "abcd")
   212  	// d1/file1b   (contents "efgh")
   213  	//
   214  	// and attempt to coalesce them into a directory:
   215  	//
   216  	// d1
   217  
   218  	assert := assert.New(t)
   219  	vh, err := FetchVolumeHandle("TestVolume")
   220  	if !assert.Nil(err) {
   221  		return
   222  	}
   223  
   224  	d1InodeNumber, err := vh.CreateDir(PosixModePerm, 0, 0)
   225  	if !assert.Nil(err) {
   226  		return
   227  	}
   228  	err = vh.Link(RootDirInodeNumber, "d1", d1InodeNumber, false)
   229  	if !assert.Nil(err) {
   230  		return
   231  	}
   232  
   233  	file1aInodeNumber, err := vh.CreateFile(PosixModePerm, 0, 0)
   234  	if !assert.Nil(err) {
   235  		return
   236  	}
   237  	err = vh.Write(file1aInodeNumber, 0, []byte("abcd"), nil)
   238  	if !assert.Nil(err) {
   239  		return
   240  	}
   241  	err = vh.Link(d1InodeNumber, "file1a", file1aInodeNumber, false)
   242  	if !assert.Nil(err) {
   243  		return
   244  	}
   245  
   246  	file1bInodeNumber, err := vh.CreateFile(PosixModePerm, 0, 0)
   247  	if !assert.Nil(err) {
   248  		return
   249  	}
   250  	err = vh.Write(file1bInodeNumber, 0, []byte("efgh"), nil)
   251  	if !assert.Nil(err) {
   252  		return
   253  	}
   254  	err = vh.Link(d1InodeNumber, "file1b", file1bInodeNumber, false)
   255  	if !assert.Nil(err) {
   256  		return
   257  	}
   258  
   259  	// test setup's done; now we can coalesce things
   260  	elements := make([]*CoalesceElement, 0, 2)
   261  	elements = append(elements, &CoalesceElement{
   262  		ContainingDirectoryInodeNumber: d1InodeNumber,
   263  		ElementInodeNumber:             file1aInodeNumber,
   264  		ElementName:                    "file1a"})
   265  	elements = append(elements, &CoalesceElement{
   266  		ContainingDirectoryInodeNumber: d1InodeNumber,
   267  		ElementInodeNumber:             file1bInodeNumber,
   268  		ElementName:                    "file1b"})
   269  
   270  	// Coalesce the above 2 files into d1
   271  	_, _, _, _, err = vh.Coalesce(d1InodeNumber, "MetaDataStream", nil, elements)
   272  	assert.NotNil(err)
   273  	assert.True(blunder.Is(err, blunder.PermDeniedError))
   274  
   275  	testTeardown(t)
   276  }
   277  
   278  func TestCoalesceMultipleLinks(t *testing.T) {
   279  	testSetup(t, false)
   280  
   281  	// We're going to take hard-linked files:
   282  	//
   283  	// d1/file1a   (contents "abcd")
   284  	// d1/file1b   (hard-linked to d1/file1a)
   285  	//
   286  	// and attempt to coalesce them into a single file:
   287  	//
   288  	// d1/combined
   289  
   290  	assert := assert.New(t)
   291  	vh, err := FetchVolumeHandle("TestVolume")
   292  	if !assert.Nil(err) {
   293  		return
   294  	}
   295  
   296  	d1InodeNumber, err := vh.CreateDir(PosixModePerm, 0, 0)
   297  	if !assert.Nil(err) {
   298  		return
   299  	}
   300  	err = vh.Link(RootDirInodeNumber, "d1", d1InodeNumber, false)
   301  	if !assert.Nil(err) {
   302  		return
   303  	}
   304  
   305  	file1aInodeNumber, err := vh.CreateFile(PosixModePerm, 0, 0)
   306  	if !assert.Nil(err) {
   307  		return
   308  	}
   309  	err = vh.Write(file1aInodeNumber, 0, []byte("abcd"), nil)
   310  	if !assert.Nil(err) {
   311  		return
   312  	}
   313  	err = vh.Link(d1InodeNumber, "file1a", file1aInodeNumber, false)
   314  	if !assert.Nil(err) {
   315  		return
   316  	}
   317  
   318  	file1bInodeNumber := file1aInodeNumber
   319  	err = vh.Link(d1InodeNumber, "file1b", file1bInodeNumber, false)
   320  	if !assert.Nil(err) {
   321  		return
   322  	}
   323  
   324  	// Now create destination file
   325  	combinedInodeNumber, err := vh.CreateFile(PosixModePerm, 0, 0)
   326  	if !assert.Nil(err) {
   327  		return
   328  	}
   329  	err = vh.Link(d1InodeNumber, "combined", combinedInodeNumber, false)
   330  	if !assert.Nil(err) {
   331  		return
   332  	}
   333  
   334  	// test setup's done; now we can coalesce things
   335  	elements := make([]*CoalesceElement, 0, 2)
   336  	elements = append(elements, &CoalesceElement{
   337  		ContainingDirectoryInodeNumber: d1InodeNumber,
   338  		ElementInodeNumber:             file1aInodeNumber,
   339  		ElementName:                    "file1a"})
   340  	elements = append(elements, &CoalesceElement{
   341  		ContainingDirectoryInodeNumber: d1InodeNumber,
   342  		ElementInodeNumber:             file1bInodeNumber,
   343  		ElementName:                    "file1b"})
   344  
   345  	// Coalesce the above 2 files into d1/combined
   346  	_, _, _, _, err = vh.Coalesce(combinedInodeNumber, "MetaDataStream", nil, elements)
   347  	assert.NotNil(err)
   348  	assert.True(blunder.Is(err, blunder.TooManyLinksError))
   349  
   350  	testTeardown(t)
   351  }
   352  
   353  func TestCoalesceDuplicates(t *testing.T) {
   354  	testSetup(t, false)
   355  
   356  	// We're going to take hard-linked files:
   357  	//
   358  	// d1/file1a   (contents "abcd")
   359  	// d1/file1b   (contents "efgh")
   360  	// d1/file1a   (again)
   361  	//
   362  	// and attempt to coalesce them into a single file:
   363  	//
   364  	// d1/combined
   365  
   366  	assert := assert.New(t)
   367  	vh, err := FetchVolumeHandle("TestVolume")
   368  	if !assert.Nil(err) {
   369  		return
   370  	}
   371  
   372  	d1InodeNumber, err := vh.CreateDir(PosixModePerm, 0, 0)
   373  	if !assert.Nil(err) {
   374  		return
   375  	}
   376  	err = vh.Link(RootDirInodeNumber, "d1", d1InodeNumber, false)
   377  	if !assert.Nil(err) {
   378  		return
   379  	}
   380  
   381  	file1aInodeNumber, err := vh.CreateFile(PosixModePerm, 0, 0)
   382  	if !assert.Nil(err) {
   383  		return
   384  	}
   385  	err = vh.Write(file1aInodeNumber, 0, []byte("abcd"), nil)
   386  	if !assert.Nil(err) {
   387  		return
   388  	}
   389  	err = vh.Link(d1InodeNumber, "file1a", file1aInodeNumber, false)
   390  	if !assert.Nil(err) {
   391  		return
   392  	}
   393  
   394  	file1bInodeNumber, err := vh.CreateFile(PosixModePerm, 0, 0)
   395  	if !assert.Nil(err) {
   396  		return
   397  	}
   398  	err = vh.Write(file1bInodeNumber, 0, []byte("efgh"), nil)
   399  	if !assert.Nil(err) {
   400  		return
   401  	}
   402  	err = vh.Link(d1InodeNumber, "file1b", file1bInodeNumber, false)
   403  	if !assert.Nil(err) {
   404  		return
   405  	}
   406  
   407  	// Now create destination file
   408  	combinedInodeNumber, err := vh.CreateFile(PosixModePerm, 0, 0)
   409  	if !assert.Nil(err) {
   410  		return
   411  	}
   412  	err = vh.Link(d1InodeNumber, "combined", combinedInodeNumber, false)
   413  	if !assert.Nil(err) {
   414  		return
   415  	}
   416  
   417  	// test setup's done; now we can coalesce things
   418  	elements := make([]*CoalesceElement, 0, 3)
   419  	elements = append(elements, &CoalesceElement{
   420  		ContainingDirectoryInodeNumber: d1InodeNumber,
   421  		ElementInodeNumber:             file1aInodeNumber,
   422  		ElementName:                    "file1a"})
   423  	elements = append(elements, &CoalesceElement{
   424  		ContainingDirectoryInodeNumber: d1InodeNumber,
   425  		ElementInodeNumber:             file1bInodeNumber,
   426  		ElementName:                    "file1b"})
   427  	elements = append(elements, &CoalesceElement{
   428  		ContainingDirectoryInodeNumber: d1InodeNumber,
   429  		ElementInodeNumber:             file1aInodeNumber,
   430  		ElementName:                    "file1a"})
   431  
   432  	// Coalesce the above 3 files into d1/combined
   433  	_, _, _, _, err = vh.Coalesce(combinedInodeNumber, "MetaDataStream", nil, elements)
   434  	assert.NotNil(err)
   435  	assert.True(blunder.Is(err, blunder.InvalidArgError))
   436  
   437  	testTeardown(t)
   438  }