Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add block adapters unit tests #5317

Merged
merged 26 commits into from
Mar 19, 2023
Merged

Add block adapters unit tests #5317

merged 26 commits into from
Mar 19, 2023

Conversation

N-o-Z
Copy link
Member

@N-o-Z N-o-Z commented Feb 22, 2023

Linked Issue

Closes #5246


Change Description

Background

Adding generic unit test for block adapters, in order to align functionality and behavior
For the scope of this PR, added testing for the majority of the adapter interface, and enabled unit testing for local and Azure block adapters

Breaking Change?

No

@N-o-Z N-o-Z added exclude-changelog PR description should not be included in next release changelog team/versioning-engine Team versioning engine labels Feb 22, 2023
@N-o-Z N-o-Z requested a review from a team February 22, 2023 18:30
@N-o-Z N-o-Z self-assigned this Feb 22, 2023
Copy link
Contributor

@itaiad200 itaiad200 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was skeptical at first when you came up with this idea.. Seeing how easy it is to add adapter tests and the guarantees they grant us, it really is a great addition to our coverage.

@@ -325,7 +325,7 @@ func (a *Adapter) Walk(ctx context.Context, walkOpt block.WalkOpts, walkFn block
return err
}
}
if marker = resp.NextMarker; marker == nil {
if marker = resp.NextMarker; marker == nil || *marker == "" {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are both nil and empty string really an option? Yikes.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes - unfortunately verified with real adapter

@@ -46,4 +46,5 @@ type Azure struct {
StorageAccessKey string
TryTimeout time.Duration
PreSignedExpiry time.Duration
Url *string
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a config parameter for testing purposes to provide a custom URL to override the default URL template - added comment

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe change to Endpoint?

var params []func(*mem.Adapter)
adapterTest.TestAdapter(t, block.BlockstoreTypeMem, params)
}
// TODO (niro): Need to enable
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A marker so you won't forget

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


func runAzurite(dockerPool *dockertest.Pool) (string, func()) {
ctx := context.Background()
resource, err := dockerPool.Run("mcr.microsoft.com/azure-storage/azurite", "latest", []string{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pin a version or wake up one day to find out we're not compatible with latest no more :)

if err != nil {
panic(err)
}
hosts.AddHost("127.0.0.1", accountHost)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we overriding the host machine /etc/hosts file? If so, I'm worried about this one. is there any other way that doesn't require overriding the machine /etc/hosts? Test can crash half way through leaving garbage in that file..

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By default the emulator uses an IP style URL where the account name is part of the pah. This breaks our code due to how we parse the URL as we expect to account to be the domain.
So we need to add a host to our local IP which maintains the same structure as the production service URL.
This was the best option I found to do that - I'm open to better suggestions

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotcha, so the real problem is that we don't support accounts as part of the path.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nopcoder suggested that we'll leverage s3.local.lakefs.io somehow. Is it possible to use a real DNS record that will point to localhost?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The domain is comprised from the account name - which is dynamically determined. How do you suggest to deal with that?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We add a DNS record *.local.azurite.lakefs.io (or something similar) that points to 127.0.0.1. Then for every account name xx we will use the host name xx.local.azurite.lakefs.io, thus avoiding hosts file modifications.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The usual way is to spin up everything (test and Azurite) inside a single docker-compose environment.

On the one hand, users cannot edit hosts lookup -- this should never work.

In the past we had a DNS record for ease of deployment of local S3 gateways with host-based addressing. It makes a log of sense for quick-starting users. But using a DNS record here hurts in other ways, it means "unit" tests require Internet connectivity.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As an alternative, you can override net.DefaultResolver with something that resolves *.azurite.example.net but falls back on the original DefaultResolver for everything else.

Comment on lines 64 to 73
client, err := service.NewClientWithSharedKeyCredential(url, cred, nil)
if err != nil {
panic(err)
}

// Check connectivity with containerName
_, err = client.GetAccountInfo(ctx, nil)
if err != nil {
panic(err)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the below lines cover connectivity check

obj := block.ObjectPointer{
StorageNamespace: storageNamespace,
Identifier: contents,
IdentifierType: block.IdentifierTypeRelative,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checking Full identifiers is critical too.

Comment on lines +163 to +164
{"simple", "abc", []string{"one ", "two ", "three"}},
{"nested", "foo/bar", []string{"one ", "two ", "three"}},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will fail for some adapters. For example, S3 forces all parts except the last to be at least 5MB.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understand - lets handle this when it becomes an issue?

return tree
}

func testAdapterMultipartUpload(t *testing.T, adapter block.Adapter, storageNamespace string) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aborting multipart uploads is also important.
It can be added in a different PR.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes - not everything was covered in this PR, I'll open a separate issue

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@N-o-Z
Copy link
Member Author

N-o-Z commented Feb 23, 2023

I was skeptical at first when you came up with this idea.. Seeing how easy it is to add adapter tests and the guarantees they grant us, it really is a great addition to our coverage. !

Credit goes to @nopcoder 😄

@N-o-Z N-o-Z requested a review from itaiad200 February 23, 2023 13:33
Copy link
Contributor

@itaiad200 itaiad200 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes to consider alternatives to hosts file modifications.

Copy link
Contributor

@arielshaqed arielshaqed left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor comment about encapsulating tests from The Internet as far as possible.

if err != nil {
panic(err)
}
hosts.AddHost("127.0.0.1", accountHost)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The usual way is to spin up everything (test and Azurite) inside a single docker-compose environment.

On the one hand, users cannot edit hosts lookup -- this should never work.

In the past we had a DNS record for ease of deployment of local S3 gateways with host-based addressing. It makes a log of sense for quick-starting users. But using a DNS record here hurts in other ways, it means "unit" tests require Internet connectivity.

if err != nil {
panic(err)
}
hosts.AddHost("127.0.0.1", accountHost)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As an alternative, you can override net.DefaultResolver with something that resolves *.azurite.example.net but falls back on the original DefaultResolver for everything else.

@N-o-Z N-o-Z requested a review from itaiad200 February 26, 2023 17:58
Copy link
Contributor

@itaiad200 itaiad200 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for applying the hosts change!

Copy link
Contributor

@arielshaqed arielshaqed left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! But I worry about binding port 53 in particular, and any constant port in general. Tests should bind only ephemeral ports, or they risk unpleasant surprises (PC firewall popups, outright refusal on POSIX, inability to run the test twice concurrently, etc.).

Can we

}

srv := &dns.Server{
Addr: ":53",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think binds to a specific port on the host machine. But that port may be occupied, maybe someone runs dnsmasq! Also because this uses a port <1024 it has to run as root on some systems.

Consider binding only on "127.0.0.1:0" or similar, and then querying the server which ephemeral port it received. Not sure you can do it with this DNS server package though. I think that this dns.Server might be able to bind an ephemeral port if you configure it with Addr: "127.0.0.1:0", and then fetch that port using net.SplitHostPort(server.Listener.Addr().String()).

# Conflicts:
#	pkg/block/azure/adapter.go
#	pkg/block/local/adapter.go
#	pkg/block/local/adapter_test.go
#	pkg/block/mem/adapter_test.go
@N-o-Z
Copy link
Member Author

N-o-Z commented Mar 2, 2023

Had to do a big refactor due to removal of the Walk function in master.
Added fixes for namespace resolution and other

@N-o-Z N-o-Z force-pushed the task/add-adapter-unit-tests branch from d69cad8 to d9bf3d6 Compare March 5, 2023 15:27
@N-o-Z N-o-Z force-pushed the task/add-adapter-unit-tests branch from d9bf3d6 to 6043605 Compare March 6, 2023 07:56
@N-o-Z N-o-Z force-pushed the task/add-adapter-unit-tests branch from 6043605 to a16fb04 Compare March 6, 2023 08:51
Copy link
Contributor

@arielshaqed arielshaqed left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

One thing missing from the tests that is particularly relevant to the local block adapter in production is testing that path traversal doesn't work.

  • Paths like a/b/./c must not be the same as a/b/c (maybe they should error out).
  • Paths like a/b/../b/c must not be the same as a/b/c (maybe they should error out).
  • Paths like a///b must be handled correctly or error out (POSIX will treat them as a/b).
  • Paths like namespace/prefix/../../../../../../../etc/passwd that escape out of namespace/prefix must error out.
  • Paths like namespace/prefix/a/b/\0/c where \0 is the NUL char (byte 0) must either error out or be interpreted the same on POSIX filesystems in local mode and on lakeFS.

Another thing to test (which might be considerably more difficult!) is that POSIX filesystems use the same sort as

Comment on lines 122 to 123
// For testing purposes - override default url template
if params.URL != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this really is only for testing, consider renaming the configuration option to something like url_for_testing. Comments are too easy to ignore.

"github.com/treeverse/lakefs/pkg/ingest/store"
)

func TestAdapter(t *testing.T, adapter block.Adapter, storageNamespace, externalPath string) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function probably should not be named Test*, that's the name of a test function. Maybe something like VerifyAdapter?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I'm missing something - but this is a test function

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really: it's a helper function for writing test functions as described in package testing.

Final counterpoint from me on this topic: suppose TestAdapter included reading the config and therefore its callers would set all values from the environment. It would need to have signature TestAdapter(t *testing.T) -- and then package testing would try to run it! In that case you would need to rename the func. So naming a function Test* is confusing when you expect it not to run automagically.

@@ -81,7 +83,7 @@ func (l *LocalWalker) Walk(_ context.Context, storageURI *url.URL, options WalkO
}
const dirPerm = 0o755
_ = os.MkdirAll(l.cacheLocation, dirPerm)
cacheName := filepath.Join(l.cacheLocation, nanoid.Must()+"-import.json")
cacheName := filepath.Join(l.cacheLocation, gonanoid.Must()+"-import.json")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand. Shouldn't this live under the system temp file area, and be handled that way?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

local block adapter is constrained to the provided path and repo namespace (and configured allowed external prefixes).
We cannot assume the user allows access to the temp path.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import assume local adapter is configured to a shared location - so cache folder must be under the adapter's path.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be quite surprising or confusing to users. We should take care to document this.

@@ -81,7 +83,7 @@ func (l *LocalWalker) Walk(_ context.Context, storageURI *url.URL, options WalkO
}
const dirPerm = 0o755
_ = os.MkdirAll(l.cacheLocation, dirPerm)
cacheName := filepath.Join(l.cacheLocation, nanoid.Must()+"-import.json")
cacheName := filepath.Join(l.cacheLocation, gonanoid.Must()+"-import.json")
const cachePerm = 0o644
if err := os.WriteFile(cacheName, jsonData, cachePerm); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What deletes this file? Especially consider what happens during failure: if the file is not deleted, the user will try again... and nothing will release this file. Especially especially consider what happens during unexpected failure.

The usual way to handle temporary files in POSIX is:

  1. Create a temporary file (creat).
  2. Delete it.
  3. Write whatever contents you need.
  4. lseek back to the start of the file.
  5. Read whatever you need.
  6. ...
  7. close the file.

POSIX filesystems explicitly support this mode: A deleted file has no name, and is deleted when no open file descriptors remain on it. This pattern is already implemented in lakeFS.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case a continuation token (file) is required for the next read, we cannot deleted the file.
The write and read will happen in a different context, and therefore we cannot use the pattern you described.
I added a remove in case of an error.
I agree we do need to have a cleanup mechanism for stale continuation token files, but not quite sure how we should do it - in any case I don't think this should be under the scope of this PR.
I'll open a new issue for it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood that this is not part of this PR. Note also that keeping temporary files in the permanent storage area (previous comment) makes this even more confusing.

Copy link
Contributor

@nopcoder nopcoder left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great @N-o-Z - added my comments/concerns

Prefix: key.Key,
}, nil
}

func ResolveNamespace(defaultNamespace, key string, identifierType IdentifierType) (QualifiedKey, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

block.ResolveNamespace - think we should name it a bit different than the name we have on the interface or name the method on the interface differently.
It can be that block.ResolveNamespace -> DefaultResolveNamespace
Or .ResolveNamespace -> ResovleQualifiedKey
I'm trying to make it clear to the caller what the code will return for each case.

Comment on lines 66 to 71
// QK - QualifiedKey interface
type QK interface {
Format() string
GetStorageType() StorageType
GetStorageNamespace() string
GetKey() string
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Think this one should be named QualifiedKey as the block adapter interface will work only with the interface.
  • We can name the block level implementation as Common/GeneralQualifiedKey and the local one as LocalQualifiedKey. Need to identify the difference between the block level qualified key type and functions vs the interface which provided by our interface - the application level would like to work with the block adapter level type which is QualifiedKey interface.
  • Naming GetXXX -> XXX - I understand that as long as the implementation provides the same property it can conflict - but maybe we can find different names for struct/interface so we can keep using getters without a Get prefix.
Suggested change
// QK - QualifiedKey interface
type QK interface {
Format() string
GetStorageType() StorageType
GetStorageNamespace() string
GetKey() string
type QualifiedKey interface {
Format() string
StorageType() StorageType
StorageNamespace() string
Key() string

Comment on lines 20 to 23
var (
ErrInvalidNamespace = errors.New("invalid namespace")
ErrInvalidStorageType = errors.New("invalid storage type")
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Move to errors.go
  • Check maybe we can merge as both are used while we parse / build addresses - as "invalid address" with format that will render "namespace" and "storage type"

@@ -302,7 +300,7 @@ func (c *Controller) GetPhysicalAddress(w http.ResponseWriter, r *http.Request,
}

address := c.PathProvider.NewPath()
qk, err := block.ResolveNamespace(repo.StorageNamespace, address, block.IdentifierTypeRelative)
qk, err := c.Catalog.ResolveNamespace(repo.StorageNamespace, address, block.IdentifierTypeRelative)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer not to have another ResolveNamespace on catalog too as already have another two.

Comment on lines +167 to +174
if f.params != nil {
localParams, err = f.params.BlockstoreLocalParams()
if err != nil {
return nil, err
}
}

return local.NewLocalWalker(localParams), nil
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. The comment is related to the f.params - do we still require it as an interface?
  2. Is it an option to call the builder without proving the right configuration for the adapter? maybe we should just return an error in f.params is nil.

Comment on lines +179 to +184
if s3EndpointURL != "" {
config = aws.Config{
Endpoint: aws.String(s3EndpointURL),
Region: aws.String("us-east-1"), // Needs region for validation as it is AWS client
S3ForcePathStyle: aws.Bool(true),
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why in this case we provide defaults? I prefer the caller to be explicit or let the adapter pull from the env.

@@ -128,7 +129,11 @@ func buildS3Adapter(statsCollector stats.Collector, params params.S3) (*s3a.Adap
func BuildGSClient(ctx context.Context, params params.GS) (*storage.Client, error) {
var opts []option.ClientOption
if params.CredentialsFile != "" {
opts = append(opts, option.WithCredentialsFile(params.CredentialsFile))
credPath, err := homedir.Expand(params.CredentialsFile)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The config package usually expand the ~ to the user home dir.

return tree
}

func testAdapterMultipartUpload(t *testing.T, adapter block.Adapter, storageNamespace string) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wonder how is this test associate to the real world case as multipart upload have minimum size of 5MB (unless it is the last part)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK this only applies to S3.
I assume that when we enable the unit tests for S3 we will need to modify the test

N-o-Z and others added 5 commits March 8, 2023 10:28
Co-authored-by: Ariel Shaqed (Scolnicov) <ariels@treeverse.io>
Co-authored-by: Ariel Shaqed (Scolnicov) <ariels@treeverse.io>
Co-authored-by: Barak Amar <barak.amar@treeverse.io>
@N-o-Z
Copy link
Member Author

N-o-Z commented Mar 15, 2023

Thanks!

One thing missing from the tests that is particularly relevant to the local block adapter in production is testing that path traversal doesn't work.

  • Paths like a/b/./c must not be the same as a/b/c (maybe they should error out).
  • Paths like a/b/../b/c must not be the same as a/b/c (maybe they should error out).
  • Paths like a///b must be handled correctly or error out (POSIX will treat them as a/b).
  • Paths like namespace/prefix/../../../../../../../etc/passwd that escape out of namespace/prefix must error out.
  • Paths like namespace/prefix/a/b/\0/c where \0 is the NUL char (byte 0) must either error out or be interpreted the same on POSIX filesystems in local mode and on lakeFS.

Another thing to test (which might be considerably more difficult!) is that POSIX filesystems use the same sort as

Thanks @arielshaqed

These are very important test cases and as I dived more into it I understand that this requires addressing in a separate PR.
I'll open a new issue to tackle both the questions raised and the testing for it.

@N-o-Z N-o-Z requested review from nopcoder and arielshaqed March 16, 2023 08:54
Copy link
Contributor

@nopcoder nopcoder left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks looks good. The only thing that hurts the "go" eyes is the multiple return values by extractParamsFromObj - looks we just need good struct name use per adapter to hold the values.

@@ -228,6 +233,7 @@ func testAdapterMultipartUpload(t *testing.T, adapter block.Adapter, storageName
}

func testAdapterExists(t *testing.T, adapter block.Adapter, storageNamespace string) {
// TODO (niro): Test abs paths
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still relevant - alt open an issue

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@@ -81,7 +83,7 @@ func (l *LocalWalker) Walk(_ context.Context, storageURI *url.URL, options WalkO
}
const dirPerm = 0o755
_ = os.MkdirAll(l.cacheLocation, dirPerm)
cacheName := filepath.Join(l.cacheLocation, nanoid.Must()+"-import.json")
cacheName := filepath.Join(l.cacheLocation, gonanoid.Must()+"-import.json")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import assume local adapter is configured to a shared location - so cache folder must be under the adapter's path.

Copy link
Contributor

@arielshaqed arielshaqed left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, a lot of thought and effort are very evident!

Huge improvement, and probably needed since before I joined the company. Please make sure to link an issue for path traversal tests once we have one in a comment on this PR, so we don't lose track.

"github.com/treeverse/lakefs/pkg/ingest/store"
)

func TestAdapter(t *testing.T, adapter block.Adapter, storageNamespace, externalPath string) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really: it's a helper function for writing test functions as described in package testing.

Final counterpoint from me on this topic: suppose TestAdapter included reading the config and therefore its callers would set all values from the environment. It would need to have signature TestAdapter(t *testing.T) -- and then package testing would try to run it! In that case you would need to rename the func. So naming a function Test* is confusing when you expect it not to run automagically.

@@ -81,7 +83,7 @@ func (l *LocalWalker) Walk(_ context.Context, storageURI *url.URL, options WalkO
}
const dirPerm = 0o755
_ = os.MkdirAll(l.cacheLocation, dirPerm)
cacheName := filepath.Join(l.cacheLocation, nanoid.Must()+"-import.json")
cacheName := filepath.Join(l.cacheLocation, gonanoid.Must()+"-import.json")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be quite surprising or confusing to users. We should take care to document this.

@@ -81,7 +83,7 @@ func (l *LocalWalker) Walk(_ context.Context, storageURI *url.URL, options WalkO
}
const dirPerm = 0o755
_ = os.MkdirAll(l.cacheLocation, dirPerm)
cacheName := filepath.Join(l.cacheLocation, nanoid.Must()+"-import.json")
cacheName := filepath.Join(l.cacheLocation, gonanoid.Must()+"-import.json")
const cachePerm = 0o644
if err := os.WriteFile(cacheName, jsonData, cachePerm); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood that this is not part of this PR. Note also that keeping temporary files in the permanent storage area (previous comment) makes this even more confusing.

@N-o-Z N-o-Z mentioned this pull request Mar 19, 2023
6 tasks
@N-o-Z N-o-Z enabled auto-merge (squash) March 19, 2023 09:29
@N-o-Z N-o-Z merged commit d9cae2e into master Mar 19, 2023
@N-o-Z N-o-Z deleted the task/add-adapter-unit-tests branch March 19, 2023 09:32
nopcoder added a commit that referenced this pull request Mar 20, 2023
* Add block adapters unit tests

* CR Fix 1

* Fix linter issue

* Add fullpath tests

* Ignore static check

* CR Fixes

* CR Fixes 2

* Rebase fixes

* Fix lint error

* Fix S3 Adapter namespace

* Fix GS Adapter namespace

* Fix ugc test

* More fixes

* Update pkg/block/blocktest/adapter.go

Co-authored-by: Ariel Shaqed (Scolnicov) <ariels@treeverse.io>

* Update pkg/block/blocktest/adapter.go

Co-authored-by: Ariel Shaqed (Scolnicov) <ariels@treeverse.io>

* Update pkg/block/mem/adapter.go

Co-authored-by: Barak Amar <barak.amar@treeverse.io>

* More fixes

* Revert WriteRange

* Add comment

* More fixes

* More fixes 2

---------

Co-authored-by: Ariel Shaqed (Scolnicov) <ariels@treeverse.io>
Co-authored-by: Barak Amar <barak.amar@treeverse.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
exclude-changelog PR description should not be included in next release changelog team/versioning-engine Team versioning engine
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Map gaps and limitations for local block adapter to serve production traffic
4 participants