<commit_before>/*******************************************************************************
 * Copyright 2016 General Electric Company. 
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License.
 *******************************************************************************/
package com.ge.predix.integration.test;

import static com.ge.predix.integration.test.SubjectResourceFixture.MARISSA_V1;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.ge.predix.acs.rest.PolicyEvaluationRequestV1;
import com.ge.predix.acs.rest.PolicyEvaluationResult;
import com.ge.predix.acs.rest.Zone;
import com.ge.predix.test.utils.ACSRestTemplateFactory;
import com.ge.predix.test.utils.PolicyHelper;
import com.ge.predix.test.utils.ZacTestUtil;
import com.ge.predix.test.utils.ZoneHelper;
import com.nurego.Nurego;
import com.nurego.model.Entitlement;
import com.nurego.model.Subscription;

@SuppressWarnings({ "nls" })
@ContextConfiguration("classpath:integration-test-spring-context.xml")
@Test
public class ACSMeteringIT extends AbstractTestNGSpringContextTests {

    @Autowired
    private ACSRestTemplateFactory acsRestTemplateFactory;

    @Autowired
    private ZoneHelper zoneHelper;

    @Autowired
    private PolicyHelper policyHelper;

    @Value("${ORG_ID:ff85feb9-be02-4a73-9b13-9e1970abf09c}")
    private String organizationId;

    @Value("${PLAN_ID:pla_1ba8-5fe8-474f-8211-163649417d8e}")
    private String planId;

    @Value("${NUREGO_API_URL}")
    private String nuregoApiBase;

    @Value("${NUREGO_API_KEY}")
    private String nuregoApiKey;

    private static final String POLICY_UPDATE_FEATURE_ID = "policyset_update";
    private static final String POLICY_EVAL_FEATURE_ID = "policy_eval";
    private Subscription subscription;

    private String zoneId;

    private String zoneUrl;

    private Zone createPrimaryTestZone;

    @Autowired
    private ZacTestUtil zacTestUtil;

    @BeforeClass
    public void setup() throws JsonParseException, JsonMappingException, IOException {
        this.zacTestUtil.assumeZacServerAvailable();

        this.createPrimaryTestZone = this.zoneHelper.createPrimaryTestZone();
        this.zoneId = this.createPrimaryTestZone.getSubdomain();
        this.zoneUrl = this.zoneHelper.getZone1Url();
        Nurego.setApiBase(this.nuregoApiBase);
        Nurego.apiKey = this.nuregoApiKey;

        // createNuregoSubscription(this.createPrimaryTestZone.getSubdomain());
    }

    public void testACSMetering() throws Exception {
        String testPolicyName = null;
        PolicyEvaluationRequestV1 policyEvaluationRequest = this.policyHelper
                .createEvalRequest(MARISSA_V1.getSubjectIdentifier(), "sanramon");
        try {
            // Get meter readings before
            Double beforePolicyUpdateMeterCount = getEntitlementUsageByFeatureId(POLICY_UPDATE_FEATURE_ID, this.zoneId);
            Double beforePolicyEvalMeterCount = getEntitlementUsageByFeatureId(POLICY_EVAL_FEATURE_ID, this.zoneId);

            System.out.println("POLICY UPDATE USAGE BEFORE:" + beforePolicyUpdateMeterCount);
            System.out.println("POLICY EVAL USAGE BEFORE:" + beforePolicyEvalMeterCount);

            OAuth2RestTemplate acsRestTemplate = this.acsRestTemplateFactory.getACSTemplateWithPolicyScope();
            String policyFile = "src/test/resources/single-site-based-policy-set.json";
            testPolicyName = this.policyHelper.setTestPolicy(acsRestTemplate, getZoneHeaders(), this.zoneUrl,
                    policyFile);
            ResponseEntity<PolicyEvaluationResult> evalResponse = acsRestTemplate.postForEntity(
                    this.zoneUrl + PolicyHelper.ACS_POLICY_EVAL_API_PATH,
                    new HttpEntity<>(policyEvaluationRequest, getZoneHeaders()), PolicyEvaluationResult.class);

            Assert.assertEquals(evalResponse.getStatusCode(), HttpStatus.OK);

            //Nurego server seems to have a lag before the counts are updated
            Thread.sleep(3000);

            Double afterPolicyUpdateMeterCount = getEntitlementUsageByFeatureId(POLICY_UPDATE_FEATURE_ID, this.zoneId);
            Double afterPolicyEvalMeterCount = getEntitlementUsageByFeatureId(POLICY_EVAL_FEATURE_ID, this.zoneId);

            System.out.println("POLICY UPDATE USAGE AFTER:" + afterPolicyUpdateMeterCount);
            System.out.println("POLICY EVAL USAGE AFTER:" + afterPolicyEvalMeterCount);

            // Assert metering counts incremented by 1
            Assert.assertEquals(afterPolicyUpdateMeterCount - beforePolicyUpdateMeterCount, 1.0);
            Assert.assertEquals(afterPolicyEvalMeterCount - beforePolicyEvalMeterCount, 1.0);
        } finally {
            if (testPolicyName != null) {
                this.policyHelper.deletePolicySet(testPolicyName);
            }
        }
    }

