/**
* Copyright (c) 2009 - 2012 Red Hat, Inc.
*
* This software is licensed to you under the GNU General Public License,
* version 2 (GPLv2). There is NO WARRANTY for this software, express or
* implied, including the implied warranties of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
* along with this software; if not, see
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* Red Hat trademarks are not licensed under GPLv2. No permission is
* granted to use or replicate Red Hat trademarks that are incorporated
* in this software or its documentation.
*/
package org.candlepin.model;
import static org.junit.Assert.*;
import org.candlepin.common.jackson.DynamicPropertyFilter;
import org.candlepin.common.jackson.HateoasBeanPropertyFilter;
import org.candlepin.controller.CandlepinPoolManager;
import org.candlepin.jackson.PoolEventFilter;
import org.candlepin.model.Pool.PoolType;
import org.candlepin.model.dto.Subscription;
import org.candlepin.policy.EntitlementRefusedException;
import org.candlepin.test.DatabaseTestFixture;
import org.candlepin.test.TestUtil;
import org.candlepin.util.Util;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import org.junit.Before;
import org.junit.Test;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
public class PoolTest extends DatabaseTestFixture {
public static final String POOL_JSON_BASE = "{\"id\": \"5\", \"owner\": {}, \"activeSubscription\": tr" +
"ue, \"subscriptionId\": \"3\", \"subscriptionSubKey\": null, \"sourceStackId\": null, \"sourceCon" +
"sumer\": {\"id\": \"5\", \"uuid\": \"\", \"name\": \"10023\", \"username\": null, \"entitlementSt" +
"atus\": \"valid\", \"serviceLevel\": \"\", \"releaseVer\": {\"releaseVer\": null }, \"type\": {\"" +
"id\": \"1004\", \"label\": \"hypervisor\", \"manifest\": false }, \"owner\": {}, \"environment\":" +
" {\"owner\": {}, \"name\": \"Library\", \"description\": null, \"id\": \"2\", \"environmentConten" +
"t\": [{\"id\": \"023947982374\", \"contentId\": \"166\", \"enabled\": null }, {\"id\": \"11\", \"" +
"contentId\": \"168\", \"enabled\": null }, {\"id\": \"192837123\", \"contentId\": \"867\", \"enab" +
"led\": null } ] }, \"entitlementCount\": 1, \"facts\": {}, \"lastCheckin\": 1381236857266, \"inst" +
"alledProducts\": [], \"canActivate\": false, \"guestIds\": [], \"capabilities\": [], \"autoheal\"" +
": true, \"href\": \"\\/consumers\\/4\"}, \"quantity\": -1, \"startDate\": 1377057600000, \"endDat" +
"e\": 1471751999000, \"productId\": \"MYSKU\", \"providedProducts\": [], \"restrictedToUsername\":" +
" null, \"contractNumber\": \"2\", \"accountNumber\": \"1\", \"orderNumber\": null, \"consumed\": " +
"1, \"exported\": 0, \"productName\": \"Awesome OS Enterprise Server\", \"calculatedAttributes\": " +
"null, \"type\": \"ENTITLEMENT_DERIVED\", \"href\": \"\\/pools\\/5\", \"stacked\": false, \"stackI" +
"d\": null, \"product_list\": []";
@Inject private OwnerCurator ownerCurator;
@Inject private ProductCurator productCurator;
@Inject private PoolCurator poolCurator;
@Inject private ConsumerCurator consumerCurator;
@Inject private ConsumerTypeCurator consumerTypeCurator;
@Inject private EntitlementCurator entitlementCurator;
@Inject private CandlepinPoolManager poolManager;
private ObjectMapper mapper;
private Pool pool;
private Product prod1;
private Product prod2;
private Owner owner;
private Consumer consumer;
private Subscription subscription;
@Before
public void createObjects() {
this.mapper = new ObjectMapper();
SimpleFilterProvider filterProvider = new SimpleFilterProvider();
filterProvider = filterProvider.addFilter("PoolFilter", new PoolEventFilter());
filterProvider = filterProvider.addFilter("OwnerFilter", new HateoasBeanPropertyFilter());
filterProvider.setDefaultFilter(new DynamicPropertyFilter());
this.mapper.setFilters(filterProvider);
beginTransaction();
try {
owner = new Owner("testowner");
ownerCurator.create(owner);
prod1 = this.createProduct(owner);
prod2 = this.createProduct(owner);
Set<Product> providedProducts = new HashSet<Product>();
providedProducts.add(prod2);
pool = TestUtil.createPool(owner, prod1, providedProducts, 1000);
subscription = TestUtil.createSubscription(owner, prod1);
subscription.setId(Util.generateDbUUID());
pool.setSourceSubscription(new SourceSubscription(subscription.getId(), "master"));
poolCurator.create(pool);
owner = pool.getOwner();
consumer = TestUtil.createConsumer(owner);
productCurator.create(prod1);
poolCurator.create(pool);
consumerTypeCurator.create(consumer.getType());
consumerCurator.create(consumer);
commitTransaction();
}
catch (RuntimeException e) {
rollbackTransaction();
throw e;
}
}
@Test
public void testCreate() {
Pool lookedUp = this.getEntityManager().find(Pool.class, pool.getId());
assertNotNull(lookedUp);
assertEquals(owner.getId(), lookedUp.getOwner().getId());
assertEquals(prod1.getId(), lookedUp.getProductId());
}
@Test
public void testCreateWithDerivedProvidedProducts() {
Product derivedProd = this.createProduct(owner);
Pool p = TestUtil.createPool(owner, prod1, new HashSet<Product>(), 1000);
p.addProvidedProduct(prod2);
Set<Product> derivedProducts = new HashSet<Product>();
derivedProducts.add(derivedProd);
p.setDerivedProvidedProducts(derivedProducts);
poolCurator.create(p);
Pool lookedUp = this.getEntityManager().find(Pool.class, p.getId());
assertEquals(1, lookedUp.getProvidedProducts().size());
assertEquals(prod2.getId(), lookedUp.getProvidedProducts().iterator().next().getId());
assertEquals(1, lookedUp.getDerivedProvidedProducts().size());
assertEquals(derivedProd.getId(), lookedUp.getDerivedProvidedProducts().iterator().next().getId());
}
@Test
public void testMultiplePoolsForOwnerProductAllowed() {
Pool duplicatePool = createPool(
owner, prod1, -1L, TestUtil.createDate(2009, 11, 30), TestUtil.createDate(2050, 11, 30)
);
// Just need to see no exception is thrown.
poolCurator.create(duplicatePool);
}
@Test
public void testIsOverflowing() {
Pool duplicatePool = createPool(
owner, prod1, -1L, TestUtil.createDate(2009, 11, 30), TestUtil.createDate(2050, 11, 30)
);
assertFalse(duplicatePool.isOverflowing());
}
@Test
public void testUnlimitedPool() {
Product newProduct = this.createProduct(owner);
Pool unlimitedPool = createPool(
owner, newProduct, -1L, TestUtil.createDate(2009, 11, 30), TestUtil.createDate(2050, 11, 30)
);
poolCurator.create(unlimitedPool);
assertTrue(unlimitedPool.entitlementsAvailable(1));
}
@Test
public void createEntitlementShouldIncreaseNumberOfMembers() throws Exception {
Long numAvailEntitlements = 1L;
Product newProduct = this.createProduct(owner);
Pool consumerPool = createPool(owner, newProduct, numAvailEntitlements,
TestUtil.createDate(2009, 11, 30), TestUtil.createDate(2050, 11, 30));
consumerPool = poolCurator.create(consumerPool);
Map<String, Integer> pQs = new HashMap<String, Integer>();
pQs.put(consumerPool.getId(), 1);
poolManager.entitleByPools(consumer, pQs);
consumerPool = poolCurator.find(consumerPool.getId());
assertFalse(consumerPool.entitlementsAvailable(1));
assertEquals(1, consumerPool.getEntitlements().size());
}
@Test
public void createEntitlementShouldUpdateConsumer() throws Exception {
Long numAvailEntitlements = 1L;
Product newProduct = this.createProduct(owner);
Pool consumerPool = createPool(
owner,
newProduct,
numAvailEntitlements,
TestUtil.createDate(2009, 11, 30),
TestUtil.createDate(2050, 11, 30)
);
poolCurator.create(consumerPool);
assertEquals(0, consumer.getEntitlements().size());
Map<String, Integer> pQs = new HashMap<String, Integer>();
pQs.put(consumerPool.getId(), 1);
poolManager.entitleByPools(consumer, pQs);
assertEquals(1, consumerCurator.find(consumer.getId()).getEntitlements().size());
}
// test subscription product changed exception
@Test
public void testLookupPoolsProvidingProduct() {
Product parentProduct = this.createProduct("1", "product-1", owner);
Product childProduct = this.createProduct("2", "product-2", owner);
Set<Product> providedProducts = new HashSet<Product>();
providedProducts.add(childProduct);
Pool pool = TestUtil.createPool(owner, parentProduct, providedProducts, 5);
poolCurator.create(pool);
List<Pool> results = poolCurator.listAvailableEntitlementPools(
null, owner, childProduct.getId(), null
);
assertEquals(1, results.size());
assertEquals(pool.getId(), results.get(0).getId());
}
/**
* After creating a new pool object, test is made to determine whether
* the created and updated values are present and not null.
*/
@Test
public void testCreationTimestamp() {
Product newProduct = this.createProduct(owner);
Pool pool = createPool(
owner, newProduct, 1L, TestUtil.createDate(2011, 3, 30), TestUtil.createDate(2022, 11, 29)
);
poolCurator.create(pool);
assertNotNull(pool.getCreated());
}
@Test
public void testInitialUpdateTimestamp() {
Product newProduct = this.createProduct(owner);
Pool pool = createPool(
owner, newProduct, 1L, TestUtil.createDate(2011, 3, 30), TestUtil.createDate(2022, 11, 29)
);
pool = poolCurator.create(pool);
assertNotNull(pool.getUpdated());
}
/**
* After updating an existing pool object, test is made to determine whether
* the updated value has changed
*/
@Test
public void testSubsequentUpdateTimestamp() {
Product newProduct = this.createProduct(owner);
Pool pool = createPool(
owner, newProduct, 1L, TestUtil.createDate(2011, 3, 30), TestUtil.createDate(2022, 11, 29)
);
pool = poolCurator.create(pool);
// set updated to 10 minutes ago
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MINUTE, -10);
pool.setUpdated(calendar.getTime());
Date updated = (Date) pool.getUpdated().clone();
pool.setQuantity(23L);
pool = poolCurator.merge(pool);
assertFalse(updated.getTime() == pool.getUpdated().getTime());
}
@Test
public void providedProductCleanup() {
Product parentProduct = this.createProduct("1", "product-1", owner);
Product childProduct1 = this.createProduct("child1", "child1", owner);
Product childProduct2 = this.createProduct("child2", "child2", owner);
Product childProduct3 = this.createProduct("child3", "child3", owner);
Product providedProduct = this.createProduct("provided", "Child 1", owner);
Set<Product> providedProducts = new HashSet<Product>();
providedProducts.add(providedProduct);
Pool pool = TestUtil.createPool(owner, parentProduct, providedProducts, 5);
poolCurator.create(pool);
pool = poolCurator.find(pool.getId());
assertEquals(1, pool.getProvidedProducts().size());
// Clear the set and create a new one:
pool.getProvidedProducts().clear();
pool.addProvidedProduct(childProduct2);
pool.addProvidedProduct(childProduct3);
poolCurator.merge(pool);
pool = poolCurator.find(pool.getId());
assertEquals(2, pool.getProvidedProducts().size());
}
// sunny test - real rules not invoked here. Can only be sure the counts are recorded.
// Rule tests already exist for quantity filter.
// Will use spec tests to see if quantity rules are followed in this scenario.
@Test
public void testEntitlementQuantityChange() throws EntitlementRefusedException {
Map<String, Integer> pQs = new HashMap<String, Integer>();
pQs.put(pool.getId(), 3);
List<Entitlement> entitlements = poolManager.entitleByPools(consumer, pQs);
Entitlement ent = entitlements.get(0);
assertTrue(ent.getQuantity() == 3);
poolManager.adjustEntitlementQuantity(consumer, ent, 5);
Entitlement ent2 = entitlementCurator.find(ent.getId());
assertTrue(ent2.getQuantity() == 5);
Pool pool2 = poolCurator.find(pool.getId());
assertTrue(pool2.getConsumed() == 5);
assertTrue(pool2.getEntitlements().size() == 1);
}
@Test
public void testPoolType() {
pool.setAttribute(Pool.Attributes.DERIVED_POOL, "true");
assertEquals(PoolType.BONUS, pool.getType());
pool.setSourceEntitlement(new Entitlement());
assertEquals(PoolType.ENTITLEMENT_DERIVED, pool.getType());
pool.setSourceEntitlement(null);
pool.setSourceStack(new SourceStack(new Consumer(), "something"));
assertEquals(PoolType.STACK_DERIVED, pool.getType());
pool.setAttribute(Pool.Attributes.UNMAPPED_GUESTS_ONLY, "true");
assertEquals(PoolType.UNMAPPED_GUEST, pool.getType());
pool.setSourceEntitlement(new Entitlement());
pool.setSourceStack(null);
assertEquals(PoolType.UNMAPPED_GUEST, pool.getType());
pool.removeAttribute(Pool.Attributes.DERIVED_POOL);
assertEquals(PoolType.NORMAL, pool.getType());
pool.setSourceEntitlement(null);
assertEquals(PoolType.NORMAL, pool.getType());
pool.setSourceStack(new SourceStack(new Consumer(), "something"));
assertEquals(PoolType.NORMAL, pool.getType());
}
@Test
public void testSetSubIdFromValue() {
pool.setSubscriptionId("testid");
assertEquals("testid", pool.getSourceSubscription().getSubscriptionId());
// subkey should be unchanged
assertEquals("master", pool.getSourceSubscription().getSubscriptionSubKey());
}
@Test
public void testSetSubIdFromNull() {
pool.setSourceSubscription(null);
pool.setSubscriptionId("testid");
assertEquals("testid", pool.getSourceSubscription().getSubscriptionId());
// subkey should be null
assertNull(pool.getSourceSubscription().getSubscriptionSubKey());
}
@Test
public void testSetSubIdNullRemoval() {
pool.getSourceSubscription().setSubscriptionSubKey(null);
pool.setSubscriptionId(null);
assertNull(pool.getSourceSubscription());
}
@Test
public void testSetSubIdNullEmptyString() {
pool.getSourceSubscription().setSubscriptionSubKey(null);
pool.setSubscriptionId("");
assertNull(pool.getSourceSubscription());
}
@Test
public void testSetSubKeyFromValue() {
pool.setSubscriptionSubKey("testkey");
assertEquals("testkey", pool.getSourceSubscription().getSubscriptionSubKey());
// subkey should be unchanged
assertEquals(subscription.getId(), pool.getSourceSubscription().getSubscriptionId());
}
@Test
public void testSetSubKeyFromNull() {
pool.setSourceSubscription(null);
pool.setSubscriptionSubKey("testid");
assertEquals("testid", pool.getSourceSubscription().getSubscriptionSubKey());
// subkey should be null
assertNull(pool.getSourceSubscription().getSubscriptionId());
}
@Test
public void testSetSubKeyNullRemoval() {
pool.getSourceSubscription().setSubscriptionId(null);
pool.setSubscriptionSubKey(null);
assertNull(pool.getSourceSubscription());
}
@Test
public void testSetSubKeyNullEmptyString() {
pool.getSourceSubscription().setSubscriptionId(null);
pool.setSubscriptionSubKey("");
assertNull(pool.getSourceSubscription());
}
@Test
public void testDeserializePoolAttributesJsonV1() throws Exception {
String attributes = "\"attributes\": [" +
" {" +
" \"name\" : \"attrib-1\"," +
" \"value\" : \"value-1\"," +
" \"entityVersion\" : 1498458083," +
" \"created\" : \"2016-09-07T15:08:13+0000\"," +
" \"updated\" : \"2016-09-07T15:08:13+0000\"" +
" }," +
" {" +
" \"name\" : \"attrib-2\"," +
" \"value\" : \"value-2\"," +
" \"entityVersion\" : 1498458083," +
" \"created\" : \"2016-09-07T15:08:13+0000\"," +
" \"updated\" : \"2016-09-07T15:08:13+0000\"" +
" }," +
" {" +
" \"name\" : 3," +
" \"value\" : 3," +
" \"entityVersion\" : 1498458083," +
" \"created\" : \"2016-09-07T15:08:13+0000\"," +
" \"updated\" : \"2016-09-07T15:08:13+0000\"" +
" }" +
"]," +
"\"productAttributes\": [" +
" {" +
" \"name\" : \"prod_attrib-1\"," +
" \"value\" : \"prod_value-1\"," +
" \"entityVersion\" : 1498458083," +
" \"created\" : \"2016-09-07T15:08:13+0000\"," +
" \"updated\" : \"2016-09-07T15:08:13+0000\"" +
" }," +
" {" +
" \"name\" : \"prod_attrib-2\"," +
" \"value\" : \"prod_value-2\"," +
" \"entityVersion\" : 1498458083," +
" \"created\" : \"2016-09-07T15:08:13+0000\"," +
" \"updated\" : \"2016-09-07T15:08:13+0000\"" +
" }," +
" {" +
" \"name\" : 3," +
" \"value\" : 3," +
" \"entityVersion\" : 1498458083," +
" \"created\" : \"2016-09-07T15:08:13+0000\"," +
" \"updated\" : \"2016-09-07T15:08:13+0000\"" +
" }" +
"]";
Map<String, String> expectedAttrib = new HashMap<String, String>();
expectedAttrib.put("attrib-1", "value-1");
expectedAttrib.put("attrib-2", "value-2");
expectedAttrib.put("3", "3");
Map<String, String> expectedProdAttrib = new HashMap<String, String>();
expectedProdAttrib.put("prod_attrib-1", "prod_value-1");
expectedProdAttrib.put("prod_attrib-2", "prod_value-2");
expectedProdAttrib.put("3", "3");
Pool pool = this.mapper.readValue(POOL_JSON_BASE + "," + attributes + "}", Pool.class);
assertEquals(expectedAttrib, pool.getAttributes());
assertEquals(expectedProdAttrib, pool.getProductAttributes());
}
@Test
public void testDeserializePoolAttributesJsonV2() throws Exception {
String attributes = "\"attributes\": {" +
" \"attrib-1\": \"value-1\"," +
" \"attrib-2\": \"value-2\"," +
" \"attrib-3\": 3" +
"}," +
"\"productAttributes\": {" +
" \"prod_attrib-1\": \"prod_value-1\"," +
" \"prod_attrib-2\": \"prod_value-2\"," +
" \"prod_attrib-3\": 3" +
"}";
Map<String, String> expectedAttrib = new HashMap<String, String>();
expectedAttrib.put("attrib-1", "value-1");
expectedAttrib.put("attrib-2", "value-2");
expectedAttrib.put("attrib-3", "3");
Map<String, String> expectedProdAttrib = new HashMap<String, String>();
expectedProdAttrib.put("prod_attrib-1", "prod_value-1");
expectedProdAttrib.put("prod_attrib-2", "prod_value-2");
expectedProdAttrib.put("prod_attrib-3", "3");
Pool pool = this.mapper.readValue(POOL_JSON_BASE + "," + attributes + "}", Pool.class);
assertEquals(expectedAttrib, pool.getAttributes());
assertEquals(expectedProdAttrib, pool.getProductAttributes());
}
@Test
public void testSerializePoolAttributes() throws Exception {
String expectedHeader = "\"attributes\":[{";
String expectedValue1 = "\"name\":\"attrib-1\",\"value\":\"value-1\"";
String expectedValue2 = "\"name\":\"attrib-2\",\"value\":\"value-2\"";
String expectedValue3 = "\"name\":\"attrib-3\",\"value\":\"3\"";
Map<String, String> attributes = new HashMap<String, String>();
attributes.put("attrib-1", "value-1");
attributes.put("attrib-2", "value-2");
attributes.put("attrib-3", "3");
this.pool.setAttributes(attributes);
String output = this.mapper.writeValueAsString(pool);
// Since the attributes are stored as a map, we can't guarantee any specific printed order.
// To deal with this, we separate the value and each header, then verify them individually.
assertTrue(output.contains(expectedHeader));
assertTrue(output.contains(expectedValue1));
assertTrue(output.contains(expectedValue2));
assertTrue(output.contains(expectedValue3));
}
}