Skip to content

Commit

Permalink
New dependencies on licensed extensions are not covered by existing l…
Browse files Browse the repository at this point in the history
…icenses when upgrading licensed extensions #174

* added unit tests
* moved TrialLicenseGeneratorTest to junit5
  • Loading branch information
oanalavinia committed Oct 7, 2024
1 parent 5f6d688 commit 4d69cb2
Show file tree
Hide file tree
Showing 5 changed files with 436 additions and 169 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public void renewLicense(ExtensionId extensionId)
try {
URL licenseRenewURL = getLicenseRenewURL(extensionId);
if (licenseRenewURL == null) {
logger.debug("Failed to renew license for [{}] because the licensor configuration is not complete. "
logger.warn("Failed to renew license for [{}] because the licensor configuration is not complete. "
+ "Check your store license renew URL and owner details.", extensionId.getId());
return;
}
Expand All @@ -109,10 +109,12 @@ public void renewLicense(ExtensionId extensionId)
String getLicenseRenewResponse = xcontext.getWiki().getURLContent(licenseRenewURL.toString(), xcontext);

if (getLicenseRenewResponse.contains("error")) {
logger.debug("Failed to renew license for [{}] on store.", extensionId.getId());
logger.warn("Failed to renew license for [{}] on store.", extensionId.getId());
} else {
logger.debug("License renewed for [{}]", extensionId.getId());
// getLicensesUpdates();
// After renewing the license on store, right now we retrieve new updates from store. Maybe we should
// simply return the updated license from the start, to not make a new request?
// getLicensesUpdates();
}
} catch (Exception e) {
logger.warn("Failed to update license for [{}]. Root cause is [{}]", extensionId,
Expand All @@ -136,8 +138,9 @@ public void getLicensesUpdates()
String licensesUpdateResponse = xcontext.getWiki().getURLContent(licensesUpdateURL.toString(), xcontext);
ObjectMapper objectMapper = new ObjectMapper();

List<String> retriedLicenses = (List<String>) objectMapper.readValue(licensesUpdateResponse, Object.class);
for (String license : retriedLicenses) {
List<String> retrievedLicenses =
(List<String>) objectMapper.readValue(licensesUpdateResponse, Object.class);
for (String license : retrievedLicenses) {
License retrivedLicense = converter.convert(License.class, base64decoder.decode(license));
if (retrivedLicense != null) {
licenseManagerProvider.get().add(retrivedLicense);
Expand Down Expand Up @@ -195,7 +198,7 @@ private URL getLicenseRenewURL(ExtensionId extensionId) throws Exception
builder.addParameter(INSTANCE_ID, instanceIdManagerProvider.get().getInstanceId().toString());
builder.addParameter(FEATURE_ID, extensionId.getId());
builder.addParameter("extensionVersion", extensionId.getVersion().getValue());
// In progress: take it from existing license.
// TODO: take it from existing license.
builder.addParameter("licenseType", "TRIAL");

return builder.build().toURL();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@
/**
* Helper methods for generating a trial license and updating it.
*
* @since 1.17
* @version $Id$
* @since 1.17
*/
@Component(roles = TrialLicenseGenerator.class)
@Singleton
Expand Down Expand Up @@ -87,7 +87,7 @@ public void generateTrialLicense(ExtensionId extensionId)
try {
URL trialURL = getTrialURL(extensionId);
if (trialURL == null) {
logger.debug("Failed to add trial license for [{}] because the licensor configuration is not complete. "
logger.warn("Failed to add trial license for [{}] because the licensor configuration is not complete. "
+ "Check your store trial URL and owner details.", extensionId.getId());
return;
}
Expand All @@ -96,7 +96,7 @@ public void generateTrialLicense(ExtensionId extensionId)
String getTrialResponse = xcontext.getWiki().getURLContent(trialURL.toString(), xcontext);

if (getTrialResponse.contains("error")) {
logger.debug("Failed to generate trial license for [{}] on store.", extensionId.getId());
logger.warn("Failed to generate trial license for [{}] on store.", extensionId.getId());
} else {
logger.debug("Trial license added for [{}]", extensionId.getId());
licenseUpdater.getLicensesUpdates();
Expand Down Expand Up @@ -152,7 +152,7 @@ private URL getTrialURL(ExtensionId extensionId) throws Exception
/**
* Check if for the given licensed extension a license is mandatory, meaning that it is not covered by the license
* of other extension (it's not dependency of other licensed extension).
*
*
* @param extensionId the extension to be checked
* @return true if is a mandatory licensed extension, false otherwise
*/
Expand All @@ -166,8 +166,8 @@ private Boolean isMandatoryLicensedExtension(ExtensionId extensionId)
*/
private Boolean isOwnerDataComplete()
{
return !(StringUtils.isEmpty(licensingConfig.getLicensingOwnerLastName())
|| StringUtils.isEmpty(licensingConfig.getLicensingOwnerFirstName())
|| StringUtils.isEmpty(licensingConfig.getLicensingOwnerEmail()));
return !(StringUtils.isEmpty(licensingConfig.getLicensingOwnerLastName()) || StringUtils.isEmpty(
licensingConfig.getLicensingOwnerFirstName()) || StringUtils.isEmpty(
licensingConfig.getLicensingOwnerEmail()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
/*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package com.xwiki.licensing.internal;

import java.io.IOException;
import java.util.Collections;
import java.util.List;

import javax.inject.Named;
import javax.inject.Provider;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.mockito.Mock;
import org.xwiki.crypto.BinaryStringEncoder;
import org.xwiki.extension.ExtensionId;
import org.xwiki.extension.repository.InstalledExtensionRepository;
import org.xwiki.instance.InstanceId;
import org.xwiki.instance.InstanceIdManager;
import org.xwiki.properties.converter.Converter;
import org.xwiki.test.LogLevel;
import org.xwiki.test.junit5.LogCaptureExtension;
import org.xwiki.test.junit5.mockito.ComponentTest;
import org.xwiki.test.junit5.mockito.InjectMockComponents;
import org.xwiki.test.junit5.mockito.MockComponent;

import com.xpn.xwiki.XWiki;
import com.xpn.xwiki.XWikiContext;
import com.xwiki.licensing.License;
import com.xwiki.licensing.LicenseManager;
import com.xwiki.licensing.LicensedExtensionManager;
import com.xwiki.licensing.LicensingConfiguration;
import com.xwiki.licensing.Licensor;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@ComponentTest
public class DefaultLicenseUpdaterTest
{
@RegisterExtension
private LogCaptureExtension logCaptureWarn = new LogCaptureExtension(LogLevel.WARN);

@InjectMockComponents
private DefaultLicenseUpdater licenseUpdater;

@MockComponent
private LicensedExtensionManager licensedExtensionManager;

@MockComponent
private InstalledExtensionRepository installedExtensionRepository;

@MockComponent
private LicensingConfiguration licensingConfig;

@MockComponent
private Provider<XWikiContext> contextProvider;

@MockComponent
private Provider<InstanceIdManager> instanceIdManagerProvider;

@MockComponent
private Provider<Licensor> licensorProvider;

@MockComponent
private Provider<LicenseManager> licenseManagerProvider;

@MockComponent
@Named("Base64")
private BinaryStringEncoder base64decoder;

@MockComponent
private Converter<License> converter;

@Mock
private XWiki xwiki;

@Mock
private XWikiContext xcontext;

@Mock
private LicenseManager licenseManager;

@Mock
private InstanceIdManager instanceIdManager;

@Mock
private Licensor licensor;

@Mock
private License license;

@BeforeEach
void configure()
{
when(contextProvider.get()).thenReturn(xcontext);
when(xcontext.getWiki()).thenReturn(xwiki);
when(licenseManagerProvider.get()).thenReturn(licenseManager);
when(instanceIdManagerProvider.get()).thenReturn(instanceIdManager);
when(instanceIdManager.getInstanceId()).thenReturn(new InstanceId("7237b65d-e5d6-4249-aa4f-7c732cba27e2"));
when(licensorProvider.get()).thenReturn(licensor);
}

@Test
void renewLicenseWithNullURL() throws Exception
{
when(licensingConfig.getStoreLicenseRenewURL()).thenReturn(null);

ExtensionId extensionId = new ExtensionId("application-test", "1.0");
licenseUpdater.renewLicense(extensionId);

assertEquals(String.format(
"Failed to renew license for [%s] because the licensor configuration is not complete."
+ " Check your store license renew URL and owner details.", extensionId.getId()),
logCaptureWarn.getMessage(0));
}

@Test
void renewLicenseWithSuccess() throws Exception
{
when(licensingConfig.getStoreLicenseRenewURL()).thenReturn("https://storeRenew.com");
when(licensingConfig.getLicensingOwnerFirstName()).thenReturn("John");
when(licensingConfig.getLicensingOwnerLastName()).thenReturn("Doe");
String renewURL =
"https://storeRenew.com?firstName=John&lastName=Doe&email&instanceId=7237b65d-e5d6-4249-aa4f-7c732cba27e2"
+ "&featureId=application-test&extensionVersion=1.0&licenseType=TRIAL";
String getLicenseRenewResponse = "success";
when(xwiki.getURLContent(renewURL, xcontext)).thenReturn(getLicenseRenewResponse);

ExtensionId extensionId = new ExtensionId("application-test", "1.0");
licenseUpdater.renewLicense(extensionId);

// After renewing the license on store, right now we retrieve new updates from store. Maybe we should simply
// return the updated license from the start, to not make a new request?
}

@Test
void renewLicenseWithError() throws Exception
{
when(licensingConfig.getStoreLicenseRenewURL()).thenReturn("https://storeRenew.com");
when(licensingConfig.getLicensingOwnerFirstName()).thenReturn("John");
when(licensingConfig.getLicensingOwnerLastName()).thenReturn("Doe");
String renewURL =
"https://storeRenew.com?firstName=John&lastName=Doe&email&instanceId=7237b65d-e5d6-4249-aa4f-7c732cba27e2"
+ "&featureId=application-test&extensionVersion=1.0&licenseType=TRIAL";
String getLicenseRenewResponse = "error";
when(xwiki.getURLContent(renewURL, xcontext)).thenReturn(getLicenseRenewResponse);

ExtensionId extensionId = new ExtensionId("application-test", "1.0");
licenseUpdater.renewLicense(extensionId);

assertEquals(String.format("Failed to renew license for [%s] on store.", extensionId.getId()),
logCaptureWarn.getMessage(0));
// After renewing the license on store, right now we retrieve new updates from store. Maybe we should simply
// return the updated license from the start, to not make a new request?
}

@Test
void getLicensesUpdatesWithNullURL() throws Exception
{
when(licensingConfig.getStoreUpdateURL()).thenReturn(null);

licenseUpdater.getLicensesUpdates();

assertEquals("Failed to update licenses because the licensor configuration is not complete. "
+ "Check your store update URL.", logCaptureWarn.getMessage(0));
}

@Test
void getLicensesUpdatesWithUpdates() throws Exception
{
when(licensingConfig.getStoreUpdateURL()).thenReturn("https://storeUpdate.com");

String updateURL =
"https://storeUpdate.com?instanceId=7237b65d-e5d6-4249-aa4f-7c732cba27e2&outputSyntax=plain&featureId"
+ "=application-test&expirationDate%3Aapplication-test=12";
String licenseResponse = "[\"license\"]";
when(xwiki.getURLContent(updateURL, xcontext)).thenReturn(licenseResponse);

ExtensionId licensedExtension = new ExtensionId("application-test", "1.0");
List<ExtensionId> mandatoryExtensions = Collections.singletonList(licensedExtension);
when(licensedExtensionManager.getMandatoryLicensedExtensions()).thenReturn(mandatoryExtensions);
when(licensor.getLicense(licensedExtension)).thenReturn(license);
when(license.getExpirationDate()).thenReturn(Long.valueOf("12"));

byte[] licenseBytes = "license".getBytes();
when(base64decoder.decode("license")).thenReturn(licenseBytes);
License convertedLicense = new License();
when(converter.convert(License.class, licenseBytes)).thenReturn(convertedLicense);

licenseUpdater.getLicensesUpdates();

verify(licenseManager).add(convertedLicense);
}

@Test
void getLicensesUpdatesWithoutUpdates() throws IOException
{
when(licensingConfig.getStoreUpdateURL()).thenReturn("https://storeUpdate.com");

String updateURL =
"https://storeUpdate.com?instanceId=7237b65d-e5d6-4249-aa4f-7c732cba27e2&outputSyntax=plain&featureId"
+ "=application-test&expirationDate%3Aapplication-test=12";
String licenseResponse = "[]";
when(xwiki.getURLContent(updateURL, xcontext)).thenReturn(licenseResponse);

ExtensionId licensedExtension = new ExtensionId("application-test", "1.0");
List<ExtensionId> mandatoryExtensions = Collections.singletonList(licensedExtension);
when(licensedExtensionManager.getMandatoryLicensedExtensions()).thenReturn(mandatoryExtensions);
when(licensor.getLicense(licensedExtension)).thenReturn(license);
when(license.getExpirationDate()).thenReturn(Long.valueOf("12"));

licenseUpdater.getLicensesUpdates();

verify(licenseManager, times(0)).add(any(License.class));
}
}
Loading

0 comments on commit 4d69cb2

Please sign in to comment.