    private HttpHeaders getZoneHeaders() {
        HttpHeaders headers = new HttpHeaders();
        headers.set("Predix-Zone-Id", this.createPrimaryTestZone.getSubdomain());
        return headers;
    }

    private Entitlement getEntitlementByFeatureId(final String featureId, final String subscriptionId)
            throws Exception {
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("provider", "cloud-foundry");
        params.put("plan_id", this.planId);
        params.put("external_subscription_id", subscriptionId);
        List<Entitlement> entitlements = Entitlement.retrieve(subscriptionId, params).getData();
        for (Entitlement entitlement : entitlements) {
            if (entitlement.getFeatureId().equals(featureId)) {
                System.out.println("Matched feature entitlements:" + entitlement.toString());
                return entitlement;
            }
        }

        return null;
    }

    private Double getEntitlementUsageByFeatureId(final String featureId, final String subscriptionId)
            throws Exception {
        Entitlement entitlement = getEntitlementByFeatureId(featureId, subscriptionId);
        if (entitlement == null) {
            throw new IllegalArgumentException(String.format("Feature '%s' does not exist.", featureId));
        }
        return entitlement.getCurrentUsedAmount();
    }

    @AfterClass
    public void cleanUp() {
        this.zoneHelper.deleteZone(this.createPrimaryTestZone.getSubdomain());
        // cancelNuregoSubscription();
    }

    // This method is not being used currently, as we are reusing the subscription and always asserting that the
    // difference between usage amount would be one. If you want to create a new subscription please uncomment
    // the following code.
    @SuppressWarnings("unused")
    private void createNuregoSubscription(String zoneId) {
        Map<String, Object> params = new HashMap<>();
        params.put("plan_id", this.planId);
        params.put("external_subscription_id", zoneId);
        params.put("provider", "cloud-foundry");
        try {
            this.subscription = Subscription.create(this.organizationId, params);
            System.out.println(" Subscription Id: " + this.subscription.getId());
        } catch (Exception e) {
            e.printStackTrace();
            Assert.fail("Failed to create Nurego Subscription.");
        }
    }

    @SuppressWarnings("unused")
    private void cancelNuregoSubscription() {
        try {
            Subscription.cancel(this.organizationId, this.subscription.getId());
        } catch (Exception e) {
            e.printStackTrace();
            Assert.fail("Failed to cancel Nurego Subscription.");
        }
    }

}<commit_msg>de6793: Work around for delay in update of nurego's state  - Increased delay to 10 seconds  - Changed System.out calls to logger calls  - Added waitForSteadyStateEntitlementUsage to busy wait until meter has completely updated its state before test  - added isMeterUpdated and isUsageSteady to simplify check if meter was changed  - Made modifications to get the file in line with the checkstyle<commit_after>/*******************************************************************************
 * Copyright 2016 General Electric Company.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *******************************************************************************/
package com.ge.predix.integration.test;

import static com.ge.predix.integration.test.SubjectResourceFixture.MARISSA_V1;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

import com.ge.predix.acs.rest.PolicyEvaluationRequestV1;
import com.ge.predix.acs.rest.PolicyEvaluationResult;
import com.ge.predix.acs.rest.Zone;
import com.ge.predix.test.utils.ACSRestTemplateFactory;
import com.ge.predix.test.utils.PolicyHelper;
import com.ge.predix.test.utils.ZacTestUtil;
import com.ge.predix.test.utils.ZoneHelper;
import com.nurego.Nurego;
import com.nurego.model.Entitlement;
import com.nurego.model.Subscription;

@SuppressWarnings({ "nls" })
@ContextConfiguration("classpath:integration-test-spring-context.xml")
@Test
public class ACSMeteringIT extends AbstractTestNGSpringContextTests {
    private static final Logger LOGGER = LoggerFactory.getLogger(ACSMeteringIT.class);

    @Autowired
    private ACSRestTemplateFactory acsRestTemplateFactory;

    @Autowired
    private ZoneHelper zoneHelper;

