github.com/gdevillele/moby@v1.13.0/pkg/graphdb/graphdb_linux_test.go (about)

     1  package graphdb
     2  
     3  import (
     4  	"database/sql"
     5  	"fmt"
     6  	"os"
     7  	"path"
     8  	"runtime"
     9  	"strconv"
    10  	"testing"
    11  
    12  	_ "github.com/mattn/go-sqlite3"
    13  )
    14  
    15  func newTestDb(t *testing.T) (*Database, string) {
    16  	p := path.Join(os.TempDir(), "sqlite.db")
    17  	conn, err := sql.Open("sqlite3", p)
    18  	db, err := NewDatabase(conn)
    19  	if err != nil {
    20  		t.Fatal(err)
    21  	}
    22  	return db, p
    23  }
    24  
    25  func destroyTestDb(dbPath string) {
    26  	os.Remove(dbPath)
    27  }
    28  
    29  func TestNewDatabase(t *testing.T) {
    30  	db, dbpath := newTestDb(t)
    31  	if db == nil {
    32  		t.Fatal("Database should not be nil")
    33  	}
    34  	db.Close()
    35  	defer destroyTestDb(dbpath)
    36  }
    37  
    38  func TestCreateRootEntity(t *testing.T) {
    39  	db, dbpath := newTestDb(t)
    40  	defer destroyTestDb(dbpath)
    41  	root := db.RootEntity()
    42  	if root == nil {
    43  		t.Fatal("Root entity should not be nil")
    44  	}
    45  }
    46  
    47  func TestGetRootEntity(t *testing.T) {
    48  	db, dbpath := newTestDb(t)
    49  	defer destroyTestDb(dbpath)
    50  
    51  	e := db.Get("/")
    52  	if e == nil {
    53  		t.Fatal("Entity should not be nil")
    54  	}
    55  	if e.ID() != "0" {
    56  		t.Fatalf("Entity id should be 0, got %s", e.ID())
    57  	}
    58  }
    59  
    60  func TestSetEntityWithDifferentName(t *testing.T) {
    61  	db, dbpath := newTestDb(t)
    62  	defer destroyTestDb(dbpath)
    63  
    64  	db.Set("/test", "1")
    65  	if _, err := db.Set("/other", "1"); err != nil {
    66  		t.Fatal(err)
    67  	}
    68  }
    69  
    70  func TestSetDuplicateEntity(t *testing.T) {
    71  	db, dbpath := newTestDb(t)
    72  	defer destroyTestDb(dbpath)
    73  
    74  	if _, err := db.Set("/foo", "42"); err != nil {
    75  		t.Fatal(err)
    76  	}
    77  	if _, err := db.Set("/foo", "43"); err == nil {
    78  		t.Fatalf("Creating an entry with a duplicate path did not cause an error")
    79  	}
    80  }
    81  
    82  func TestCreateChild(t *testing.T) {
    83  	db, dbpath := newTestDb(t)
    84  	defer destroyTestDb(dbpath)
    85  
    86  	child, err := db.Set("/db", "1")
    87  	if err != nil {
    88  		t.Fatal(err)
    89  	}
    90  	if child == nil {
    91  		t.Fatal("Child should not be nil")
    92  	}
    93  	if child.ID() != "1" {
    94  		t.Fail()
    95  	}
    96  }
    97  
    98  func TestParents(t *testing.T) {
    99  	db, dbpath := newTestDb(t)
   100  	defer destroyTestDb(dbpath)
   101  
   102  	for i := 1; i < 6; i++ {
   103  		a := strconv.Itoa(i)
   104  		if _, err := db.Set("/"+a, a); err != nil {
   105  			t.Fatal(err)
   106  		}
   107  	}
   108  
   109  	for i := 6; i < 11; i++ {
   110  		a := strconv.Itoa(i)
   111  		p := strconv.Itoa(i - 5)
   112  
   113  		key := fmt.Sprintf("/%s/%s", p, a)
   114  
   115  		if _, err := db.Set(key, a); err != nil {
   116  			t.Fatal(err)
   117  		}
   118  
   119  		parents, err := db.Parents(key)
   120  		if err != nil {
   121  			t.Fatal(err)
   122  		}
   123  
   124  		if len(parents) != 1 {
   125  			t.Fatalf("Expected 1 entry for %s got %d", key, len(parents))
   126  		}
   127  
   128  		if parents[0] != p {
   129  			t.Fatalf("ID %s received, %s expected", parents[0], p)
   130  		}
   131  	}
   132  }
   133  
   134  func TestChildren(t *testing.T) {
   135  	// TODO Windows: Port this test
   136  	if runtime.GOOS == "windows" {
   137  		t.Skip("Needs porting to Windows")
   138  	}
   139  	db, dbpath := newTestDb(t)
   140  	defer destroyTestDb(dbpath)
   141  
   142  	str := "/"
   143  	for i := 1; i < 6; i++ {
   144  		a := strconv.Itoa(i)
   145  		if _, err := db.Set(str+a, a); err != nil {
   146  			t.Fatal(err)
   147  		}
   148  
   149  		str = str + a + "/"
   150  	}
   151  
   152  	str = "/"
   153  	for i := 10; i < 30; i++ { // 20 entities
   154  		a := strconv.Itoa(i)
   155  		if _, err := db.Set(str+a, a); err != nil {
   156  			t.Fatal(err)
   157  		}
   158  
   159  		str = str + a + "/"
   160  	}
   161  	entries, err := db.Children("/", 5)
   162  	if err != nil {
   163  		t.Fatal(err)
   164  	}
   165  
   166  	if len(entries) != 11 {
   167  		t.Fatalf("Expect 11 entries for / got %d", len(entries))
   168  	}
   169  
   170  	entries, err = db.Children("/", 20)
   171  	if err != nil {
   172  		t.Fatal(err)
   173  	}
   174  
   175  	if len(entries) != 25 {
   176  		t.Fatalf("Expect 25 entries for / got %d", len(entries))
   177  	}
   178  }
   179  
   180  func TestListAllRootChildren(t *testing.T) {
   181  	// TODO Windows: Port this test
   182  	if runtime.GOOS == "windows" {
   183  		t.Skip("Needs porting to Windows")
   184  	}
   185  
   186  	db, dbpath := newTestDb(t)
   187  	defer destroyTestDb(dbpath)
   188  
   189  	for i := 1; i < 6; i++ {
   190  		a := strconv.Itoa(i)
   191  		if _, err := db.Set("/"+a, a); err != nil {
   192  			t.Fatal(err)
   193  		}
   194  	}
   195  	entries := db.List("/", -1)
   196  	if len(entries) != 5 {
   197  		t.Fatalf("Expect 5 entries for / got %d", len(entries))
   198  	}
   199  }
   200  
   201  func TestListAllSubChildren(t *testing.T) {
   202  	// TODO Windows: Port this test
   203  	if runtime.GOOS == "windows" {
   204  		t.Skip("Needs porting to Windows")
   205  	}
   206  	db, dbpath := newTestDb(t)
   207  	defer destroyTestDb(dbpath)
   208  
   209  	_, err := db.Set("/webapp", "1")
   210  	if err != nil {
   211  		t.Fatal(err)
   212  	}
   213  	child2, err := db.Set("/db", "2")
   214  	if err != nil {
   215  		t.Fatal(err)
   216  	}
   217  	child4, err := db.Set("/logs", "4")
   218  	if err != nil {
   219  		t.Fatal(err)
   220  	}
   221  	if _, err := db.Set("/db/logs", child4.ID()); err != nil {
   222  		t.Fatal(err)
   223  	}
   224  
   225  	child3, err := db.Set("/sentry", "3")
   226  	if err != nil {
   227  		t.Fatal(err)
   228  	}
   229  	if _, err := db.Set("/webapp/sentry", child3.ID()); err != nil {
   230  		t.Fatal(err)
   231  	}
   232  	if _, err := db.Set("/webapp/db", child2.ID()); err != nil {
   233  		t.Fatal(err)
   234  	}
   235  
   236  	entries := db.List("/webapp", 1)
   237  	if len(entries) != 3 {
   238  		t.Fatalf("Expect 3 entries for / got %d", len(entries))
   239  	}
   240  
   241  	entries = db.List("/webapp", 0)
   242  	if len(entries) != 2 {
   243  		t.Fatalf("Expect 2 entries for / got %d", len(entries))
   244  	}
   245  }
   246  
   247  func TestAddSelfAsChild(t *testing.T) {
   248  	// TODO Windows: Port this test
   249  	if runtime.GOOS == "windows" {
   250  		t.Skip("Needs porting to Windows")
   251  	}
   252  	db, dbpath := newTestDb(t)
   253  	defer destroyTestDb(dbpath)
   254  
   255  	child, err := db.Set("/test", "1")
   256  	if err != nil {
   257  		t.Fatal(err)
   258  	}
   259  	if _, err := db.Set("/test/other", child.ID()); err == nil {
   260  		t.Fatal("Error should not be nil")
   261  	}
   262  }
   263  
   264  func TestAddChildToNonExistentRoot(t *testing.T) {
   265  	db, dbpath := newTestDb(t)
   266  	defer destroyTestDb(dbpath)
   267  
   268  	if _, err := db.Set("/myapp", "1"); err != nil {
   269  		t.Fatal(err)
   270  	}
   271  
   272  	if _, err := db.Set("/myapp/proxy/db", "2"); err == nil {
   273  		t.Fatal("Error should not be nil")
   274  	}
   275  }
   276  
   277  func TestWalkAll(t *testing.T) {
   278  	// TODO Windows: Port this test
   279  	if runtime.GOOS == "windows" {
   280  		t.Skip("Needs porting to Windows")
   281  	}
   282  	db, dbpath := newTestDb(t)
   283  	defer destroyTestDb(dbpath)
   284  	_, err := db.Set("/webapp", "1")
   285  	if err != nil {
   286  		t.Fatal(err)
   287  	}
   288  	child2, err := db.Set("/db", "2")
   289  	if err != nil {
   290  		t.Fatal(err)
   291  	}
   292  	child4, err := db.Set("/db/logs", "4")
   293  	if err != nil {
   294  		t.Fatal(err)
   295  	}
   296  	if _, err := db.Set("/webapp/logs", child4.ID()); err != nil {
   297  		t.Fatal(err)
   298  	}
   299  
   300  	child3, err := db.Set("/sentry", "3")
   301  	if err != nil {
   302  		t.Fatal(err)
   303  	}
   304  	if _, err := db.Set("/webapp/sentry", child3.ID()); err != nil {
   305  		t.Fatal(err)
   306  	}
   307  	if _, err := db.Set("/webapp/db", child2.ID()); err != nil {
   308  		t.Fatal(err)
   309  	}
   310  
   311  	child5, err := db.Set("/gograph", "5")
   312  	if err != nil {
   313  		t.Fatal(err)
   314  	}
   315  	if _, err := db.Set("/webapp/same-ref-diff-name", child5.ID()); err != nil {
   316  		t.Fatal(err)
   317  	}
   318  
   319  	if err := db.Walk("/", func(p string, e *Entity) error {
   320  		t.Logf("Path: %s Entity: %s", p, e.ID())
   321  		return nil
   322  	}, -1); err != nil {
   323  		t.Fatal(err)
   324  	}
   325  }
   326  
   327  func TestGetEntityByPath(t *testing.T) {
   328  	// TODO Windows: Port this test
   329  	if runtime.GOOS == "windows" {
   330  		t.Skip("Needs porting to Windows")
   331  	}
   332  	db, dbpath := newTestDb(t)
   333  	defer destroyTestDb(dbpath)
   334  	_, err := db.Set("/webapp", "1")
   335  	if err != nil {
   336  		t.Fatal(err)
   337  	}
   338  	child2, err := db.Set("/db", "2")
   339  	if err != nil {
   340  		t.Fatal(err)
   341  	}
   342  	child4, err := db.Set("/logs", "4")
   343  	if err != nil {
   344  		t.Fatal(err)
   345  	}
   346  	if _, err := db.Set("/db/logs", child4.ID()); err != nil {
   347  		t.Fatal(err)
   348  	}
   349  
   350  	child3, err := db.Set("/sentry", "3")
   351  	if err != nil {
   352  		t.Fatal(err)
   353  	}
   354  	if _, err := db.Set("/webapp/sentry", child3.ID()); err != nil {
   355  		t.Fatal(err)
   356  	}
   357  	if _, err := db.Set("/webapp/db", child2.ID()); err != nil {
   358  		t.Fatal(err)
   359  	}
   360  
   361  	child5, err := db.Set("/gograph", "5")
   362  	if err != nil {
   363  		t.Fatal(err)
   364  	}
   365  	if _, err := db.Set("/webapp/same-ref-diff-name", child5.ID()); err != nil {
   366  		t.Fatal(err)
   367  	}
   368  
   369  	entity := db.Get("/webapp/db/logs")
   370  	if entity == nil {
   371  		t.Fatal("Entity should not be nil")
   372  	}
   373  	if entity.ID() != "4" {
   374  		t.Fatalf("Expected to get entity with id 4, got %s", entity.ID())
   375  	}
   376  }
   377  
   378  func TestEnitiesPaths(t *testing.T) {
   379  	// TODO Windows: Port this test
   380  	if runtime.GOOS == "windows" {
   381  		t.Skip("Needs porting to Windows")
   382  	}
   383  	db, dbpath := newTestDb(t)
   384  	defer destroyTestDb(dbpath)
   385  	_, err := db.Set("/webapp", "1")
   386  	if err != nil {
   387  		t.Fatal(err)
   388  	}
   389  	child2, err := db.Set("/db", "2")
   390  	if err != nil {
   391  		t.Fatal(err)
   392  	}
   393  	child4, err := db.Set("/logs", "4")
   394  	if err != nil {
   395  		t.Fatal(err)
   396  	}
   397  	if _, err := db.Set("/db/logs", child4.ID()); err != nil {
   398  		t.Fatal(err)
   399  	}
   400  
   401  	child3, err := db.Set("/sentry", "3")
   402  	if err != nil {
   403  		t.Fatal(err)
   404  	}
   405  	if _, err := db.Set("/webapp/sentry", child3.ID()); err != nil {
   406  		t.Fatal(err)
   407  	}
   408  	if _, err := db.Set("/webapp/db", child2.ID()); err != nil {
   409  		t.Fatal(err)
   410  	}
   411  
   412  	child5, err := db.Set("/gograph", "5")
   413  	if err != nil {
   414  		t.Fatal(err)
   415  	}
   416  	if _, err := db.Set("/webapp/same-ref-diff-name", child5.ID()); err != nil {
   417  		t.Fatal(err)
   418  	}
   419  
   420  	out := db.List("/", -1)
   421  	for _, p := range out.Paths() {
   422  		t.Log(p)
   423  	}
   424  }
   425  
   426  func TestDeleteRootEntity(t *testing.T) {
   427  	db, dbpath := newTestDb(t)
   428  	defer destroyTestDb(dbpath)
   429  
   430  	if err := db.Delete("/"); err == nil {
   431  		t.Fatal("Error should not be nil")
   432  	}
   433  }
   434  
   435  func TestDeleteEntity(t *testing.T) {
   436  	// TODO Windows: Port this test
   437  	if runtime.GOOS == "windows" {
   438  		t.Skip("Needs porting to Windows")
   439  	}
   440  	db, dbpath := newTestDb(t)
   441  	defer destroyTestDb(dbpath)
   442  	_, err := db.Set("/webapp", "1")
   443  	if err != nil {
   444  		t.Fatal(err)
   445  	}
   446  	child2, err := db.Set("/db", "2")
   447  	if err != nil {
   448  		t.Fatal(err)
   449  	}
   450  	child4, err := db.Set("/logs", "4")
   451  	if err != nil {
   452  		t.Fatal(err)
   453  	}
   454  	if _, err := db.Set("/db/logs", child4.ID()); err != nil {
   455  		t.Fatal(err)
   456  	}
   457  
   458  	child3, err := db.Set("/sentry", "3")
   459  	if err != nil {
   460  		t.Fatal(err)
   461  	}
   462  	if _, err := db.Set("/webapp/sentry", child3.ID()); err != nil {
   463  		t.Fatal(err)
   464  	}
   465  	if _, err := db.Set("/webapp/db", child2.ID()); err != nil {
   466  		t.Fatal(err)
   467  	}
   468  
   469  	child5, err := db.Set("/gograph", "5")
   470  	if err != nil {
   471  		t.Fatal(err)
   472  	}
   473  	if _, err := db.Set("/webapp/same-ref-diff-name", child5.ID()); err != nil {
   474  		t.Fatal(err)
   475  	}
   476  
   477  	if err := db.Delete("/webapp/sentry"); err != nil {
   478  		t.Fatal(err)
   479  	}
   480  	entity := db.Get("/webapp/sentry")
   481  	if entity != nil {
   482  		t.Fatal("Entity /webapp/sentry should be nil")
   483  	}
   484  }
   485  
   486  func TestCountRefs(t *testing.T) {
   487  	// TODO Windows: Port this test
   488  	if runtime.GOOS == "windows" {
   489  		t.Skip("Needs porting to Windows")
   490  	}
   491  	db, dbpath := newTestDb(t)
   492  	defer destroyTestDb(dbpath)
   493  
   494  	db.Set("/webapp", "1")
   495  
   496  	if db.Refs("1") != 1 {
   497  		t.Fatal("Expect reference count to be 1")
   498  	}
   499  
   500  	db.Set("/db", "2")
   501  	db.Set("/webapp/db", "2")
   502  	if db.Refs("2") != 2 {
   503  		t.Fatal("Expect reference count to be 2")
   504  	}
   505  }
   506  
   507  func TestPurgeId(t *testing.T) {
   508  	// TODO Windows: Port this test
   509  	if runtime.GOOS == "windows" {
   510  		t.Skip("Needs porting to Windows")
   511  	}
   512  
   513  	db, dbpath := newTestDb(t)
   514  	defer destroyTestDb(dbpath)
   515  
   516  	db.Set("/webapp", "1")
   517  
   518  	if c := db.Refs("1"); c != 1 {
   519  		t.Fatalf("Expect reference count to be 1, got %d", c)
   520  	}
   521  
   522  	db.Set("/db", "2")
   523  	db.Set("/webapp/db", "2")
   524  
   525  	count, err := db.Purge("2")
   526  	if err != nil {
   527  		t.Fatal(err)
   528  	}
   529  	if count != 2 {
   530  		t.Fatalf("Expected 2 references to be removed, got %d", count)
   531  	}
   532  }
   533  
   534  // Regression test https://github.com/docker/docker/issues/12334
   535  func TestPurgeIdRefPaths(t *testing.T) {
   536  	// TODO Windows: Port this test
   537  	if runtime.GOOS == "windows" {
   538  		t.Skip("Needs porting to Windows")
   539  	}
   540  	db, dbpath := newTestDb(t)
   541  	defer destroyTestDb(dbpath)
   542  
   543  	db.Set("/webapp", "1")
   544  	db.Set("/db", "2")
   545  
   546  	db.Set("/db/webapp", "1")
   547  
   548  	if c := db.Refs("1"); c != 2 {
   549  		t.Fatalf("Expected 2 reference for webapp, got %d", c)
   550  	}
   551  	if c := db.Refs("2"); c != 1 {
   552  		t.Fatalf("Expected 1 reference for db, got %d", c)
   553  	}
   554  
   555  	if rp := db.RefPaths("2"); len(rp) != 1 {
   556  		t.Fatalf("Expected 1 reference path for db, got %d", len(rp))
   557  	}
   558  
   559  	count, err := db.Purge("2")
   560  	if err != nil {
   561  		t.Fatal(err)
   562  	}
   563  
   564  	if count != 2 {
   565  		t.Fatalf("Expected 2 rows to be removed, got %d", count)
   566  	}
   567  
   568  	if c := db.Refs("2"); c != 0 {
   569  		t.Fatalf("Expected 0 reference for db, got %d", c)
   570  	}
   571  	if c := db.Refs("1"); c != 1 {
   572  		t.Fatalf("Expected 1 reference for webapp, got %d", c)
   573  	}
   574  }
   575  
   576  func TestRename(t *testing.T) {
   577  	// TODO Windows: Port this test
   578  	if runtime.GOOS == "windows" {
   579  		t.Skip("Needs porting to Windows")
   580  	}
   581  	db, dbpath := newTestDb(t)
   582  	defer destroyTestDb(dbpath)
   583  
   584  	db.Set("/webapp", "1")
   585  
   586  	if db.Refs("1") != 1 {
   587  		t.Fatal("Expect reference count to be 1")
   588  	}
   589  
   590  	db.Set("/db", "2")
   591  	db.Set("/webapp/db", "2")
   592  
   593  	if db.Get("/webapp/db") == nil {
   594  		t.Fatal("Cannot find entity at path /webapp/db")
   595  	}
   596  
   597  	if err := db.Rename("/webapp/db", "/webapp/newdb"); err != nil {
   598  		t.Fatal(err)
   599  	}
   600  	if db.Get("/webapp/db") != nil {
   601  		t.Fatal("Entity should not exist at /webapp/db")
   602  	}
   603  	if db.Get("/webapp/newdb") == nil {
   604  		t.Fatal("Cannot find entity at path /webapp/newdb")
   605  	}
   606  
   607  }
   608  
   609  func TestCreateMultipleNames(t *testing.T) {
   610  	// TODO Windows: Port this test
   611  	if runtime.GOOS == "windows" {
   612  		t.Skip("Needs porting to Windows")
   613  	}
   614  
   615  	db, dbpath := newTestDb(t)
   616  	defer destroyTestDb(dbpath)
   617  
   618  	db.Set("/db", "1")
   619  	if _, err := db.Set("/myapp", "1"); err != nil {
   620  		t.Fatal(err)
   621  	}
   622  
   623  	db.Walk("/", func(p string, e *Entity) error {
   624  		t.Logf("%s\n", p)
   625  		return nil
   626  	}, -1)
   627  }
   628  
   629  func TestRefPaths(t *testing.T) {
   630  	db, dbpath := newTestDb(t)
   631  	defer destroyTestDb(dbpath)
   632  
   633  	db.Set("/webapp", "1")
   634  
   635  	db.Set("/db", "2")
   636  	db.Set("/webapp/db", "2")
   637  
   638  	refs := db.RefPaths("2")
   639  	if len(refs) != 2 {
   640  		t.Fatalf("Expected reference count to be 2, got %d", len(refs))
   641  	}
   642  }
   643  
   644  func TestExistsTrue(t *testing.T) {
   645  	db, dbpath := newTestDb(t)
   646  	defer destroyTestDb(dbpath)
   647  
   648  	db.Set("/testing", "1")
   649  
   650  	if !db.Exists("/testing") {
   651  		t.Fatalf("/tesing should exist")
   652  	}
   653  }
   654  
   655  func TestExistsFalse(t *testing.T) {
   656  	// TODO Windows: Port this test
   657  	if runtime.GOOS == "windows" {
   658  		t.Skip("Needs porting to Windows")
   659  	}
   660  	db, dbpath := newTestDb(t)
   661  	defer destroyTestDb(dbpath)
   662  
   663  	db.Set("/toerhe", "1")
   664  
   665  	if db.Exists("/testing") {
   666  		t.Fatalf("/tesing should not exist")
   667  	}
   668  
   669  }
   670  
   671  func TestGetNameWithTrailingSlash(t *testing.T) {
   672  	db, dbpath := newTestDb(t)
   673  	defer destroyTestDb(dbpath)
   674  
   675  	db.Set("/todo", "1")
   676  
   677  	e := db.Get("/todo/")
   678  	if e == nil {
   679  		t.Fatalf("Entity should not be nil")
   680  	}
   681  }
   682  
   683  func TestConcurrentWrites(t *testing.T) {
   684  	// TODO Windows: Port this test
   685  	if runtime.GOOS == "windows" {
   686  		t.Skip("Needs porting to Windows")
   687  	}
   688  	db, dbpath := newTestDb(t)
   689  	defer destroyTestDb(dbpath)
   690  
   691  	errs := make(chan error, 2)
   692  
   693  	save := func(name string, id string) {
   694  		if _, err := db.Set(fmt.Sprintf("/%s", name), id); err != nil {
   695  			errs <- err
   696  		}
   697  		errs <- nil
   698  	}
   699  	purge := func(id string) {
   700  		if _, err := db.Purge(id); err != nil {
   701  			errs <- err
   702  		}
   703  		errs <- nil
   704  	}
   705  
   706  	save("/1", "1")
   707  
   708  	go purge("1")
   709  	go save("/2", "2")
   710  
   711  	any := false
   712  	for i := 0; i < 2; i++ {
   713  		if err := <-errs; err != nil {
   714  			any = true
   715  			t.Log(err)
   716  		}
   717  	}
   718  	if any {
   719  		t.Fail()
   720  	}
   721  }