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 mock impl for Adobe Granite Asset API #49

Merged
merged 14 commits into from
Aug 20, 2024
Merged
3 changes: 3 additions & 0 deletions changes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
<action type="update" dev="sseifert">
Update to latest OSGi Mock, Sling Mock.
</action>
<action type="update" dev="senn">
Implement Adobe Granite Asset API mocks.
</action>
</release>

<release version="5.5.4" date="2024-07-18">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,17 @@ protected final Map<String, Object> resourceResolverFactoryActivatorPropsMergeWi
return assetManager;
}

/**
* @return Adobe Granite Asset manager
*/
public @NotNull com.adobe.granite.asset.api.AssetManager graniteAssetManager() {
com.adobe.granite.asset.api.AssetManager assetManager = resourceResolver().adaptTo(com.adobe.granite.asset.api.AssetManager.class);
if (assetManager == null) {
throw new RuntimeException("No granite asset manager");
}
return assetManager;
}

/**
* @return Content builder for building test content
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,5 @@
/**
* AEM context implementation for unit tests.
*/
@org.osgi.annotation.versioning.Version("2.0.0")
@org.osgi.annotation.versioning.Version("2.1.0")
package io.wcm.testing.mock.aem.context;
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
*/
package io.wcm.testing.mock.aem.dam;

import com.day.cq.dam.api.Rendition;
import org.apache.sling.api.adapter.AdapterFactory;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
Expand All @@ -33,7 +34,6 @@

import com.day.cq.dam.api.Asset;
import com.day.cq.dam.api.AssetManager;
import com.day.cq.dam.api.Rendition;
import com.day.cq.dam.commons.util.DamUtil;

/**
Expand All @@ -45,7 +45,10 @@
AdapterFactory.ADAPTABLE_CLASSES + "=org.apache.sling.api.resource.ResourceResolver",
AdapterFactory.ADAPTER_CLASSES + "=com.day.cq.dam.api.Asset",
AdapterFactory.ADAPTER_CLASSES + "=com.day.cq.dam.api.AssetManager",
AdapterFactory.ADAPTER_CLASSES + "=com.day.cq.dam.api.Rendition"
AdapterFactory.ADAPTER_CLASSES + "=com.day.cq.dam.api.Rendition",
AdapterFactory.ADAPTER_CLASSES + "=com.adobe.granite.asset.api.Asset",
AdapterFactory.ADAPTER_CLASSES + "=com.adobe.granite.asset.api.AssetManager",
AdapterFactory.ADAPTER_CLASSES + "=com.adobe.granite.asset.api.Rendition"
})
@ProviderType
public final class MockAemDamAdapterFactory implements AdapterFactory {
Expand Down Expand Up @@ -73,19 +76,25 @@ private void activate(BundleContext context) {

@SuppressWarnings("unchecked")
senn marked this conversation as resolved.
Show resolved Hide resolved
private @Nullable <AdapterType> AdapterType getAdapter(@NotNull final Resource resource, @NotNull final Class<AdapterType> type) {
if (type == Asset.class && DamUtil.isAsset(resource)) {
return (AdapterType)new MockAsset(resource, eventAdmin, bundleContext);
if (DamUtil.isAsset(resource)) {
if (type == com.adobe.granite.asset.api.Asset.class) {
return (AdapterType) new MockGraniteAssetWrapper(new MockAsset(resource, eventAdmin, bundleContext));
} else if (type == Asset.class) {
return (AdapterType) new MockAsset(resource, eventAdmin, bundleContext);
}
}
if (type == Rendition.class && DamUtil.isRendition(resource)) {
return (AdapterType)new MockRendition(resource);
if ((type == Rendition.class || type == com.adobe.granite.asset.api.Rendition.class) && DamUtil.isRendition(resource)) {
return (AdapterType) new MockRendition(resource);
}
return null;
}

@SuppressWarnings("unchecked")
private @Nullable <AdapterType> AdapterType getAdapter(@NotNull final ResourceResolver resolver, @NotNull final Class<AdapterType> type) {
if (type == AssetManager.class) {
return (AdapterType)new MockAssetManager(resolver, eventAdmin, bundleContext);
return (AdapterType) new MockAssetManager(resolver, eventAdmin, bundleContext);
} else if(type == com.adobe.granite.asset.api.AssetManager.class) {
return (AdapterType) new MockGraniteAssetManagerWrapper(resolver);
}
return null;
}
Expand Down
35 changes: 11 additions & 24 deletions core/src/main/java/io/wcm/testing/mock/aem/dam/MockAsset.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,37 +19,20 @@
*/
package io.wcm.testing.mock.aem.dam;