    @Autowired
    private PolicyHelper policyHelper;

    @Value("${ORG_ID:ff85feb9-be02-4a73-9b13-9e1970abf09c}")
    private String organizationId;

    @Value("${PLAN_ID:pla_1ba8-5fe8-474f-8211-163649417d8e}")
    private String planId;

    @Value("${NUREGO_API_URL}")
    private String nuregoApiBase;

    @Value("${NUREGO_API_KEY}")
    private String nuregoApiKey;

    @Value("${STEADY_STATE_SLEEP_MS:10000}")
    private int steadyStateSleepMS;

    private static final String POLICY_UPDATE_FEATURE_ID = "policyset_update";
    private static final String POLICY_EVAL_FEATURE_ID = "policy_eval";
    private static final int MAX_ITERATIONS = 10;
    private static final int NUREGO_UPDATE_SLEEP_MS = 1000;
    private Subscription subscription;

    private String zoneId;

    private String zoneUrl;

    private Zone createPrimaryTestZone;

    @Autowired
    private ZacTestUtil zacTestUtil;

    @BeforeClass
    public void setup() throws Exception {
        this.zacTestUtil.assumeZacServerAvailable();

        this.createPrimaryTestZone = this.zoneHelper.createPrimaryTestZone();
        this.zoneId = this.createPrimaryTestZone.getSubdomain();
        this.zoneUrl = this.zoneHelper.getZone1Url();
        Nurego.setApiBase(this.nuregoApiBase);
        Nurego.apiKey = this.nuregoApiKey;

        //Busy wait for the meter to achieve steady state for POLICY_UPDATE and POLICY_EVAL
        waitForSteadyStateEntitlementUsage(POLICY_UPDATE_FEATURE_ID, this.zoneId);
        waitForSteadyStateEntitlementUsage(POLICY_EVAL_FEATURE_ID, this.zoneId);
    }

    @Test
    public void testACSMetering() throws Exception {
        String testPolicyName = null;
        PolicyEvaluationRequestV1 policyEvaluationRequest = this.policyHelper
                .createEvalRequest(MARISSA_V1.getSubjectIdentifier(), "sanramon");
        try {
            // Get meter readings before
            Double beforePolicyUpdateMeterCount = getEntitlementUsageByFeatureId(POLICY_UPDATE_FEATURE_ID, this.zoneId);
            Double beforePolicyEvalMeterCount = getEntitlementUsageByFeatureId(POLICY_EVAL_FEATURE_ID, this.zoneId);

            LOGGER.info("POLICY UPDATE USAGE BEFORE:" + beforePolicyUpdateMeterCount);
            LOGGER.info("POLICY EVAL USAGE BEFORE:" + beforePolicyEvalMeterCount);

            OAuth2RestTemplate acsRestTemplate = this.acsRestTemplateFactory.getACSTemplateWithPolicyScope();
            String policyFile = "src/test/resources/single-site-based-policy-set.json";
            testPolicyName = this.policyHelper.setTestPolicy(acsRestTemplate, getZoneHeaders(), this.zoneUrl,
                    policyFile);
            ResponseEntity<PolicyEvaluationResult> evalResponse = acsRestTemplate.postForEntity(
                    this.zoneUrl + PolicyHelper.ACS_POLICY_EVAL_API_PATH,
                    new HttpEntity<>(policyEvaluationRequest, getZoneHeaders()), PolicyEvaluationResult.class);

            Assert.assertEquals(evalResponse.getStatusCode(), HttpStatus.OK);

            // Nurego server seems to have a lag before the counts are updated
            // Wait for Nurego to be updated before proceeding with assertion
            Double afterPolicyUpdateMeterCount = 0.0;
            Double afterPolicyEvalMeterCount = 0.0;
            Double updateMeterCount = 0.0;
            Double evalMeterCount = 0.0;
            for (int i = 0; i < MAX_ITERATIONS; i++) {
                Thread.sleep(NUREGO_UPDATE_SLEEP_MS);
                afterPolicyUpdateMeterCount = getEntitlementUsageByFeatureId(POLICY_UPDATE_FEATURE_ID, this.zoneId);
                afterPolicyEvalMeterCount = getEntitlementUsageByFeatureId(POLICY_EVAL_FEATURE_ID, this.zoneId);

                if (isMeterUpdated(beforePolicyUpdateMeterCount, afterPolicyUpdateMeterCount)
                        && isMeterUpdated(beforePolicyEvalMeterCount, afterPolicyEvalMeterCount)) {
                    LOGGER.debug("POLICY UPDATE USAGE AFTER: " + afterPolicyUpdateMeterCount);
                    LOGGER.debug("POLICY EVAL USAGE AFTER: " + afterPolicyEvalMeterCount);
                    break;
                }
            }

            // Assert metering counts incremented by 1
            updateMeterCount = afterPolicyUpdateMeterCount - beforePolicyUpdateMeterCount;
            evalMeterCount = afterPolicyEvalMeterCount - beforePolicyEvalMeterCount;
            Assert.assertEquals(updateMeterCount, 1.0);
            Assert.assertEquals(evalMeterCount, 1.0);
        } finally {
            if (testPolicyName != null) {
                this.policyHelper.deletePolicySet(testPolicyName);
            }
        }
    }

