diff --git a/build.gradle b/build.gradle index 4680598165d285..ee9e5307532710 100644 --- a/build.gradle +++ b/build.gradle @@ -231,7 +231,8 @@ project.ext.externalDependency = [ 'common': 'commons-io:commons-io:2.7', 'jline':'jline:jline:1.4.1', 'jetbrains':' org.jetbrains.kotlin:kotlin-stdlib:1.6.0', - 'annotationApi': 'javax.annotation:javax.annotation-api:1.3.2' + 'annotationApi': 'javax.annotation:javax.annotation-api:1.3.2', + 'classGraph': 'io.github.classgraph:classgraph:4.8.165', ] allprojects { diff --git a/buildSrc/src/main/java/com/linkedin/metadata/aspect/plugins/config b/buildSrc/src/main/java/com/linkedin/metadata/aspect/plugins/config new file mode 120000 index 00000000000000..087629f8ac1df2 --- /dev/null +++ b/buildSrc/src/main/java/com/linkedin/metadata/aspect/plugins/config @@ -0,0 +1 @@ +../../../../../../../../../entity-registry/src/main/java/com/linkedin/metadata/aspect/plugins/config \ No newline at end of file diff --git a/datahub-frontend/app/controllers/AuthenticationController.java b/datahub-frontend/app/controllers/AuthenticationController.java index 9c232e965a0034..d9568c25f6e8c6 100644 --- a/datahub-frontend/app/controllers/AuthenticationController.java +++ b/datahub-frontend/app/controllers/AuthenticationController.java @@ -15,12 +15,15 @@ import com.linkedin.common.urn.CorpuserUrn; import com.linkedin.common.urn.Urn; import com.typesafe.config.Config; +import java.net.URI; +import java.net.URISyntaxException; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.util.Base64; import java.util.Optional; import javax.annotation.Nonnull; import javax.inject.Inject; +import org.apache.commons.httpclient.InvalidRedirectLocationException; import org.apache.commons.lang3.StringUtils; import org.pac4j.core.client.Client; import org.pac4j.core.context.Cookie; @@ -86,7 +89,17 @@ public Result authenticate(Http.Request request) { final Optional maybeRedirectPath = Optional.ofNullable(request.getQueryString(AUTH_REDIRECT_URI_PARAM)); - final String redirectPath = maybeRedirectPath.orElse("/"); + String redirectPath = maybeRedirectPath.orElse("/"); + try { + URI redirectUri = new URI(redirectPath); + if (redirectUri.getScheme() != null || redirectUri.getAuthority() != null) { + throw new InvalidRedirectLocationException("Redirect location must be relative to the base url, cannot " + + "redirect to other domains: " + redirectPath, redirectPath); + } + } catch (URISyntaxException | InvalidRedirectLocationException e) { + _logger.warn(e.getMessage()); + redirectPath = "/"; + } if (AuthUtils.hasValidSessionCookie(request)) { return Results.redirect(redirectPath); diff --git a/datahub-frontend/test/app/ApplicationTest.java b/datahub-frontend/test/app/ApplicationTest.java index 8d80c2cfaa47dc..534cffb5cc7fe4 100644 --- a/datahub-frontend/test/app/ApplicationTest.java +++ b/datahub-frontend/test/app/ApplicationTest.java @@ -195,8 +195,27 @@ public void testAPI() throws ParseException { } @Test - public void testOidcRedirectToRequestedUrl() throws InterruptedException { + public void testOidcRedirectToRequestedUrl() { browser.goTo("/authenticate?redirect_uri=%2Fcontainer%2Furn%3Ali%3Acontainer%3ADATABASE"); assertEquals("container/urn:li:container:DATABASE", browser.url()); } + + /** + * The Redirect Uri parameter is used to store a previous relative location within the app to be able to + * take a user back to their expected page. Redirecting to other domains should be blocked. + */ + @Test + public void testInvalidRedirectUrl() { + browser.goTo("/authenticate?redirect_uri=https%3A%2F%2Fwww.google.com"); + assertEquals("", browser.url()); + + browser.goTo("/authenticate?redirect_uri=file%3A%2F%2FmyFile"); + assertEquals("", browser.url()); + + browser.goTo("/authenticate?redirect_uri=ftp%3A%2F%2FsomeFtp"); + assertEquals("", browser.url()); + + browser.goTo("/authenticate?redirect_uri=localhost%3A9002%2Flogin"); + assertEquals("", browser.url()); + } } diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/domain/CreateDomainResolver.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/domain/CreateDomainResolver.java index 9099394d32bd0b..19809170aad38c 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/domain/CreateDomainResolver.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/domain/CreateDomainResolver.java @@ -2,7 +2,6 @@ import static com.linkedin.datahub.graphql.resolvers.ResolverUtils.*; import static com.linkedin.datahub.graphql.resolvers.mutate.MutationUtils.*; -import static com.linkedin.datahub.graphql.resolvers.mutate.util.OwnerUtils.*; import static com.linkedin.metadata.Constants.*; import com.linkedin.common.AuditStamp; @@ -16,7 +15,6 @@ import com.linkedin.datahub.graphql.exception.DataHubGraphQLException; import com.linkedin.datahub.graphql.generated.CreateDomainInput; import com.linkedin.datahub.graphql.generated.OwnerEntityType; -import com.linkedin.datahub.graphql.generated.OwnershipType; import com.linkedin.datahub.graphql.resolvers.mutate.util.DomainUtils; import com.linkedin.datahub.graphql.resolvers.mutate.util.OwnerUtils; import com.linkedin.domain.DomainProperties; @@ -100,14 +98,8 @@ public CompletableFuture get(DataFetchingEnvironment environment) throws String domainUrn = _entityClient.ingestProposal(proposal, context.getAuthentication(), false); - OwnershipType ownershipType = OwnershipType.TECHNICAL_OWNER; - if (!_entityService.exists( - UrnUtils.getUrn(mapOwnershipTypeToEntity(ownershipType.name())))) { - log.warn("Technical owner does not exist, defaulting to None ownership."); - ownershipType = OwnershipType.NONE; - } OwnerUtils.addCreatorAsOwner( - context, domainUrn, OwnerEntityType.CORP_USER, ownershipType, _entityService); + context, domainUrn, OwnerEntityType.CORP_USER, _entityService); return domainUrn; } catch (DataHubGraphQLException e) { throw e; diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/glossary/CreateGlossaryNodeResolver.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/glossary/CreateGlossaryNodeResolver.java index 815b4662e1ed24..6a204286ba44e6 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/glossary/CreateGlossaryNodeResolver.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/glossary/CreateGlossaryNodeResolver.java @@ -2,7 +2,6 @@ import static com.linkedin.datahub.graphql.resolvers.ResolverUtils.bindArgument; import static com.linkedin.datahub.graphql.resolvers.mutate.MutationUtils.*; -import static com.linkedin.datahub.graphql.resolvers.mutate.util.OwnerUtils.*; import static com.linkedin.metadata.Constants.*; import com.linkedin.common.urn.GlossaryNodeUrn; @@ -13,7 +12,6 @@ import com.linkedin.datahub.graphql.exception.AuthorizationException; import com.linkedin.datahub.graphql.generated.CreateGlossaryEntityInput; import com.linkedin.datahub.graphql.generated.OwnerEntityType; -import com.linkedin.datahub.graphql.generated.OwnershipType; import com.linkedin.datahub.graphql.resolvers.mutate.util.GlossaryUtils; import com.linkedin.datahub.graphql.resolvers.mutate.util.OwnerUtils; import com.linkedin.entity.client.EntityClient; @@ -72,19 +70,8 @@ public CompletableFuture get(DataFetchingEnvironment environment) throws String glossaryNodeUrn = _entityClient.ingestProposal(proposal, context.getAuthentication(), false); - OwnershipType ownershipType = OwnershipType.TECHNICAL_OWNER; - if (!_entityService.exists( - UrnUtils.getUrn(mapOwnershipTypeToEntity(ownershipType.name())))) { - log.warn("Technical owner does not exist, defaulting to None ownership."); - ownershipType = OwnershipType.NONE; - } - OwnerUtils.addCreatorAsOwner( - context, - glossaryNodeUrn, - OwnerEntityType.CORP_USER, - ownershipType, - _entityService); + context, glossaryNodeUrn, OwnerEntityType.CORP_USER, _entityService); return glossaryNodeUrn; } catch (Exception e) { log.error( diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/glossary/CreateGlossaryTermResolver.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/glossary/CreateGlossaryTermResolver.java index 90979fe918f71a..147663059aa82c 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/glossary/CreateGlossaryTermResolver.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/glossary/CreateGlossaryTermResolver.java @@ -2,7 +2,6 @@ import static com.linkedin.datahub.graphql.resolvers.ResolverUtils.bindArgument; import static com.linkedin.datahub.graphql.resolvers.mutate.MutationUtils.*; -import static com.linkedin.datahub.graphql.resolvers.mutate.util.OwnerUtils.*; import static com.linkedin.metadata.Constants.*; import com.linkedin.common.urn.GlossaryNodeUrn; @@ -14,7 +13,6 @@ import com.linkedin.datahub.graphql.exception.AuthorizationException; import com.linkedin.datahub.graphql.generated.CreateGlossaryEntityInput; import com.linkedin.datahub.graphql.generated.OwnerEntityType; -import com.linkedin.datahub.graphql.generated.OwnershipType; import com.linkedin.datahub.graphql.resolvers.mutate.util.GlossaryUtils; import com.linkedin.datahub.graphql.resolvers.mutate.util.OwnerUtils; import com.linkedin.entity.EntityResponse; @@ -88,19 +86,9 @@ public CompletableFuture get(DataFetchingEnvironment environment) throws String glossaryTermUrn = _entityClient.ingestProposal(proposal, context.getAuthentication(), false); - OwnershipType ownershipType = OwnershipType.TECHNICAL_OWNER; - if (!_entityService.exists( - UrnUtils.getUrn(mapOwnershipTypeToEntity(ownershipType.name())))) { - log.warn("Technical owner does not exist, defaulting to None ownership."); - ownershipType = OwnershipType.NONE; - } OwnerUtils.addCreatorAsOwner( - context, - glossaryTermUrn, - OwnerEntityType.CORP_USER, - ownershipType, - _entityService); + context, glossaryTermUrn, OwnerEntityType.CORP_USER, _entityService); return glossaryTermUrn; } catch (Exception e) { log.error( diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/mutate/AddOwnerResolver.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/mutate/AddOwnerResolver.java index 9c0d009ff9b0e8..d1ea81fab083c3 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/mutate/AddOwnerResolver.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/mutate/AddOwnerResolver.java @@ -6,7 +6,6 @@ import com.linkedin.common.urn.CorpuserUrn; import com.linkedin.common.urn.Urn; import com.linkedin.datahub.graphql.QueryContext; -import com.linkedin.datahub.graphql.exception.AuthorizationException; import com.linkedin.datahub.graphql.generated.AddOwnerInput; import com.linkedin.datahub.graphql.generated.OwnerInput; import com.linkedin.datahub.graphql.generated.ResourceRefInput; @@ -40,10 +39,7 @@ public CompletableFuture get(DataFetchingEnvironment environment) throw } OwnerInput ownerInput = ownerInputBuilder.build(); - if (!OwnerUtils.isAuthorizedToUpdateOwners(environment.getContext(), targetUrn)) { - throw new AuthorizationException( - "Unauthorized to perform this action. Please contact your DataHub administrator."); - } + OwnerUtils.validateAuthorizedToUpdateOwners(environment.getContext(), targetUrn); return CompletableFuture.supplyAsync( () -> { diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/mutate/AddOwnersResolver.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/mutate/AddOwnersResolver.java index c64b2403364c8e..96500f23303f87 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/mutate/AddOwnersResolver.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/mutate/AddOwnersResolver.java @@ -6,7 +6,6 @@ import com.linkedin.common.urn.CorpuserUrn; import com.linkedin.common.urn.Urn; import com.linkedin.datahub.graphql.QueryContext; -import com.linkedin.datahub.graphql.exception.AuthorizationException; import com.linkedin.datahub.graphql.generated.AddOwnersInput; import com.linkedin.datahub.graphql.generated.OwnerInput; import com.linkedin.datahub.graphql.generated.ResourceRefInput; @@ -34,10 +33,7 @@ public CompletableFuture get(DataFetchingEnvironment environment) throw return CompletableFuture.supplyAsync( () -> { - if (!OwnerUtils.isAuthorizedToUpdateOwners(environment.getContext(), targetUrn)) { - throw new AuthorizationException( - "Unauthorized to perform this action. Please contact your DataHub administrator."); - } + OwnerUtils.validateAuthorizedToUpdateOwners(environment.getContext(), targetUrn); OwnerUtils.validateAddOwnerInput(owners, targetUrn, _entityService); try { diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/mutate/BatchAddOwnersResolver.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/mutate/BatchAddOwnersResolver.java index 94182835de159a..4d57031954e31a 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/mutate/BatchAddOwnersResolver.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/mutate/BatchAddOwnersResolver.java @@ -5,7 +5,6 @@ import com.linkedin.common.urn.Urn; import com.linkedin.common.urn.UrnUtils; import com.linkedin.datahub.graphql.QueryContext; -import com.linkedin.datahub.graphql.exception.AuthorizationException; import com.linkedin.datahub.graphql.generated.BatchAddOwnersInput; import com.linkedin.datahub.graphql.generated.OwnerInput; import com.linkedin.datahub.graphql.generated.ResourceRefInput; @@ -74,10 +73,7 @@ private void validateInputResource(ResourceRefInput resource, QueryContext conte "Malformed input provided: owners cannot be applied to subresources."); } - if (!OwnerUtils.isAuthorizedToUpdateOwners(context, resourceUrn)) { - throw new AuthorizationException( - "Unauthorized to perform this action. Please contact your DataHub administrator."); - } + OwnerUtils.validateAuthorizedToUpdateOwners(context, resourceUrn); LabelUtils.validateResource( resourceUrn, resource.getSubResource(), resource.getSubResourceType(), _entityService); } diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/mutate/BatchRemoveOwnersResolver.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/mutate/BatchRemoveOwnersResolver.java index 30e04ac36ee0f7..c0996b07fb9616 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/mutate/BatchRemoveOwnersResolver.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/mutate/BatchRemoveOwnersResolver.java @@ -5,7 +5,6 @@ import com.linkedin.common.urn.Urn; import com.linkedin.common.urn.UrnUtils; import com.linkedin.datahub.graphql.QueryContext; -import com.linkedin.datahub.graphql.exception.AuthorizationException; import com.linkedin.datahub.graphql.generated.BatchRemoveOwnersInput; import com.linkedin.datahub.graphql.generated.ResourceRefInput; import com.linkedin.datahub.graphql.resolvers.mutate.util.LabelUtils; @@ -14,7 +13,6 @@ import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; import java.util.List; -import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; @@ -32,10 +30,10 @@ public CompletableFuture get(DataFetchingEnvironment environment) throw bindArgument(environment.getArgument("input"), BatchRemoveOwnersInput.class); final List owners = input.getOwnerUrns(); final List resources = input.getResources(); - final Optional maybeOwnershipTypeUrn = + final Urn ownershipTypeUrn = input.getOwnershipTypeUrn() == null - ? Optional.empty() - : Optional.of(Urn.createFromString(input.getOwnershipTypeUrn())); + ? null + : Urn.createFromString(input.getOwnershipTypeUrn()); final QueryContext context = environment.getContext(); return CompletableFuture.supplyAsync( @@ -46,7 +44,7 @@ public CompletableFuture get(DataFetchingEnvironment environment) throw try { // Then execute the bulk remove - batchRemoveOwners(owners, maybeOwnershipTypeUrn, resources, context); + batchRemoveOwners(owners, ownershipTypeUrn, resources, context); return true; } catch (Exception e) { log.error( @@ -71,24 +69,21 @@ private void validateInputResource(ResourceRefInput resource, QueryContext conte "Malformed input provided: owners cannot be removed from subresources."); } - if (!OwnerUtils.isAuthorizedToUpdateOwners(context, resourceUrn)) { - throw new AuthorizationException( - "Unauthorized to perform this action. Please contact your DataHub administrator."); - } + OwnerUtils.validateAuthorizedToUpdateOwners(context, resourceUrn); LabelUtils.validateResource( resourceUrn, resource.getSubResource(), resource.getSubResourceType(), _entityService); } private void batchRemoveOwners( List ownerUrns, - Optional maybeOwnershipTypeUrn, + Urn ownershipTypeUrn, List resources, QueryContext context) { log.debug("Batch removing owners. owners: {}, resources: {}", ownerUrns, resources); try { OwnerUtils.removeOwnersFromResources( ownerUrns.stream().map(UrnUtils::getUrn).collect(Collectors.toList()), - maybeOwnershipTypeUrn, + ownershipTypeUrn, resources, UrnUtils.getUrn(context.getActorUrn()), _entityService); diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/mutate/RemoveOwnerResolver.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/mutate/RemoveOwnerResolver.java index 9827aa0666d19b..ec62a951573e2a 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/mutate/RemoveOwnerResolver.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/mutate/RemoveOwnerResolver.java @@ -6,14 +6,12 @@ import com.linkedin.common.urn.CorpuserUrn; import com.linkedin.common.urn.Urn; import com.linkedin.datahub.graphql.QueryContext; -import com.linkedin.datahub.graphql.exception.AuthorizationException; import com.linkedin.datahub.graphql.generated.RemoveOwnerInput; import com.linkedin.datahub.graphql.generated.ResourceRefInput; import com.linkedin.datahub.graphql.resolvers.mutate.util.OwnerUtils; import com.linkedin.metadata.entity.EntityService; import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; -import java.util.Optional; import java.util.concurrent.CompletableFuture; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -31,15 +29,12 @@ public CompletableFuture get(DataFetchingEnvironment environment) throw Urn ownerUrn = Urn.createFromString(input.getOwnerUrn()); Urn targetUrn = Urn.createFromString(input.getResourceUrn()); - Optional maybeOwnershipTypeUrn = + Urn ownershipTypeUrn = input.getOwnershipTypeUrn() == null - ? Optional.empty() - : Optional.of(Urn.createFromString(input.getOwnershipTypeUrn())); + ? null + : Urn.createFromString(input.getOwnershipTypeUrn()); - if (!OwnerUtils.isAuthorizedToUpdateOwners(environment.getContext(), targetUrn)) { - throw new AuthorizationException( - "Unauthorized to perform this action. Please contact your DataHub administrator."); - } + OwnerUtils.validateAuthorizedToUpdateOwners(environment.getContext(), targetUrn); return CompletableFuture.supplyAsync( () -> { @@ -50,7 +45,7 @@ public CompletableFuture get(DataFetchingEnvironment environment) throw ((QueryContext) environment.getContext()).getActorUrn()); OwnerUtils.removeOwnersFromResources( ImmutableList.of(ownerUrn), - maybeOwnershipTypeUrn, + ownershipTypeUrn, ImmutableList.of(new ResourceRefInput(input.getResourceUrn(), null, null)), actor, _entityService); diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/mutate/util/OwnerUtils.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/mutate/util/OwnerUtils.java index 15c3c14c7b8f67..55d408d3f7aab3 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/mutate/util/OwnerUtils.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/mutate/util/OwnerUtils.java @@ -15,6 +15,7 @@ import com.linkedin.common.urn.UrnUtils; import com.linkedin.datahub.graphql.QueryContext; import com.linkedin.datahub.graphql.authorization.AuthorizationUtils; +import com.linkedin.datahub.graphql.exception.AuthorizationException; import com.linkedin.datahub.graphql.generated.OwnerEntityType; import com.linkedin.datahub.graphql.generated.OwnerInput; import com.linkedin.datahub.graphql.generated.OwnershipType; @@ -26,8 +27,8 @@ import com.linkedin.mxe.MetadataChangeProposal; import java.util.ArrayList; import java.util.List; -import java.util.Optional; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import lombok.extern.slf4j.Slf4j; // TODO: Move to consuming from OwnerService @@ -42,22 +43,22 @@ public class OwnerUtils { private OwnerUtils() {} public static void addOwnersToResources( - List owners, - List resources, - Urn actor, + List ownerInputs, + List resourceRefs, + Urn actorUrn, EntityService entityService) { final List changes = new ArrayList<>(); - for (ResourceRefInput resource : resources) { + for (ResourceRefInput resource : resourceRefs) { changes.add( buildAddOwnersProposal( - owners, UrnUtils.getUrn(resource.getResourceUrn()), entityService)); + ownerInputs, UrnUtils.getUrn(resource.getResourceUrn()), actorUrn, entityService)); } - EntityUtils.ingestChangeProposals(changes, entityService, actor, false); + EntityUtils.ingestChangeProposals(changes, entityService, actorUrn, false); } public static void removeOwnersFromResources( List ownerUrns, - Optional maybeOwnershipTypeUrn, + @Nullable Urn ownershipTypeUrn, List resources, Urn actor, EntityService entityService) { @@ -66,7 +67,7 @@ public static void removeOwnersFromResources( changes.add( buildRemoveOwnersProposal( ownerUrns, - maybeOwnershipTypeUrn, + ownershipTypeUrn, UrnUtils.getUrn(resource.getResourceUrn()), actor, entityService)); @@ -75,7 +76,7 @@ public static void removeOwnersFromResources( } static MetadataChangeProposal buildAddOwnersProposal( - List owners, Urn resourceUrn, EntityService entityService) { + List owners, Urn resourceUrn, Urn actor, EntityService entityService) { Ownership ownershipAspect = (Ownership) EntityUtils.getAspectFromEntity( @@ -83,8 +84,9 @@ static MetadataChangeProposal buildAddOwnersProposal( Constants.OWNERSHIP_ASPECT_NAME, entityService, new Ownership()); + ownershipAspect.setLastModified(EntityUtils.getAuditStamp(actor)); for (OwnerInput input : owners) { - addOwner( + addOwnerToAspect( ownershipAspect, UrnUtils.getUrn(input.getOwnerUrn()), input.getType(), @@ -96,7 +98,7 @@ static MetadataChangeProposal buildAddOwnersProposal( public static MetadataChangeProposal buildRemoveOwnersProposal( List ownerUrns, - Optional maybeOwnershipTypeUrn, + @Nullable Urn ownershipTypeUrn, Urn resourceUrn, Urn actor, EntityService entityService) { @@ -108,36 +110,19 @@ public static MetadataChangeProposal buildRemoveOwnersProposal( entityService, new Ownership()); ownershipAspect.setLastModified(EntityUtils.getAuditStamp(actor)); - removeOwnersIfExists(ownershipAspect, ownerUrns, maybeOwnershipTypeUrn); + removeOwnersIfExists(ownershipAspect, ownerUrns, ownershipTypeUrn); return buildMetadataChangeProposalWithUrn( resourceUrn, Constants.OWNERSHIP_ASPECT_NAME, ownershipAspect); } - private static void addOwner( - Ownership ownershipAspect, Urn ownerUrn, OwnershipType type, Urn ownershipUrn) { + private static void addOwnerToAspect( + Ownership ownershipAspect, Urn ownerUrn, OwnershipType type, Urn ownershipTypeUrn) { if (!ownershipAspect.hasOwners()) { ownershipAspect.setOwners(new OwnerArray()); } - final OwnerArray ownerArray = new OwnerArray(ownershipAspect.getOwners()); - ownerArray.removeIf( - owner -> { - // Remove old ownership if it exists (check ownerUrn + type (entity & deprecated type)) - - // Owner is not what we are looking for - if (!owner.getOwner().equals(ownerUrn)) { - return false; - } - - // Check custom entity type urn if exists - if (owner.getTypeUrn() != null) { - return owner.getTypeUrn().equals(ownershipUrn); - } - - // Fall back to mapping deprecated type to the new ownership entity, if it matches remove - return mapOwnershipTypeToEntity(OwnershipType.valueOf(owner.getType().toString()).name()) - .equals(ownershipUrn.toString()); - }); + OwnerArray ownerArray = new OwnerArray(ownershipAspect.getOwners()); + removeExistingOwnerIfExists(ownerArray, ownerUrn, ownershipTypeUrn); Owner newOwner = new Owner(); @@ -150,49 +135,52 @@ private static void addOwner( : com.linkedin.common.OwnershipType.CUSTOM; newOwner.setType(gmsType); - newOwner.setTypeUrn(ownershipUrn); + newOwner.setTypeUrn(ownershipTypeUrn); newOwner.setSource(new OwnershipSource().setType(OwnershipSourceType.MANUAL)); newOwner.setOwner(ownerUrn); ownerArray.add(newOwner); ownershipAspect.setOwners(ownerArray); } + private static void removeExistingOwnerIfExists( + OwnerArray ownerArray, Urn ownerUrn, Urn ownershipTypeUrn) { + ownerArray.removeIf( + owner -> { + // Remove old ownership if it exists (check ownerUrn + type (entity & deprecated type)) + return isOwnerEqual(owner, ownerUrn, ownershipTypeUrn); + }); + } + + public static boolean isOwnerEqual( + @Nonnull Owner owner, @Nonnull Urn ownerUrn, @Nullable Urn ownershipTypeUrn) { + if (!owner.getOwner().equals(ownerUrn)) { + return false; + } + if (owner.getTypeUrn() != null) { + return owner.getTypeUrn().equals(ownershipTypeUrn); + } + if (ownershipTypeUrn == null) { + return true; + } + // Fall back to mapping deprecated type to the new ownership entity + return mapOwnershipTypeToEntity(OwnershipType.valueOf(owner.getType().toString()).name()) + .equals(ownershipTypeUrn.toString()); + } + private static void removeOwnersIfExists( - Ownership ownership, List ownerUrns, Optional maybeOwnershipTypeUrn) { - if (!ownership.hasOwners()) { - ownership.setOwners(new OwnerArray()); + Ownership ownershipAspect, List ownerUrns, Urn ownershipTypeUrn) { + if (!ownershipAspect.hasOwners()) { + ownershipAspect.setOwners(new OwnerArray()); } - OwnerArray ownerArray = ownership.getOwners(); + OwnerArray ownerArray = ownershipAspect.getOwners(); for (Urn ownerUrn : ownerUrns) { - if (maybeOwnershipTypeUrn.isPresent()) { - ownerArray.removeIf( - owner -> { - // Remove ownership if it exists (check ownerUrn + type (entity & deprecated type)) - - // Owner is not what we are looking for - if (!owner.getOwner().equals(ownerUrn)) { - return false; - } - - // Check custom entity type urn if exists - if (owner.getTypeUrn() != null) { - return owner.getTypeUrn().equals(maybeOwnershipTypeUrn.get()); - } - - // Fall back to mapping deprecated type to the new ownership entity, if it matches - // remove - return mapOwnershipTypeToEntity( - OwnershipType.valueOf(owner.getType().toString()).name()) - .equals(maybeOwnershipTypeUrn.get().toString()); - }); - } else { - ownerArray.removeIf(owner -> owner.getOwner().equals(ownerUrn)); - } + removeExistingOwnerIfExists(ownerArray, ownerUrn, ownershipTypeUrn); } } - public static boolean isAuthorizedToUpdateOwners(@Nonnull QueryContext context, Urn resourceUrn) { + public static void validateAuthorizedToUpdateOwners( + @Nonnull QueryContext context, Urn resourceUrn) { final DisjunctivePrivilegeGroup orPrivilegeGroups = new DisjunctivePrivilegeGroup( ImmutableList.of( @@ -200,26 +188,27 @@ public static boolean isAuthorizedToUpdateOwners(@Nonnull QueryContext context, new ConjunctivePrivilegeGroup( ImmutableList.of(PoliciesConfig.EDIT_ENTITY_OWNERS_PRIVILEGE.getType())))); - return AuthorizationUtils.isAuthorized( - context.getAuthorizer(), - context.getActorUrn(), - resourceUrn.getEntityType(), - resourceUrn.toString(), - orPrivilegeGroups); + boolean authorized = + AuthorizationUtils.isAuthorized( + context.getAuthorizer(), + context.getActorUrn(), + resourceUrn.getEntityType(), + resourceUrn.toString(), + orPrivilegeGroups); + if (!authorized) { + throw new AuthorizationException( + "Unauthorized to update owners. Please contact your DataHub administrator."); + } } - public static Boolean validateAddOwnerInput( + public static void validateAddOwnerInput( List owners, Urn resourceUrn, EntityService entityService) { for (OwnerInput owner : owners) { - boolean result = validateAddOwnerInput(owner, resourceUrn, entityService); - if (!result) { - return false; - } + validateAddOwnerInput(owner, resourceUrn, entityService); } - return true; } - public static Boolean validateAddOwnerInput( + public static void validateAddOwnerInput( OwnerInput owner, Urn resourceUrn, EntityService entityService) { if (!entityService.exists(resourceUrn)) { @@ -229,8 +218,6 @@ public static Boolean validateAddOwnerInput( } validateOwner(owner, entityService); - - return true; } public static void validateOwner(OwnerInput owner, EntityService entityService) { @@ -277,23 +264,26 @@ public static void validateOwner(OwnerInput owner, EntityService entityService) } } - public static Boolean validateRemoveInput(Urn resourceUrn, EntityService entityService) { + public static void validateRemoveInput(Urn resourceUrn, EntityService entityService) { if (!entityService.exists(resourceUrn)) { throw new IllegalArgumentException( String.format( "Failed to change ownership for resource %s. Resource does not exist.", resourceUrn)); } - return true; } public static void addCreatorAsOwner( QueryContext context, String urn, OwnerEntityType ownerEntityType, - OwnershipType ownershipType, EntityService entityService) { try { Urn actorUrn = CorpuserUrn.createFromString(context.getActorUrn()); + OwnershipType ownershipType = OwnershipType.TECHNICAL_OWNER; + if (!entityService.exists(UrnUtils.getUrn(mapOwnershipTypeToEntity(ownershipType.name())))) { + log.warn("Technical owner does not exist, defaulting to None ownership."); + ownershipType = OwnershipType.NONE; + } String ownershipTypeUrn = mapOwnershipTypeToEntity(ownershipType.name()); if (!entityService.exists(UrnUtils.getUrn(ownershipTypeUrn))) { diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/tag/CreateTagResolver.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/tag/CreateTagResolver.java index 153c95c697a774..9e3ca0f2d45a65 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/tag/CreateTagResolver.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/tag/CreateTagResolver.java @@ -2,17 +2,14 @@ import static com.linkedin.datahub.graphql.resolvers.ResolverUtils.*; import static com.linkedin.datahub.graphql.resolvers.mutate.MutationUtils.*; -import static com.linkedin.datahub.graphql.resolvers.mutate.util.OwnerUtils.*; import static com.linkedin.metadata.Constants.*; -import com.linkedin.common.urn.UrnUtils; import com.linkedin.data.template.SetMode; import com.linkedin.datahub.graphql.QueryContext; import com.linkedin.datahub.graphql.authorization.AuthorizationUtils; import com.linkedin.datahub.graphql.exception.AuthorizationException; import com.linkedin.datahub.graphql.generated.CreateTagInput; import com.linkedin.datahub.graphql.generated.OwnerEntityType; -import com.linkedin.datahub.graphql.generated.OwnershipType; import com.linkedin.datahub.graphql.resolvers.mutate.util.OwnerUtils; import com.linkedin.entity.client.EntityClient; import com.linkedin.metadata.entity.EntityService; @@ -72,15 +69,9 @@ public CompletableFuture get(DataFetchingEnvironment environment) throws key, TAG_ENTITY_NAME, TAG_PROPERTIES_ASPECT_NAME, mapTagProperties(input)); String tagUrn = _entityClient.ingestProposal(proposal, context.getAuthentication(), false); - OwnershipType ownershipType = OwnershipType.TECHNICAL_OWNER; - if (!_entityService.exists( - UrnUtils.getUrn(mapOwnershipTypeToEntity(ownershipType.name())))) { - log.warn("Technical owner does not exist, defaulting to None ownership."); - ownershipType = OwnershipType.NONE; - } OwnerUtils.addCreatorAsOwner( - context, tagUrn, OwnerEntityType.CORP_USER, ownershipType, _entityService); + context, tagUrn, OwnerEntityType.CORP_USER, _entityService); return tagUrn; } catch (Exception e) { log.error( diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/rolemetadata/mappers/AccessMapper.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/rolemetadata/mappers/AccessMapper.java index 3eb090e4524395..2d6bd31c84fd90 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/rolemetadata/mappers/AccessMapper.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/rolemetadata/mappers/AccessMapper.java @@ -1,5 +1,6 @@ package com.linkedin.datahub.graphql.types.rolemetadata.mappers; +import com.linkedin.common.RoleAssociationArray; import com.linkedin.common.urn.Urn; import com.linkedin.datahub.graphql.generated.EntityType; import com.linkedin.datahub.graphql.generated.Role; @@ -19,8 +20,10 @@ public com.linkedin.datahub.graphql.generated.Access apply( @Nonnull final com.linkedin.common.Access access, @Nonnull final Urn entityUrn) { com.linkedin.datahub.graphql.generated.Access result = new com.linkedin.datahub.graphql.generated.Access(); + RoleAssociationArray roles = + access.getRoles() != null ? access.getRoles() : new RoleAssociationArray(); result.setRoles( - access.getRoles().stream() + roles.stream() .map(association -> this.mapRoleAssociation(association, entityUrn)) .collect(Collectors.toList())); return result; diff --git a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/TestUtils.java b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/TestUtils.java index 69cd73ecd7d68d..de507eda8cdef7 100644 --- a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/TestUtils.java +++ b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/TestUtils.java @@ -1,5 +1,7 @@ package com.linkedin.datahub.graphql; +import static org.mockito.Mockito.mock; + import com.datahub.authentication.Actor; import com.datahub.authentication.ActorType; import com.datahub.authentication.Authentication; @@ -10,7 +12,8 @@ import com.linkedin.common.urn.UrnUtils; import com.linkedin.data.schema.annotation.PathSpecBasedSchemaAnnotationVisitor; import com.linkedin.metadata.entity.EntityService; -import com.linkedin.metadata.entity.ebean.transactions.AspectsBatchImpl; +import com.linkedin.metadata.entity.ebean.batch.AspectsBatchImpl; +import com.linkedin.metadata.entity.ebean.batch.MCPUpsertBatchItem; import com.linkedin.metadata.models.registry.ConfigEntityRegistry; import com.linkedin.metadata.models.registry.EntityRegistry; import com.linkedin.mxe.MetadataChangeProposal; @@ -19,13 +22,14 @@ public class TestUtils { - public static EntityService getMockEntityService() { + public static EntityService getMockEntityService() { PathSpecBasedSchemaAnnotationVisitor.class .getClassLoader() .setClassAssertionStatus(PathSpecBasedSchemaAnnotationVisitor.class.getName(), false); EntityRegistry registry = new ConfigEntityRegistry(TestUtils.class.getResourceAsStream("/test-entity-registry.yaml")); - EntityService mockEntityService = Mockito.mock(EntityService.class); + EntityService mockEntityService = + (EntityService) Mockito.mock(EntityService.class); Mockito.when(mockEntityService.getEntityRegistry()).thenReturn(registry); return mockEntityService; } @@ -35,11 +39,11 @@ public static QueryContext getMockAllowContext() { } public static QueryContext getMockAllowContext(String actorUrn) { - QueryContext mockContext = Mockito.mock(QueryContext.class); + QueryContext mockContext = mock(QueryContext.class); Mockito.when(mockContext.getActorUrn()).thenReturn(actorUrn); - Authorizer mockAuthorizer = Mockito.mock(Authorizer.class); - AuthorizationResult result = Mockito.mock(AuthorizationResult.class); + Authorizer mockAuthorizer = mock(Authorizer.class); + AuthorizationResult result = mock(AuthorizationResult.class); Mockito.when(result.getType()).thenReturn(AuthorizationResult.Type.ALLOW); Mockito.when(mockAuthorizer.authorize(Mockito.any())).thenReturn(result); @@ -52,11 +56,11 @@ public static QueryContext getMockAllowContext(String actorUrn) { } public static QueryContext getMockAllowContext(String actorUrn, AuthorizationRequest request) { - QueryContext mockContext = Mockito.mock(QueryContext.class); + QueryContext mockContext = mock(QueryContext.class); Mockito.when(mockContext.getActorUrn()).thenReturn(actorUrn); - Authorizer mockAuthorizer = Mockito.mock(Authorizer.class); - AuthorizationResult result = Mockito.mock(AuthorizationResult.class); + Authorizer mockAuthorizer = mock(Authorizer.class); + AuthorizationResult result = mock(AuthorizationResult.class); Mockito.when(result.getType()).thenReturn(AuthorizationResult.Type.ALLOW); Mockito.when(mockAuthorizer.authorize(Mockito.eq(request))).thenReturn(result); @@ -73,11 +77,11 @@ public static QueryContext getMockDenyContext() { } public static QueryContext getMockDenyContext(String actorUrn) { - QueryContext mockContext = Mockito.mock(QueryContext.class); + QueryContext mockContext = mock(QueryContext.class); Mockito.when(mockContext.getActorUrn()).thenReturn(actorUrn); - Authorizer mockAuthorizer = Mockito.mock(Authorizer.class); - AuthorizationResult result = Mockito.mock(AuthorizationResult.class); + Authorizer mockAuthorizer = mock(Authorizer.class); + AuthorizationResult result = mock(AuthorizationResult.class); Mockito.when(result.getType()).thenReturn(AuthorizationResult.Type.DENY); Mockito.when(mockAuthorizer.authorize(Mockito.any())).thenReturn(result); @@ -90,11 +94,11 @@ public static QueryContext getMockDenyContext(String actorUrn) { } public static QueryContext getMockDenyContext(String actorUrn, AuthorizationRequest request) { - QueryContext mockContext = Mockito.mock(QueryContext.class); + QueryContext mockContext = mock(QueryContext.class); Mockito.when(mockContext.getActorUrn()).thenReturn(actorUrn); - Authorizer mockAuthorizer = Mockito.mock(Authorizer.class); - AuthorizationResult result = Mockito.mock(AuthorizationResult.class); + Authorizer mockAuthorizer = mock(Authorizer.class); + AuthorizationResult result = mock(AuthorizationResult.class); Mockito.when(result.getType()).thenReturn(AuthorizationResult.Type.DENY); Mockito.when(mockAuthorizer.authorize(Mockito.eq(request))).thenReturn(result); @@ -107,32 +111,44 @@ public static QueryContext getMockDenyContext(String actorUrn, AuthorizationRequ } public static void verifyIngestProposal( - EntityService mockService, int numberOfInvocations, MetadataChangeProposal proposal) { + EntityService mockService, + int numberOfInvocations, + MetadataChangeProposal proposal) { verifyIngestProposal(mockService, numberOfInvocations, List.of(proposal)); } public static void verifyIngestProposal( - EntityService mockService, int numberOfInvocations, List proposals) { + EntityService mockService, + int numberOfInvocations, + List proposals) { AspectsBatchImpl batch = - AspectsBatchImpl.builder().mcps(proposals, mockService.getEntityRegistry()).build(); + AspectsBatchImpl.builder() + .mcps( + proposals, + mock(AuditStamp.class), + mockService.getEntityRegistry(), + mockService.getSystemEntityClient()) + .build(); Mockito.verify(mockService, Mockito.times(numberOfInvocations)) - .ingestProposal(Mockito.eq(batch), Mockito.any(AuditStamp.class), Mockito.eq(false)); + .ingestProposal(Mockito.eq(batch), Mockito.eq(false)); } public static void verifySingleIngestProposal( - EntityService mockService, int numberOfInvocations, MetadataChangeProposal proposal) { + EntityService mockService, + int numberOfInvocations, + MetadataChangeProposal proposal) { Mockito.verify(mockService, Mockito.times(numberOfInvocations)) .ingestProposal(Mockito.eq(proposal), Mockito.any(AuditStamp.class), Mockito.eq(false)); } - public static void verifyIngestProposal(EntityService mockService, int numberOfInvocations) { + public static void verifyIngestProposal( + EntityService mockService, int numberOfInvocations) { Mockito.verify(mockService, Mockito.times(numberOfInvocations)) - .ingestProposal( - Mockito.any(AspectsBatchImpl.class), Mockito.any(AuditStamp.class), Mockito.eq(false)); + .ingestProposal(Mockito.any(AspectsBatchImpl.class), Mockito.eq(false)); } public static void verifySingleIngestProposal( - EntityService mockService, int numberOfInvocations) { + EntityService mockService, int numberOfInvocations) { Mockito.verify(mockService, Mockito.times(numberOfInvocations)) .ingestProposal( Mockito.any(MetadataChangeProposal.class), @@ -140,12 +156,9 @@ public static void verifySingleIngestProposal( Mockito.eq(false)); } - public static void verifyNoIngestProposal(EntityService mockService) { + public static void verifyNoIngestProposal(EntityService mockService) { Mockito.verify(mockService, Mockito.times(0)) - .ingestProposal( - Mockito.any(AspectsBatchImpl.class), - Mockito.any(AuditStamp.class), - Mockito.anyBoolean()); + .ingestProposal(Mockito.any(AspectsBatchImpl.class), Mockito.anyBoolean()); } private TestUtils() {} diff --git a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/delete/BatchUpdateSoftDeletedResolverTest.java b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/delete/BatchUpdateSoftDeletedResolverTest.java index 49ccc751d35f63..56b01be29e1633 100644 --- a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/delete/BatchUpdateSoftDeletedResolverTest.java +++ b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/delete/BatchUpdateSoftDeletedResolverTest.java @@ -5,7 +5,6 @@ import static org.testng.Assert.*; import com.google.common.collect.ImmutableList; -import com.linkedin.common.AuditStamp; import com.linkedin.common.Status; import com.linkedin.common.urn.Urn; import com.linkedin.common.urn.UrnUtils; @@ -15,7 +14,7 @@ import com.linkedin.datahub.graphql.resolvers.mutate.MutationUtils; import com.linkedin.metadata.Constants; import com.linkedin.metadata.entity.EntityService; -import com.linkedin.metadata.entity.ebean.transactions.AspectsBatchImpl; +import com.linkedin.metadata.entity.ebean.batch.AspectsBatchImpl; import com.linkedin.mxe.MetadataChangeProposal; import graphql.schema.DataFetchingEnvironment; import java.util.List; @@ -184,10 +183,7 @@ public void testGetEntityClientException() throws Exception { Mockito.doThrow(RuntimeException.class) .when(mockService) - .ingestProposal( - Mockito.any(AspectsBatchImpl.class), - Mockito.any(AuditStamp.class), - Mockito.anyBoolean()); + .ingestProposal(Mockito.any(AspectsBatchImpl.class), Mockito.anyBoolean()); BatchUpdateSoftDeletedResolver resolver = new BatchUpdateSoftDeletedResolver(mockService); diff --git a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/deprecation/BatchUpdateDeprecationResolverTest.java b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/deprecation/BatchUpdateDeprecationResolverTest.java index 8c3620fa978a98..be7f200a6b9d72 100644 --- a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/deprecation/BatchUpdateDeprecationResolverTest.java +++ b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/deprecation/BatchUpdateDeprecationResolverTest.java @@ -5,7 +5,6 @@ import static org.testng.Assert.*; import com.google.common.collect.ImmutableList; -import com.linkedin.common.AuditStamp; import com.linkedin.common.Deprecation; import com.linkedin.common.urn.Urn; import com.linkedin.common.urn.UrnUtils; @@ -16,7 +15,7 @@ import com.linkedin.datahub.graphql.resolvers.mutate.MutationUtils; import com.linkedin.metadata.Constants; import com.linkedin.metadata.entity.EntityService; -import com.linkedin.metadata.entity.ebean.transactions.AspectsBatchImpl; +import com.linkedin.metadata.entity.ebean.batch.AspectsBatchImpl; import com.linkedin.mxe.MetadataChangeProposal; import graphql.schema.DataFetchingEnvironment; import java.util.List; @@ -217,10 +216,7 @@ public void testGetEntityClientException() throws Exception { Mockito.doThrow(RuntimeException.class) .when(mockService) - .ingestProposal( - Mockito.any(AspectsBatchImpl.class), - Mockito.any(AuditStamp.class), - Mockito.anyBoolean()); + .ingestProposal(Mockito.any(AspectsBatchImpl.class), Mockito.anyBoolean()); BatchUpdateDeprecationResolver resolver = new BatchUpdateDeprecationResolver(mockService); diff --git a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/domain/BatchSetDomainResolverTest.java b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/domain/BatchSetDomainResolverTest.java index d5ba88066e8461..32f0d30e7751a0 100644 --- a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/domain/BatchSetDomainResolverTest.java +++ b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/domain/BatchSetDomainResolverTest.java @@ -5,7 +5,6 @@ import static org.testng.Assert.*; import com.google.common.collect.ImmutableList; -import com.linkedin.common.AuditStamp; import com.linkedin.common.UrnArray; import com.linkedin.common.urn.Urn; import com.linkedin.common.urn.UrnUtils; @@ -18,7 +17,7 @@ import com.linkedin.events.metadata.ChangeType; import com.linkedin.metadata.Constants; import com.linkedin.metadata.entity.EntityService; -import com.linkedin.metadata.entity.ebean.transactions.AspectsBatchImpl; +import com.linkedin.metadata.entity.ebean.batch.AspectsBatchImpl; import com.linkedin.metadata.utils.GenericRecordUtils; import com.linkedin.mxe.MetadataChangeProposal; import graphql.schema.DataFetchingEnvironment; @@ -311,10 +310,7 @@ public void testGetEntityClientException() throws Exception { Mockito.doThrow(RuntimeException.class) .when(mockService) - .ingestProposal( - Mockito.any(AspectsBatchImpl.class), - Mockito.any(AuditStamp.class), - Mockito.anyBoolean()); + .ingestProposal(Mockito.any(AspectsBatchImpl.class), Mockito.anyBoolean()); BatchSetDomainResolver resolver = new BatchSetDomainResolver(mockService); diff --git a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/embed/UpdateEmbedResolverTest.java b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/embed/UpdateEmbedResolverTest.java index 45a17744a26971..241951319c75ed 100644 --- a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/embed/UpdateEmbedResolverTest.java +++ b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/embed/UpdateEmbedResolverTest.java @@ -7,7 +7,6 @@ import com.datahub.authentication.Authentication; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; -import com.linkedin.common.AuditStamp; import com.linkedin.common.Embed; import com.linkedin.common.urn.CorpuserUrn; import com.linkedin.common.urn.Urn; @@ -19,7 +18,7 @@ import com.linkedin.entity.client.EntityClient; import com.linkedin.metadata.Constants; import com.linkedin.metadata.entity.EntityService; -import com.linkedin.metadata.entity.ebean.transactions.AspectsBatchImpl; +import com.linkedin.metadata.entity.ebean.batch.AspectsBatchImpl; import com.linkedin.mxe.MetadataChangeProposal; import com.linkedin.r2.RemoteInvocationException; import graphql.schema.DataFetchingEnvironment; @@ -142,8 +141,7 @@ public void testGetFailureEntityDoesNotExist() throws Exception { assertThrows(CompletionException.class, () -> resolver.get(mockEnv).join()); Mockito.verify(mockService, Mockito.times(0)) - .ingestProposal( - Mockito.any(AspectsBatchImpl.class), Mockito.any(AuditStamp.class), Mockito.eq(false)); + .ingestProposal(Mockito.any(AspectsBatchImpl.class), Mockito.eq(false)); ; } @@ -161,8 +159,7 @@ public void testGetUnauthorized() throws Exception { assertThrows(CompletionException.class, () -> resolver.get(mockEnv).join()); Mockito.verify(mockService, Mockito.times(0)) - .ingestProposal( - Mockito.any(AspectsBatchImpl.class), Mockito.any(AuditStamp.class), Mockito.eq(false)); + .ingestProposal(Mockito.any(AspectsBatchImpl.class), Mockito.eq(false)); } @Test diff --git a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/owner/AddOwnersResolverTest.java b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/owner/AddOwnersResolverTest.java index 74f88f95fc171e..5e199f2c6b2c71 100644 --- a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/owner/AddOwnersResolverTest.java +++ b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/owner/AddOwnersResolverTest.java @@ -4,7 +4,6 @@ import static org.testng.Assert.*; import com.google.common.collect.ImmutableList; -import com.linkedin.common.AuditStamp; import com.linkedin.common.Owner; import com.linkedin.common.OwnerArray; import com.linkedin.common.Ownership; @@ -21,7 +20,7 @@ import com.linkedin.datahub.graphql.resolvers.mutate.util.OwnerUtils; import com.linkedin.metadata.Constants; import com.linkedin.metadata.entity.EntityService; -import com.linkedin.metadata.entity.ebean.transactions.AspectsBatchImpl; +import com.linkedin.metadata.entity.ebean.batch.AspectsBatchImpl; import graphql.schema.DataFetchingEnvironment; import java.util.concurrent.CompletionException; import org.mockito.Mockito; @@ -399,10 +398,7 @@ public void testGetEntityClientException() throws Exception { Mockito.doThrow(RuntimeException.class) .when(mockService) - .ingestProposal( - Mockito.any(AspectsBatchImpl.class), - Mockito.any(AuditStamp.class), - Mockito.anyBoolean()); + .ingestProposal(Mockito.any(AspectsBatchImpl.class), Mockito.anyBoolean()); AddOwnersResolver resolver = new AddOwnersResolver(Mockito.mock(EntityService.class)); diff --git a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/owner/BatchAddOwnersResolverTest.java b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/owner/BatchAddOwnersResolverTest.java index 92a789530d6e4f..92960f45232b5a 100644 --- a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/owner/BatchAddOwnersResolverTest.java +++ b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/owner/BatchAddOwnersResolverTest.java @@ -4,7 +4,6 @@ import static org.testng.Assert.*; import com.google.common.collect.ImmutableList; -import com.linkedin.common.AuditStamp; import com.linkedin.common.Owner; import com.linkedin.common.OwnerArray; import com.linkedin.common.Ownership; @@ -20,7 +19,7 @@ import com.linkedin.datahub.graphql.resolvers.mutate.util.OwnerUtils; import com.linkedin.metadata.Constants; import com.linkedin.metadata.entity.EntityService; -import com.linkedin.metadata.entity.ebean.transactions.AspectsBatchImpl; +import com.linkedin.metadata.entity.ebean.batch.AspectsBatchImpl; import graphql.schema.DataFetchingEnvironment; import java.util.concurrent.CompletionException; import org.mockito.Mockito; @@ -337,10 +336,7 @@ public void testGetEntityClientException() throws Exception { Mockito.doThrow(RuntimeException.class) .when(mockService) - .ingestProposal( - Mockito.any(AspectsBatchImpl.class), - Mockito.any(AuditStamp.class), - Mockito.anyBoolean()); + .ingestProposal(Mockito.any(AspectsBatchImpl.class), Mockito.anyBoolean()); BatchAddOwnersResolver resolver = new BatchAddOwnersResolver(mockService); diff --git a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/owner/BatchRemoveOwnersResolverTest.java b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/owner/BatchRemoveOwnersResolverTest.java index 7cef90ffee5121..10c95c1bac648e 100644 --- a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/owner/BatchRemoveOwnersResolverTest.java +++ b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/owner/BatchRemoveOwnersResolverTest.java @@ -4,7 +4,6 @@ import static org.testng.Assert.*; import com.google.common.collect.ImmutableList; -import com.linkedin.common.AuditStamp; import com.linkedin.common.Owner; import com.linkedin.common.OwnerArray; import com.linkedin.common.Ownership; @@ -17,7 +16,7 @@ import com.linkedin.datahub.graphql.resolvers.mutate.BatchRemoveOwnersResolver; import com.linkedin.metadata.Constants; import com.linkedin.metadata.entity.EntityService; -import com.linkedin.metadata.entity.ebean.transactions.AspectsBatchImpl; +import com.linkedin.metadata.entity.ebean.batch.AspectsBatchImpl; import graphql.schema.DataFetchingEnvironment; import java.util.concurrent.CompletionException; import org.mockito.Mockito; @@ -204,10 +203,7 @@ public void testGetEntityClientException() throws Exception { Mockito.doThrow(RuntimeException.class) .when(mockService) - .ingestProposal( - Mockito.any(AspectsBatchImpl.class), - Mockito.any(AuditStamp.class), - Mockito.anyBoolean()); + .ingestProposal(Mockito.any(AspectsBatchImpl.class), Mockito.anyBoolean()); BatchRemoveOwnersResolver resolver = new BatchRemoveOwnersResolver(mockService); diff --git a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/tag/AddTagsResolverTest.java b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/tag/AddTagsResolverTest.java index 340802cde467b8..2468cef0e1216f 100644 --- a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/tag/AddTagsResolverTest.java +++ b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/tag/AddTagsResolverTest.java @@ -5,7 +5,6 @@ import static org.testng.Assert.*; import com.google.common.collect.ImmutableList; -import com.linkedin.common.AuditStamp; import com.linkedin.common.GlobalTags; import com.linkedin.common.TagAssociation; import com.linkedin.common.TagAssociationArray; @@ -17,7 +16,8 @@ import com.linkedin.datahub.graphql.resolvers.mutate.AddTagsResolver; import com.linkedin.datahub.graphql.resolvers.mutate.MutationUtils; import com.linkedin.metadata.entity.EntityService; -import com.linkedin.metadata.entity.ebean.transactions.AspectsBatchImpl; +import com.linkedin.metadata.entity.ebean.batch.AspectsBatchImpl; +import com.linkedin.metadata.entity.ebean.batch.MCPUpsertBatchItem; import com.linkedin.mxe.MetadataChangeProposal; import graphql.schema.DataFetchingEnvironment; import java.util.concurrent.CompletionException; @@ -210,12 +210,11 @@ public void testGetUnauthorized() throws Exception { @Test public void testGetEntityClientException() throws Exception { - EntityService mockService = getMockEntityService(); + EntityService mockService = getMockEntityService(); Mockito.doThrow(RuntimeException.class) .when(mockService) - .ingestProposal( - Mockito.any(AspectsBatchImpl.class), Mockito.any(AuditStamp.class), Mockito.eq(false)); + .ingestProposal(Mockito.any(AspectsBatchImpl.class), Mockito.eq(false)); AddTagsResolver resolver = new AddTagsResolver(Mockito.mock(EntityService.class)); diff --git a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/tag/BatchAddTagsResolverTest.java b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/tag/BatchAddTagsResolverTest.java index 71354627b11452..c174d917748eba 100644 --- a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/tag/BatchAddTagsResolverTest.java +++ b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/tag/BatchAddTagsResolverTest.java @@ -5,7 +5,6 @@ import static org.testng.Assert.*; import com.google.common.collect.ImmutableList; -import com.linkedin.common.AuditStamp; import com.linkedin.common.GlobalTags; import com.linkedin.common.TagAssociation; import com.linkedin.common.TagAssociationArray; @@ -19,7 +18,7 @@ import com.linkedin.datahub.graphql.resolvers.mutate.MutationUtils; import com.linkedin.metadata.Constants; import com.linkedin.metadata.entity.EntityService; -import com.linkedin.metadata.entity.ebean.transactions.AspectsBatchImpl; +import com.linkedin.metadata.entity.ebean.batch.AspectsBatchImpl; import com.linkedin.mxe.MetadataChangeProposal; import graphql.schema.DataFetchingEnvironment; import java.util.List; @@ -197,10 +196,7 @@ public void testGetFailureTagDoesNotExist() throws Exception { assertThrows(CompletionException.class, () -> resolver.get(mockEnv).join()); Mockito.verify(mockService, Mockito.times(0)) - .ingestProposal( - Mockito.any(AspectsBatchImpl.class), - Mockito.any(AuditStamp.class), - Mockito.anyBoolean()); + .ingestProposal(Mockito.any(AspectsBatchImpl.class), Mockito.anyBoolean()); } @Test @@ -240,10 +236,7 @@ public void testGetFailureResourceDoesNotExist() throws Exception { assertThrows(CompletionException.class, () -> resolver.get(mockEnv).join()); Mockito.verify(mockService, Mockito.times(0)) - .ingestProposal( - Mockito.any(AspectsBatchImpl.class), - Mockito.any(AuditStamp.class), - Mockito.anyBoolean()); + .ingestProposal(Mockito.any(AspectsBatchImpl.class), Mockito.anyBoolean()); } @Test @@ -266,10 +259,7 @@ public void testGetUnauthorized() throws Exception { assertThrows(CompletionException.class, () -> resolver.get(mockEnv).join()); Mockito.verify(mockService, Mockito.times(0)) - .ingestProposal( - Mockito.any(AspectsBatchImpl.class), - Mockito.any(AuditStamp.class), - Mockito.anyBoolean()); + .ingestProposal(Mockito.any(AspectsBatchImpl.class), Mockito.anyBoolean()); } @Test @@ -278,10 +268,7 @@ public void testGetEntityClientException() throws Exception { Mockito.doThrow(RuntimeException.class) .when(mockService) - .ingestProposal( - Mockito.any(AspectsBatchImpl.class), - Mockito.any(AuditStamp.class), - Mockito.anyBoolean()); + .ingestProposal(Mockito.any(AspectsBatchImpl.class), Mockito.anyBoolean()); BatchAddTagsResolver resolver = new BatchAddTagsResolver(mockService); diff --git a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/tag/BatchRemoveTagsResolverTest.java b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/tag/BatchRemoveTagsResolverTest.java index 8cd10afee293ea..ba75b41388587c 100644 --- a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/tag/BatchRemoveTagsResolverTest.java +++ b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/tag/BatchRemoveTagsResolverTest.java @@ -5,7 +5,6 @@ import static org.testng.Assert.*; import com.google.common.collect.ImmutableList; -import com.linkedin.common.AuditStamp; import com.linkedin.common.GlobalTags; import com.linkedin.common.TagAssociation; import com.linkedin.common.TagAssociationArray; @@ -20,7 +19,7 @@ import com.linkedin.events.metadata.ChangeType; import com.linkedin.metadata.Constants; import com.linkedin.metadata.entity.EntityService; -import com.linkedin.metadata.entity.ebean.transactions.AspectsBatchImpl; +import com.linkedin.metadata.entity.ebean.batch.AspectsBatchImpl; import com.linkedin.metadata.utils.GenericRecordUtils; import com.linkedin.mxe.MetadataChangeProposal; import graphql.schema.DataFetchingEnvironment; @@ -199,10 +198,7 @@ public void testGetFailureResourceDoesNotExist() throws Exception { assertThrows(CompletionException.class, () -> resolver.get(mockEnv).join()); Mockito.verify(mockService, Mockito.times(0)) - .ingestProposal( - Mockito.any(AspectsBatchImpl.class), - Mockito.any(AuditStamp.class), - Mockito.anyBoolean()); + .ingestProposal(Mockito.any(AspectsBatchImpl.class), Mockito.anyBoolean()); } @Test @@ -225,10 +221,7 @@ public void testGetUnauthorized() throws Exception { assertThrows(CompletionException.class, () -> resolver.get(mockEnv).join()); Mockito.verify(mockService, Mockito.times(0)) - .ingestProposal( - Mockito.any(AspectsBatchImpl.class), - Mockito.any(AuditStamp.class), - Mockito.anyBoolean()); + .ingestProposal(Mockito.any(AspectsBatchImpl.class), Mockito.anyBoolean()); } @Test @@ -237,10 +230,7 @@ public void testGetEntityClientException() throws Exception { Mockito.doThrow(RuntimeException.class) .when(mockService) - .ingestProposal( - Mockito.any(AspectsBatchImpl.class), - Mockito.any(AuditStamp.class), - Mockito.anyBoolean()); + .ingestProposal(Mockito.any(AspectsBatchImpl.class), Mockito.anyBoolean()); BatchRemoveTagsResolver resolver = new BatchRemoveTagsResolver(mockService); diff --git a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/term/AddTermsResolverTest.java b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/term/AddTermsResolverTest.java index cb827a42333b23..397bb533ff871b 100644 --- a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/term/AddTermsResolverTest.java +++ b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/term/AddTermsResolverTest.java @@ -4,7 +4,6 @@ import static org.testng.Assert.*; import com.google.common.collect.ImmutableList; -import com.linkedin.common.AuditStamp; import com.linkedin.common.GlossaryTermAssociation; import com.linkedin.common.GlossaryTermAssociationArray; import com.linkedin.common.GlossaryTerms; @@ -16,7 +15,7 @@ import com.linkedin.datahub.graphql.resolvers.mutate.AddTermsResolver; import com.linkedin.metadata.Constants; import com.linkedin.metadata.entity.EntityService; -import com.linkedin.metadata.entity.ebean.transactions.AspectsBatchImpl; +import com.linkedin.metadata.entity.ebean.batch.AspectsBatchImpl; import graphql.schema.DataFetchingEnvironment; import java.util.concurrent.CompletionException; import org.mockito.Mockito; @@ -58,8 +57,7 @@ public void testGetSuccessNoExistingTerms() throws Exception { // Unable to easily validate exact payload due to the injected timestamp Mockito.verify(mockService, Mockito.times(1)) - .ingestProposal( - Mockito.any(AspectsBatchImpl.class), Mockito.any(AuditStamp.class), Mockito.eq(false)); + .ingestProposal(Mockito.any(AspectsBatchImpl.class), Mockito.eq(false)); Mockito.verify(mockService, Mockito.times(1)) .exists(Mockito.eq(Urn.createFromString(TEST_TERM_1_URN))); @@ -105,8 +103,7 @@ public void testGetSuccessExistingTerms() throws Exception { // Unable to easily validate exact payload due to the injected timestamp Mockito.verify(mockService, Mockito.times(1)) - .ingestProposal( - Mockito.any(AspectsBatchImpl.class), Mockito.any(AuditStamp.class), Mockito.eq(false)); + .ingestProposal(Mockito.any(AspectsBatchImpl.class), Mockito.eq(false)); Mockito.verify(mockService, Mockito.times(1)) .exists(Mockito.eq(Urn.createFromString(TEST_TERM_1_URN))); @@ -141,10 +138,7 @@ public void testGetFailureTermDoesNotExist() throws Exception { assertThrows(CompletionException.class, () -> resolver.get(mockEnv).join()); Mockito.verify(mockService, Mockito.times(0)) - .ingestProposal( - Mockito.any(AspectsBatchImpl.class), - Mockito.any(AuditStamp.class), - Mockito.anyBoolean()); + .ingestProposal(Mockito.any(AspectsBatchImpl.class), Mockito.anyBoolean()); } @Test @@ -173,10 +167,7 @@ public void testGetFailureResourceDoesNotExist() throws Exception { assertThrows(CompletionException.class, () -> resolver.get(mockEnv).join()); Mockito.verify(mockService, Mockito.times(0)) - .ingestProposal( - Mockito.any(AspectsBatchImpl.class), - Mockito.any(AuditStamp.class), - Mockito.anyBoolean()); + .ingestProposal(Mockito.any(AspectsBatchImpl.class), Mockito.anyBoolean()); } @Test @@ -195,10 +186,7 @@ public void testGetUnauthorized() throws Exception { assertThrows(CompletionException.class, () -> resolver.get(mockEnv).join()); Mockito.verify(mockService, Mockito.times(0)) - .ingestProposal( - Mockito.any(AspectsBatchImpl.class), - Mockito.any(AuditStamp.class), - Mockito.anyBoolean()); + .ingestProposal(Mockito.any(AspectsBatchImpl.class), Mockito.anyBoolean()); } @Test @@ -207,10 +195,7 @@ public void testGetEntityClientException() throws Exception { Mockito.doThrow(RuntimeException.class) .when(mockService) - .ingestProposal( - Mockito.any(AspectsBatchImpl.class), - Mockito.any(AuditStamp.class), - Mockito.anyBoolean()); + .ingestProposal(Mockito.any(AspectsBatchImpl.class), Mockito.anyBoolean()); AddTermsResolver resolver = new AddTermsResolver(Mockito.mock(EntityService.class)); diff --git a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/term/BatchAddTermsResolverTest.java b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/term/BatchAddTermsResolverTest.java index 7df19fad52689f..2c85e870dd6acb 100644 --- a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/term/BatchAddTermsResolverTest.java +++ b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/term/BatchAddTermsResolverTest.java @@ -4,7 +4,6 @@ import static org.testng.Assert.*; import com.google.common.collect.ImmutableList; -import com.linkedin.common.AuditStamp; import com.linkedin.common.GlossaryTermAssociation; import com.linkedin.common.GlossaryTermAssociationArray; import com.linkedin.common.GlossaryTerms; @@ -17,7 +16,7 @@ import com.linkedin.datahub.graphql.resolvers.mutate.BatchAddTermsResolver; import com.linkedin.metadata.Constants; import com.linkedin.metadata.entity.EntityService; -import com.linkedin.metadata.entity.ebean.transactions.AspectsBatchImpl; +import com.linkedin.metadata.entity.ebean.batch.AspectsBatchImpl; import graphql.schema.DataFetchingEnvironment; import java.util.concurrent.CompletionException; import org.mockito.Mockito; @@ -239,10 +238,7 @@ public void testGetEntityClientException() throws Exception { Mockito.doThrow(RuntimeException.class) .when(mockService) - .ingestProposal( - Mockito.any(AspectsBatchImpl.class), - Mockito.any(AuditStamp.class), - Mockito.anyBoolean()); + .ingestProposal(Mockito.any(AspectsBatchImpl.class), Mockito.anyBoolean()); BatchAddTermsResolver resolver = new BatchAddTermsResolver(mockService); diff --git a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/term/BatchRemoveTermsResolverTest.java b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/term/BatchRemoveTermsResolverTest.java index 659ce40542a9cf..c2520f4dfb7121 100644 --- a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/term/BatchRemoveTermsResolverTest.java +++ b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/term/BatchRemoveTermsResolverTest.java @@ -4,7 +4,6 @@ import static org.testng.Assert.*; import com.google.common.collect.ImmutableList; -import com.linkedin.common.AuditStamp; import com.linkedin.common.GlossaryTermAssociation; import com.linkedin.common.GlossaryTermAssociationArray; import com.linkedin.common.GlossaryTerms; @@ -17,7 +16,7 @@ import com.linkedin.datahub.graphql.resolvers.mutate.BatchRemoveTermsResolver; import com.linkedin.metadata.Constants; import com.linkedin.metadata.entity.EntityService; -import com.linkedin.metadata.entity.ebean.transactions.AspectsBatchImpl; +import com.linkedin.metadata.entity.ebean.batch.AspectsBatchImpl; import graphql.schema.DataFetchingEnvironment; import java.util.concurrent.CompletionException; import org.mockito.Mockito; @@ -200,10 +199,7 @@ public void testGetEntityClientException() throws Exception { Mockito.doThrow(RuntimeException.class) .when(mockService) - .ingestProposal( - Mockito.any(AspectsBatchImpl.class), - Mockito.any(AuditStamp.class), - Mockito.anyBoolean()); + .ingestProposal(Mockito.any(AspectsBatchImpl.class), Mockito.anyBoolean()); BatchRemoveTermsResolver resolver = new BatchRemoveTermsResolver(mockService); diff --git a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/utils/OwnerUtilsTest.java b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/utils/OwnerUtilsTest.java new file mode 100644 index 00000000000000..b4097d9dd045df --- /dev/null +++ b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/utils/OwnerUtilsTest.java @@ -0,0 +1,110 @@ +package com.linkedin.datahub.graphql.utils; + +import static org.testng.AssertJUnit.*; + +import com.linkedin.common.Owner; +import com.linkedin.common.OwnershipType; +import com.linkedin.common.urn.Urn; +import com.linkedin.datahub.graphql.resolvers.mutate.util.OwnerUtils; +import java.net.URISyntaxException; +import org.testng.annotations.Test; + +public class OwnerUtilsTest { + + public static String TECHNICAL_OWNER_OWNERSHIP_TYPE_URN = + "urn:li:ownershipType:__system__technical_owner"; + public static String BUSINESS_OWNER_OWNERSHIP_TYPE_URN = + "urn:li:ownershipType:__system__business_owner"; + + @Test + public void testMapOwnershipType() { + assertEquals( + OwnerUtils.mapOwnershipTypeToEntity("TECHNICAL_OWNER"), TECHNICAL_OWNER_OWNERSHIP_TYPE_URN); + } + + @Test + public void testIsOwnerEqualUrnOnly() throws URISyntaxException { + Urn ownerUrn1 = new Urn("urn:li:corpuser:foo"); + Owner owner1 = new Owner(); + owner1.setOwner(ownerUrn1); + assertTrue(OwnerUtils.isOwnerEqual(owner1, ownerUrn1, null)); + + Urn ownerUrn2 = new Urn("urn:li:corpuser:bar"); + assertFalse(OwnerUtils.isOwnerEqual(owner1, ownerUrn2, null)); + } + + @Test + public void testIsOwnerEqualWithLegacyTypeOnly() throws URISyntaxException { + + Urn technicalOwnershipTypeUrn = new Urn(TECHNICAL_OWNER_OWNERSHIP_TYPE_URN); + Urn ownerUrn1 = new Urn("urn:li:corpuser:foo"); + Owner ownerWithTechnicalOwnership = new Owner(); + ownerWithTechnicalOwnership.setOwner(ownerUrn1); + ownerWithTechnicalOwnership.setType(OwnershipType.TECHNICAL_OWNER); + + assertTrue( + OwnerUtils.isOwnerEqual(ownerWithTechnicalOwnership, ownerUrn1, technicalOwnershipTypeUrn)); + + Owner ownerWithBusinessOwnership = new Owner(); + ownerWithBusinessOwnership.setOwner(ownerUrn1); + ownerWithBusinessOwnership.setType(OwnershipType.BUSINESS_OWNER); + assertFalse( + OwnerUtils.isOwnerEqual( + ownerWithBusinessOwnership, ownerUrn1, new Urn(TECHNICAL_OWNER_OWNERSHIP_TYPE_URN))); + } + + @Test + public void testIsOwnerEqualOnlyOwnershipTypeUrn() throws URISyntaxException { + + Urn technicalOwnershipTypeUrn = new Urn(TECHNICAL_OWNER_OWNERSHIP_TYPE_URN); + Urn businessOwnershipTypeUrn = new Urn(BUSINESS_OWNER_OWNERSHIP_TYPE_URN); + Urn ownerUrn1 = new Urn("urn:li:corpuser:foo"); + + Owner ownerWithTechnicalOwnership = new Owner(); + ownerWithTechnicalOwnership.setOwner(ownerUrn1); + ownerWithTechnicalOwnership.setTypeUrn(technicalOwnershipTypeUrn); + + Owner ownerWithBusinessOwnership = new Owner(); + ownerWithBusinessOwnership.setOwner(ownerUrn1); + ownerWithBusinessOwnership.setTypeUrn(businessOwnershipTypeUrn); + + Owner ownerWithoutOwnershipType = new Owner(); + ownerWithoutOwnershipType.setOwner(ownerUrn1); + ownerWithoutOwnershipType.setType(OwnershipType.NONE); + + assertTrue( + OwnerUtils.isOwnerEqual(ownerWithTechnicalOwnership, ownerUrn1, technicalOwnershipTypeUrn)); + assertFalse( + OwnerUtils.isOwnerEqual(ownerWithBusinessOwnership, ownerUrn1, technicalOwnershipTypeUrn)); + assertFalse(OwnerUtils.isOwnerEqual(ownerWithTechnicalOwnership, ownerUrn1, null)); + assertTrue(OwnerUtils.isOwnerEqual(ownerWithoutOwnershipType, ownerUrn1, null)); + } + + public void testIsOwnerEqualWithBothLegacyAndNewType() throws URISyntaxException { + Urn technicalOwnershipTypeUrn = new Urn(TECHNICAL_OWNER_OWNERSHIP_TYPE_URN); + Urn businessOwnershipTypeUrn = new Urn(BUSINESS_OWNER_OWNERSHIP_TYPE_URN); + Urn ownerUrn1 = new Urn("urn:li:corpuser:foo"); + + Owner ownerWithLegacyTechnicalOwnership = new Owner(); + ownerWithLegacyTechnicalOwnership.setOwner(ownerUrn1); + ownerWithLegacyTechnicalOwnership.setType(OwnershipType.TECHNICAL_OWNER); + + assertTrue( + OwnerUtils.isOwnerEqual( + ownerWithLegacyTechnicalOwnership, ownerUrn1, technicalOwnershipTypeUrn)); + assertFalse( + OwnerUtils.isOwnerEqual( + ownerWithLegacyTechnicalOwnership, ownerUrn1, businessOwnershipTypeUrn)); + + Owner ownerWithNewTechnicalOwnership = new Owner(); + ownerWithLegacyTechnicalOwnership.setOwner(ownerUrn1); + ownerWithLegacyTechnicalOwnership.setTypeUrn(technicalOwnershipTypeUrn); + + assertTrue( + OwnerUtils.isOwnerEqual( + ownerWithNewTechnicalOwnership, ownerUrn1, technicalOwnershipTypeUrn)); + assertFalse( + OwnerUtils.isOwnerEqual( + ownerWithNewTechnicalOwnership, ownerUrn1, businessOwnershipTypeUrn)); + } +} diff --git a/datahub-upgrade/src/main/java/com/linkedin/datahub/upgrade/restorebackup/RestoreStorageStep.java b/datahub-upgrade/src/main/java/com/linkedin/datahub/upgrade/restorebackup/RestoreStorageStep.java index 5c4567c856d0ed..5c4e8cdc47e345 100644 --- a/datahub-upgrade/src/main/java/com/linkedin/datahub/upgrade/restorebackup/RestoreStorageStep.java +++ b/datahub-upgrade/src/main/java/com/linkedin/datahub/upgrade/restorebackup/RestoreStorageStep.java @@ -39,7 +39,7 @@ public class RestoreStorageStep implements UpgradeStep { private static final int REPORT_BATCH_SIZE = 1000; private static final int DEFAULT_THREAD_POOL = 4; - private final EntityService _entityService; + private final EntityService _entityService; private final EntityRegistry _entityRegistry; private final Map>>> _backupReaders; diff --git a/datahub-upgrade/src/main/java/com/linkedin/datahub/upgrade/restoreindices/SendMAEStep.java b/datahub-upgrade/src/main/java/com/linkedin/datahub/upgrade/restoreindices/SendMAEStep.java index 574b1f08b5f543..bedf200a1c0553 100644 --- a/datahub-upgrade/src/main/java/com/linkedin/datahub/upgrade/restoreindices/SendMAEStep.java +++ b/datahub-upgrade/src/main/java/com/linkedin/datahub/upgrade/restoreindices/SendMAEStep.java @@ -34,7 +34,7 @@ public class SendMAEStep implements UpgradeStep { private static final boolean DEFAULT_URN_BASED_PAGINATION = false; private final Database _server; - private final EntityService _entityService; + private final EntityService _entityService; public class KafkaJob implements Callable { UpgradeContext context; diff --git a/datahub-web-react/src/app/entity/shared/EntityDropdown/MoveGlossaryEntityModal.tsx b/datahub-web-react/src/app/entity/shared/EntityDropdown/MoveGlossaryEntityModal.tsx index 37a625f58100b3..51b39be4e20ea2 100644 --- a/datahub-web-react/src/app/entity/shared/EntityDropdown/MoveGlossaryEntityModal.tsx +++ b/datahub-web-react/src/app/entity/shared/EntityDropdown/MoveGlossaryEntityModal.tsx @@ -7,6 +7,7 @@ import { useUpdateParentNodeMutation } from '../../../../graphql/glossary.genera import NodeParentSelect from './NodeParentSelect'; import { useGlossaryEntityData } from '../GlossaryEntityContext'; import { getGlossaryRootToUpdate, getParentNodeToUpdate, updateGlossarySidebar } from '../../../glossary/utils'; +import { getModalDomContainer } from '../../../../utils/focus'; const StyledItem = styled(Form.Item)` margin-bottom: 0; @@ -78,6 +79,7 @@ function MoveGlossaryEntityModal(props: Props) { } + getContainer={getModalDomContainer} >
diff --git a/datahub-web-react/src/app/entity/shared/EntityDropdown/NodeParentSelect.tsx b/datahub-web-react/src/app/entity/shared/EntityDropdown/NodeParentSelect.tsx index c3bfac35c2ca6d..e7f5827e33dcc7 100644 --- a/datahub-web-react/src/app/entity/shared/EntityDropdown/NodeParentSelect.tsx +++ b/datahub-web-react/src/app/entity/shared/EntityDropdown/NodeParentSelect.tsx @@ -21,6 +21,7 @@ interface Props { selectedParentUrn: string; setSelectedParentUrn: (parent: string) => void; isMoving?: boolean; + autofocus?: boolean; } function NodeParentSelect(props: Props) { @@ -65,6 +66,7 @@ function NodeParentSelect(props: Props) { onClear={clearSelectedParent} onFocus={() => setIsFocusedOnInput(true)} dropdownStyle={isShowingGlossaryBrowser || !searchQuery ? { display: 'none' } : {}} + autoFocus={props.autofocus} > {nodeSearchResults?.map((result) => ( diff --git a/datahub-web-react/src/app/entity/shared/components/styled/AddLinkModal.tsx b/datahub-web-react/src/app/entity/shared/components/styled/AddLinkModal.tsx index 68a8cf40943629..9e18de3b294bf7 100644 --- a/datahub-web-react/src/app/entity/shared/components/styled/AddLinkModal.tsx +++ b/datahub-web-react/src/app/entity/shared/components/styled/AddLinkModal.tsx @@ -5,6 +5,7 @@ import { useEntityData, useMutationUrn } from '../../EntityContext'; import { useAddLinkMutation } from '../../../../../graphql/mutations.generated'; import analytics, { EventType, EntityActionType } from '../../../../analytics'; import { useUserContext } from '../../../../context/useUserContext'; +import { getModalDomContainer } from '../../../../../utils/focus'; type AddLinkProps = { buttonProps?: Record; @@ -73,6 +74,7 @@ export const AddLinkModal = ({ buttonProps, refetch }: AddLinkProps) => { Add , ]} + getContainer={getModalDomContainer} > } + getContainer={getModalDomContainer} >