import java.io.InputStream;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.jcr.Binary;

import com.day.cq.commons.jcr.JcrConstants;
import com.day.cq.dam.api.*;
stefanseifert marked this conversation as resolved.
Show resolved Hide resolved
import org.apache.commons.collections4.IteratorUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.jackrabbit.api.security.user.User;
import org.apache.sling.api.resource.PersistenceException;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceUtil;
import org.apache.sling.api.resource.ResourceWrapper;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.resource.*;
import org.apache.sling.testing.mock.sling.loader.ContentLoader;
import org.jetbrains.annotations.NotNull;
import org.osgi.framework.BundleContext;
import org.osgi.service.event.EventAdmin;

import com.day.cq.commons.jcr.JcrConstants;
import com.day.cq.dam.api.Asset;
import com.day.cq.dam.api.DamConstants;
import com.day.cq.dam.api.DamEvent;
import com.day.cq.dam.api.Rendition;
import com.day.cq.dam.api.RenditionPicker;
import com.day.cq.dam.api.Revision;
import javax.jcr.Binary;
import java.io.InputStream;
import java.util.*;

/**
* Mock implementation of {@link Asset}.
Expand Down Expand Up @@ -80,7 +63,11 @@ class MockAsset extends ResourceWrapper implements Asset {
@Override
public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) {
if (type == Resource.class) {
return (AdapterType)resource;
return (AdapterType) resource;
}
//to be able to adapt to granite asset
if (type == com.adobe.granite.asset.api.Asset.class) {
Copy link
Contributor

Choose a reason for hiding this comment

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

You can also implement this in the AdapterFactory, which might be a bit cleaner?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

makes it a lot harder to access inner resources and assets. I'd rather not.

return (AdapterType) new MockGraniteAssetWrapper(this);
}
return super.adaptTo(type);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package io.wcm.testing.mock.aem.dam;

import com.adobe.granite.asset.api.Asset;
import com.adobe.granite.asset.api.AssetManager;
import com.day.cq.dam.api.DamConstants;
import org.apache.jackrabbit.JcrConstants;
import org.apache.sling.api.resource.PersistenceException;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.jetbrains.annotations.NotNull;

import java.util.Objects;

/**
* Mock implementation of Adobe Granite {@link AssetManager}. This is done by wrapping a {@link MockAssetManager}.
*/
public class MockGraniteAssetManagerWrapper implements AssetManager {

private final ResourceResolver resourceResolver;
private final com.day.cq.dam.api.AssetManager cqAssetManager;

MockGraniteAssetManagerWrapper(@NotNull ResourceResolver resourceResolver) {
this.resourceResolver = resourceResolver;
this.cqAssetManager = resourceResolver.adaptTo(com.day.cq.dam.api.AssetManager.class);
}

@Override
public Asset createAsset(String s) {
com.day.cq.dam.api.Asset asset = cqAssetManager.createAsset(s, null, null, false);
if (asset instanceof MockAsset) {
senn marked this conversation as resolved.
Show resolved Hide resolved
return new MockGraniteAssetWrapper((MockAsset) asset);
}
throw new UnsupportedOperationException("Not in a mock context");
}

@Override
public Asset getAsset(String s) {
Resource resource = resourceResolver.getResource(s);
return resource != null ? resource.adaptTo(Asset.class) : null;
}

@Override
public Asset getAssetByIdentifier(String s) {
throw new UnsupportedOperationException();
}

@Override
public boolean assetExists(String s) {
Resource assetResource = resourceResolver.getResource(s);
return assetResource != null && Objects.equals(DamConstants.NT_DAM_ASSET, assetResource.getValueMap().get(JcrConstants.JCR_PRIMARYTYPE, String.class));
}

@Override
public void removeAsset(String s) {
try {
Resource assetResource = resourceResolver.getResource(s);
if (assetResource != null) {
resourceResolver.delete(assetResource);
}
} catch (PersistenceException pe) {
throw new RuntimeException(pe);
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 why removeAsset does not throw exceptions, but given that fact, this is indeed the correct way to do it :o

}
}

@Override
public void copyAsset(String s, String s1) {
throw new UnsupportedOperationException();
}

@Override
public void moveAsset(String s, String s1) {
throw new UnsupportedOperationException();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package io.wcm.testing.mock.aem.dam;

import com.adobe.granite.asset.api.Asset;
import com.adobe.granite.asset.api.AssetMetadata;
import com.adobe.granite.asset.api.AssetRelation;
import com.adobe.granite.asset.api.Rendition;
import org.apache.commons.lang3.StringUtils;
import org.apache.sling.api.resource.ResourceWrapper;

import javax.jcr.Binary;
import java.io.InputStream;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
* Mock implementation of Adobe Granite {@link Asset}. This is done by wrapping a {@link MockAsset}
*/
@SuppressWarnings("null")
public class MockGraniteAssetWrapper extends ResourceWrapper implements Asset {

private final MockAsset asset;

MockGraniteAssetWrapper(MockAsset asset) {
senn marked this conversation as resolved.
Show resolved Hide resolved
super(asset.getResource());
this.asset = asset;
}

@SuppressWarnings("unchecked")
@Override
public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) {
//to be able to adapt to CQ asset
if (type == com.day.cq.dam.api.Asset.class) {
return (AdapterType) asset;
}
return asset.adaptTo(type);
}

@Override
public com.adobe.granite.asset.api.Rendition getRendition(String s) {
return (com.adobe.granite.asset.api.Rendition) asset.getRendition(s);
}

@Override
public Iterator<? extends Rendition> listRenditions() {
List<Rendition> graniteRenditions = new LinkedList<>();
Iterator<? extends com.day.cq.dam.api.Rendition> renditions = asset.listRenditions();
while (renditions.hasNext()) {
graniteRenditions.add((com.adobe.granite.asset.api.Rendition) renditions.next());
}
return graniteRenditions.iterator();
}

@Override
public String getIdentifier() {
return asset.getID();
}

@Override
public com.adobe.granite.asset.api.Rendition setRendition(String s, InputStream inputStream, Map<String, Object> map) {
if (map.size() == 1) {
Object val = map.values().iterator().next();
if (val != null) {
return (com.adobe.granite.asset.api.Rendition) asset.addRendition(s, inputStream, val.toString());
}
}
return (com.adobe.granite.asset.api.Rendition) asset.addRendition(s, inputStream, map);
}

@Override
public com.adobe.granite.asset.api.Rendition setRendition(String s, Binary binary, Map<String, Object> map) {
return (com.adobe.granite.asset.api.Rendition) asset.addRendition(s, binary, map);
}

@Override
public void removeRendition(String s) {
asset.removeRendition(s);
}

@Override
public Iterator<? extends com.adobe.granite.asset.api.Asset> listRelated(String s) {
throw new UnsupportedOperationException();
}

@Override
public Iterator<? extends AssetRelation> listRelations(String s) {
throw new UnsupportedOperationException();
}

@Override
public AssetMetadata getAssetMetadata() {
throw new UnsupportedOperationException();
}

@Override
public AssetRelation addRelation(String s, String s1, Map<String, Object> map) {
throw new UnsupportedOperationException();
}

@Override
public void setRelation(String s, String s1) {
throw new UnsupportedOperationException();
}

@Override
public AssetRelation addRelation(String s, String s1) {
throw new UnsupportedOperationException();
}

@Override
public void orderRelationBefore(String s, String s1, String s2) {
throw new UnsupportedOperationException();
}

@Override
public void removeRelation(String s, String s1) {
throw new UnsupportedOperationException();
}

@Override
public void removeRelation(String s) {
throw new UnsupportedOperationException();
}

@Override
public int hashCode() {
return getPath().hashCode();
}

@Override
public boolean equals(Object obj) {
if (!(obj instanceof MockGraniteAssetWrapper)) {
return false;
}
return StringUtils.equals(getPath(), ((MockGraniteAssetWrapper)obj).getPath());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@
import com.day.cq.dam.commons.util.DamUtil;

/**
* Mock implementation of {@link Rendition}.
* Mock implementation of {@link Rendition} and {@link com.adobe.granite.asset.api.Rendition}.
*/
@SuppressWarnings("null")
class MockRendition extends ResourceWrapper implements Rendition {
class MockRendition extends ResourceWrapper implements Rendition, com.adobe.granite.asset.api.Rendition {

private final Resource resource;
private final Resource contentResource;
Expand All @@ -60,6 +60,10 @@ public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) {
if (type == Resource.class) {
return (AdapterType)resource;
}
//to be able to adapt to granite rendition and back
if (type == Rendition.class || type == com.adobe.granite.asset.api.Rendition.class) {
return (AdapterType) this;
}
return super.adaptTo(type);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,5 @@
/**
* Mock implementation of selected AEM DAM APIs.
*/
@org.osgi.annotation.versioning.Version("2.3.0")
@org.osgi.annotation.versioning.Version("2.4.0")
package io.wcm.testing.mock.aem.dam;
Loading