/**
* 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.policy;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.candlepin.audit.EventFactory;
import org.candlepin.audit.EventSink;
import org.candlepin.common.config.Configuration;
import org.candlepin.config.ConfigProperties;
import org.candlepin.controller.ProductManager;
import org.candlepin.jackson.ProductCachedSerializationModule;
import org.candlepin.model.Consumer;
import org.candlepin.model.Entitlement;
import org.candlepin.model.Owner;
import org.candlepin.model.OwnerCurator;
import org.candlepin.model.OwnerProductCurator;
import org.candlepin.model.Pool;
import org.candlepin.model.Product;
import org.candlepin.model.ProductCurator;
import org.candlepin.model.ProductShareCurator;
import org.candlepin.model.Rules;
import org.candlepin.model.RulesCurator;
import org.candlepin.policy.js.JsRunner;
import org.candlepin.policy.js.JsRunnerProvider;
import org.candlepin.policy.js.JsRunnerRequestCache;
import org.candlepin.policy.js.RuleExecutionException;
import org.candlepin.policy.js.RulesObjectMapper;
import org.candlepin.policy.js.entitlement.AbstractEntitlementRules.Rule;
import org.candlepin.policy.js.entitlement.Enforcer;
import org.candlepin.policy.js.entitlement.EntitlementRules;
import org.candlepin.service.ProductServiceAdapter;
import org.candlepin.test.DatabaseTestFixture;
import org.candlepin.test.DateSourceForTesting;
import org.candlepin.test.TestDateUtil;
import org.candlepin.test.TestUtil;
import com.google.inject.Provider;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.xnap.commons.i18n.I18n;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
public class EnforcerTest extends DatabaseTestFixture {
@Inject private I18n i18n;
@Mock private ProductServiceAdapter productAdapter;
@Mock private RulesCurator rulesCurator;
@Mock private Configuration config;
@Mock private Provider<JsRunnerRequestCache> cacheProvider;
@Mock private JsRunnerRequestCache cache;
@Mock private ProductCurator mockProductCurator;
@Mock private OwnerCurator mockOwnerCurator;
@Mock private OwnerProductCurator mockOwnerProductCurator;
@Mock private ProductShareCurator mockProductShareCurator;
@Mock private ProductManager mockProductManager;
@Mock private EventSink mockEventSink;
@Mock private EventFactory mockEventFactory;
private Enforcer enforcer;
private Owner owner;
private Consumer consumer;
private static final String PRODUCT_CPULIMITED = "CPULIMITED001";
@Before
public void createEnforcer() throws Exception {
MockitoAnnotations.initMocks(this);
when(config.getInt(eq(ConfigProperties.PRODUCT_CACHE_MAX))).thenReturn(100);
owner = createOwner();
ownerCurator.create(owner);
consumer = TestUtil.createConsumer(owner);
consumerTypeCurator.create(consumer.getType());
consumerCurator.create(consumer);
BufferedReader reader = new BufferedReader(new InputStreamReader(
getClass().getResourceAsStream("/rules/test-rules.js")));
StringBuilder builder = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
builder.append(line + "\n");
}
reader.close();
Rules rules = mock(Rules.class);
when(rules.getRules()).thenReturn(builder.toString());
when(rulesCurator.getRules()).thenReturn(rules);
when(rulesCurator.getUpdated()).thenReturn(TestDateUtil.date(2010, 1, 1));
when(cacheProvider.get()).thenReturn(cache);
JsRunner jsRules = new JsRunnerProvider(rulesCurator, cacheProvider).get();
enforcer = new EntitlementRules(
new DateSourceForTesting(2010, 1, 1), jsRules, i18n, config, consumerCurator, poolCurator,
mockProductCurator,
new RulesObjectMapper(new ProductCachedSerializationModule(mockProductCurator)),
mockOwnerCurator, mockOwnerProductCurator, mockProductShareCurator, mockProductManager,
mockEventSink, mockEventFactory
);
}
@Test
public void shouldParseValidMapping() {
Rule func1rule = new EntitlementRules.Rule(
"func1", 1, new HashSet<String>() { { add("attr1"); add("attr2"); add("attr3"); } });
assertEquals(func1rule,
((EntitlementRules) enforcer).parseRule("func1:1:attr1:attr2:attr3"));
assertEquals(new EntitlementRules.Rule("func3", 3, new HashSet<String>() { { add("attr4"); } }),
((EntitlementRules) enforcer).parseRule("func3:3:attr4"));
}
@Test(expected = IllegalArgumentException.class)
public void shouldFailParsingIfNoOderIsPresent() {
((EntitlementRules) enforcer).parseRule("func3:attr4");
}
@Test(expected = IllegalArgumentException.class)
public void shouldFailParsingIfNotAllParametersArePresent() {
((EntitlementRules) enforcer).parseRule("func3:3");
}
@Test
public void shouldCreateMappingBetweenAttributesAndFunctions() {
String attributesAndRules =
"func1:1:attr1:attr2:attr3, func2:2:attr1, func3:3:attr4, func5:5:attr1:attr4";
Map<String, Set<EntitlementRules.Rule>> parsed =
((EntitlementRules) enforcer).parseAttributeMappings(attributesAndRules);
assertTrue(parsed.get("attr1").contains(
rule("func1", 1, "attr1", "attr2", "attr3")));
assertTrue(parsed.get("attr1").contains(rule("func2", 2, "attr1")));
assertTrue(parsed.get("attr4").contains(rule("func3", 3, "attr4")));
assertTrue(parsed.get("attr4").contains(rule("func5", 5, "attr1", "attr4")));
assertTrue(parsed.get("attr1").contains(rule("func5", 5, "attr1", "attr4")));
}
@Test
public void shouldSelectAllRulesMappedToSingleAttribute() {
Map<String, Set<EntitlementRules.Rule>> rules =
new HashMap<String, Set<EntitlementRules.Rule>>() {
{
put("attr1", rules(rule("func5", 5, "attr1"), rule("func1", 2,
"attr1")));
put("attr3", rules(rule("func3", 2, "attr3")));
}
};
List<EntitlementRules.Rule> orderedAndFilteredRules = ((EntitlementRules) enforcer)
.rulesForAttributes(new HashSet<String>() { { add("attr1"); } }, rules);
assertEquals(
new LinkedList<EntitlementRules.Rule>() {
{
add(rule("func5", 5, "attr1"));
add(rule("func1", 2, "attr1"));
add(rule("global", 0, new String[0]));
}
},
orderedAndFilteredRules
);
}
@Test
public void shouldSelectAllRulesMappedToMultipleAttributes() {
Map<String, Set<EntitlementRules.Rule>> rules = new HashMap<String, Set<EntitlementRules.Rule>>() {
{
put("attr1", rules(
rule("func5", 5, "attr1", "attr2", "attr3"),
rule("func1", 2, "attr1", "attr2"),
rule("func6", 4, "attr1", "attr2", "attr3", "attr4"))
);
put("attr3", rules(rule("func3", 3, "attr3")));
}
};
List<EntitlementRules.Rule> orderedAndFilteredRules = ((EntitlementRules) enforcer)
.rulesForAttributes(new HashSet<String>() {
{
add("attr1"); add("attr2"); add("attr3");
}}, rules);
assertEquals(new LinkedList<EntitlementRules.Rule>() {
{
add(rule("func5", 5, "attr1", "attr2", "attr3"));
add(rule("func3", 3, "attr3"));
add(rule("func1", 2, "attr1", "attr2"));
add(rule("global", 0, new String[0]));
}}, orderedAndFilteredRules);
}
// This exception should mention wrapping a MissingFactException
@Test(expected = RuleExecutionException.class)
public void testRuleFailsWhenConsumerDoesntHaveFact() {
Product product = TestUtil.createProduct("a-product", "A product for testing");
product.setAttribute(PRODUCT_CPULIMITED, "2");
product = this.createProduct(product, owner);
ValidationResult result = enforcer.preEntitlement(
TestUtil.createConsumer(),
entitlementPoolWithMembersAndExpiration(owner, product, 1, 2, expiryDate(2000, 1, 1)), 1);
assertFalse(result.isSuccessful());
assertTrue(result.hasErrors());
assertFalse(result.hasWarnings());
}
private EntitlementRules.Rule rule(String name, int priority, String... attrs) {
Set<String> attributes = new HashSet<String>();
for (String attr : attrs) {
attributes.add(attr);
}
return new EntitlementRules.Rule(name, priority, attributes);
}
private Set<EntitlementRules.Rule> rules(EntitlementRules.Rule... rules) {
return new HashSet<EntitlementRules.Rule>(Arrays.asList(rules));
}
private Date expiryDate(int year, int month, int day) {
return TestDateUtil.date(year, month, day);
}
private Pool entitlementPoolWithMembersAndExpiration(Owner theOwner, Product product,
final int currentMembers, final int maxMembers, Date expiry) {
Pool p = createPool(theOwner, product,
Long.valueOf(maxMembers), new Date(), expiry);
for (int i = 0; i < currentMembers; i++) {
Consumer c = createConsumer(theOwner);
Entitlement e = createEntitlement(theOwner, c, p, null);
e.setQuantity(1);
entitlementCurator.create(e);
p.getEntitlements().add(e);
poolCurator.merge(p);
}
poolCurator.refresh(p);
return p;
}
}