    private HttpHeaders getZoneHeaders() {
        HttpHeaders headers = new HttpHeaders();
        headers.set("Predix-Zone-Id", this.createPrimaryTestZone.getSubdomain());
        return headers;
    }

    private Entitlement getEntitlementByFeatureId(final String featureId, final String subscriptionId)
            throws Exception {
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("provider", "cloud-foundry");
        params.put("plan_id", this.planId);
        params.put("external_subscription_id", subscriptionId);
        List<Entitlement> entitlements = Entitlement.retrieve(subscriptionId, params).getData();
        for (Entitlement entitlement : entitlements) {
            if (entitlement.getFeatureId().equals(featureId)) {
                System.out.println("Matched feature entitlements:" + entitlement.toString());
                return entitlement;
            }
        }

        return null;
    }

    private Double getEntitlementUsageByFeatureId(final String featureId, final String subscriptionId)
            throws Exception {
        Entitlement entitlement = getEntitlementByFeatureId(featureId, subscriptionId);
        if (entitlement == null) {
            throw new IllegalArgumentException(String.format("Feature '%s' does not exist.", featureId));
        }
        return entitlement.getCurrentUsedAmount();
    }

    private boolean waitForSteadyStateEntitlementUsage(final String featureId, final String subscriptionId)
            throws Exception {
        double usageBeforeWait = 0.0;
        double usageAfterWait = 0.0;
        int iteration;

        for (iteration = 0; iteration < MAX_ITERATIONS; iteration++) {
            usageBeforeWait = getEntitlementUsageByFeatureId(featureId, subscriptionId);

            Thread.sleep(steadyStateSleepMS);

            usageAfterWait = getEntitlementUsageByFeatureId(featureId, subscriptionId);

            if (isUsageSteady(usageBeforeWait, usageAfterWait)) {
                String msg = String.format("Meter has reached a steady state of '%f' for '%s' with subscription '%s'",
                        usageAfterWait, POLICY_UPDATE_FEATURE_ID, this.planId);
                LOGGER.info(msg);
                break;
            }
        }

        return isUsageSteady(usageBeforeWait, usageAfterWait);
    }

    private boolean isMeterUpdated(final double readBeforeSleep, final double readAfterSleep) {
        return !isUsageSteady(readBeforeSleep, readAfterSleep);
    }

    private boolean isUsageSteady(final double readBeforeSleep, final double readAfterSleep) {
        return readBeforeSleep == readAfterSleep;
    }

    @AfterClass
    public void cleanUp() {
        this.zoneHelper.deleteZone(this.createPrimaryTestZone.getSubdomain());
        // cancelNuregoSubscription();
    }

    // This method is not being used currently, as we are reusing the subscription and always asserting that the
    // difference between usage amount would be one. If you want to create a new subscription please uncomment
    // the following code.
    @SuppressWarnings("unused")
    private void createNuregoSubscription(final String subscriptionId) {
        Map<String, Object> params = new HashMap<>();
        params.put("plan_id", this.planId);
        params.put("external_subscription_id", subscriptionId);
        params.put("provider", "cloud-foundry");
        try {
            this.subscription = Subscription.create(this.organizationId, params);
            System.out.println(" Subscription Id: " + this.subscription.getId());
        } catch (Exception e) {
            e.printStackTrace();
            Assert.fail("Failed to create Nurego Subscription.");
        }
    }

    @SuppressWarnings("unused")
    private void cancelNuregoSubscription() {
        try {
            Subscription.cancel(this.organizationId, this.subscription.getId());
        } catch (Exception e) {
            e.printStackTrace();
            Assert.fail("Failed to cancel Nurego Subscription.");
        }
    }

}
{'fraction_non_alphanumeric': 0.09906396255850235, 'fraction_numerical': 0.00765405616224649, 'mean_word_length': 3.431410671851372, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 4}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '986709', 'n_tokens_mistral': 5647, 'n_tokens_neox': 5442, 'n_words': 1224}