e2etest/newe2e_resource_definitions.go (187 lines of code) (raw):

package e2etest import ( "github.com/Azure/azure-storage-azcopy/v10/cmd" "github.com/google/uuid" ) // ResourceDefinition itself exists to loosely accept the handful of relevant types as a part of CreateResource and ValidateResource. type ResourceDefinition interface { // DefinitionTarget returns the location level this definition applies at. DefinitionTarget() cmd.LocationLevel // GenerateAdoptiveParent is designed for scaling a definition down to a root resource for creation GenerateAdoptiveParent(a Asserter) ResourceDefinition // MatchAdoptiveChild scales a resource of the same level up one level to the real definition level MatchAdoptiveChild(a Asserter, target ResourceManager) (ResourceManager, ResourceDefinition) // ApplyDefinition manages tree traversal by itself. applicationFunctions should realistically be creation of the underlying resource or validation. ApplyDefinition(a Asserter, target ResourceManager, applicationFunctions map[cmd.LocationLevel]func(Asserter, ResourceManager, ResourceDefinition)) // ShouldExist determines whether the resource should exist. // This should be checked in functions called by ApplyDefinition, as it is intended to alter creation and validation behavior. ShouldExist() bool } type MatchedResourceDefinition[T ResourceManager] interface { ResourceDefinition resourceDefinition() T } type ResourceDefinitionService struct { //Location common.Location // todo do we want/need this? does it make sense? CreateResource currently takes a ResourceManager, which can't target an AccountResourceManager because definitions differ Containers map[string]ResourceDefinitionContainer } func (r ResourceDefinitionService) GenerateAdoptiveParent(a Asserter) ResourceDefinition { a.HelperMarker().Helper() a.Error("Cannot generate account definition (yet)") return nil } func (r ResourceDefinitionService) MatchAdoptiveChild(a Asserter, target ResourceManager) (ResourceManager, ResourceDefinition) { a.HelperMarker().Helper() targetSvc, ok := target.(ServiceResourceManager) a.AssertNow("adoptive parent definitions must match the level of the target they're finding a child for", Equal{}, ok, true) a.AssertNow("adoptive parent definitions can only have one container", Equal{}, len(r.Containers), 1) for k, v := range r.Containers { return targetSvc.GetContainer(k), v } panic("sanity check: assertnow should have caught this") } func (r ResourceDefinitionService) ApplyDefinition(a Asserter, target ResourceManager, applicationFunctions map[cmd.LocationLevel]func(Asserter, ResourceManager, ResourceDefinition)) { a.HelperMarker().Helper() a.AssertNow("target must match level", Equal{}, target.Level(), r.DefinitionTarget()) serviceManager := target.(ServiceResourceManager) // Run the application function for services if applicationFunc, ok := applicationFunctions[r.DefinitionTarget()]; ok { applicationFunc(a, target, r) } for name, containerDef := range r.Containers { containerDef.ContainerName = &name containerManager := serviceManager.GetContainer(name) containerDef.ApplyDefinition(a, containerManager, applicationFunctions) } } func (r ResourceDefinitionService) DefinitionTarget() cmd.LocationLevel { return cmd.ELocationLevel.Service() } func (r ResourceDefinitionService) ShouldExist() bool { return true // Account can't not exist, won't be used in validation, etc. } func (r ResourceDefinitionService) resourceDefinition() ServiceResourceManager { panic("marker method") } type ResourceDefinitionContainer struct { // ContainerName is overwritten if used as a part of a parent definition ContainerName *string Properties ContainerProperties Objects ObjectResourceMapping // ContainerShouldExist is true unless set to false. Useful in negative validation (e.g. remove) ContainerShouldExist *bool } func (r ResourceDefinitionContainer) GenerateAdoptiveParent(a Asserter) ResourceDefinition { cName := DerefOrDefault(r.ContainerName, uuid.NewString()) return &ResourceDefinitionService{Containers: map[string]ResourceDefinitionContainer{ cName: r, }} } func (r ResourceDefinitionContainer) MatchAdoptiveChild(a Asserter, target ResourceManager) (ResourceManager, ResourceDefinition) { a.HelperMarker().Helper() targetCont, ok := target.(ContainerResourceManager) objs := r.Objects.Flatten() a.AssertNow("adoptive parent definitions must match the level of the target they're finding a child for", Equal{}, ok, true) a.AssertNow("adoptive parent definitions can only have one container", Equal{}, len(objs), 1) for k, v := range objs { return targetCont.GetObject(a, k, v.EntityType), v } panic("sanity check: assertnow should have caught this") } func (r ResourceDefinitionContainer) ApplyDefinition(a Asserter, target ResourceManager, applicationFunctions map[cmd.LocationLevel]func(Asserter, ResourceManager, ResourceDefinition)) { a.HelperMarker().Helper() a.AssertNow("target must match level", Equal{}, target.Level(), r.DefinitionTarget()) containerManager := target.(ContainerResourceManager) // Run the application function for containers if applicationFunc, ok := applicationFunctions[r.DefinitionTarget()]; ok { applicationFunc(a, target, r) } if r.Objects == nil { return } for name, objectDef := range r.Objects.Flatten() { objectDef.ObjectName = &name objectManager := containerManager.GetObject(a, name, objectDef.EntityType) objectDef.ApplyDefinition(a, objectManager, applicationFunctions) } } func (r ResourceDefinitionContainer) resourceDefinition() ContainerResourceManager { panic("marker method") } func (r ResourceDefinitionContainer) DefinitionTarget() cmd.LocationLevel { return cmd.ELocationLevel.Container() } func (r ResourceDefinitionContainer) ShouldExist() bool { return r.ContainerShouldExist == nil || *r.ContainerShouldExist } type ResourceDefinitionObject struct { // ObjectName is overwritten if used as a part of a parent definition ObjectName *string ObjectProperties Body ObjectContentContainer // ObjectShouldExist is true unless set to false. Useful in negative validation (e.g. remove) ObjectShouldExist *bool // This is used only to pass the size of the object when making a list of expected objects Size string } func (r ResourceDefinitionObject) Clone() ResourceDefinitionObject { var md5 []byte if r.HTTPHeaders.contentMD5 != nil { md5 = make([]byte, len(r.HTTPHeaders.contentMD5)) copy(md5, r.HTTPHeaders.contentMD5) } var body ObjectContentContainer if r.Body != nil { body = r.Body.Clone() } return ResourceDefinitionObject{ ObjectName: ClonePointer(r.ObjectName), ObjectProperties: ObjectProperties{ EntityType: r.EntityType, HTTPHeaders: contentHeaders{ cacheControl: ClonePointer(r.HTTPHeaders.cacheControl), contentDisposition: ClonePointer(r.HTTPHeaders.contentDisposition), contentEncoding: ClonePointer(r.HTTPHeaders.contentEncoding), contentLanguage: ClonePointer(r.HTTPHeaders.contentLanguage), contentType: ClonePointer(r.HTTPHeaders.contentType), contentMD5: md5, }, Metadata: r.Metadata.Clone(), BlobProperties: BlobProperties{ Type: ClonePointer(r.BlobProperties.Type), Tags: CloneMap(r.BlobProperties.Tags), BlockBlobAccessTier: ClonePointer(r.BlobProperties.BlockBlobAccessTier), PageBlobAccessTier: ClonePointer(r.BlobProperties.PageBlobAccessTier), VersionId: ClonePointer(r.BlobProperties.VersionId), }, BlobFSProperties: BlobFSProperties{ Permissions: ClonePointer(r.BlobFSProperties.Permissions), Owner: ClonePointer(r.BlobFSProperties.Owner), Group: ClonePointer(r.BlobFSProperties.Group), ACL: ClonePointer(r.BlobFSProperties.ACL), }, FileProperties: FileProperties{ FileAttributes: ClonePointer(r.FileProperties.FileAttributes), FileCreationTime: ClonePointer(r.FileProperties.FileCreationTime), FileLastWriteTime: ClonePointer(r.FileProperties.FileLastWriteTime), FilePermissions: ClonePointer(r.FileProperties.FilePermissions), }, }, Body: body, ObjectShouldExist: ClonePointer(r.ObjectShouldExist), } } func (r ResourceDefinitionObject) GenerateAdoptiveParent(a Asserter) ResourceDefinition { oName := DerefOrDefault(r.ObjectName, uuid.NewString()) return &ResourceDefinitionContainer{ Objects: ObjectResourceMappingFlat{ oName: r, }, } } func (r ResourceDefinitionObject) MatchAdoptiveChild(a Asserter, target ResourceManager) (ResourceManager, ResourceDefinition) { a.HelperMarker().Helper() a.Error("objects have no semantic children") panic("sanity check: error should catch this") } func (r ResourceDefinitionObject) ApplyDefinition(a Asserter, target ResourceManager, applicationFunctions map[cmd.LocationLevel]func(Asserter, ResourceManager, ResourceDefinition)) { a.HelperMarker().Helper() a.AssertNow("target must match level", Equal{}, target.Level(), r.DefinitionTarget()) // Run the application function for containers if applicationFunc, ok := applicationFunctions[r.DefinitionTarget()]; ok { applicationFunc(a, target, r) } } func (r ResourceDefinitionObject) DefinitionTarget() cmd.LocationLevel { return cmd.ELocationLevel.Object() } func (r ResourceDefinitionObject) resourceDefinition() ObjectResourceManager { panic("marker method") } func (r ResourceDefinitionObject) ShouldExist() bool { return r.ObjectShouldExist == nil || *r.ObjectShouldExist }