github.com/TeaOSLab/EdgeNode@v1.3.8/internal/caches/storage_file_test.go (about)

     1  package caches
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
     7  	"github.com/TeaOSLab/EdgeNode/internal/utils"
     8  	"github.com/TeaOSLab/EdgeNode/internal/utils/testutils"
     9  	"github.com/iwind/TeaGo/Tea"
    10  	_ "github.com/iwind/TeaGo/bootstrap"
    11  	"github.com/iwind/TeaGo/logs"
    12  	"io"
    13  	"net/http"
    14  	"runtime"
    15  	"strconv"
    16  	"sync"
    17  	"testing"
    18  	"time"
    19  )
    20  
    21  func TestFileStorage_Init(t *testing.T) {
    22  	if !testutils.IsSingleTesting() {
    23  		return
    24  	}
    25  
    26  	var storage = NewFileStorage(&serverconfigs.HTTPCachePolicy{
    27  		Id:   1,
    28  		IsOn: true,
    29  		Options: map[string]interface{}{
    30  			"dir": Tea.Root + "/caches",
    31  		},
    32  	})
    33  
    34  	defer storage.Stop()
    35  
    36  	err := storage.Init()
    37  	if err != nil {
    38  		t.Fatal(err)
    39  	}
    40  	//t.Log(storage.list.m)
    41  
    42  	/**err = storage.Write("c", bytes.NewReader([]byte("i am c")), 4, "second")
    43  	if err != nil {
    44  		t.Fatal(err)
    45  	}**/
    46  	//logs.PrintAsJSON(storage.list.m, t)
    47  
    48  	time.Sleep(2 * time.Second)
    49  	storage.purgeLoop()
    50  	t.Log(storage.list.(*SQLiteFileList).Stat(func(hash string) bool {
    51  		return true
    52  	}))
    53  }
    54  
    55  func TestFileStorage_OpenWriter(t *testing.T) {
    56  	if !testutils.IsSingleTesting() {
    57  		return
    58  	}
    59  
    60  	var storage = NewFileStorage(&serverconfigs.HTTPCachePolicy{
    61  		Id:   1,
    62  		IsOn: true,
    63  		Options: map[string]interface{}{
    64  			"dir": Tea.Root + "/caches",
    65  		},
    66  	})
    67  
    68  	defer storage.Stop()
    69  
    70  	err := storage.Init()
    71  	if err != nil {
    72  		t.Fatal(err)
    73  	}
    74  	now := time.Now()
    75  	defer func() {
    76  		t.Log(time.Since(now).Seconds()*1000, "ms")
    77  	}()
    78  
    79  	header := []byte("Header")
    80  	body := []byte("This is Body")
    81  	writer, err := storage.OpenWriter("my-key", time.Now().Unix()+86400, 200, -1, -1, -1, false)
    82  	if err != nil {
    83  		t.Fatal(err)
    84  	}
    85  	t.Log(writer)
    86  
    87  	_, err = writer.WriteHeader(header)
    88  	if err != nil {
    89  		t.Fatal(err)
    90  	}
    91  
    92  	_, err = writer.Write(body)
    93  	if err != nil {
    94  		t.Fatal(err)
    95  	}
    96  
    97  	err = writer.Close()
    98  	if err != nil {
    99  		t.Fatal(err)
   100  	}
   101  
   102  	t.Log("header:", writer.HeaderSize(), "body:", writer.BodySize())
   103  	t.Log("ok")
   104  }
   105  
   106  func TestFileStorage_OpenWriter_Partial(t *testing.T) {
   107  	if !testutils.IsSingleTesting() {
   108  		return
   109  	}
   110  
   111  	var storage = NewFileStorage(&serverconfigs.HTTPCachePolicy{
   112  		Id:   2,
   113  		IsOn: true,
   114  		Options: map[string]interface{}{
   115  			"dir": Tea.Root + "/caches",
   116  		},
   117  	})
   118  
   119  	defer storage.Stop()
   120  
   121  	err := storage.Init()
   122  	if err != nil {
   123  		t.Fatal(err)
   124  	}
   125  
   126  	writer, err := storage.OpenWriter("my-key", time.Now().Unix()+86400, 200, -1, -1, -1, true)
   127  	if err != nil {
   128  		t.Fatal(err)
   129  	}
   130  
   131  	_, err = writer.WriteHeader([]byte("Content-Type:text/html; charset=utf-8"))
   132  	if err != nil {
   133  		t.Fatal(err)
   134  	}
   135  
   136  	err = writer.WriteAt(0, []byte("Hello, World"))
   137  	if err != nil {
   138  		t.Fatal(err)
   139  	}
   140  
   141  	err = writer.Close()
   142  	if err != nil {
   143  		t.Fatal(err)
   144  	}
   145  	t.Log(writer)
   146  }
   147  
   148  func TestFileStorage_OpenWriter_HTTP(t *testing.T) {
   149  	if !testutils.IsSingleTesting() {
   150  		return
   151  	}
   152  
   153  	var storage = NewFileStorage(&serverconfigs.HTTPCachePolicy{
   154  		Id:   1,
   155  		IsOn: true,
   156  		Options: map[string]interface{}{
   157  			"dir": Tea.Root + "/caches",
   158  		},
   159  	})
   160  
   161  	defer storage.Stop()
   162  
   163  	err := storage.Init()
   164  	if err != nil {
   165  		t.Fatal(err)
   166  	}
   167  	now := time.Now()
   168  	defer func() {
   169  		t.Log(time.Since(now).Seconds()*1000, "ms")
   170  	}()
   171  
   172  	writer, err := storage.OpenWriter("my-http-response", time.Now().Unix()+86400, 200, -1, -1, -1, false)
   173  	if err != nil {
   174  		t.Fatal(err)
   175  	}
   176  	t.Log(writer)
   177  
   178  	resp := &http.Response{
   179  		StatusCode: http.StatusOK,
   180  		Header: http.Header{
   181  			"Content-Type":  []string{"text/html; charset=utf-8"},
   182  			"Last-Modified": []string{"Wed, 06 Jan 2021 10:03:29 GMT"},
   183  			"Server":        []string{"CDN-Server"},
   184  		},
   185  		Body: io.NopCloser(bytes.NewBuffer([]byte("THIS IS HTTP BODY"))),
   186  	}
   187  
   188  	for k, v := range resp.Header {
   189  		for _, v1 := range v {
   190  			_, err = writer.WriteHeader([]byte(k + ":" + v1 + "\n"))
   191  			if err != nil {
   192  				t.Fatal(err)
   193  			}
   194  		}
   195  	}
   196  
   197  	buf := make([]byte, 1024)
   198  	for {
   199  		n, err := resp.Body.Read(buf)
   200  		if n > 0 {
   201  			_, err = writer.Write(buf[:n])
   202  			if err != nil {
   203  				t.Fatal(err)
   204  			}
   205  		}
   206  		if err != nil {
   207  			break
   208  		}
   209  	}
   210  
   211  	err = writer.Close()
   212  	if err != nil {
   213  		t.Fatal(err)
   214  	}
   215  
   216  	t.Log("header:", writer.HeaderSize(), "body:", writer.BodySize())
   217  	t.Log("ok")
   218  }
   219  
   220  func TestFileStorage_Concurrent_Open_DifferentFile(t *testing.T) {
   221  	if !testutils.IsSingleTesting() {
   222  		return
   223  	}
   224  
   225  	var storage = NewFileStorage(&serverconfigs.HTTPCachePolicy{
   226  		Id:   1,
   227  		IsOn: true,
   228  		Options: map[string]interface{}{
   229  			"dir": Tea.Root + "/caches",
   230  		},
   231  	})
   232  
   233  	defer storage.Stop()
   234  
   235  	err := storage.Init()
   236  	if err != nil {
   237  		t.Fatal(err)
   238  	}
   239  	now := time.Now()
   240  	defer func() {
   241  		t.Log(time.Since(now).Seconds()*1000, "ms")
   242  	}()
   243  
   244  	wg := sync.WaitGroup{}
   245  	count := 100
   246  	wg.Add(count)
   247  
   248  	for i := 0; i < count; i++ {
   249  		go func(i int) {
   250  			defer wg.Done()
   251  
   252  			writer, err := storage.OpenWriter("abc"+strconv.Itoa(i), time.Now().Unix()+3600, 200, -1, -1, -1, false)
   253  			if err != nil {
   254  				if errors.Is(err, ErrFileIsWriting) {
   255  					t.Error(err)
   256  					return
   257  				}
   258  				return
   259  			}
   260  			//t.Log(writer)
   261  
   262  			_, err = writer.Write([]byte("Hello,World"))
   263  			if err != nil {
   264  				t.Error(err)
   265  				return
   266  			}
   267  
   268  			// 故意造成慢速写入
   269  			time.Sleep(1 * time.Second)
   270  
   271  			err = writer.Close()
   272  			if err != nil {
   273  				t.Error(err)
   274  				return
   275  			}
   276  		}(i)
   277  	}
   278  
   279  	wg.Wait()
   280  }
   281  
   282  func TestFileStorage_Concurrent_Open_SameFile(t *testing.T) {
   283  	if !testutils.IsSingleTesting() {
   284  		return
   285  	}
   286  
   287  	var storage = NewFileStorage(&serverconfigs.HTTPCachePolicy{
   288  		Id:   1,
   289  		IsOn: true,
   290  		Options: map[string]interface{}{
   291  			"dir": Tea.Root + "/caches",
   292  		},
   293  	})
   294  
   295  	defer storage.Stop()
   296  
   297  	err := storage.Init()
   298  	if err != nil {
   299  		t.Fatal(err)
   300  	}
   301  	now := time.Now()
   302  	defer func() {
   303  		t.Log(time.Since(now).Seconds()*1000, "ms")
   304  	}()
   305  
   306  	wg := sync.WaitGroup{}
   307  	count := 100
   308  	wg.Add(count)
   309  
   310  	for i := 0; i < count; i++ {
   311  		go func(i int) {
   312  			defer wg.Done()
   313  
   314  			writer, err := storage.OpenWriter("abc"+strconv.Itoa(0), time.Now().Unix()+3600, 200, -1, -1, -1, false)
   315  			if err != nil {
   316  				if errors.Is(err, ErrFileIsWriting) {
   317  					t.Error(err)
   318  					return
   319  				}
   320  				return
   321  			}
   322  			//t.Log(writer)
   323  
   324  			t.Log("writing")
   325  			_, err = writer.Write([]byte("Hello,World"))
   326  			if err != nil {
   327  				t.Error(err)
   328  				return
   329  			}
   330  
   331  			// 故意造成慢速写入
   332  			time.Sleep(time.Duration(1) * time.Second)
   333  
   334  			err = writer.Close()
   335  			if err != nil {
   336  				t.Error(err)
   337  				return
   338  			}
   339  		}(i)
   340  	}
   341  
   342  	wg.Wait()
   343  }
   344  
   345  func TestFileStorage_Read(t *testing.T) {
   346  	if !testutils.IsSingleTesting() {
   347  		return
   348  	}
   349  
   350  	var storage = NewFileStorage(&serverconfigs.HTTPCachePolicy{
   351  		Id:   1,
   352  		IsOn: true,
   353  		Options: map[string]interface{}{
   354  			"dir": Tea.Root + "/caches",
   355  		},
   356  	})
   357  
   358  	defer storage.Stop()
   359  
   360  	err := storage.Init()
   361  	if err != nil {
   362  		t.Fatal(err)
   363  	}
   364  	now := time.Now()
   365  	reader, err := storage.OpenReader("my-key", false, false)
   366  	if err != nil {
   367  		t.Fatal(err)
   368  	}
   369  	buf := make([]byte, 6)
   370  	t.Log(reader.Status())
   371  	err = reader.ReadHeader(buf, func(n int) (goNext bool, err error) {
   372  		t.Log("header:", string(buf[:n]))
   373  		return true, nil
   374  	})
   375  	if err != nil {
   376  		t.Fatal(err)
   377  	}
   378  	err = reader.ReadBody(buf, func(n int) (goNext bool, err error) {
   379  		t.Log("body:", string(buf[:n]))
   380  		return true, nil
   381  	})
   382  	if err != nil {
   383  		t.Fatal(err)
   384  	}
   385  	t.Log(time.Since(now).Seconds()*1000, "ms")
   386  }
   387  
   388  func TestFileStorage_Read_HTTP_Response(t *testing.T) {
   389  	if !testutils.IsSingleTesting() {
   390  		return
   391  	}
   392  
   393  	var storage = NewFileStorage(&serverconfigs.HTTPCachePolicy{
   394  		Id:   1,
   395  		IsOn: true,
   396  		Options: map[string]interface{}{
   397  			"dir": Tea.Root + "/caches",
   398  		},
   399  	})
   400  
   401  	defer storage.Stop()
   402  
   403  	err := storage.Init()
   404  	if err != nil {
   405  		t.Fatal(err)
   406  	}
   407  	now := time.Now()
   408  	reader, err := storage.OpenReader("my-http-response", false, false)
   409  	if err != nil {
   410  		t.Fatal(err)
   411  	}
   412  	buf := make([]byte, 32)
   413  	t.Log(reader.Status())
   414  
   415  	headerBuf := []byte{}
   416  	err = reader.ReadHeader(buf, func(n int) (goNext bool, err error) {
   417  		headerBuf = append(headerBuf, buf...)
   418  		for {
   419  			nIndex := bytes.Index(headerBuf, []byte{'\n'})
   420  			if nIndex >= 0 {
   421  				row := headerBuf[:nIndex]
   422  				spaceIndex := bytes.Index(row, []byte{':'})
   423  				if spaceIndex <= 0 {
   424  					return false, errors.New("invalid header")
   425  				}
   426  
   427  				t.Log("header row:", string(row[:spaceIndex]), string(row[spaceIndex+1:]))
   428  				headerBuf = headerBuf[nIndex+1:]
   429  			} else {
   430  				break
   431  			}
   432  		}
   433  		return true, nil
   434  	})
   435  	if err != nil {
   436  		t.Fatal(err)
   437  	}
   438  	err = reader.ReadBody(buf, func(n int) (goNext bool, err error) {
   439  		t.Log("body:", string(buf[:n]))
   440  		return true, nil
   441  	})
   442  	if err != nil {
   443  		t.Fatal(err)
   444  	}
   445  	t.Log(time.Since(now).Seconds()*1000, "ms")
   446  }
   447  
   448  func TestFileStorage_Read_NotFound(t *testing.T) {
   449  	if !testutils.IsSingleTesting() {
   450  		return
   451  	}
   452  
   453  	var storage = NewFileStorage(&serverconfigs.HTTPCachePolicy{
   454  		Id:   1,
   455  		IsOn: true,
   456  		Options: map[string]interface{}{
   457  			"dir": Tea.Root + "/caches",
   458  		},
   459  	})
   460  
   461  	defer storage.Stop()
   462  
   463  	err := storage.Init()
   464  	if err != nil {
   465  		t.Fatal(err)
   466  	}
   467  	now := time.Now()
   468  	buf := make([]byte, 6)
   469  	reader, err := storage.OpenReader("my-key-10000", false, false)
   470  	if err != nil {
   471  		if err == ErrNotFound {
   472  			t.Log("cache not fund")
   473  			return
   474  		}
   475  		t.Fatal(err)
   476  	}
   477  
   478  	err = reader.ReadBody(buf, func(n int) (goNext bool, err error) {
   479  		t.Log("body:", string(buf[:n]))
   480  		return true, nil
   481  	})
   482  	if err != nil {
   483  		t.Fatal(err)
   484  	}
   485  	t.Log(time.Since(now).Seconds()*1000, "ms")
   486  }
   487  
   488  func TestFileStorage_Delete(t *testing.T) {
   489  	if !testutils.IsSingleTesting() {
   490  		return
   491  	}
   492  
   493  	var storage = NewFileStorage(&serverconfigs.HTTPCachePolicy{
   494  		Id:   1,
   495  		IsOn: true,
   496  		Options: map[string]interface{}{
   497  			"dir": Tea.Root + "/caches",
   498  		},
   499  	})
   500  
   501  	defer storage.Stop()
   502  
   503  	err := storage.Init()
   504  	if err != nil {
   505  		t.Fatal(err)
   506  	}
   507  	err = storage.Delete("my-key")
   508  	if err != nil {
   509  		t.Fatal(err)
   510  	}
   511  	t.Log("ok")
   512  }
   513  
   514  func TestFileStorage_Stat(t *testing.T) {
   515  	if !testutils.IsSingleTesting() {
   516  		return
   517  	}
   518  
   519  	var storage = NewFileStorage(&serverconfigs.HTTPCachePolicy{
   520  		Id:   1,
   521  		IsOn: true,
   522  		Options: map[string]interface{}{
   523  			"dir": Tea.Root + "/caches",
   524  		},
   525  	})
   526  
   527  	defer storage.Stop()
   528  
   529  	err := storage.Init()
   530  	if err != nil {
   531  		t.Fatal(err)
   532  	}
   533  
   534  	before := time.Now()
   535  	defer func() {
   536  		t.Log(time.Since(before).Seconds()*1000, "ms")
   537  	}()
   538  
   539  	stat, err := storage.Stat()
   540  	if err != nil {
   541  		t.Fatal(err)
   542  	}
   543  	logs.PrintAsJSON(stat, t)
   544  }
   545  
   546  func TestFileStorage_CleanAll(t *testing.T) {
   547  	if !testutils.IsSingleTesting() {
   548  		return
   549  	}
   550  
   551  	var storage = NewFileStorage(&serverconfigs.HTTPCachePolicy{
   552  		Id:   1,
   553  		IsOn: true,
   554  		Options: map[string]interface{}{
   555  			"dir": Tea.Root + "/caches",
   556  		},
   557  	})
   558  
   559  	defer storage.Stop()
   560  
   561  	err := storage.Init()
   562  	if err != nil {
   563  		t.Fatal(err)
   564  	}
   565  
   566  	before := time.Now()
   567  	defer func() {
   568  		t.Log(time.Since(before).Seconds()*1000, "ms")
   569  	}()
   570  
   571  	c, _ := storage.list.Count()
   572  	t.Log("before:", c)
   573  
   574  	err = storage.CleanAll()
   575  	if err != nil {
   576  		t.Fatal(err)
   577  	}
   578  
   579  	c, _ = storage.list.Count()
   580  	t.Log("after:", c)
   581  	t.Log("ok")
   582  }
   583  
   584  func TestFileStorage_Stop(t *testing.T) {
   585  	if !testutils.IsSingleTesting() {
   586  		return
   587  	}
   588  
   589  	var storage = NewFileStorage(&serverconfigs.HTTPCachePolicy{
   590  		Id:   1,
   591  		IsOn: true,
   592  		Options: map[string]interface{}{
   593  			"dir": Tea.Root + "/caches",
   594  		},
   595  	})
   596  
   597  	defer storage.Stop()
   598  
   599  	err := storage.Init()
   600  	if err != nil {
   601  		t.Fatal(err)
   602  	}
   603  	storage.Stop()
   604  }
   605  
   606  func TestFileStorage_DecodeFile(t *testing.T) {
   607  	if !testutils.IsSingleTesting() {
   608  		return
   609  	}
   610  
   611  	var storage = NewFileStorage(&serverconfigs.HTTPCachePolicy{
   612  		Id:   1,
   613  		IsOn: true,
   614  		Options: map[string]interface{}{
   615  			"dir": Tea.Root + "/caches",
   616  		},
   617  	})
   618  
   619  	defer storage.Stop()
   620  
   621  	err := storage.Init()
   622  	if err != nil {
   623  		t.Fatal(err)
   624  	}
   625  	_, path, _ := storage.keyPath("my-key")
   626  	t.Log(path)
   627  }
   628  
   629  func TestFileStorage_RemoveCacheFile(t *testing.T) {
   630  	if !testutils.IsSingleTesting() {
   631  		return
   632  	}
   633  
   634  	var storage = NewFileStorage(nil)
   635  
   636  	defer storage.Stop()
   637  
   638  	t.Log(storage.removeCacheFile("/Users/WorkSpace/EdgeProject/EdgeCache/p43/15/7e/157eba0dfc6dfb6fbbf20b1f9e584674.cache"))
   639  }
   640  
   641  func TestFileStorage_ScanGarbageCaches(t *testing.T) {
   642  	if !testutils.IsSingleTesting() {
   643  		return
   644  	}
   645  
   646  	var storage = NewFileStorage(&serverconfigs.HTTPCachePolicy{
   647  		Id:      43,
   648  		Options: map[string]any{"dir": "/Users/WorkSpace/EdgeProject/EdgeCache"},
   649  	})
   650  	err := storage.Init()
   651  	if err != nil {
   652  		t.Fatal(err)
   653  	}
   654  
   655  	err = storage.ScanGarbageCaches(func(path string) error {
   656  		t.Log(path, PartialRangesFilePath(path))
   657  		return nil
   658  	})
   659  	if err != nil {
   660  		t.Fatal(err)
   661  	}
   662  }
   663  
   664  func BenchmarkFileStorage_Read(b *testing.B) {
   665  	runtime.GOMAXPROCS(1)
   666  
   667  	_ = utils.SetRLimit(1 << 20)
   668  
   669  	var storage = NewFileStorage(&serverconfigs.HTTPCachePolicy{
   670  		Id:   1,
   671  		IsOn: true,
   672  		Options: map[string]interface{}{
   673  			"dir": Tea.Root + "/caches",
   674  		},
   675  	})
   676  
   677  	defer storage.Stop()
   678  
   679  	err := storage.Init()
   680  	if err != nil {
   681  		b.Fatal(err)
   682  	}
   683  	for i := 0; i < b.N; i++ {
   684  		reader, err := storage.OpenReader("my-key", false, false)
   685  		if err != nil {
   686  			b.Fatal(err)
   687  		}
   688  		buf := make([]byte, 1024)
   689  		_ = reader.ReadBody(buf, func(n int) (goNext bool, err error) {
   690  			return true, nil
   691  		})
   692  		_ = reader.Close()
   693  	}
   694  }
   695  
   696  func BenchmarkFileStorage_KeyPath(b *testing.B) {
   697  	runtime.GOMAXPROCS(1)
   698  
   699  	var storage = &FileStorage{
   700  		options: &serverconfigs.HTTPFileCacheStorage{},
   701  		policy:  &serverconfigs.HTTPCachePolicy{Id: 1},
   702  	}
   703  
   704  	for i := 0; i < b.N; i++ {
   705  		_, _, _ = storage.keyPath(strconv.Itoa(i))
   706  	}
   707  }