go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/config/impl/filesystem/fs_test.go (about)

     1  // Copyright 2016 The LUCI 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 filesystem
    16  
    17  import (
    18  	"context"
    19  	"io/ioutil"
    20  	"net/url"
    21  	"os"
    22  	"path/filepath"
    23  	"testing"
    24  
    25  	. "github.com/smartystreets/goconvey/convey"
    26  
    27  	"go.chromium.org/luci/common/errors"
    28  	"go.chromium.org/luci/config"
    29  )
    30  
    31  func withFolder(files map[string]string, cb func(folder string)) {
    32  	folder, err := ioutil.TempDir("", "fs_test_")
    33  	if err != nil {
    34  		panic(err)
    35  	}
    36  	defer os.RemoveAll(folder)
    37  
    38  	for fpath, content := range files {
    39  		if content == "" {
    40  			content = fpath
    41  		}
    42  		fpath = filepath.Join(folder, filepath.FromSlash(fpath))
    43  		if err := os.MkdirAll(filepath.Dir(fpath), 0777); err != nil {
    44  			panic(err)
    45  		}
    46  		if err := os.WriteFile(fpath, []byte(content), 0666); err != nil {
    47  			panic(err)
    48  		}
    49  	}
    50  
    51  	cb(folder)
    52  }
    53  
    54  func TestFSImpl(t *testing.T) {
    55  	t.Parallel()
    56  
    57  	ctx := context.Background()
    58  
    59  	withFolder(map[string]string{
    60  		"projects/doodly/something/file.cfg": "",
    61  		"projects/foobar/something/file.cfg": "",
    62  		"projects/foobar/another/file.cfg":   "",
    63  		"services/foosrv/something.cfg":      "",
    64  		"projects/foobar.json": `{
    65  			"Name": "A cool project",
    66  			"Url": "https://something.example.com"
    67  		}`,
    68  	}, func(folder string) {
    69  		Convey("basic Test Filesystem config client", t, func() {
    70  			const expectedRev = "a1b9f654acc5008452980a98ec930cbfdeec82d6"
    71  
    72  			client, err := New(folder)
    73  			So(err, ShouldBeNil)
    74  
    75  			Convey("GetConfig", func() {
    76  				expect := &config.Config{
    77  					Meta: config.Meta{
    78  						ConfigSet:   "projects/foobar",
    79  						Path:        "something/file.cfg",
    80  						ContentHash: "v1:72b8fe0ecd5e7560762aed58063aeb3795e69bd8",
    81  						Revision:    expectedRev,
    82  						ViewURL:     "file://./something/file.cfg",
    83  					},
    84  					Content: "projects/foobar/something/file.cfg",
    85  				}
    86  
    87  				Convey("All content", func() {
    88  					cfg, err := client.GetConfig(ctx, "projects/foobar", "something/file.cfg", false)
    89  					So(err, ShouldBeNil)
    90  					So(cfg, ShouldResemble, expect)
    91  				})
    92  
    93  				Convey("services", func() {
    94  					cfg, err := client.GetConfig(ctx, "services/foosrv", "something.cfg", false)
    95  					So(err, ShouldBeNil)
    96  					So(cfg, ShouldResemble, &config.Config{
    97  						Meta: config.Meta{
    98  							ConfigSet:   "services/foosrv",
    99  							Path:        "something.cfg",
   100  							ContentHash: "v1:536a41710e0cb4f21950d5e0e32642bda58fce9a",
   101  							Revision:    expectedRev,
   102  							ViewURL:     "file://./something.cfg",
   103  						},
   104  						Content: "services/foosrv/something.cfg",
   105  					})
   106  				})
   107  
   108  				Convey("just meta", func() {
   109  					cfg, err := client.GetConfig(ctx, "projects/foobar", "something/file.cfg", true)
   110  					So(err, ShouldBeNil)
   111  					So(cfg.ContentHash, ShouldEqual, "v1:72b8fe0ecd5e7560762aed58063aeb3795e69bd8")
   112  					So(cfg.Content, ShouldEqual, "")
   113  
   114  					Convey("make sure it doesn't poison the cache", func() {
   115  						cfg, err := client.GetConfig(ctx, "projects/foobar", "something/file.cfg", false)
   116  						So(err, ShouldBeNil)
   117  						So(cfg, ShouldResemble, expect)
   118  					})
   119  				})
   120  			})
   121  
   122  			Convey("GetConfigs", func() {
   123  				cfg, err := client.GetConfigs(ctx, "projects/foobar", nil, false)
   124  				So(err, ShouldBeNil)
   125  				So(cfg, ShouldResemble, map[string]config.Config{
   126  					"another/file.cfg": {
   127  						Meta: config.Meta{
   128  							ConfigSet:   "projects/foobar",
   129  							Path:        "another/file.cfg",
   130  							ContentHash: "v1:1b136cf89ccbd1d5f42cecae874367b0258d810d",
   131  							Revision:    expectedRev,
   132  							ViewURL:     "file://./another/file.cfg",
   133  						},
   134  						Content: "projects/foobar/another/file.cfg",
   135  					},
   136  					"something/file.cfg": {
   137  						Meta: config.Meta{
   138  							ConfigSet:   "projects/foobar",
   139  							Path:        "something/file.cfg",
   140  							ContentHash: "v1:72b8fe0ecd5e7560762aed58063aeb3795e69bd8",
   141  							Revision:    expectedRev,
   142  							ViewURL:     "file://./something/file.cfg",
   143  						},
   144  						Content: "projects/foobar/something/file.cfg",
   145  					},
   146  				})
   147  			})
   148  
   149  			Convey("ListFiles", func() {
   150  				cfg, err := client.ListFiles(ctx, "projects/foobar")
   151  				So(err, ShouldBeNil)
   152  				So(cfg, ShouldResemble, []string{
   153  					"another/file.cfg",
   154  					"something/file.cfg",
   155  				})
   156  			})
   157  
   158  			Convey("GetProjectConfigs", func() {
   159  				cfgs, err := client.GetProjectConfigs(ctx, "something/file.cfg", false)
   160  				So(err, ShouldBeNil)
   161  				So(cfgs, ShouldResemble, []config.Config{
   162  					{
   163  						Meta: config.Meta{
   164  							ConfigSet:   "projects/doodly",
   165  							Path:        "something/file.cfg",
   166  							ContentHash: "v1:5a2f9983dbb615a58e1d267633396e72f6710ef2",
   167  							Revision:    expectedRev,
   168  							ViewURL:     "file://./something/file.cfg",
   169  						},
   170  						Content: "projects/doodly/something/file.cfg",
   171  					},
   172  					{
   173  						Meta: config.Meta{
   174  							ConfigSet:   "projects/foobar",
   175  							Path:        "something/file.cfg",
   176  							ContentHash: "v1:72b8fe0ecd5e7560762aed58063aeb3795e69bd8",
   177  							Revision:    expectedRev,
   178  							ViewURL:     "file://./something/file.cfg",
   179  						},
   180  						Content: "projects/foobar/something/file.cfg",
   181  					},
   182  				})
   183  			})
   184  
   185  			Convey("GetProjects", func() {
   186  				projs, err := client.GetProjects(ctx)
   187  				So(err, ShouldBeNil)
   188  				So(projs, ShouldResemble, []config.Project{
   189  					{
   190  						ID:       "doodly",
   191  						Name:     "doodly",
   192  						RepoType: "FILESYSTEM",
   193  					},
   194  					{
   195  						ID:       "foobar",
   196  						Name:     "A cool project",
   197  						RepoType: "FILESYSTEM",
   198  						RepoURL:  &url.URL{Scheme: "https", Host: "something.example.com"},
   199  					},
   200  				})
   201  			})
   202  
   203  		})
   204  	})
   205  
   206  	withFolder(map[string]string{
   207  		"projects/doodly/file.cfg": "",
   208  		"projects/woodly/file.cfg": "",
   209  	}, func(folder string) {
   210  		Convey("rereads configs in sloppy mode", t, func() {
   211  			client, err := New(folder)
   212  			So(err, ShouldBeNil)
   213  
   214  			cfgs, err := client.GetProjectConfigs(ctx, "file.cfg", false)
   215  			So(err, ShouldBeNil)
   216  			So(cfgs, ShouldResemble, []config.Config{
   217  				{
   218  					Meta: config.Meta{
   219  						ConfigSet:   "projects/doodly",
   220  						Path:        "file.cfg",
   221  						ContentHash: "v1:a4f9e9ab503a00964c88e696067feed0702a81b3",
   222  						Revision:    "42a1ca1c43387844fafbb1c958a0d12f3ea61347",
   223  						ViewURL:     "file://./file.cfg",
   224  					},
   225  					Content: "projects/doodly/file.cfg",
   226  				}, {
   227  					Meta: config.Meta{
   228  						ConfigSet:   "projects/woodly",
   229  						Path:        "file.cfg",
   230  						ContentHash: "v1:722c6274d1e657691764199fa1095114a3569dee",
   231  						Revision:    "42a1ca1c43387844fafbb1c958a0d12f3ea61347",
   232  						ViewURL:     "file://./file.cfg",
   233  					},
   234  					Content: "projects/woodly/file.cfg",
   235  				},
   236  			})
   237  
   238  			err = os.WriteFile(
   239  				filepath.Join(folder, filepath.FromSlash("projects/doodly/file.cfg")),
   240  				[]byte("blarg"),
   241  				0666)
   242  			So(err, ShouldBeNil)
   243  
   244  			cfgs, err = client.GetProjectConfigs(ctx, "file.cfg", false)
   245  			So(err, ShouldBeNil)
   246  			So(cfgs, ShouldResemble, []config.Config{
   247  				{
   248  					Meta: config.Meta{
   249  						ConfigSet:   "projects/doodly",
   250  						Path:        "file.cfg",
   251  						ContentHash: "v1:a593942cb7ea9ffcd8ccf2f0fa23c338e23bfecd",
   252  						Revision:    "e841b8e92756491dae3302e1e31f673e0613ad0c",
   253  						ViewURL:     "file://./file.cfg",
   254  					},
   255  					Content: "blarg",
   256  				}, {
   257  					Meta: config.Meta{
   258  						ConfigSet:   "projects/woodly",
   259  						Path:        "file.cfg",
   260  						ContentHash: "v1:722c6274d1e657691764199fa1095114a3569dee",
   261  						Revision:    "e841b8e92756491dae3302e1e31f673e0613ad0c",
   262  						ViewURL:     "file://./file.cfg",
   263  					},
   264  					Content: "projects/woodly/file.cfg",
   265  				},
   266  			})
   267  		})
   268  	})
   269  
   270  	versioned := map[string]string{
   271  		"v1/projects/foobar/something/file.cfg": "",
   272  		"v2/projects/foobar/something/file.cfg": "",
   273  	}
   274  
   275  	withFolder(versioned, func(folder string) {
   276  		symlink := filepath.Join(folder, "link")
   277  
   278  		Convey("Test versioned Filesystem", t, func() {
   279  			So(errors.FilterFunc(os.Remove(symlink), os.IsNotExist), ShouldBeNil)
   280  			So(os.Symlink(filepath.Join(folder, "v1"), symlink), ShouldBeNil)
   281  			client, err := New(symlink)
   282  			So(err, ShouldBeNil)
   283  
   284  			Convey("v1", func() {
   285  				cfg, err := client.GetConfig(ctx, "projects/foobar", "something/file.cfg", false)
   286  				So(err, ShouldBeNil)
   287  				So(cfg.Content, ShouldEqual, "v1/projects/foobar/something/file.cfg")
   288  
   289  				Convey("v2", func() {
   290  					So(errors.Filter(os.Remove(symlink), os.ErrNotExist), ShouldBeNil)
   291  					So(os.Symlink(filepath.Join(folder, "v2"), symlink), ShouldBeNil)
   292  
   293  					cfg, err := client.GetConfig(ctx, "projects/foobar", "something/file.cfg", false)
   294  					So(err, ShouldBeNil)
   295  					So(cfg.Content, ShouldEqual, "v2/projects/foobar/something/file.cfg")
   296  				})
   297  			})
   298  
   299  		})
   300  	})
   301  
   302  }