killbill-memoizeit
Changes
.circleci/config.yml 219(+219 -0)
.travis.yml 29(+11 -18)
beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/TestOverdueIntegration.java 7(+5 -2)
beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestCatalogRetireElements.java 18(+9 -9)
beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationInvoice.java 26(+13 -13)
beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationInvoiceWithRepairLogic.java 6(+0 -6)
beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationParentInvoice.java 2(+1 -1)
beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationWithCatalogUpdate.java 15(+7 -8)
beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestInvoiceSystemDisabling.java 2(+1 -1)
beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestMigrationSubscriptions.java 16(+9 -7)
beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithFakeKPMPlugin.java 46(+19 -27)
beatrix/src/test/java/org/killbill/billing/beatrix/integration/usage/TestConsumableInArrear.java 5(+0 -5)
entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/DefaultEventsStream.java 15(+15 -0)
entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlement.java 16(+8 -8)
entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlementApi.java 38(+19 -19)
entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionApi.java 24(+12 -12)
entitlement/src/test/java/org/killbill/billing/entitlement/api/TestRegessionSubscriptionApi.java 2(+1 -1)
entitlement/src/test/java/org/killbill/billing/entitlement/dao/TestDefaultBlockingStateDao.java 2(+1 -1)
entitlement/src/test/java/org/killbill/billing/entitlement/engine/core/TestEntitlementUtils.java 2(+1 -1)
entitlement/src/test/java/org/killbill/billing/entitlement/EntitlementTestSuiteWithEmbeddedDB.java 8(+1 -7)
invoice/src/main/java/org/killbill/billing/invoice/generator/DefaultInvoiceGenerator.java 17(+15 -2)
invoice/src/main/java/org/killbill/billing/invoice/generator/FixedAndRecurringInvoiceItemGenerator.java 5(+2 -3)
invoice/src/main/java/org/killbill/billing/invoice/generator/UsageInvoiceItemGenerator.java 6(+3 -3)
invoice/src/main/java/org/killbill/billing/invoice/provider/DefaultNoOpInvoiceProviderPlugin.java 5(+1 -4)
invoice/src/main/java/org/killbill/billing/invoice/provider/NoOpInvoiceProviderPluginProvider.java 2(+1 -1)
junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestDefaultInternalBillingApi.java 5(+3 -2)
overdue/src/test/java/org/killbill/billing/overdue/notification/TestOverdueCheckNotifier.java 3(+2 -1)
payment/src/main/java/org/killbill/billing/payment/invoice/InvoicePaymentControlPluginApi.java 64(+36 -28)
pom.xml 2(+1 -1)
profiles/killbill/src/main/java/org/killbill/billing/server/notifications/PushNotificationKey.java 10(+9 -1)
profiles/killbill/src/main/java/org/killbill/billing/server/notifications/PushNotificationListener.java 7(+5 -2)
subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java 16(+8 -8)
subscription/src/main/java/org/killbill/billing/subscription/api/transfer/DefaultSubscriptionBaseTransferApi.java 7(+4 -3)
subscription/src/main/java/org/killbill/billing/subscription/engine/dao/BundleSqlDao.java 26(+16 -10)
subscription/src/main/java/org/killbill/billing/subscription/engine/dao/DefaultSubscriptionDao.java 62(+35 -27)
subscription/src/main/java/org/killbill/billing/subscription/engine/dao/model/SubscriptionBundleModelDao.java 15(+13 -2)
subscription/src/main/java/org/killbill/billing/subscription/engine/dao/SubscriptionDao.java 5(+2 -3)
subscription/src/main/resources/org/killbill/billing/subscription/engine/dao/BundleSqlDao.sql.stg 17(+16 -1)
subscription/src/main/resources/org/killbill/billing/subscription/migration/V20170920200757__bundle_external_key.sql 2(+2 -0)
subscription/src/test/java/org/killbill/billing/subscription/api/transfer/TestTransfer.java 2(+1 -1)
subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiCreate.java 15(+12 -3)
subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiError.java 4(+2 -2)
subscription/src/test/java/org/killbill/billing/subscription/DefaultSubscriptionTestInitializer.java 2(+1 -1)
subscription/src/test/java/org/killbill/billing/subscription/engine/dao/MockSubscriptionDaoMemory.java 8(+4 -4)
subscription/src/test/java/org/killbill/billing/subscription/engine/dao/TestSubscriptionDao.java 169(+169 -0)
subscription/src/test/java/org/killbill/billing/subscription/engine/dao/TestSubscriptionModelDao.java 51(+51 -0)
subscription/src/test/java/org/killbill/billing/subscription/SubscriptionTestSuiteNoDB.java 1(+1 -0)
subscription/src/test/java/org/killbill/billing/subscription/SubscriptionTestSuiteWithEmbeddedDB.java 7(+1 -6)
util/src/main/java/org/killbill/billing/util/security/shiro/dao/RolesPermissionsSqlDao.java 12(+12 -0)
util/src/main/resources/org/killbill/billing/util/migration/V20171011170256__tag_definition_object_types.sql 2(+2 -0)
util/src/main/resources/org/killbill/billing/util/security/shiro/dao/RolesPermissionsSqlDao.sql.stg 13(+13 -0)
util/src/test/java/org/killbill/billing/util/callcontext/TestInternalCallContextFactory.java 8(+5 -3)
util/src/test/java/org/killbill/billing/util/customfield/api/TestDefaultCustomFieldUserApi.java 4(+2 -2)
util/src/test/java/org/killbill/billing/util/security/shiro/realm/TestKillBillJdbcRealm.java 27(+27 -0)
Details
.circleci/config.yml 219(+219 -0)
diff --git a/.circleci/config.yml b/.circleci/config.yml
new file mode 100644
index 0000000..ca7b9fc
--- /dev/null
+++ b/.circleci/config.yml
@@ -0,0 +1,219 @@
+defaults: &defaults
+ working_directory: ~/repo
+ environment:
+ MAVEN_OPTS: -server -showversion -XX:+PrintCommandLineFlags -XX:+UseCodeCacheFlushing -Xms1024M -Xmx2048M -XX:+CMSClassUnloadingEnabled -XX:-OmitStackTraceInFastThrow -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+CMSConcurrentMTEnabled -XX:+CMSParallelRemarkEnabled -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 -XX:+ScavengeBeforeFullGC -XX:+CMSScavengeBeforeRemark -XX:NewSize=600m -XX:MaxNewSize=900m -XX:SurvivorRatio=10 -XX:+DisableExplicitGC -Djava.security.egd=file:/dev/./urandom
+
+version: 2
+jobs:
+ build:
+ <<: *defaults
+ docker:
+ - image: killbill/kbbuild:0.1.0
+ steps:
+ - checkout
+ - restore_cache:
+ key: v1-dependencies-{{ .Branch }}-{{ checksum "pom.xml" }}
+ - run:
+ name: Setup dependencies
+ command: |
+ if [ "${CIRCLE_BRANCH}" != "master" ]; then
+ for i in killbill-oss-parent killbill-api killbill-plugin-api killbill-commons killbill-platform; do
+ if [ -n "$(git ls-remote --heads https://github.com/killbill/$i.git ${CIRCLE_BRANCH})" ]; then
+ echo "*** Setting up $i"
+ mkdir -p /home/killbill/$i
+ git clone https://github.com/killbill/$i.git /home/killbill/$i
+ pushd /home/killbill/$i
+ git checkout -b ${CIRCLE_BRANCH} origin/${CIRCLE_BRANCH}
+ mvn clean install -DskipTests=true
+ popd
+ fi
+ done
+ fi
+ - run: mvn -DskipTests=true clean install dependency:go-offline
+ - save_cache:
+ paths:
+ - ~/.m2
+ key: v1-dependencies-{{ .Branch }}-{{ checksum "pom.xml" }}
+
+ test-h2:
+ <<: *defaults
+ docker:
+ - image: killbill/kbbuild:0.1.0
+ steps:
+ - checkout
+ - restore_cache:
+ key: v1-dependencies-{{ .Branch }}-{{ checksum "pom.xml" }}
+ - run: mvn clean install -Ptravis
+ - run:
+ name: Save test results
+ command: |
+ mkdir -p ~/junit/
+ find . -type f -regex ".*/target/surefire-reports/.*xml" -exec cp {} ~/junit/ \;
+ when: always
+ - store_test_results:
+ path: ~/junit
+ - store_artifacts:
+ path: ~/junit
+ test-mysql:
+ <<: *defaults
+ docker:
+ - image: killbill/kbbuild:0.1.0
+ - image: killbill/mariadb:0.18
+ environment:
+ - MYSQL_ROOT_PASSWORD=root
+ steps:
+ - checkout
+ - restore_cache:
+ key: v1-dependencies-{{ .Branch }}-{{ checksum "pom.xml" }}
+ - run:
+ name: Setup latest DDL
+ command: |
+ set +e
+ count=0
+ until mysqladmin ping -h 127.0.0.1 -u root --password=root --silent; do
+ if [[ "$count" == "25" ]]; then
+ exit 1
+ fi
+ (( count++ ))
+
+ printf '.'
+ sleep 5
+ done
+
+ set -e
+ ./bin/db-helper -a create --driver mysql -u root -p root -t yes -h 127.0.0.1
+ - run: mvn clean install -Plocaltest-mysql
+ - run:
+ name: Save test results
+ command: |
+ mkdir -p ~/junit/
+ find . -type f -regex ".*/target/surefire-reports/.*xml" -exec cp {} ~/junit/ \;
+ when: always
+ - store_test_results:
+ path: ~/junit
+ - store_artifacts:
+ path: ~/junit
+ test-postgresql:
+ <<: *defaults
+ docker:
+ - image: killbill/kbbuild:0.1.0
+ - image: killbill/postgresql:0.18
+ environment:
+ - POSTGRES_PASSWORD=postgres
+ steps:
+ - checkout
+ - restore_cache:
+ key: v1-dependencies-{{ .Branch }}-{{ checksum "pom.xml" }}
+ - run:
+ name: Setup latest DDL
+ command: ./bin/db-helper -a create --driver postgres -u postgres -p postgres -t yes
+ - run: mvn clean install -Plocaltest-postgresql
+ - run:
+ name: Save test results
+ command: |
+ mkdir -p ~/junit/
+ find . -type f -regex ".*/target/surefire-reports/.*xml" -exec cp {} ~/junit/ \;
+ when: always
+ - store_test_results:
+ path: ~/junit
+ - store_artifacts:
+ path: ~/junit
+
+ integration-tests:
+ <<: *defaults
+ docker:
+ - image: killbill/kbbuild:0.1.0
+ - image: killbill/mariadb:0.18
+ environment:
+ - MYSQL_ROOT_PASSWORD=root
+ steps:
+ - checkout
+ - restore_cache:
+ key: v1-dependencies-{{ .Branch }}-{{ checksum "pom.xml" }}
+ - run:
+ name: Setup latest DDL
+ command: ./bin/db-helper -a create --driver mysql -u root -p root -t yes -h 127.0.0.1
+ - run:
+ name: Run integration tests
+ command: |
+ set +e
+
+ mvn clean install -DskipTests=true
+ nohup ./bin/start-server -s &
+
+ mkdir -p /home/killbill/killbill-integration-tests
+ git clone https://github.com/killbill/killbill-integration-tests.git /home/killbill/killbill-integration-tests
+ pushd /home/killbill/killbill-integration-tests
+ if [ "${CIRCLE_BRANCH}" != "master" ]; then
+ if [ -n "$(git ls-remote --heads https://github.com/killbill/killbill-integration-tests.git ${CIRCLE_BRANCH})" ]; then
+ git checkout -b ${CIRCLE_BRANCH} origin/${CIRCLE_BRANCH}
+ fi
+ fi
+ bundle install
+
+ count=0
+ until $(curl --output /dev/null --silent --fail http://127.0.0.1:8080/1.0/healthcheck); do
+ if [[ "$count" == "25" ]]; then
+ exit 1
+ fi
+ (( count++ ))
+
+ printf '.'
+ sleep 5
+ done
+
+ set -e
+ mkdir -p /tmp/test-results
+ bundle exec rake test:core | tee /tmp/test-results/test.txt 2>&1
+ - store_test_results:
+ path: /tmp/test-results
+ - store_artifacts:
+ path: /tmp/test-results
+
+workflows:
+ version: 2
+ build-and-test:
+ jobs:
+ - build:
+ filters:
+ branches:
+ only:
+ - master
+ - work-for-release-0.19.x
+ - circle-ci-experiment
+ - test-h2:
+ requires:
+ - build
+ filters:
+ branches:
+ only:
+ - master
+ - circle-ci-experiment
+ - test-mysql:
+ requires:
+ - build
+ filters:
+ branches:
+ only:
+ - master
+ - work-for-release-0.19.x
+ - circle-ci-experiment
+ - test-postgresql:
+ requires:
+ - build
+ filters:
+ branches:
+ only:
+ - master
+ - circle-ci-experiment
+ - integration-tests:
+ requires:
+ - test-h2
+ - test-mysql
+ - test-postgresql
+ filters:
+ branches:
+ only:
+ - master
+ - work-for-release-0.19.x
+ - circle-ci-experiment
.travis.yml 29(+11 -18)
diff --git a/.travis.yml b/.travis.yml
index be5eefd..feec69b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -8,37 +8,30 @@ cache:
dist: trusty
before_install:
+ - grep -q -z '<artifactId>killbill-oss-parent</artifactId>[[:space:]]\+<groupId>org.kill-bill.billing</groupId>[[:space:]]\+<version>[0-9\.]*-SNAPSHOT</version>' pom.xml && echo "killbill-oss-parent SNAPSHOT has been found, exiting." && exit 0 || true
- echo "<settings><profiles><profile><repositories><repository><id>central</id><name>bintray</name><url>http://jcenter.bintray.com</url></repository></repositories><id>bintray</id></profile></profiles><activeProfiles><activeProfile>bintray</activeProfile></activeProfiles></settings>" > /var/tmp/settings.xml
- - mvn -N io.takari:maven:wrapper -Dmaven=3.3.9
+ - |
+ function keep_alive() {
+ while true; do
+ echo -en "\a"
+ sleep 5
+ done
+ }
+ keep_alive &
before_script:
- jdk_switcher use $JDK
-script: if [[ -v COMMAND ]]; then $COMMAND; else travis_retry ./mvnw -q -Djava.security.egd=file:/dev/./urandom -Dorg.slf4j.simpleLogger.defaultLogLevel=WARN -Dorg.slf4j.simpleLogger.log.org.killbill.billing.util.cache=ERROR -Dorg.slf4j.simpleLogger.log.org.killbill.billing.lifecycle=ERROR -Dlogback.configurationFile=$PWD/profiles/killbill/src/test/resources/logback.travis.xml clean install $PHASE -pl '!beatrix,!profiles,!profiles/killbill,!profiles/killpay' 2>&1 | egrep -v 'Download|Install|[ \t]*at [ \ta-zA-Z0-9\.\:\(\)]+'; [ ${PIPESTATUS[0]} == 0 ]; fi
-# Remove --quiet to avoid timeouts
-install: mvn -U install -DskipTests=true --settings /var/tmp/settings.xml | egrep -v 'Download|Install'
+script: mvn -q -Djava.security.egd=file:/dev/./urandom -Dorg.slf4j.simpleLogger.defaultLogLevel=WARN -Dorg.slf4j.simpleLogger.log.org.killbill.billing.util.cache=ERROR -Dorg.slf4j.simpleLogger.log.org.killbill.billing.lifecycle=ERROR -Dlogback.configurationFile=$PWD/profiles/killbill/src/test/resources/logback.travis.xml clean install $PHASE -pl '!beatrix,!profiles,!profiles/killbill,!profiles/killpay'
+install: mvn -q -U install -DskipTests=true --settings /var/tmp/settings.xml
notifications:
email:
- kill-bill-commits@googlegroups.com
-env:
- global:
- - MAVEN_OPTS="-Xmx512m -XX:MaxPermSize=192m"
-
matrix:
include:
- - env: PHASE="-Ptravis,jdk16" JDK=oraclejdk8
- - env: PHASE="-Ptravis,jdk16" JDK=openjdk8
- - env: PHASE="-Ptravis,jdk17" JDK=oraclejdk8
- - env: PHASE="-Ptravis,jdk17" JDK=openjdk8
- - env: PHASE="-Ptravis,jdk18" JDK=oraclejdk8
- env: PHASE="-Ptravis,jdk18" JDK=openjdk8
- - env: PHASE="-Pmysql,jdk18" JDK=oraclejdk8
- env: PHASE="-Pmysql,jdk18" JDK=openjdk8
- - env: PHASE="-Ppostgresql,jdk18" JDK=oraclejdk8
- env: PHASE="-Ppostgresql,jdk18" JDK=openjdk8
fast_finish: true
-
-after_success:
- - '[ "${TRAVIS_PULL_REQUEST}" = "false" ] && echo "<settings><servers><server><id>sonatype-nexus-snapshots</id><username>\${env.OSSRH_USER}</username><password>\${env.OSSRH_PASS}</password></server></servers></settings>" > ~/settings.xml && mvn deploy -DskipTests=true --settings ~/settings.xml | egrep "WARN|ERR|\[INFO\]\ ---|Upload" | egrep -v "[0-9]+/[0-9]+ [kKmM]B" ; rm -f ~/settings.xml'
diff --git a/account/src/test/java/org/killbill/billing/account/dao/TestAccountDao.java b/account/src/test/java/org/killbill/billing/account/dao/TestAccountDao.java
index e8ea8f0..2bc7bd3 100644
--- a/account/src/test/java/org/killbill/billing/account/dao/TestAccountDao.java
+++ b/account/src/test/java/org/killbill/billing/account/dao/TestAccountDao.java
@@ -184,7 +184,7 @@ public class TestAccountDao extends AccountTestSuiteWithEmbeddedDB {
@Test(groups = "slow", description = "Test Account DAO: tags")
public void testTags() throws TagApiException, TagDefinitionApiException {
final AccountModelDao account = createTestAccount();
- final TagDefinitionModelDao tagDefinition = tagDefinitionDao.create(UUID.randomUUID().toString().substring(0, 4), UUID.randomUUID().toString(), internalCallContext);
+ final TagDefinitionModelDao tagDefinition = tagDefinitionDao.create(UUID.randomUUID().toString().substring(0, 4), UUID.randomUUID().toString(), ObjectType.ACCOUNT.name(), internalCallContext);
final Tag tag = new DescriptiveTag(tagDefinition.getId(), ObjectType.ACCOUNT, account.getId(), internalCallContext.getCreatedDate());
tagDao.create(new TagModelDao(tag), internalCallContext);
diff --git a/api/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseInternalApi.java b/api/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseInternalApi.java
index d17adb7..33c4db0 100644
--- a/api/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseInternalApi.java
+++ b/api/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseInternalApi.java
@@ -47,11 +47,11 @@ public interface SubscriptionBaseInternalApi {
final boolean isMigrated, InternalCallContext context) throws SubscriptionBaseApiException;
public List<SubscriptionBaseWithAddOns> createBaseSubscriptionsWithAddOns(UUID accountId, Iterable<BaseEntitlementWithAddOnsSpecifier> baseEntitlementWithAddOnsSpecifier,
- InternalCallContext contextWithValidAccountRecordId) throws SubscriptionBaseApiException;
+ boolean renameCancelledBundleIfExist, InternalCallContext contextWithValidAccountRecordId) throws SubscriptionBaseApiException;
public void cancelBaseSubscriptions(Iterable<SubscriptionBase> subscriptions, BillingActionPolicy policy, int accountBillCycleDayLocal, InternalCallContext context) throws SubscriptionBaseApiException;
- public SubscriptionBaseBundle createBundleForAccount(UUID accountId, String bundleName, InternalCallContext context)
+ public SubscriptionBaseBundle createBundleForAccount(UUID accountId, String bundleName, boolean renameCancelledBundleIfExist, InternalCallContext context)
throws SubscriptionBaseApiException;
public List<SubscriptionBaseBundle> getBundlesForAccountAndKey(UUID accountId, String bundleKey, InternalTenantContext context)
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/TestOverdueIntegration.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/TestOverdueIntegration.java
index b4b9016..fdc849d 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/TestOverdueIntegration.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/TestOverdueIntegration.java
@@ -29,6 +29,7 @@ import java.util.UUID;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.killbill.billing.ErrorCode;
+import org.killbill.billing.api.FlakyRetryAnalyzer;
import org.killbill.billing.api.TestApiListener.NextEvent;
import org.killbill.billing.beatrix.integration.BeatrixIntegrationModule;
import org.killbill.billing.beatrix.util.InvoiceChecker.ExpectedInvoiceItemCheck;
@@ -954,7 +955,8 @@ public class TestOverdueIntegration extends TestOverdueBase {
checkODState(OverdueWrapper.CLEAR_STATE_NAME);
}
- @Test(groups = "slow", description = "Test overdue state with number of unpaid invoices condition")
+ // Flaky, see https://github.com/killbill/killbill/issues/782
+ @Test(groups = "slow", description = "Test overdue state with number of unpaid invoices condition", retryAnalyzer = FlakyRetryAnalyzer.class)
public void testOverdueStateWithNumberOfUnpaidInvoicesCondition() throws Exception {
// 2012-05-01T00:03:42.000Z
clock.setTime(new DateTime(2012, 5, 1, 0, 3, 42, 0));
@@ -1026,7 +1028,8 @@ public class TestOverdueIntegration extends TestOverdueBase {
checkODState(OverdueWrapper.CLEAR_STATE_NAME);
}
- @Test(groups = "slow", description = "Test overdue state with total unpaid invoice balance condition")
+ // Flaky, see https://github.com/killbill/killbill/issues/782
+ @Test(groups = "slow", description = "Test overdue state with total unpaid invoice balance condition", retryAnalyzer = FlakyRetryAnalyzer.class)
public void testOverdueStateWithTotalUnpaidInvoiceBalanceCondition() throws Exception {
// 2012-05-01T00:03:42.000Z
clock.setTime(new DateTime(2012, 5, 1, 0, 3, 42, 0));
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestCatalogRetireElements.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestCatalogRetireElements.java
index 33c8f44..62a00e8 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestCatalogRetireElements.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestCatalogRetireElements.java
@@ -84,7 +84,7 @@ public class TestCatalogRetireElements extends TestIntegrationBase {
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(productName, term, PriceListSet.DEFAULT_PRICELIST_NAME, null);
try {
- entitlementApi.createBaseEntitlement(account.getId(), spec, "externalKey2", null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ entitlementApi.createBaseEntitlement(account.getId(), spec, "externalKey2", null, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
fail(); // force to fail is there is not an exception
} catch (final EntitlementApiException e) {
assertEquals(e.getCode(), ErrorCode.CAT_PLAN_NOT_FOUND.getCode());
@@ -143,7 +143,7 @@ public class TestCatalogRetireElements extends TestIntegrationBase {
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(productName, term, PriceListSet.DEFAULT_PRICELIST_NAME, null);
try {
- entitlementApi.createBaseEntitlement(account.getId(), spec, "externalKey2", null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ entitlementApi.createBaseEntitlement(account.getId(), spec, "externalKey2", null, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
fail(); // force to fail is there is not an exception
} catch (final EntitlementApiException e) {
assertEquals(e.getCode(), ErrorCode.CAT_PLAN_NOT_FOUND.getCode());
@@ -182,7 +182,7 @@ public class TestCatalogRetireElements extends TestIntegrationBase {
final PlanPhaseSpecifier spec1 = new PlanPhaseSpecifier(productName, term, "DEFAULT", null);
busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
- Entitlement bpEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec1, "externalKey", null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ Entitlement bpEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec1, "externalKey", null, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
assertNotNull(bpEntitlement);
@@ -241,7 +241,7 @@ public class TestCatalogRetireElements extends TestIntegrationBase {
// Catalog v3 should start now.
try {
- entitlementApi.createBaseEntitlement(account.getId(), spec2, "externalKey2", null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ entitlementApi.createBaseEntitlement(account.getId(), spec2, "externalKey2", null, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
fail(); // force to fail is there is not an exception
} catch (final EntitlementApiException e) {
assertEquals(e.getCode(), ErrorCode.CAT_NO_SUCH_PRODUCT.getCode());
@@ -272,7 +272,7 @@ public class TestCatalogRetireElements extends TestIntegrationBase {
final PlanPhaseSpecifier spec1 = new PlanPhaseSpecifier(productName, term, "DEFAULT", null);
busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
- Entitlement bpEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec1, "externalKey", null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ Entitlement bpEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec1, "externalKey", null, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
assertNotNull(bpEntitlement);
@@ -341,7 +341,7 @@ public class TestCatalogRetireElements extends TestIntegrationBase {
// Catalog v3 should start now.
try {
- entitlementApi.createBaseEntitlement(account.getId(), spec2, "externalKey2", null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ entitlementApi.createBaseEntitlement(account.getId(), spec2, "externalKey2", null, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
fail(); // force to fail is there is not an exception
} catch (final EntitlementApiException e) {
assertEquals(e.getCode(), ErrorCode.CAT_NO_SUCH_PRODUCT.getCode());
@@ -394,7 +394,7 @@ public class TestCatalogRetireElements extends TestIntegrationBase {
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(productName, term, PriceListSet.DEFAULT_PRICELIST_NAME, null);
try {
- entitlementApi.createBaseEntitlement(account.getId(), spec, "externalKey2", null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ entitlementApi.createBaseEntitlement(account.getId(), spec, "externalKey2", null, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
fail(); // force to fail is there is not an exception
} catch (final EntitlementApiException e) {
assertTrue(e.getLocalizedMessage().startsWith("Could not find any product named 'Pistol'"));
@@ -430,7 +430,7 @@ public class TestCatalogRetireElements extends TestIntegrationBase {
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(productName, term, "SpecialDiscount", null);
busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
- final Entitlement bpEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, "externalKey", null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement bpEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, "externalKey", null, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
assertNotNull(bpEntitlement);
@@ -449,7 +449,7 @@ public class TestCatalogRetireElements extends TestIntegrationBase {
// PriceList "SpecialDiscount" at this point.
try {
- entitlementApi.createBaseEntitlement(account.getId(), spec, "externalKey2", null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ entitlementApi.createBaseEntitlement(account.getId(), spec, "externalKey2", null, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
fail(); // force to fail is there is not an exception
} catch (final EntitlementApiException e) {
assertTrue(e.getLocalizedMessage().startsWith("Could not find any product named 'Pistol'"));
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegration.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegration.java
index 89507b5..2265bbf 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegration.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegration.java
@@ -82,7 +82,7 @@ public class TestIntegration extends TestIntegrationBase {
SubscriptionEventType.START_BILLING, null, null, null, null);
Invoice dryRunInvoice = invoiceUserApi.triggerInvoiceGeneration(account.getId(), clock.getUTCToday(), dryRun, callContext);
expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2012, 4, 1), null, InvoiceItemType.FIXED, new BigDecimal("0")));
- invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, callContext, expectedInvoices);
+ invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, expectedInvoices);
final DefaultEntitlement bpSubscription = createBaseEntitlementAndCheckForCompletion(account.getId(), "bundleKey", "Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
// Check bundle after BP got created otherwise we get an error from auditApi.
@@ -97,7 +97,7 @@ public class TestIntegration extends TestIntegrationBase {
SubscriptionEventType.START_BILLING, null, bpSubscription.getBundleId(), null, null);
dryRunInvoice = invoiceUserApi.triggerInvoiceGeneration(account.getId(), clock.getUTCToday(), dryRun, callContext);
expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2012, 4, 1), new LocalDate(2012, 5, 1), InvoiceItemType.RECURRING, new BigDecimal("399.95")));
- invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, callContext, expectedInvoices);
+ invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, expectedInvoices);
addAOEntitlementAndCheckForCompletion(bpSubscription.getBundleId(), "Telescopic-Scope", ProductCategory.ADD_ON, BillingPeriod.MONTHLY, NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
@@ -116,7 +116,7 @@ public class TestIntegration extends TestIntegrationBase {
// The second invoice should be adjusted for the AO (we paid for the full period) and since we paid we should also see a CBA
expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2012, 4, 1), new LocalDate(2012, 4, 1), InvoiceItemType.CBA_ADJ, new BigDecimal("399.95"),
false /* Avoid checking dates for CBA because code is using context and context createdDate is wrong in the test as we reset the clock too late, bummer... */ ));
- invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, callContext, expectedInvoices);
+ invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, expectedInvoices);
cancelEntitlementAndCheckForCompletion(bpSubscription, NextEvent.BLOCK, NextEvent.BLOCK, NextEvent.CANCEL, NextEvent.CANCEL, NextEvent.INVOICE);
@@ -157,7 +157,7 @@ public class TestIntegration extends TestIntegrationBase {
subscription.getId(), subscription.getBundleId(), null, null);
Invoice dryRunInvoice = invoiceUserApi.triggerInvoiceGeneration(account.getId(), clock.getUTCToday(), dryRun, callContext);
expectedInvoices.add(new ExpectedInvoiceItemCheck(initialCreationDate.toLocalDate(), null, InvoiceItemType.FIXED, new BigDecimal("0")));
- invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, callContext, expectedInvoices);
+ invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, expectedInvoices);
clock.addDeltaFromReality(1000); // Make sure CHANGE does not collide with CREATE
@@ -181,7 +181,7 @@ public class TestIntegration extends TestIntegrationBase {
// Verify first next targetDate
dryRunInvoice = invoiceUserApi.triggerInvoiceGeneration(account.getId(), new LocalDate(nextDate, testTimeZone), dryRun, callContext);
- invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, callContext, expectedInvoices);
+ invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, expectedInvoices);
setDateAndCheckForCompletion(nextDate, NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
@@ -207,7 +207,7 @@ public class TestIntegration extends TestIntegrationBase {
dryRunInvoice = invoiceUserApi.triggerInvoiceGeneration(account.getId(), new LocalDate(nextDate, testTimeZone), dryRun, callContext);
expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2012, 3, 31), new LocalDate(2012, 4, 30), InvoiceItemType.RECURRING, new BigDecimal("29.95")));
- invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, callContext, expectedInvoices);
+ invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, expectedInvoices);
addDaysAndCheckForCompletion(31, NextEvent.CHANGE, NextEvent.NULL_INVOICE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
invoiceChecker.checkInvoice(account.getId(), invoiceItemCount++, callContext, expectedInvoices);
@@ -421,49 +421,6 @@ public class TestIntegration extends TestIntegrationBase {
checkNoMoreInvoiceToGenerate(account);
}
- @Test(groups = {"stress"}, enabled = false)
- public void stressTest() throws Exception {
- final int maxIterations = 100;
- for (int curIteration = 0; curIteration < maxIterations; curIteration++) {
- if (curIteration != 0) {
- beforeMethod();
- }
-
- log.info("################################ ITERATION " + curIteration + " #########################");
- afterMethod();
- beforeMethod();
- testBasePlanCompleteWithBillingDayInPast();
- Thread.sleep(1000);
- afterMethod();
- beforeMethod();
- testBasePlanCompleteWithBillingDayAlignedWithTrial();
- Thread.sleep(1000);
- afterMethod();
- beforeMethod();
- testBasePlanCompleteWithBillingDayInFuture();
- if (curIteration < maxIterations - 1) {
- afterMethod();
- Thread.sleep(1000);
- }
- }
- }
-
- @Test(groups = {"stress"}, enabled = false)
- public void stressTestDebug() throws Exception {
- final int maxIterations = 100;
- for (int curIteration = 0; curIteration < maxIterations; curIteration++) {
- log.info("################################ ITERATION " + curIteration + " #########################");
- if (curIteration != 0) {
- beforeMethod();
- }
- testAddonsWithMultipleAlignments();
- if (curIteration < maxIterations - 1) {
- afterMethod();
- Thread.sleep(1000);
- }
- }
- }
-
@Test(groups = "slow")
public void testAddonsWithMultipleAlignments() throws Exception {
final DateTime initialDate = new DateTime(2012, 4, 25, 0, 13, 42, 0, testTimeZone);
@@ -510,6 +467,8 @@ public class TestIntegration extends TestIntegrationBase {
checkNoMoreInvoiceToGenerate(account);
}
+
+
@Test(groups = "slow")
public void testCreateMultipleBPWithSameExternalKey() throws Exception {
final DateTime initialDate = new DateTime(2012, 4, 25, 0, 13, 42, 0, testTimeZone);
@@ -531,17 +490,37 @@ public class TestIntegration extends TestIntegrationBase {
final String newProductName = "Pistol";
final DefaultEntitlement newBaseEntitlement = createBaseEntitlementAndCheckForCompletion(account.getId(), "bundleKey", newProductName, ProductCategory.BASE, term, NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
- final SubscriptionBundle newBundle = subscriptionApi.getActiveSubscriptionBundleForExternalKey("bundleKey", callContext);
+ final List<SubscriptionBundle> bundles = subscriptionApi.getSubscriptionBundlesForExternalKey("bundleKey", callContext);
+ Assert.assertEquals(bundles.size(), 2);
+
+ final SubscriptionBundle newBundle = subscriptionApi.getActiveSubscriptionBundleForExternalKey("bundleKey", callContext);
assertNotEquals(initialBundle.getId(), newBundle.getId());
assertEquals(initialBundle.getAccountId(), newBundle.getAccountId());
assertEquals(initialBundle.getExternalKey(), newBundle.getExternalKey());
- final Entitlement refreshedBseEntitlement = entitlementApi.getEntitlementForId(baseEntitlement.getId(), callContext);
-
- assertEquals(refreshedBseEntitlement.getState(), EntitlementState.CANCELLED);
+ final Entitlement refreshedBaseEntitlement = entitlementApi.getEntitlementForId(baseEntitlement.getId(), callContext);
+ assertEquals(refreshedBaseEntitlement.getState(), EntitlementState.CANCELLED);
assertEquals(newBaseEntitlement.getState(), EntitlementState.ACTIVE);
+
+ // One more time
+ busHandler.pushExpectedEvents(NextEvent.BLOCK, NextEvent.CANCEL, NextEvent.NULL_INVOICE);
+ newBaseEntitlement.cancelEntitlementWithPolicy(EntitlementActionPolicy.IMMEDIATE, ImmutableList.<PluginProperty>of(), callContext);
+ assertListenerStatus();
+
+ final String newerProductName = "Shotgun";
+ final DefaultEntitlement newerBaseEntitlement = createBaseEntitlementAndCheckForCompletion(account.getId(), "bundleKey", newerProductName, ProductCategory.BASE, term, NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
+ assertEquals(newerBaseEntitlement.getState(), EntitlementState.ACTIVE);
+
+ final List<SubscriptionBundle> bundlesAgain = subscriptionApi.getSubscriptionBundlesForExternalKey("bundleKey", callContext);
+ Assert.assertEquals(bundlesAgain.size(), 3);
+
+ final SubscriptionBundle newerBundle = subscriptionApi.getActiveSubscriptionBundleForExternalKey("bundleKey", callContext);
+ assertNotEquals(initialBundle.getId(), newerBundle.getId());
+ assertEquals(initialBundle.getAccountId(), newerBundle.getAccountId());
+ assertEquals(initialBundle.getExternalKey(), newerBundle.getExternalKey());
+
checkNoMoreInvoiceToGenerate(account);
}
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
index 1c7d63e..f85f029 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
@@ -18,15 +18,18 @@
package org.killbill.billing.beatrix.integration;
-import com.google.common.base.Function;
-import com.google.common.base.Joiner;
-import com.google.common.base.Predicate;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import com.google.inject.Guice;
-import com.google.inject.Injector;
-import com.google.inject.Stage;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.Callable;
+
+import javax.annotation.Nullable;
+import javax.inject.Inject;
+import javax.inject.Named;
+
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.LocalDate;
@@ -122,30 +125,31 @@ import org.skife.config.TimeSpan;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.Assert;
+import org.testng.IHookCallBack;
+import org.testng.IHookable;
+import org.testng.ITestResult;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
-import javax.annotation.Nullable;
-import javax.inject.Inject;
-import javax.inject.Named;
-import java.math.BigDecimal;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
-import java.util.concurrent.Callable;
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Stage;
-import static org.awaitility.Awaitility.await;
import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.awaitility.Awaitility.await;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
-
-public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
+public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB implements IHookable {
protected static final DateTimeZone testTimeZone = DateTimeZone.UTC;
protected static final Logger log = LoggerFactory.getLogger(TestIntegrationBase.class);
@@ -295,6 +299,7 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
protected ConfigurableInvoiceConfig invoiceConfig;
+ @Override
protected void assertListenerStatus() {
busHandler.assertListenerStatus();
}
@@ -329,16 +334,10 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
lifecycle.fireStartupSequencePostEventRegistration();
paymentPlugin.clear();
-
- // Make sure we start with a clean state
- assertListenerStatus();
}
@AfterMethod(groups = "slow")
public void afterMethod() throws Exception {
- // Make sure we finish in a clean state
- assertListenerStatus();
-
lifecycle.fireShutdownSequencePriorEventUnRegistration();
busService.getBus().unregister(busHandler);
lifecycle.fireShutdownSequencePostEventUnRegistration();
@@ -658,7 +657,7 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
public Entitlement apply(@Nullable final Void dontcare) {
try {
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(productName, billingPeriod, PriceListSet.DEFAULT_PRICELIST_NAME, null);
- final Entitlement entitlement = entitlementApi.createBaseEntitlement(accountId, spec, bundleExternalKey, overrides, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement entitlement = entitlementApi.createBaseEntitlement(accountId, spec, bundleExternalKey, overrides, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertNotNull(entitlement);
return entitlement;
} catch (final EntitlementApiException e) {
@@ -1014,6 +1013,16 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
}
@Override
+ public List<String> getInvoicePluginNames() {
+ return defaultInvoiceConfig.getInvoicePluginNames();
+ }
+
+ @Override
+ public List<String> getInvoicePluginNames(final InternalTenantContext tenantContext) {
+ return defaultInvoiceConfig.getInvoicePluginNames();
+ }
+
+ @Override
public boolean isEmailNotificationsEnabled() {
return defaultInvoiceConfig.isEmailNotificationsEnabled();
}
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationInvoice.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationInvoice.java
index ae26efd..8155e6d 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationInvoice.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationInvoice.java
@@ -91,7 +91,7 @@ public class TestIntegrationInvoice extends TestIntegrationBase {
// This will verify that the upcoming Phase is found and the invoice is generated at the right date, with correct items
DryRunArguments dryRun = new TestDryRunArguments(DryRunType.UPCOMING_INVOICE);
Invoice dryRunInvoice = invoiceUserApi.triggerInvoiceGeneration(account.getId(), null, dryRun, callContext);
- invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, callContext, expectedInvoices);
+ invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, expectedInvoices);
// Move through time and verify we get the same invoice
busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
@@ -104,7 +104,7 @@ public class TestIntegrationInvoice extends TestIntegrationBase {
// This will verify that the upcoming invoice notification is found and the invoice is generated at the right date, with correct items
expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2015, 7, 14), new LocalDate(2015, 8, 14), InvoiceItemType.RECURRING, new BigDecimal("249.95")));
dryRunInvoice = invoiceUserApi.triggerInvoiceGeneration(account.getId(), null, dryRun, callContext);
- invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, callContext, expectedInvoices);
+ invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, expectedInvoices);
// Move through time and verify we get the same invoice
@@ -118,7 +118,7 @@ public class TestIntegrationInvoice extends TestIntegrationBase {
// One more time, this will verify that the upcoming invoice notification is found and the invoice is generated at the right date, with correct items
expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2015, 8, 14), new LocalDate(2015, 9, 14), InvoiceItemType.RECURRING, new BigDecimal("249.95")));
dryRunInvoice = invoiceUserApi.triggerInvoiceGeneration(account.getId(), null, dryRun, callContext);
- invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, callContext, expectedInvoices);
+ invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, expectedInvoices);
}
//
@@ -155,7 +155,7 @@ public class TestIntegrationInvoice extends TestIntegrationBase {
DryRunArguments dryRun = new TestDryRunArguments(DryRunType.UPCOMING_INVOICE);
Invoice dryRunInvoice = invoiceUserApi.triggerInvoiceGeneration(account.getId(), null, dryRun, callContext);
- invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, callContext, expectedInvoices);
+ invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, expectedInvoices);
busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
// 2014-2-1
@@ -167,7 +167,7 @@ public class TestIntegrationInvoice extends TestIntegrationBase {
// Since we only have one subscription next dryRun will show the annual
expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2015, 2, 1), new LocalDate(2016, 2, 1), InvoiceItemType.RECURRING, new BigDecimal("2399.95")));
dryRunInvoice = invoiceUserApi.triggerInvoiceGeneration(account.getId(), null, dryRun, callContext);
- invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, callContext, expectedInvoices);
+ invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, expectedInvoices);
expectedInvoices.clear();
// 2014-12-15
@@ -184,7 +184,7 @@ public class TestIntegrationInvoice extends TestIntegrationBase {
// Verify next dryRun invoice and then move the clock to that date to also verify real invoice is the same
expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2015, 1, 14), new LocalDate(2015, 2, 14), InvoiceItemType.RECURRING, new BigDecimal("249.95")));
dryRunInvoice = invoiceUserApi.triggerInvoiceGeneration(account.getId(), null, dryRun, callContext);
- invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, callContext, expectedInvoices);
+ invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, expectedInvoices);
busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
// 2015-1-14
@@ -199,13 +199,13 @@ public class TestIntegrationInvoice extends TestIntegrationBase {
expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2015, 2, 14), new LocalDate(2015, 3, 14), InvoiceItemType.RECURRING, new BigDecimal("249.95")));
dryRunInvoice = invoiceUserApi.triggerInvoiceGeneration(account.getId(), null, dryRunWIthSubscription, callContext);
assertEquals(dryRunInvoice.getTargetDate(), new LocalDate(2015, 2, 14));
- invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, callContext, expectedInvoices);
+ invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, expectedInvoices);
expectedInvoices.clear();
// Then we test first the next expected invoice at the account level
expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2015, 2, 1), new LocalDate(2016, 2, 1), InvoiceItemType.RECURRING, new BigDecimal("2399.95")));
dryRunInvoice = invoiceUserApi.triggerInvoiceGeneration(account.getId(), null, dryRun, callContext);
- invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, callContext, expectedInvoices);
+ invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, expectedInvoices);
busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
// 2015-2-1
@@ -216,7 +216,7 @@ public class TestIntegrationInvoice extends TestIntegrationBase {
expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2015, 2, 14), new LocalDate(2015, 3, 14), InvoiceItemType.RECURRING, new BigDecimal("249.95")));
dryRunInvoice = invoiceUserApi.triggerInvoiceGeneration(account.getId(), null, dryRun, callContext);
- invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, callContext, expectedInvoices);
+ invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, expectedInvoices);
}
@Test(groups = "slow")
@@ -349,7 +349,7 @@ public class TestIntegrationInvoice extends TestIntegrationBase {
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Blowdart", BillingPeriod.MONTHLY, "notrial", null);
busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE, NextEvent.INVOICE_PAYMENT, NextEvent.PAYMENT);
- entitlementApi.createBaseEntitlement(account.getId(), spec, "bundleExternalKey", ImmutableList.<PlanPhasePriceOverride>of(), null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ entitlementApi.createBaseEntitlement(account.getId(), spec, "bundleExternalKey", ImmutableList.<PlanPhasePriceOverride>of(), null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
// 2017-02-28
@@ -383,7 +383,7 @@ public class TestIntegrationInvoice extends TestIntegrationBase {
final LocalDate futureDate = new LocalDate(2017, 5, 1);
// No CREATE event as this is set in the future
- final Entitlement createdEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, futureDate, futureDate, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement createdEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, futureDate, futureDate, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertEquals(createdEntitlement.getState(), Entitlement.EntitlementState.PENDING);
assertEquals(createdEntitlement.getEffectiveStartDate().compareTo(futureDate), 0);
assertEquals(createdEntitlement.getEffectiveEndDate(), null);
@@ -466,7 +466,7 @@ public class TestIntegrationInvoice extends TestIntegrationBase {
final LocalDate futureDate = new LocalDate(2017, 5, 1);
// No CREATE event as this is set in the future
- final Entitlement createdEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, futureDate, futureDate, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement createdEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, futureDate, futureDate, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertEquals(createdEntitlement.getState(), Entitlement.EntitlementState.PENDING);
assertEquals(createdEntitlement.getEffectiveStartDate().compareTo(futureDate), 0);
assertEquals(createdEntitlement.getEffectiveEndDate(), null);
@@ -519,7 +519,7 @@ public class TestIntegrationInvoice extends TestIntegrationBase {
final List<PlanPhasePriceOverride> overrides = new ArrayList<PlanPhasePriceOverride>();
overrides.add(new DefaultPlanPhasePriceOverride("blowdart-monthly-notrial-evergreen", account.getCurrency(), null, BigDecimal.ZERO, ImmutableList.<UsagePriceOverride>of()));
busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
- final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, "bundleExternalKey", overrides, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, "bundleExternalKey", overrides, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
invoiceChecker.checkInvoice(account.getId(), 1, callContext,
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationInvoiceWithRepairLogic.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationInvoiceWithRepairLogic.java
index 18f2da2..a755f9c 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationInvoiceWithRepairLogic.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationInvoiceWithRepairLogic.java
@@ -64,12 +64,6 @@ public class TestIntegrationInvoiceWithRepairLogic extends TestIntegrationBase {
@Inject
protected InvoiceDao invoiceDao;
-
- @AfterMethod(groups = "slow")
- public void afterMethod() throws Exception {
- super.afterMethod();
- }
-
@Test(groups = "slow")
public void testSimplePartialRepairWithItemAdjustment() throws Exception {
// We take april as it has 30 days (easier to play with BCD)
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationParentInvoice.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationParentInvoice.java
index a8fd0c1..324e747 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationParentInvoice.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationParentInvoice.java
@@ -918,7 +918,7 @@ public class TestIntegrationParentInvoice extends TestIntegrationBase {
clock.setTime(date);
assertListenerStatus();
- createBaseEntitlementAndCheckForCompletion(childAccount.getId(), "bundleKey1", "Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
+ createBaseEntitlementAndCheckForCompletion(childAccount.getId(), "bundleKey2", "Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
// Move through time and verify new parent Invoice.
busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.INVOICE, NextEvent.INVOICE);
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationWithCatalogUpdate.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationWithCatalogUpdate.java
index 33cef16..b128d8a 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationWithCatalogUpdate.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationWithCatalogUpdate.java
@@ -40,7 +40,6 @@ import org.killbill.billing.catalog.api.CatalogUserApi;
import org.killbill.billing.catalog.api.Plan;
import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
-import org.killbill.billing.catalog.api.PlanSpecifier;
import org.killbill.billing.catalog.api.PriceListSet;
import org.killbill.billing.catalog.api.ProductCategory;
import org.killbill.billing.catalog.api.SimplePlanDescriptor;
@@ -182,7 +181,7 @@ public class TestIntegrationWithCatalogUpdate extends TestIntegrationBase {
try {
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Zoe", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
- entitlementApi.createBaseEntitlement(account.getId(), spec, UUID.randomUUID().toString(), null, null, null, false, ImmutableList.<PluginProperty>of(), testCallContext);
+ entitlementApi.createBaseEntitlement(account.getId(), spec, UUID.randomUUID().toString(), null, null, null, false, true, ImmutableList.<PluginProperty>of(), testCallContext);
fail("Creating entitlement should fail");
} catch (final EntitlementApiException e) {
assertEquals(e.getCode(), ErrorCode.CAT_MULTIPLE_MATCHING_PLANS_FOR_PRICELIST.getCode());
@@ -248,7 +247,7 @@ public class TestIntegrationWithCatalogUpdate extends TestIntegrationBase {
final List<ExpectedInvoiceItemCheck> expectedInvoices = new ArrayList<ExpectedInvoiceItemCheck>();
expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2016, 6, 1), new LocalDate(2016, 7, 1), InvoiceItemType.RECURRING, BigDecimal.TEN));
- invoiceChecker.checkInvoiceNoAudits(invoices.get(0), callContext, expectedInvoices);
+ invoiceChecker.checkInvoiceNoAudits(invoices.get(0), expectedInvoices);
int invoiceSize = 2;
LocalDate startDate = new LocalDate(2016, 7, 1);
@@ -265,7 +264,7 @@ public class TestIntegrationWithCatalogUpdate extends TestIntegrationBase {
assertEquals(invoices.size(), invoiceSize);
expectedInvoices.add(new ExpectedInvoiceItemCheck(startDate, endDate, InvoiceItemType.RECURRING, BigDecimal.TEN));
- invoiceChecker.checkInvoiceNoAudits(invoices.get(invoices.size() - 1), callContext, expectedInvoices);
+ invoiceChecker.checkInvoiceNoAudits(invoices.get(invoices.size() - 1), expectedInvoices);
startDate = endDate;
invoiceSize++;
@@ -284,7 +283,7 @@ public class TestIntegrationWithCatalogUpdate extends TestIntegrationBase {
final PlanPhaseSpecifier specZero = new PlanPhaseSpecifier("zeroDesc-monthly", null);
busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
- final Entitlement baseEntitlement = entitlementApi.createBaseEntitlement(account.getId(), specZero, UUID.randomUUID().toString(), ImmutableList.<PlanPhasePriceOverride>of(), null, null, false, ImmutableList.<PluginProperty>of(), testCallContext);
+ final Entitlement baseEntitlement = entitlementApi.createBaseEntitlement(account.getId(), specZero, UUID.randomUUID().toString(), ImmutableList.<PlanPhasePriceOverride>of(), null, null, false, true, ImmutableList.<PluginProperty>of(), testCallContext);
assertListenerStatus();
Subscription refreshedBaseEntitlement = subscriptionApi.getSubscriptionForEntitlementId(baseEntitlement.getId(), testCallContext);
@@ -313,7 +312,7 @@ public class TestIntegrationWithCatalogUpdate extends TestIntegrationBase {
final PlanPhaseSpecifier specNonZero = new PlanPhaseSpecifier("superfoo-monthly", null);
busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE, NextEvent.INVOICE_PAYMENT, NextEvent.PAYMENT);
- final Entitlement baseEntitlement2 = entitlementApi.createBaseEntitlement(account.getId(), specNonZero, UUID.randomUUID().toString(), ImmutableList.<PlanPhasePriceOverride>of(), null, null, false, ImmutableList.<PluginProperty>of(), testCallContext);
+ final Entitlement baseEntitlement2 = entitlementApi.createBaseEntitlement(account.getId(), specNonZero, UUID.randomUUID().toString(), ImmutableList.<PlanPhasePriceOverride>of(), null, null, false, true, ImmutableList.<PluginProperty>of(), testCallContext);
assertListenerStatus();
busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.INVOICE_PAYMENT, NextEvent.PAYMENT);
@@ -374,7 +373,7 @@ public class TestIntegrationWithCatalogUpdate extends TestIntegrationBase {
final PlanPhaseSpecifier planPhaseSpec = new PlanPhaseSpecifier("hello-monthly", null);
busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
- final Entitlement baseEntitlement = entitlementApi.createBaseEntitlement(account.getId(), planPhaseSpec, UUID.randomUUID().toString(), ImmutableList.<PlanPhasePriceOverride>of(), null, null, false, ImmutableList.<PluginProperty>of(), testCallContext);
+ final Entitlement baseEntitlement = entitlementApi.createBaseEntitlement(account.getId(), planPhaseSpec, UUID.randomUUID().toString(), ImmutableList.<PlanPhasePriceOverride>of(), null, null, false, true, ImmutableList.<PluginProperty>of(), testCallContext);
assertListenerStatus();
Subscription refreshedBaseEntitlement = subscriptionApi.getSubscriptionForEntitlementId(baseEntitlement.getId(), testCallContext);
@@ -408,7 +407,7 @@ public class TestIntegrationWithCatalogUpdate extends TestIntegrationBase {
} else {
busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
}
- final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, UUID.randomUUID().toString(), overrides, null, null, false, ImmutableList.<PluginProperty>of(), testCallContext);
+ final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, UUID.randomUUID().toString(), overrides, null, null, false, true, ImmutableList.<PluginProperty>of(), testCallContext);
assertListenerStatus();
return entitlement;
}
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestInvoiceSystemDisabling.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestInvoiceSystemDisabling.java
index cc57eae..200aadf 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestInvoiceSystemDisabling.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestInvoiceSystemDisabling.java
@@ -80,7 +80,7 @@ public class TestInvoiceSystemDisabling extends TestIntegrationBase {
assertListenerStatus();
final ImmutableList<ExpectedInvoiceItemCheck> expected = ImmutableList.<ExpectedInvoiceItemCheck>of(new ExpectedInvoiceItemCheck(new LocalDate(2012, 4, 1), null, InvoiceItemType.FIXED, BigDecimal.ZERO),
new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 1), new LocalDate(2012, 6, 1), InvoiceItemType.RECURRING, new BigDecimal("249.95")));
- invoiceChecker.checkInvoiceNoAudits(invoice, callContext, expected);
+ invoiceChecker.checkInvoiceNoAudits(invoice, expected);
// Still parked
Assert.assertTrue(parkedAccountsManager.isParked(internalCallContext));
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestMigrationSubscriptions.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestMigrationSubscriptions.java
index 6e9c19a..0357f98 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestMigrationSubscriptions.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestMigrationSubscriptions.java
@@ -86,7 +86,7 @@ public class TestMigrationSubscriptions extends TestIntegrationBase {
// Entitlement wil be created in PENDING state
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
- final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, "bundleKey", null, entitlementMigrationDate, billingMigrationDate, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, "bundleKey", null, entitlementMigrationDate, billingMigrationDate, false, true, ImmutableList.<PluginProperty>of(), callContext);
Assert.assertEquals(entitlement.getState(), EntitlementState.PENDING);
// Move clock to entitlementMigrationDate (migration cutOverDate), and expect the associated event
@@ -142,7 +142,7 @@ public class TestMigrationSubscriptions extends TestIntegrationBase {
// Entitlement wil be created in ACTIVE state because entitlementMigrationDate was set in the past
busHandler.pushExpectedEvents(NextEvent.BLOCK);
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, PhaseType.EVERGREEN);
- final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, "bundleKey", null, entitlementMigrationDate, billingMigrationDate, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, "bundleKey", null, entitlementMigrationDate, billingMigrationDate, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
Assert.assertEquals(entitlement.getState(), EntitlementState.ACTIVE);
@@ -187,7 +187,7 @@ public class TestMigrationSubscriptions extends TestIntegrationBase {
// Entitlement wil be created in ACTIVE state because entitlementMigrationDate was set in the past
busHandler.pushExpectedEvents(NextEvent.BLOCK);
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, PhaseType.EVERGREEN);
- final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, "bundleKey", null, entitlementMigrationDate, billingMigrationDate, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, "bundleKey", null, entitlementMigrationDate, billingMigrationDate, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
Assert.assertEquals(entitlement.getState(), EntitlementState.ACTIVE);
@@ -256,6 +256,7 @@ public class TestMigrationSubscriptions extends TestIntegrationBase {
final List<Entitlement> baseEntitlements = entitlementApi.createBaseEntitlementsWithAddOns(
account.getId(),
baseEntitlementWithAddOnsSpecifierList,
+ true,
ImmutableList.<PluginProperty>of(),
callContext);
assertListenerStatus();
@@ -308,6 +309,7 @@ public class TestMigrationSubscriptions extends TestIntegrationBase {
final List<Entitlement> baseEntitlements = entitlementApi.createBaseEntitlementsWithAddOns(
account.getId(),
baseEntitlementWithAddOnsSpecifierList,
+ true,
ImmutableList.<PluginProperty>of(),
callContext);
assertListenerStatus();
@@ -352,7 +354,7 @@ public class TestMigrationSubscriptions extends TestIntegrationBase {
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("pistol-monthly-notrial", null);
busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
- entitlementApi.createBaseEntitlement(account.getId(), spec, "bundleExternalKey", ImmutableList.<PlanPhasePriceOverride>of(), null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ entitlementApi.createBaseEntitlement(account.getId(), spec, "bundleExternalKey", ImmutableList.<PlanPhasePriceOverride>of(), null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
clock.addMonths(1);
@@ -381,7 +383,7 @@ public class TestMigrationSubscriptions extends TestIntegrationBase {
// Unlike the previous scenario, we create the subscription and set the blocking state at the same time
busHandler.pushExpectedEvents(NextEvent.BLOCK, NextEvent.CREATE, NextEvent.BLOCK);
subscriptionApi.addBlockingState(blockingState1, null, ImmutableList.<PluginProperty>of(), callContext);
- entitlementApi.createBaseEntitlement(account.getId(), spec, "bundleExternalKey", ImmutableList.<PlanPhasePriceOverride>of(), null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ entitlementApi.createBaseEntitlement(account.getId(), spec, "bundleExternalKey", ImmutableList.<PlanPhasePriceOverride>of(), null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
clock.addMonths(1);
@@ -418,7 +420,7 @@ public class TestMigrationSubscriptions extends TestIntegrationBase {
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("pistol-monthly-notrial", null);
busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
- entitlementApi.createBaseEntitlement(account.getId(), spec, "bundleExternalKey", ImmutableList.<PlanPhasePriceOverride>of(), null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ entitlementApi.createBaseEntitlement(account.getId(), spec, "bundleExternalKey", ImmutableList.<PlanPhasePriceOverride>of(), null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
// Add less than a day between the CREATE and the BLOCK, to verify invoicing behavior
@@ -462,7 +464,7 @@ public class TestMigrationSubscriptions extends TestIntegrationBase {
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("pistol-monthly-notrial", null);
busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
- final Entitlement baseEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, "bundleExternalKey", ImmutableList.<PlanPhasePriceOverride>of(), null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement baseEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, "bundleExternalKey", ImmutableList.<PlanPhasePriceOverride>of(), null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
clock.addDays(1);
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestPaymentRefund.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestPaymentRefund.java
index 86912e4..15d05da 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestPaymentRefund.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestPaymentRefund.java
@@ -152,7 +152,7 @@ public class TestPaymentRefund extends TestIntegrationBase {
// No end date for the trial item (fixed price of zero), and CTD should be today (i.e. when the trial started)
invoiceChecker.checkChargedThroughDate(bpEntitlement.getId(), clock.getUTCToday(), callContext);
- setDateAndCheckForCompletion(new DateTime(2012, 3, 2, 23, 59, 59, 0, testTimeZone), NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+ setDateAndCheckForCompletion(new DateTime(2012, 3, 2, 23, 59, 0, 0, testTimeZone), NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
invoice = invoiceChecker.checkInvoice(account.getId(), ++invoiceItemCount, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2012, 3, 2),
new LocalDate(2012, 3, 31), InvoiceItemType.RECURRING, new BigDecimal("233.82")));
payment = paymentChecker.checkPayment(account.getId(), 1, callContext, new ExpectedPaymentCheck(new LocalDate(2012, 3, 2), new BigDecimal("233.82"), TransactionStatus.SUCCESS, invoice.getId(), Currency.USD));
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestPublicBus.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestPublicBus.java
index fc49f94..e3d7799 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestPublicBus.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestPublicBus.java
@@ -24,7 +24,6 @@ import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicInteger;
import org.joda.time.DateTime;
-import org.killbill.billing.DBTestingHelper;
import org.killbill.billing.account.api.Account;
import org.killbill.billing.api.TestApiListener.NextEvent;
import org.killbill.billing.callcontext.DefaultCallContext;
@@ -81,10 +80,7 @@ public class TestPublicBus extends TestIntegrationBase {
TODO modify sequence to allow optional registration of publicListener
*/
- try {
- DBTestingHelper.get().getInstance().cleanupAllTables();
- } catch (final Exception ignored) {
- }
+ cleanupAllTables();
log.debug("RESET TEST FRAMEWORK");
@@ -107,9 +103,6 @@ public class TestPublicBus extends TestIntegrationBase {
paymentPlugin.clear();
this.externalBusCount = new AtomicInteger(0);
-
- // Make sure we start with a clean state
- assertListenerStatus();
}
@AfterMethod(groups = "slow")
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestSubscription.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestSubscription.java
index 880c3a5..ff77fb8 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestSubscription.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestSubscription.java
@@ -30,7 +30,6 @@ import org.killbill.billing.api.TestApiListener.NextEvent;
import org.killbill.billing.beatrix.util.InvoiceChecker.ExpectedInvoiceItemCheck;
import org.killbill.billing.catalog.api.BillingActionPolicy;
import org.killbill.billing.catalog.api.BillingPeriod;
-import org.killbill.billing.catalog.api.PlanPhase;
import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
import org.killbill.billing.catalog.api.PriceListSet;
import org.killbill.billing.catalog.api.ProductCategory;
@@ -105,7 +104,7 @@ public class TestSubscription extends TestIntegrationBase {
TestDryRunArguments dryRun = new TestDryRunArguments(DryRunType.SUBSCRIPTION_ACTION, productName, ProductCategory.BASE, BillingPeriod.MONTHLY, null, null,
SubscriptionEventType.CHANGE, bpEntitlement.getId(), bpEntitlement.getBundleId(), null, BillingActionPolicy.IMMEDIATE);
Invoice dryRunInvoice = invoiceUserApi.triggerInvoiceGeneration(account.getId(), clock.getUTCToday(), dryRun, callContext);
- invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, callContext, toBeChecked);
+ invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, toBeChecked);
changeEntitlementAndCheckForCompletion(bpEntitlement, productName, BillingPeriod.MONTHLY, BillingActionPolicy.IMMEDIATE, NextEvent.CHANGE, NextEvent.INVOICE);
@@ -236,7 +235,7 @@ public class TestSubscription extends TestIntegrationBase {
NextEvent.INVOICE,
NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT
);
- final List<Entitlement> allEntitlements = entitlementApi.createBaseEntitlementsWithAddOns(account.getId(), entitlementWithAddOnsSpecifierList, ImmutableList.<PluginProperty>of(), callContext);
+ final List<Entitlement> allEntitlements = entitlementApi.createBaseEntitlementsWithAddOns(account.getId(), entitlementWithAddOnsSpecifierList, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
checkNoMoreInvoiceToGenerate(account);
@@ -320,7 +319,7 @@ public class TestSubscription extends TestIntegrationBase {
NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT
);
- final List<Entitlement> entitlements = entitlementApi.createBaseEntitlementsWithAddOns(account.getId(), entitlementWithAddOnsSpecifierList, ImmutableList.<PluginProperty>of(), callContext);
+ final List<Entitlement> entitlements = entitlementApi.createBaseEntitlementsWithAddOns(account.getId(), entitlementWithAddOnsSpecifierList, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
Assert.assertEquals(entitlements.size(), 5);
@@ -355,7 +354,7 @@ public class TestSubscription extends TestIntegrationBase {
final BaseEntitlementWithAddOnsSpecifier cartSpecifierA = new DefaultBaseEntitlementWithAddOnsSpecifier(null, externalKeyA, specifierListA, null, null, false);
entitlementWithAddOnsSpecifierList.add(cartSpecifierA);
- entitlementApi.createBaseEntitlementsWithAddOns(account.getId(), entitlementWithAddOnsSpecifierList, ImmutableList.<PluginProperty>of(), callContext);
+ entitlementApi.createBaseEntitlementsWithAddOns(account.getId(), entitlementWithAddOnsSpecifierList, true, ImmutableList.<PluginProperty>of(), callContext);
}
@Test(groups = "slow")
@@ -442,7 +441,7 @@ public class TestSubscription extends TestIntegrationBase {
final LocalDate futureDate = new LocalDate(2015, 10, 1);
// No CREATE event as this is set in the future
- final Entitlement createdEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, futureDate, futureDate, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement createdEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, futureDate, futureDate, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertEquals(createdEntitlement.getEffectiveStartDate().compareTo(futureDate), 0);
assertEquals(createdEntitlement.getEffectiveEndDate(), null);
assertListenerStatus();
@@ -474,7 +473,7 @@ public class TestSubscription extends TestIntegrationBase {
final LocalDate futureDate = new LocalDate(2015, 10, 1);
// No CREATE event as this is set in the future
- final Entitlement createdEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, futureDate, futureDate, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement createdEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, futureDate, futureDate, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertEquals(createdEntitlement.getState(), EntitlementState.PENDING);
assertEquals(createdEntitlement.getEffectiveStartDate().compareTo(futureDate), 0);
assertEquals(createdEntitlement.getEffectiveEndDate(), null);
@@ -518,7 +517,7 @@ public class TestSubscription extends TestIntegrationBase {
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, null);
busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
- final Entitlement createdEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, initialDate, initialDate, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement createdEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, initialDate, initialDate, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertEquals(createdEntitlement.getEffectiveStartDate().compareTo(initialDate), 0);
assertEquals(createdEntitlement.getEffectiveEndDate(), null);
assertListenerStatus();
@@ -547,7 +546,7 @@ public class TestSubscription extends TestIntegrationBase {
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, null);
busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
- final Entitlement createdEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, initialDate, initialDate, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement createdEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, initialDate, initialDate, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertEquals(createdEntitlement.getEffectiveStartDate().compareTo(initialDate), 0);
assertEquals(createdEntitlement.getEffectiveEndDate(), null);
assertListenerStatus();
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestTagApi.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestTagApi.java
index 0654926..11dbba0 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestTagApi.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestTagApi.java
@@ -35,6 +35,9 @@ import org.killbill.billing.util.tag.ControlTagType;
import org.killbill.billing.util.tag.Tag;
import org.killbill.billing.util.tag.TagDefinition;
+import com.google.common.collect.ImmutableSet;
+
+import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
public class TestTagApi extends TestIntegrationBase {
@@ -95,9 +98,14 @@ public class TestTagApi extends TestIntegrationBase {
// Create a new tag definition
//
busHandler.pushExpectedEvents(NextEvent.TAG_DEFINITION);
- final TagDefinition tagDefinition = tagUserApi.createTagDefinition("foo", "foo desc", callContext);
+ final TagDefinition tagDefinition = tagUserApi.createTagDefinition("foo", "foo desc", ImmutableSet.<ObjectType>of(ObjectType.ACCOUNT, ObjectType.INVOICE), callContext);
assertListenerStatus();
+ final TagDefinition tagDefinition2 = tagUserApi.getTagDefinition(tagDefinition.getId(), callContext);
+ assertEquals(tagDefinition2.getApplicableObjectTypes().size(), 2);
+ assertEquals(tagDefinition2.getApplicableObjectTypes().get(0), ObjectType.ACCOUNT);
+ assertEquals(tagDefinition2.getApplicableObjectTypes().get(1), ObjectType.INVOICE);
+
//
// Add 2 Tags on the invoice (1 invoice tag and 1 user tag)
//
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithBCDUpdate.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithBCDUpdate.java
index f8a4499..49583e8 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithBCDUpdate.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithBCDUpdate.java
@@ -572,7 +572,7 @@ public class TestWithBCDUpdate extends TestIntegrationBase {
overrides.add(new DefaultPlanPhasePriceOverride("blowdart-monthly-notrial-evergreen", account.getCurrency(), null, BigDecimal.ZERO, ImmutableList.<UsagePriceOverride>of()));
busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
// BP creation : Will set Account BCD to the first (DateOfFirstRecurringNonZeroCharge is the subscription start date in this case)
- final Entitlement baseEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, "bundleExternalKey", overrides, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement baseEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, "bundleExternalKey", overrides, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
invoiceChecker.checkInvoice(account.getId(), 1, callContext,
@@ -634,7 +634,7 @@ public class TestWithBCDUpdate extends TestIntegrationBase {
overrides.add(new DefaultPlanPhasePriceOverride("blowdart-monthly-notrial-evergreen", account.getCurrency(), null, BigDecimal.ZERO, ImmutableList.<UsagePriceOverride>of()));
busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
// BP creation : Will set Account BCD to the first (DateOfFirstRecurringNonZeroCharge is the subscription start date in this case)
- final Entitlement baseEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, "bundleExternalKey", overrides, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement baseEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, "bundleExternalKey", overrides, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
invoiceChecker.checkInvoice(account.getId(), 1, callContext,
@@ -692,7 +692,7 @@ public class TestWithBCDUpdate extends TestIntegrationBase {
overrides.add(new DefaultPlanPhasePriceOverride("blowdart-monthly-notrial-evergreen", account.getCurrency(), null, BigDecimal.ZERO, ImmutableList.<UsagePriceOverride>of()));
busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
// BP creation : Will set Account BCD to the first (DateOfFirstRecurringNonZeroCharge is the subscription start date in this case)
- final Entitlement baseEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, "bundleExternalKey", overrides, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement baseEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, "bundleExternalKey", overrides, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
invoiceChecker.checkInvoice(account.getId(), 1, callContext,
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithFakeKPMPlugin.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithFakeKPMPlugin.java
index b239488..60e3176 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithFakeKPMPlugin.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithFakeKPMPlugin.java
@@ -1,6 +1,6 @@
/*
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -21,7 +21,6 @@ import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -38,12 +37,10 @@ import org.killbill.billing.notification.plugin.api.ExtBusEventType;
import org.killbill.billing.osgi.BundleRegistry;
import org.killbill.billing.osgi.BundleWithConfig;
import org.killbill.billing.osgi.FileInstall;
-import org.killbill.billing.osgi.PureOSGIBundleFinder;
import org.killbill.billing.osgi.api.PluginInfo;
import org.killbill.billing.osgi.api.PluginStateChange;
import org.killbill.billing.osgi.api.PluginsInfoApi;
import org.killbill.billing.osgi.api.config.PluginConfig;
-import org.killbill.billing.osgi.api.config.PluginConfigServiceApi;
import org.killbill.billing.osgi.api.config.PluginLanguage;
import org.killbill.billing.osgi.api.config.PluginType;
import org.killbill.billing.osgi.config.OSGIConfig;
@@ -51,7 +48,6 @@ import org.killbill.billing.osgi.pluginconf.PluginConfigException;
import org.killbill.billing.osgi.pluginconf.PluginFinder;
import org.killbill.billing.platform.api.KillbillConfigSource;
import org.killbill.billing.util.jackson.ObjectMapper;
-import org.killbill.billing.util.nodes.KillbillNodesApi;
import org.killbill.billing.util.nodes.NodeCommand;
import org.killbill.billing.util.nodes.NodeCommandMetadata;
import org.killbill.billing.util.nodes.NodeCommandProperty;
@@ -61,8 +57,10 @@ import org.killbill.billing.util.nodes.PluginNodeCommandMetadata;
import org.killbill.billing.util.nodes.SystemNodeCommandType;
import org.mockito.Mockito;
import org.osgi.framework.Bundle;
+import org.osgi.framework.launch.Framework;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import com.fasterxml.jackson.databind.SerializationFeature;
@@ -79,8 +77,10 @@ import com.google.inject.Module;
import com.google.inject.Stage;
import com.google.inject.util.Modules;
-import static org.awaitility.Awaitility.await;
import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.awaitility.Awaitility.await;
+import static org.mockito.Mockito.RETURNS_MOCKS;
+import static org.mockito.Mockito.withSettings;
public class TestWithFakeKPMPlugin extends TestIntegrationBase {
@@ -226,13 +226,16 @@ public class TestWithFakeKPMPlugin extends TestIntegrationBase {
@Inject
public FakeBundleRegistry() {
- super(null);
+ super(Mockito.mock(FileInstall.class, withSettings().defaultAnswer(RETURNS_MOCKS)));
bundles = new ArrayList<BundleWithMetadata>();
}
- public void installNewBundle(final String pluginName, @Nullable final String version, final PluginLanguage pluginLanguage) {
+ @Override
+ public void installBundles(final Framework framework) {
+ super.installBundles(framework);
+
final Bundle bundle = Mockito.mock(Bundle.class);
- Mockito.when(bundle.getSymbolicName()).thenReturn(pluginName);
+ Mockito.when(bundle.getSymbolicName()).thenReturn(NEW_PLUGIN_NAME);
final BundleWithConfig config = new BundleWithConfig(bundle, new PluginConfig() {
@Override
@@ -247,7 +250,7 @@ public class TestWithFakeKPMPlugin extends TestIntegrationBase {
@Override
public String getPluginName() {
- return pluginName;
+ return NEW_PLUGIN_NAME;
}
@Override
@@ -257,7 +260,7 @@ public class TestWithFakeKPMPlugin extends TestIntegrationBase {
@Override
public String getVersion() {
- return version;
+ return NEW_PLUGIN_VERSION;
}
@Override
@@ -272,7 +275,7 @@ public class TestWithFakeKPMPlugin extends TestIntegrationBase {
@Override
public PluginLanguage getPluginLanguage() {
- return pluginLanguage;
+ return PluginLanguage.JAVA;
}
@Override
@@ -296,10 +299,6 @@ public class TestWithFakeKPMPlugin extends TestIntegrationBase {
}
}).orNull();
}
-
- public Collection<BundleWithMetadata> getBundles() {
- return bundles;
- }
}
public static class OverrideModuleForOSGI implements Module {
@@ -317,16 +316,12 @@ public class TestWithFakeKPMPlugin extends TestIntegrationBase {
g.injectMembers(this);
}
- @BeforeClass(groups = "slow")
+ @BeforeMethod(groups = "slow")
public void beforeMethod() throws Exception {
-
- try {
- DBTestingHelper.get().getInstance().cleanupAllTables();
- } catch (final Exception ignored) {
- }
-
log.debug("RESET TEST FRAMEWORK");
+ cleanupAllTables();
+
clock.resetDeltaFromReality();
busHandler.reset();
@@ -335,9 +330,6 @@ public class TestWithFakeKPMPlugin extends TestIntegrationBase {
externalBus.register(new FakeKPMPlugin());
lifecycle.fireStartupSequencePostEventRegistration();
-
- // Make sure we start with a clean state
- assertListenerStatus();
}
@Test(groups = "slow")
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithTaxItems.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithTaxItems.java
index 6d1b9df..4c88a98 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithTaxItems.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithTaxItems.java
@@ -18,9 +18,11 @@
package org.killbill.billing.beatrix.integration;
import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.UUID;
-import java.util.concurrent.atomic.AtomicBoolean;
import javax.inject.Inject;
@@ -38,6 +40,7 @@ import org.killbill.billing.invoice.api.DryRunType;
import org.killbill.billing.invoice.api.Invoice;
import org.killbill.billing.invoice.api.InvoiceItem;
import org.killbill.billing.invoice.api.InvoiceItemType;
+import org.killbill.billing.invoice.model.ExternalChargeInvoiceItem;
import org.killbill.billing.invoice.model.TaxInvoiceItem;
import org.killbill.billing.invoice.plugin.api.InvoicePluginApi;
import org.killbill.billing.osgi.api.OSGIServiceDescriptor;
@@ -49,6 +52,7 @@ import org.killbill.billing.util.callcontext.CallContext;
import org.killbill.billing.util.tag.ControlTagType;
import org.killbill.billing.util.tag.Tag;
import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
@@ -85,6 +89,12 @@ public class TestWithTaxItems extends TestIntegrationBase {
}, testInvoicePluginApi);
}
+ @BeforeMethod(groups = "slow")
+ public void beforeMethod() throws Exception {
+ super.beforeMethod();
+ testInvoicePluginApi.reset();
+ }
+
private void add_AUTO_INVOICING_OFF_Tag(final UUID id) throws TagDefinitionApiException, TagApiException {
busHandler.pushExpectedEvent(NextEvent.TAG);
tagUserApi.addTag(id, ObjectType.ACCOUNT, ControlTagType.AUTO_INVOICING_OFF.getId(), callContext);
@@ -133,7 +143,7 @@ public class TestWithTaxItems extends TestIntegrationBase {
assertListenerStatus();
// Make sure TestInvoicePluginApi will return an additional TAX item
- testInvoicePluginApi.addTaxItem();
+ testInvoicePluginApi.addTaxItem(UUID.randomUUID(), new TaxInvoiceItem(UUID.randomUUID(), null, account.getId(), null, "Tax Item", new LocalDate(2012, 5, 1), BigDecimal.ONE, account.getCurrency()));
// Remove AUTO_INVOICING_OFF => Invoice + Payment
remove_AUTO_INVOICING_OFF_Tag(account.getId(), NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
@@ -149,7 +159,7 @@ public class TestWithTaxItems extends TestIntegrationBase {
assertListenerStatus();
// Make sure TestInvoicePluginApi will return an additional TAX item
- testInvoicePluginApi.addTaxItem();
+ testInvoicePluginApi.addTaxItem(UUID.randomUUID(), new TaxInvoiceItem(UUID.randomUUID(), null, account.getId(), null, "Tax Item", new LocalDate(2012, 5, 1), BigDecimal.ONE, account.getCurrency()));
// Remove AUTO_INVOICING_OFF => Invoice + Payment
remove_AUTO_INVOICING_OFF_Tag(account.getId(), NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
@@ -171,12 +181,11 @@ public class TestWithTaxItems extends TestIntegrationBase {
assertListenerStatus();
// Make sure TestInvoicePluginApi will return an additional TAX item
- testInvoicePluginApi.addTaxItem();
+ testInvoicePluginApi.addTaxItem(UUID.randomUUID(), new TaxInvoiceItem(UUID.randomUUID(), null, account.getId(), null, "Tax Item", new LocalDate(2012, 5, 1), BigDecimal.ONE, account.getCurrency()));
// Remove AUTO_INVOICING_OFF => Invoice + Payment
remove_AUTO_INVOICING_OFF_Tag(account.getId(), NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
-
invoiceChecker.checkInvoice(account.getId(), 3, callContext,
new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 1), new LocalDate(2012, 6, 1), InvoiceItemType.RECURRING, new BigDecimal("249.95")),
new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 1), new LocalDate(2012, 6, 1), InvoiceItemType.REPAIR_ADJ, new BigDecimal("-29.95")),
@@ -205,6 +214,7 @@ public class TestWithTaxItems extends TestIntegrationBase {
invoiceChecker.checkInvoice(account.getId(), 1, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2012, 4, 1), null, InvoiceItemType.FIXED, new BigDecimal("0")));
subscriptionChecker.checkSubscriptionCreated(bpSubscription.getId(), internalCallContext);
+
busHandler.pushExpectedEvents(NextEvent.INVOICE);
invoiceUserApi.insertCredit(account.getId(), new BigDecimal("100"), clock.getUTCToday(), account.getCurrency(), true, "VIP", callContext);
assertListenerStatus();
@@ -214,17 +224,17 @@ public class TestWithTaxItems extends TestIntegrationBase {
new ExpectedInvoiceItemCheck(new LocalDate(2012, 4, 1), new LocalDate(2012, 4, 1), InvoiceItemType.CREDIT_ADJ, new BigDecimal("-100")));
// Make sure TestInvoicePluginApi will return an additional TAX item
- testInvoicePluginApi.addTaxItem();
+ testInvoicePluginApi.addTaxItem(UUID.randomUUID(), new TaxInvoiceItem(UUID.randomUUID(), null, account.getId(), null, "Tax Item", new LocalDate(2012, 4, 1), BigDecimal.ONE, account.getCurrency()));
// Verify dry-run scenario
final Invoice dryRunInvoice = invoiceUserApi.triggerInvoiceGeneration(account.getId(), new LocalDate(2012, 5, 1), new TestDryRunArguments(DryRunType.TARGET_DATE), callContext);
- invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, callContext,
+ invoiceChecker.checkInvoiceNoAudits(dryRunInvoice,
ImmutableList.<ExpectedInvoiceItemCheck>of(new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 1), new LocalDate(2012, 6, 1), InvoiceItemType.RECURRING, new BigDecimal("29.95")),
new ExpectedInvoiceItemCheck(new LocalDate(2012, 4, 1), null, InvoiceItemType.TAX, new BigDecimal("1.0")),
new ExpectedInvoiceItemCheck(new LocalDate(2012, 4, 1), new LocalDate(2012, 4, 1), InvoiceItemType.CBA_ADJ, new BigDecimal("-30.95"))));
// Make sure TestInvoicePluginApi will return an additional TAX item
- testInvoicePluginApi.addTaxItem();
+ testInvoicePluginApi.addTaxItem(UUID.randomUUID(), new TaxInvoiceItem(UUID.randomUUID(), null, account.getId(), null, "Tax Item", new LocalDate(2012, 5, 1), BigDecimal.ONE, account.getCurrency()));
// Move to Evergreen PHASE to verify non-dry-run scenario
busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.INVOICE);
@@ -237,26 +247,80 @@ public class TestWithTaxItems extends TestIntegrationBase {
new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 1), new LocalDate(2012, 5, 1), InvoiceItemType.CBA_ADJ, new BigDecimal("-30.95")));
}
+ @Test(groups = "slow")
+ public void testUpdateTaxItems() throws Exception {
+
+ clock.setDay(new LocalDate(2012, 4, 1));
+
+ final AccountData accountData = getAccountData(1);
+ final Account account = createAccountWithNonOsgiPaymentMethod(accountData);
+
+ // Create original subscription (Trial PHASE) -> $0 invoice.
+ final DefaultEntitlement bpSubscription = createBaseEntitlementAndCheckForCompletion(account.getId(), "bundleKey", "Pistol", ProductCategory.BASE, BillingPeriod.MONTHLY, NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
+ invoiceChecker.checkInvoice(account.getId(), 1, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2012, 4, 1), null, InvoiceItemType.FIXED, new BigDecimal("0")));
+ subscriptionChecker.checkSubscriptionCreated(bpSubscription.getId(), internalCallContext);
+
+ // Add tags to keep DRAFT invoices and reuse them
+ add_AUTO_INVOICING_DRAFT_Tag(account.getId(), ObjectType.ACCOUNT);
+ add_AUTO_INVOICING_REUSE_DRAFT_Tag(account.getId(), ObjectType.ACCOUNT);
+
+ // Make sure TestInvoicePluginApi will return an additional TAX item
+ final UUID invoiceTaxItemId = UUID.randomUUID();
+ testInvoicePluginApi.addTaxItem(invoiceTaxItemId, new TaxInvoiceItem(invoiceTaxItemId, null, account.getId(), null, "Tax Item", new LocalDate(2012, 4, 1), BigDecimal.ONE, account.getCurrency()));
+
+ // Insert external charge autoCommit = false => Invoice will be in DRAFT
+ invoiceUserApi.insertExternalCharges(account.getId(), clock.getUTCNow().toLocalDate(), ImmutableList.<InvoiceItem>of(new ExternalChargeInvoiceItem(null, account.getId(), null, "foo", new LocalDate(2012, 4, 1), null, new BigDecimal("33.80"), account.getCurrency())), false, callContext);
+
+ // Make sure TestInvoicePluginApi **update** the original TAX item
+ testInvoicePluginApi.addTaxItem(invoiceTaxItemId, new TaxInvoiceItem(invoiceTaxItemId, null, account.getId(), null, "Tax Item", new LocalDate(2012, 4, 1), new BigDecimal("12.45"), account.getCurrency()));
+
+ // Move to Evergreen PHASE, but invoice remains in DRAFT mode
+ busHandler.pushExpectedEvents(NextEvent.PHASE /*, NextEvent.INVOICE */);
+ clock.addDays(30);
+ assertListenerStatus();
+
+ final List<Invoice> accountInvoices = invoiceUserApi.getInvoicesByAccount(account.getId(), false, callContext);
+ assertEquals(accountInvoices.size(), 2);
+
+ // Commit invoice
+ busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.INVOICE_PAYMENT, NextEvent.PAYMENT);
+ invoiceUserApi.commitInvoice(accountInvoices.get(1).getId(), callContext);
+ assertListenerStatus();
+
+ invoiceChecker.checkInvoice(account.getId(), 2, callContext,
+ new ExpectedInvoiceItemCheck(new LocalDate(2012, 4, 1), null, InvoiceItemType.EXTERNAL_CHARGE, new BigDecimal("33.80")),
+ new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 1), new LocalDate(2012, 6, 1), InvoiceItemType.RECURRING, new BigDecimal("29.95")),
+ new ExpectedInvoiceItemCheck(new LocalDate(2012, 4, 1), null, InvoiceItemType.TAX, new BigDecimal("12.45")));
+
+ }
+
public class TestInvoicePluginApi implements InvoicePluginApi {
- AtomicBoolean addTaxItem;
+ private final Map<UUID, TaxInvoiceItem> taxItems;
public TestInvoicePluginApi() {
- this.addTaxItem = new AtomicBoolean();
+ taxItems = new HashMap<UUID, TaxInvoiceItem>();
}
@Override
public List<InvoiceItem> getAdditionalInvoiceItems(final Invoice invoice, final boolean isDryRun, final Iterable<PluginProperty> pluginProperties, final CallContext callContext) {
- return addTaxItem.compareAndSet(true, false) ? ImmutableList.<InvoiceItem>of(createTaxInvoiceItem(invoice)) : ImmutableList.<InvoiceItem>of();
+ final List<InvoiceItem> result = new ArrayList<InvoiceItem>();
+ for (UUID itemId : taxItems.keySet()) {
+ final TaxInvoiceItem item = taxItems.get(itemId);
+ result.add(new TaxInvoiceItem(item.getId(), invoice.getId(), invoice.getAccountId(), item.getBundleId(), "Tax Item", item.getStartDate(), item.getAmount(), invoice.getCurrency()));
+ }
+ taxItems.clear();
+ return result;
}
- private InvoiceItem createTaxInvoiceItem(final Invoice invoice) {
- return new TaxInvoiceItem(invoice.getId(), invoice.getAccountId(), null, "Tax Item", clock.getUTCNow().toLocalDate(), BigDecimal.ONE, invoice.getCurrency());
+ public void reset() {
+ taxItems.clear();
}
- public void addTaxItem() {
- this.addTaxItem.set(true);
+ public void addTaxItem(final UUID invoiceItemId, final TaxInvoiceItem item) {
+ taxItems.put(invoiceItemId, item);
}
+
}
}
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithTimeZones.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithTimeZones.java
index 2c1cc04..94b47e6 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithTimeZones.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithTimeZones.java
@@ -81,7 +81,7 @@ public class TestWithTimeZones extends TestIntegrationBase {
SubscriptionEventType.START_BILLING, null, null, null, null);
final Invoice dryRunInvoice = invoiceUserApi.triggerInvoiceGeneration(account.getId(), clock.getUTCToday(), dryRun, callContext);
expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2015, 9, 1), null, InvoiceItemType.FIXED, new BigDecimal("0")));
- invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, callContext, expectedInvoices);
+ invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, expectedInvoices);
final DefaultEntitlement bpSubscription = createBaseEntitlementAndCheckForCompletion(account.getId(), "bundleKey", "Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
// Check bundle after BP got created otherwise we get an error from auditApi.
@@ -136,7 +136,7 @@ public class TestWithTimeZones extends TestIntegrationBase {
busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Blowdart", BillingPeriod.MONTHLY, "notrial", null);
- Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, "Something", ImmutableList.<PlanPhasePriceOverride>of(), null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, "Something", ImmutableList.<PlanPhasePriceOverride>of(), null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
// Cancel the next month specifying just a LocalDate
@@ -181,7 +181,7 @@ public class TestWithTimeZones extends TestIntegrationBase {
busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Blowdart", BillingPeriod.MONTHLY, "notrial", null);
- Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, "Something", ImmutableList.<PlanPhasePriceOverride>of(), null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, "Something", ImmutableList.<PlanPhasePriceOverride>of(), null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
// Cancel the next month specifying just a LocalDate
@@ -234,7 +234,7 @@ public class TestWithTimeZones extends TestIntegrationBase {
busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Blowdart", BillingPeriod.MONTHLY, "notrial", null);
// Pass a date of today, to trigger TimeAwareContext#toUTCDateTime
- final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, "Something", ImmutableList.<PlanPhasePriceOverride>of(), clock.getUTCToday(), clock.getUTCToday(), false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, "Something", ImmutableList.<PlanPhasePriceOverride>of(), clock.getUTCToday(), clock.getUTCToday(), false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
Assert.assertEquals(entitlement.getEffectiveStartDate().compareTo(new LocalDate("2015-03-08")), 0);
@@ -357,7 +357,7 @@ public class TestWithTimeZones extends TestIntegrationBase {
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("pistol-monthly-notrial",null);
busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE, NextEvent.INVOICE_PAYMENT, NextEvent.PAYMENT);
- entitlementApi.createBaseEntitlement(account.getId(), spec, "bundleExternalKey", ImmutableList.<PlanPhasePriceOverride>of(), null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ entitlementApi.createBaseEntitlement(account.getId(), spec, "bundleExternalKey", ImmutableList.<PlanPhasePriceOverride>of(), null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/usage/TestConsumableInArrear.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/usage/TestConsumableInArrear.java
index 9aa8eb1..52f5921 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/usage/TestConsumableInArrear.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/usage/TestConsumableInArrear.java
@@ -54,11 +54,6 @@ import com.google.common.collect.ImmutableList;
public class TestConsumableInArrear extends TestIntegrationBase {
- @BeforeMethod(groups = "slow")
- public void beforeMethod() throws Exception {
- super.beforeMethod();
- }
-
@Test(groups = "slow")
public void testWithNoUsageInPeriodAndOldUsage() throws Exception {
// We take april as it has 30 days (easier to play with BCD)
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/util/AuditChecker.java b/beatrix/src/test/java/org/killbill/billing/beatrix/util/AuditChecker.java
index fbc182f..db44b58 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/util/AuditChecker.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/util/AuditChecker.java
@@ -152,12 +152,12 @@ public class AuditChecker {
public void checkInvoiceCreated(final Invoice invoice, final CallContext context) {
final List<AuditLog> invoiceLogs = getAuditLogForInvoice(invoice, context);
- Assert.assertEquals(invoiceLogs.size(), 1);
+ //Assert.assertEquals(invoiceLogs.size(), 1);
checkAuditLog(ChangeType.INSERT, context, invoiceLogs.get(0), invoice.getId(), InvoiceSqlDao.class, false, false);
for (InvoiceItem cur : invoice.getInvoiceItems()) {
final List<AuditLog> auditLogs = getAuditLogForInvoiceItem(cur, context);
- Assert.assertEquals(auditLogs.size(), 1);
+ Assert.assertTrue(auditLogs.size() >= 1);
checkAuditLog(ChangeType.INSERT, context, auditLogs.get(0), cur.getId(), InvoiceItemSqlDao.class, false, false);
}
}
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/util/InvoiceChecker.java b/beatrix/src/test/java/org/killbill/billing/beatrix/util/InvoiceChecker.java
index 8060745..304a0d4 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/util/InvoiceChecker.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/util/InvoiceChecker.java
@@ -79,7 +79,7 @@ public class InvoiceChecker {
checkInvoice(invoice, context, expected);
}
- public void checkInvoiceNoAudits(final Invoice invoice, final CallContext context, final List<ExpectedInvoiceItemCheck> expected) throws InvoiceApiException {
+ public void checkInvoiceNoAudits(final Invoice invoice, final List<ExpectedInvoiceItemCheck> expected) throws InvoiceApiException {
final List<InvoiceItem> actual = invoice.getInvoiceItems();
Assert.assertEquals(actual.size(), expected.size(), String.format("Expected items: %s, actual items: %s", expected, actual));
for (final ExpectedInvoiceItemCheck cur : expected) {
@@ -146,7 +146,7 @@ public class InvoiceChecker {
}
public void checkInvoice(final Invoice invoice, final CallContext context, final List<ExpectedInvoiceItemCheck> expected) throws InvoiceApiException {
- checkInvoiceNoAudits(invoice, context, expected);
+ checkInvoiceNoAudits(invoice, expected);
auditChecker.checkInvoiceCreated(invoice, context);
}
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/util/PaymentChecker.java b/beatrix/src/test/java/org/killbill/billing/beatrix/util/PaymentChecker.java
index 03440c5..9925dde 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/util/PaymentChecker.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/util/PaymentChecker.java
@@ -93,7 +93,7 @@ public class PaymentChecker {
final PaymentTransaction transaction = getPurchaseTransaction(payment);
Assert.assertTrue(transaction.getAmount().compareTo(expected.getAmount()) == 0, "Actual amount " + transaction.getAmount() + ", expected amount " + expected.getAmount());
Assert.assertEquals(transaction.getTransactionStatus(), expected.getStatus());
- Assert.assertEquals(transaction.getEffectiveDate().toLocalDate().compareTo(expected.getPaymentDate()), 0);
+ Assert.assertEquals(transaction.getEffectiveDate().toLocalDate().compareTo(expected.getPaymentDate()), 0, "Actual date " + transaction.getEffectiveDate() + ", expected date " + expected.getPaymentDate());
auditChecker.checkPaymentCreated(payment, context);
}
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementApi.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementApi.java
index eb1ff14..d36367d 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementApi.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementApi.java
@@ -124,7 +124,7 @@ public class DefaultEntitlementApi extends DefaultEntitlementApiBase implements
@Override
public Entitlement createBaseEntitlement(final UUID accountId, final PlanPhaseSpecifier planPhaseSpecifier, final String externalKey, final List<PlanPhasePriceOverride> overrides,
- @Nullable final LocalDate entitlementEffectiveDate, @Nullable final LocalDate billingEffectiveDate, final boolean isMigrated,
+ @Nullable final LocalDate entitlementEffectiveDate, @Nullable final LocalDate billingEffectiveDate, final boolean isMigrated, final boolean renameCancelledBundleIfExist,
final Iterable<PluginProperty> properties, final CallContext callContext) throws EntitlementApiException {
logCreateEntitlement(log, null, planPhaseSpecifier, overrides, entitlementEffectiveDate, billingEffectiveDate);
@@ -162,7 +162,7 @@ public class DefaultEntitlementApi extends DefaultEntitlementApiBase implements
final DateTime entitlementRequestedDate = dateHelper.fromLocalDateAndReferenceTime(baseEntitlementWithAddOnsSpecifier.getEntitlementEffectiveDate(), now, contextWithValidAccountRecordId);
checkForAccountBlockingChange(accountId, entitlementRequestedDate, contextWithValidAccountRecordId);
- final SubscriptionBaseBundle bundle = subscriptionBaseInternalApi.createBundleForAccount(accountId, externalKey, contextWithValidAccountRecordId);
+ final SubscriptionBaseBundle bundle = subscriptionBaseInternalApi.createBundleForAccount(accountId, externalKey, renameCancelledBundleIfExist, contextWithValidAccountRecordId);
final BaseEntitlementWithAddOnsSpecifier baseEntitlementWithAddOnsSpecifier = getFirstBaseEntitlementWithAddOnsSpecifier(updatedPluginContext.getBaseEntitlementWithAddOnsSpecifiers());
final EntitlementSpecifier specifier = getFirstEntitlementSpecifier(baseEntitlementWithAddOnsSpecifier);
@@ -206,7 +206,7 @@ public class DefaultEntitlementApi extends DefaultEntitlementApiBase implements
}
@Override
- public List<Entitlement> createBaseEntitlementsWithAddOns(final UUID accountId, final Iterable<BaseEntitlementWithAddOnsSpecifier> baseEntitlementWithAddOnsSpecifiers, final Iterable<PluginProperty> properties, final CallContext callContext) throws EntitlementApiException {
+ public List<Entitlement> createBaseEntitlementsWithAddOns(final UUID accountId, final Iterable<BaseEntitlementWithAddOnsSpecifier> baseEntitlementWithAddOnsSpecifiers, final boolean renameCancelledBundleIfExist, final Iterable<PluginProperty> properties, final CallContext callContext) throws EntitlementApiException {
logCreateEntitlementsWithAOs(log, baseEntitlementWithAddOnsSpecifiers);
@@ -240,7 +240,7 @@ public class DefaultEntitlementApi extends DefaultEntitlementApiBase implements
// Note that to fully check for block_change we should also look for BlockingState at the BUNDLE/SUBSCRIPTION level in case some of the input contain a BP that already exists.
checkForAccountBlockingChange(accountId, upTo, contextWithValidAccountRecordId);
- final List<SubscriptionBaseWithAddOns> subscriptionsWithAddOns = subscriptionBaseInternalApi.createBaseSubscriptionsWithAddOns(accountId, baseEntitlementWithAddOnsSpecifiers, contextWithValidAccountRecordId);
+ final List<SubscriptionBaseWithAddOns> subscriptionsWithAddOns = subscriptionBaseInternalApi.createBaseSubscriptionsWithAddOns(accountId, baseEntitlementWithAddOnsSpecifiers, renameCancelledBundleIfExist, contextWithValidAccountRecordId);
final Map<BlockingState, UUID> blockingStateMap = new HashMap<BlockingState, UUID>();
int i = 0;
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionApi.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionApi.java
index f8b59ef..a9416a7 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionApi.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionApi.java
@@ -268,7 +268,7 @@ public class DefaultSubscriptionApi implements SubscriptionApi {
logUpdateExternalKey(log, bundleId, newExternalKey);
- final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContextWithoutAccountRecordId(callContext);
+ final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(bundleId, ObjectType.BUNDLE, callContext);
final SubscriptionBaseBundle bundle;
final ImmutableAccountData account;
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/DefaultEventsStream.java b/entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/DefaultEventsStream.java
index c991055..7c84dac 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/DefaultEventsStream.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/DefaultEventsStream.java
@@ -91,6 +91,7 @@ public class DefaultEventsStream implements EventsStream {
final List<SubscriptionBase> allSubscriptionsForBundle,
final int defaultBillCycleDayLocal,
final InternalTenantContext contextWithValidAccountRecordId, final DateTime utcNow) {
+ sanityChecks(account, bundle, baseSubscription, subscription);
this.account = account;
this.bundle = bundle;
this.blockingStates = blockingStates;
@@ -106,6 +107,20 @@ public class DefaultEventsStream implements EventsStream {
setup();
}
+ private void sanityChecks(@Nullable final ImmutableAccountData account,
+ @Nullable final SubscriptionBaseBundle bundle,
+ @Nullable final SubscriptionBase baseSubscription,
+ @Nullable final SubscriptionBase subscription) {
+ for (final Object object : new Object[]{account, bundle, baseSubscription, subscription}) {
+ Preconditions.checkNotNull(object,
+ "accountId='%s', bundleId='%s', baseSubscriptionId='%s', subscriptionId='%s'",
+ account != null ? account.getId() : null,
+ bundle != null ? bundle.getId() : null,
+ baseSubscription != null ? baseSubscription.getId() : null,
+ subscription != null ? subscription.getId() : null);
+ }
+ }
+
@Override
public UUID getAccountId() {
return account.getId();
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlement.java b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlement.java
index f84a951..c5cc731 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlement.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlement.java
@@ -57,7 +57,7 @@ public class TestDefaultEntitlement extends EntitlementTestSuiteWithEmbeddedDB {
// Create entitlement and check each field
testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
- final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
assertEquals(entitlement.getState(), EntitlementState.ACTIVE);
assertEquals(entitlement.getSourceType(), EntitlementSourceType.NATIVE);
@@ -85,7 +85,7 @@ public class TestDefaultEntitlement extends EntitlementTestSuiteWithEmbeddedDB {
// Create entitlement and check each field
testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
- final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
assertEquals(entitlement.getState(), EntitlementState.ACTIVE);
@@ -118,7 +118,7 @@ public class TestDefaultEntitlement extends EntitlementTestSuiteWithEmbeddedDB {
// Create entitlement and check each field
testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
- final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
assertEquals(entitlement.getState(), EntitlementState.ACTIVE);
@@ -151,7 +151,7 @@ public class TestDefaultEntitlement extends EntitlementTestSuiteWithEmbeddedDB {
// Create entitlement and check each field
testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
- final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
testListener.pushExpectedEvents(NextEvent.CANCEL, NextEvent.BLOCK);
@@ -176,7 +176,7 @@ public class TestDefaultEntitlement extends EntitlementTestSuiteWithEmbeddedDB {
// Create entitlement and check each field
testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
- final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
final DateTime ctd = clock.getUTCNow().plusDays(30).plusMonths(1);
@@ -219,7 +219,7 @@ public class TestDefaultEntitlement extends EntitlementTestSuiteWithEmbeddedDB {
// Create entitlement and check each field
testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
- final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
final DateTime ctd = clock.getUTCNow().plusDays(30).plusMonths(1);
@@ -259,7 +259,7 @@ public class TestDefaultEntitlement extends EntitlementTestSuiteWithEmbeddedDB {
// Create entitlement and check each field
testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
- final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
// Immediate change during trial
@@ -295,7 +295,7 @@ public class TestDefaultEntitlement extends EntitlementTestSuiteWithEmbeddedDB {
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
// Create entitlement and check each field
- final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, startDate, startDate, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, startDate, startDate, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
assertEquals(entitlement.getState(), EntitlementState.PENDING);
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlementApi.java b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlementApi.java
index 4965c31..58285fb 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlementApi.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlementApi.java
@@ -63,7 +63,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
// Keep the same object for the whole test, to make sure we refresh its state before r/w calls
testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
- final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
// Add ADD_ON
@@ -126,7 +126,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
// Keep the same object for the whole test, to make sure we refresh its state before r/w calls
testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
- final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
testListener.pushExpectedEvent(NextEvent.PHASE);
@@ -159,7 +159,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
// Create entitlement and check each field
testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
- final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
assertEquals(entitlement.getAccountId(), account.getId());
assertEquals(entitlement.getExternalKey(), account.getExternalKey());
@@ -251,7 +251,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
// Create entitlement and check each field
testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
- final Entitlement baseEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement baseEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
// Add ADD_ON
@@ -290,7 +290,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
// Create entitlement and check each field
final LocalDate startDate = initialDate.plusDays(10);
- final Entitlement baseEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, startDate, startDate, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement baseEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, startDate, startDate, false, true, ImmutableList.<PluginProperty>of(), callContext);
// Add ADD_ON immediately. Because BASE is PENDING should fail
final PlanPhaseSpecifier spec1 = new PlanPhaseSpecifier("Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
@@ -341,7 +341,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
// Create entitlement and check each field
testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
- final Entitlement baseEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement baseEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
clock.addDays(1);
@@ -416,7 +416,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
// Create entitlement
testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, null);
- final Entitlement baseEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement baseEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
// Get the phase event out of the way
@@ -507,7 +507,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
// Create entitlement (with migrated flag so we can check later that transferred subscription is in right status)
testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
- final Entitlement baseEntitlement = entitlementApi.createBaseEntitlement(accountSrc.getId(), spec, accountSrc.getExternalKey(), null, null, null, true, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement baseEntitlement = entitlementApi.createBaseEntitlement(accountSrc.getId(), spec, accountSrc.getExternalKey(), null, null, null, true, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
assertEquals(baseEntitlement.getSourceType(), EntitlementSourceType.MIGRATED);
// Again to make sure this flag is correctly wrote/set
@@ -555,7 +555,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
// Keep the same object for the whole test, to make sure we refresh its state before r/w calls
testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.PHASE);
- final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, initialDate, initialDate, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, initialDate, initialDate, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
assertEquals(entitlement.getAccountId(), account.getId());
@@ -601,7 +601,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
- Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, entitlementDate, billingDate, false, ImmutableList.<PluginProperty>of(), callContext);
+ Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, entitlementDate, billingDate, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
assertEquals(entitlement.getState(), EntitlementState.PENDING);
@@ -659,7 +659,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
testListener.pushExpectedEvents(NextEvent.CREATE);
- final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, entitlementDate, billingDate, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, entitlementDate, billingDate, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
assertEquals(entitlement.getState(), EntitlementState.PENDING);
@@ -686,7 +686,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
testListener.pushExpectedEvents(NextEvent.BLOCK);
- final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, entitlementDate, billingDate, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, entitlementDate, billingDate, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
assertEquals(entitlement.getState(), EntitlementState.ACTIVE);
@@ -710,7 +710,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
testListener.pushExpectedEvents(NextEvent.BLOCK, NextEvent.CREATE);
- final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, entitlementDate, billingDate, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, entitlementDate, billingDate, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
assertEquals(entitlement.getState(), EntitlementState.ACTIVE);
@@ -730,7 +730,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
testListener.pushExpectedEvents(NextEvent.BLOCK, NextEvent.CREATE);
- final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, entitlementDate, billingDate, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, entitlementDate, billingDate, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
assertEquals(entitlement.getState(), EntitlementState.ACTIVE);
@@ -750,7 +750,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
testListener.pushExpectedEvents(NextEvent.BLOCK, NextEvent.CREATE);
- final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, entitlementDate, billingDate, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, entitlementDate, billingDate, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
assertEquals(entitlement.getState(), EntitlementState.ACTIVE);
@@ -768,7 +768,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
final String bundleKey2 = "bundleKey2";
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
testListener.pushExpectedEvents(NextEvent.BLOCK, NextEvent.CREATE);
- entitlementApi.createBaseEntitlement(account.getId(), spec, bundleKey2, null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ entitlementApi.createBaseEntitlement(account.getId(), spec, bundleKey2, null, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
@@ -790,7 +790,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
// We expect 3 {BLOCK, CREATE} events for the 3 subscriptions created,.
testListener.pushExpectedEvents(NextEvent.BLOCK, NextEvent.CREATE, NextEvent.BLOCK, NextEvent.CREATE, NextEvent.BLOCK, NextEvent.CREATE);
- final List<Entitlement> entitlements = entitlementApi.createBaseEntitlementsWithAddOns(account.getId(), baseEntitlementWithAddOnsSpecifiers, ImmutableList.<PluginProperty>of(), callContext);
+ final List<Entitlement> entitlements = entitlementApi.createBaseEntitlementsWithAddOns(account.getId(), baseEntitlementWithAddOnsSpecifiers, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
// Retun only the created subscriptions
@@ -821,7 +821,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
final Iterable<BaseEntitlementWithAddOnsSpecifier> baseEntitlementWithAddOnsSpecifiers = ImmutableList.of(baseEntitlementWithAddOnsSpecifier2);
- entitlementApi.createBaseEntitlementsWithAddOns(account.getId(), baseEntitlementWithAddOnsSpecifiers, ImmutableList.<PluginProperty>of(), callContext);
+ entitlementApi.createBaseEntitlementsWithAddOns(account.getId(), baseEntitlementWithAddOnsSpecifiers, true, ImmutableList.<PluginProperty>of(), callContext);
}
@Test(groups = "slow")
@@ -841,7 +841,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
testListener.pushExpectedEvents(NextEvent.BLOCK, NextEvent.CREATE, NextEvent.BLOCK, NextEvent.CREATE);
- entitlementApi.createBaseEntitlementsWithAddOns(account.getId(), baseEntitlementWithAddOnsSpecifiers, ImmutableList.<PluginProperty>of(), callContext);
+ entitlementApi.createBaseEntitlementsWithAddOns(account.getId(), baseEntitlementWithAddOnsSpecifiers, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
}
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionApi.java b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionApi.java
index c73dcdb..6fca4f6 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionApi.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionApi.java
@@ -61,14 +61,14 @@ public class TestDefaultSubscriptionApi extends EntitlementTestSuiteWithEmbedded
final Account account = createAccount(getAccountData(7));
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
- final Entitlement entitlement1 = entitlementApi.createBaseEntitlement(account.getId(), spec, UUID.randomUUID().toString(), null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement entitlement1 = entitlementApi.createBaseEntitlement(account.getId(), spec, UUID.randomUUID().toString(), null, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
// Sleep 1 sec so created date are apart from each other and ordering in the bundle does not default on the UUID which is random.
try {
Thread.sleep(1000);
} catch (InterruptedException ignore) {
}
testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
- final Entitlement entitlement2 = entitlementApi.createBaseEntitlement(account.getId(), spec, UUID.randomUUID().toString(), null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement entitlement2 = entitlementApi.createBaseEntitlement(account.getId(), spec, UUID.randomUUID().toString(), null, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
testListener.pushExpectedEvents(NextEvent.BLOCK);
@@ -114,7 +114,7 @@ public class TestDefaultSubscriptionApi extends EntitlementTestSuiteWithEmbedded
// Create entitlement and check each field
testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
- final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, externalKey, null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, externalKey, null, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
assertEquals(entitlement.getAccountId(), account.getId());
assertEquals(entitlement.getExternalKey(), externalKey);
@@ -148,7 +148,7 @@ public class TestDefaultSubscriptionApi extends EntitlementTestSuiteWithEmbedded
// Create entitlement and check each field
testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
- final Entitlement entitlement2 = entitlementApi.createBaseEntitlement(account.getId(), spec2, externalKey, null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement entitlement2 = entitlementApi.createBaseEntitlement(account.getId(), spec2, externalKey, null, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
assertEquals(entitlement2.getAccountId(), account.getId());
assertEquals(entitlement2.getExternalKey(), externalKey);
@@ -219,7 +219,7 @@ public class TestDefaultSubscriptionApi extends EntitlementTestSuiteWithEmbedded
// Create entitlement
testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, null);
- final Entitlement baseEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement baseEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
// Get the phase event out of the way
@@ -277,7 +277,7 @@ public class TestDefaultSubscriptionApi extends EntitlementTestSuiteWithEmbedded
final LocalDate effectiveDate = initialDate.plusMonths(1);
// Create entitlement and check each field
- final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, externalKey, null, effectiveDate, effectiveDate, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, externalKey, null, effectiveDate, effectiveDate, false, true, ImmutableList.<PluginProperty>of(), callContext);
final Subscription subscription = subscriptionApi.getSubscriptionForEntitlementId(entitlement.getId(), callContext);
@@ -309,7 +309,7 @@ public class TestDefaultSubscriptionApi extends EntitlementTestSuiteWithEmbedded
final LocalDate futureDate = new LocalDate(2013, 9, 1);
// No CREATE event as this is set in the future
- final Entitlement createdEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, futureDate, futureDate, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement createdEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, futureDate, futureDate, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertEquals(createdEntitlement.getEffectiveStartDate().compareTo(futureDate), 0);
assertEquals(createdEntitlement.getEffectiveEndDate(), null);
@@ -337,7 +337,7 @@ public class TestDefaultSubscriptionApi extends EntitlementTestSuiteWithEmbedded
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, null);
testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
- final Entitlement createdEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, initialDate, initialDate, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement createdEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, initialDate, initialDate, false, true, ImmutableList.<PluginProperty>of(), callContext);
final Iterable<BlockingState> iterableForCreateState = subscriptionApi.getBlockingStates(account.getId(), ImmutableList.of(BlockingStateType.SUBSCRIPTION), null, OrderingType.ASCENDING, SubscriptionApi.ALL_EVENTS, callContext);
assertTrue(iterableForCreateState.iterator().hasNext());
@@ -412,7 +412,7 @@ public class TestDefaultSubscriptionApi extends EntitlementTestSuiteWithEmbedded
// Create entitlement and check each field
testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
- final Entitlement baseEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement baseEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
clock.addDays(5);
@@ -486,7 +486,7 @@ public class TestDefaultSubscriptionApi extends EntitlementTestSuiteWithEmbedded
// Create entitlement and check each field
testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
- final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
clock.addDays(1);
@@ -526,7 +526,7 @@ public class TestDefaultSubscriptionApi extends EntitlementTestSuiteWithEmbedded
// Create entitlement
testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, null);
- final Entitlement baseEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement baseEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
// 2013-08-10 : Stay in TRIAL to ensure IMMEDIATE billing policy is used
@@ -576,7 +576,7 @@ public class TestDefaultSubscriptionApi extends EntitlementTestSuiteWithEmbedded
final LocalDate effectiveDate = initialDate.plusMonths(1);
try {
- entitlementApi.createBaseEntitlement(account.getId(), spec, externalKey, null, effectiveDate, effectiveDate, false, ImmutableList.<PluginProperty>of(), callContext);
+ entitlementApi.createBaseEntitlement(account.getId(), spec, externalKey, null, effectiveDate, effectiveDate, false, true, ImmutableList.<PluginProperty>of(), callContext);
Assert.fail();
} catch (final EntitlementApiException e) {
assertEquals(e.getCode(), ErrorCode.EXTERNAL_KEY_LIMIT_EXCEEDED.getCode());
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestRegessionSubscriptionApi.java b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestRegessionSubscriptionApi.java
index ae12fdc..6576c09 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestRegessionSubscriptionApi.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestRegessionSubscriptionApi.java
@@ -65,7 +65,7 @@ public class TestRegessionSubscriptionApi extends EntitlementTestSuiteWithEmbedd
final Account account = createAccount(getAccountData(7));
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
- final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, UUID.randomUUID().toString(), null, entitlementEffectiveDate, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, UUID.randomUUID().toString(), null, entitlementEffectiveDate, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
// Because of the BlockingState event ENT_STARTED, the entitlement date should be correctly set
Assert.assertEquals(entitlement.getEffectiveStartDate(), entitlementEffectiveDate);
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/block/TestBlockingApi.java b/entitlement/src/test/java/org/killbill/billing/entitlement/block/TestBlockingApi.java
index d3283b8..4ffb21b 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/block/TestBlockingApi.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/block/TestBlockingApi.java
@@ -143,7 +143,7 @@ public class TestBlockingApi extends EntitlementTestSuiteWithEmbeddedDB {
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, null);
testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
- Entitlement baseEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ Entitlement baseEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
assertEquals(baseEntitlement.getState(), EntitlementState.BLOCKED);
@@ -204,7 +204,7 @@ public class TestBlockingApi extends EntitlementTestSuiteWithEmbeddedDB {
// Try create subscription right now
try {
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("shotgun-monthly", null);
- entitlementApi.createBaseEntitlement(account.getId(), spec, "xyzqe", null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ entitlementApi.createBaseEntitlement(account.getId(), spec, "xyzqe", null, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
fail("Should fail to create entitlement when ACCOUNT has been 'change' blocked");
} catch (final EntitlementApiException e) {
assertEquals(e.getCode(), ErrorCode.BLOCK_BLOCKED_ACTION.getCode());
@@ -213,7 +213,7 @@ public class TestBlockingApi extends EntitlementTestSuiteWithEmbeddedDB {
// Try create subscription in the future
try {
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("shotgun-monthly", null);
- entitlementApi.createBaseEntitlement(account.getId(), spec, "xyzqe", null, initialDate.plusDays(3), null, false, ImmutableList.<PluginProperty>of(), callContext);
+ entitlementApi.createBaseEntitlement(account.getId(), spec, "xyzqe", null, initialDate.plusDays(3), null, false, true, ImmutableList.<PluginProperty>of(), callContext);
fail("Should fail to create entitlement when ACCOUNT has been 'change' blocked");
} catch (final EntitlementApiException e) {
assertEquals(e.getCode(), ErrorCode.BLOCK_BLOCKED_ACTION.getCode());
@@ -222,7 +222,7 @@ public class TestBlockingApi extends EntitlementTestSuiteWithEmbeddedDB {
// Try create subscription in the past
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("shotgun-monthly", null);
testListener.pushExpectedEvents(NextEvent.BLOCK, NextEvent.CREATE);
- entitlementApi.createBaseEntitlement(account.getId(), spec, "xyzqe", null, initialDate.minusDays(3), null, false, ImmutableList.<PluginProperty>of(), callContext);
+ entitlementApi.createBaseEntitlement(account.getId(), spec, "xyzqe", null, initialDate.minusDays(3), null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
}
@@ -235,7 +235,7 @@ public class TestBlockingApi extends EntitlementTestSuiteWithEmbeddedDB {
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("shotgun-monthly", null);
testListener.pushExpectedEvents(NextEvent.BLOCK, NextEvent.CREATE);
- final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, "xyzqe", null, initialDate.minusDays(3), null, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, "xyzqe", null, initialDate.minusDays(3), null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
testListener.pushExpectedEvent(NextEvent.BLOCK);
@@ -277,7 +277,7 @@ public class TestBlockingApi extends EntitlementTestSuiteWithEmbeddedDB {
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("shotgun-monthly", null);
testListener.pushExpectedEvents(NextEvent.BLOCK, NextEvent.CREATE);
- final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, "xyzqe", null, initialDate.minusDays(3), null, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, "xyzqe", null, initialDate.minusDays(3), null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
// Create future BlockingState
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/dao/TestDefaultBlockingStateDao.java b/entitlement/src/test/java/org/killbill/billing/entitlement/dao/TestDefaultBlockingStateDao.java
index c15abba..519e758 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/dao/TestDefaultBlockingStateDao.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/dao/TestDefaultBlockingStateDao.java
@@ -60,7 +60,7 @@ public class TestDefaultBlockingStateDao extends EntitlementTestSuiteWithEmbedde
// See TestEntitlementUtils for a more comprehensive test
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
- final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
final BlockingStateType type = BlockingStateType.SUBSCRIPTION;
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/engine/core/TestEntitlementUtils.java b/entitlement/src/test/java/org/killbill/billing/entitlement/engine/core/TestEntitlementUtils.java
index fd0d5b7..d2406a5 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/engine/core/TestEntitlementUtils.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/engine/core/TestEntitlementUtils.java
@@ -73,7 +73,7 @@ public class TestEntitlementUtils extends EntitlementTestSuiteWithEmbeddedDB {
// Create base entitlement
testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
final PlanPhaseSpecifier baseSpec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
- baseEntitlement = (DefaultEntitlement) entitlementApi.createBaseEntitlement(account.getId(), baseSpec, account.getExternalKey(), null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ baseEntitlement = (DefaultEntitlement) entitlementApi.createBaseEntitlement(account.getId(), baseSpec, account.getExternalKey(), null, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
// Add ADD_ON
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/EntitlementTestSuiteWithEmbeddedDB.java b/entitlement/src/test/java/org/killbill/billing/entitlement/EntitlementTestSuiteWithEmbeddedDB.java
index 9f6f218..120548c 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/EntitlementTestSuiteWithEmbeddedDB.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/EntitlementTestSuiteWithEmbeddedDB.java
@@ -140,9 +140,6 @@ public class EntitlementTestSuiteWithEmbeddedDB extends GuicyKillbillTestSuiteWi
startTestFamework(testListener, clock, busService, subscriptionBaseService, entitlementService);
this.catalog = initCatalog(catalogService);
- // Make sure we start with a clean state
- assertListenerStatus();
-
configureShiro();
login("EntitlementUser");
}
@@ -174,12 +171,8 @@ public class EntitlementTestSuiteWithEmbeddedDB extends GuicyKillbillTestSuiteWi
@AfterMethod(groups = "slow")
public void afterMethod() throws Exception {
-
securityApi.logout();
- // Make sure we finish in a clean state
- assertListenerStatus();
-
stopTestFramework(testListener, busService, subscriptionBaseService, entitlementService);
}
@@ -289,6 +282,7 @@ public class EntitlementTestSuiteWithEmbeddedDB extends GuicyKillbillTestSuiteWi
return account;
}
+ @Override
protected void assertListenerStatus() {
testListener.assertListenerStatus();
}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/api/InvoiceApiHelper.java b/invoice/src/main/java/org/killbill/billing/invoice/api/InvoiceApiHelper.java
index 047f073..5b8cbe7 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/api/InvoiceApiHelper.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/api/InvoiceApiHelper.java
@@ -82,10 +82,11 @@ public class InvoiceApiHelper {
final Iterable<Invoice> invoicesForPlugins = withAccountLock.prepareInvoices();
+ final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(accountId, context);
final List<InvoiceModelDao> invoiceModelDaos = new LinkedList<InvoiceModelDao>();
for (final Invoice invoiceForPlugin : invoicesForPlugins) {
// Call plugin
- final List<InvoiceItem> additionalInvoiceItems = invoicePluginDispatcher.getAdditionalInvoiceItems(invoiceForPlugin, isDryRun, context);
+ final List<InvoiceItem> additionalInvoiceItems = invoicePluginDispatcher.getAdditionalInvoiceItems(invoiceForPlugin, isDryRun, context, internalCallContext);
invoiceForPlugin.addInvoiceItems(additionalInvoiceItems);
// Transformation to InvoiceModelDao
@@ -98,7 +99,6 @@ public class InvoiceApiHelper {
invoiceModelDaos.add(invoiceModelDao);
}
- final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(accountId, context);
final List<InvoiceItemModelDao> createdInvoiceItems = dao.createInvoices(invoiceModelDaos, internalCallContext);
return fromInvoiceItemModelDao(createdInvoiceItems);
} catch (final LockFailedException e) {
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/config/MultiTenantInvoiceConfig.java b/invoice/src/main/java/org/killbill/billing/invoice/config/MultiTenantInvoiceConfig.java
index 45de5f6..ba2e1e0 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/config/MultiTenantInvoiceConfig.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/config/MultiTenantInvoiceConfig.java
@@ -17,6 +17,8 @@
package org.killbill.billing.invoice.config;
+import java.util.List;
+
import javax.inject.Inject;
import javax.inject.Named;
@@ -119,6 +121,20 @@ public class MultiTenantInvoiceConfig extends MultiTenantConfigBase implements I
}
@Override
+ public List<String> getInvoicePluginNames() {
+ return staticConfig.getInvoicePluginNames();
+ }
+
+ @Override
+ public List<String> getInvoicePluginNames(final InternalTenantContext tenantContext) {
+ final String result = getStringTenantConfig("getInvoicePluginNames", tenantContext);
+ if (result != null) {
+ return convertToListString(result, "getInvoicePluginNames");
+ }
+ return getInvoicePluginNames();
+ }
+
+ @Override
public boolean isInvoicingSystemEnabled() {
return staticConfig.isInvoicingSystemEnabled();
}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/dao/DefaultInvoiceDao.java b/invoice/src/main/java/org/killbill/billing/invoice/dao/DefaultInvoiceDao.java
index f7802ed..75d4550 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/dao/DefaultInvoiceDao.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/dao/DefaultInvoiceDao.java
@@ -41,6 +41,7 @@ import org.killbill.billing.catalog.api.Currency;
import org.killbill.billing.entity.EntityPersistenceException;
import org.killbill.billing.invoice.InvoiceDispatcher.FutureAccountNotifications;
import org.killbill.billing.invoice.InvoiceDispatcher.FutureAccountNotifications.SubscriptionNotification;
+import org.killbill.billing.invoice.InvoicePluginDispatcher;
import org.killbill.billing.invoice.api.DefaultInvoicePaymentErrorEvent;
import org.killbill.billing.invoice.api.DefaultInvoicePaymentInfoEvent;
import org.killbill.billing.invoice.api.Invoice;
@@ -276,17 +277,6 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
}
@Override
- public InvoiceModelDao getEarliestDraftInvoiceByAccount(final InternalTenantContext context) {
- return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<InvoiceModelDao>() {
- @Override
- public InvoiceModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
- final InvoiceSqlDao invoiceDao = entitySqlDaoWrapperFactory.become(InvoiceSqlDao.class);
- return invoiceDao.getEarliestDraftInvoiceByAccount(context);
- }
- });
- }
-
- @Override
public void createInvoice(final InvoiceModelDao invoice,
final FutureAccountNotifications callbackDateTimePerSubscriptions,
final InternalCallContext context) {
@@ -351,9 +341,15 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
// Create the invoice items if needed (note: they may not necessarily belong to that invoice)
for (final InvoiceItemModelDao invoiceItemModelDao : invoiceModelDao.getInvoiceItems()) {
- if (transInvoiceItemSqlDao.getById(invoiceItemModelDao.getId().toString(), context) == null) {
+ final InvoiceItemModelDao existingInvoiceItem = transInvoiceItemSqlDao.getById(invoiceItemModelDao.getId().toString(), context);
+ if (existingInvoiceItem == null) {
createdInvoiceItems.add(createInvoiceItemFromTransaction(transInvoiceItemSqlDao, invoiceItemModelDao, context));
allInvoiceIds.add(invoiceItemModelDao.getInvoiceId());
+ } else if (InvoicePluginDispatcher.ALLOWED_INVOICE_ITEM_TYPES.contains(invoiceItemModelDao.getType()) &&
+ (invoiceItemModelDao.getAmount().compareTo(existingInvoiceItem.getAmount()) != 0)) {
+ checkAgainstExistingInvoiceItemState(existingInvoiceItem, invoiceItemModelDao);
+
+ transInvoiceItemSqlDao.updateAmount(invoiceItemModelDao.getId().toString(), invoiceItemModelDao.getAmount(), context);
}
}
@@ -1307,4 +1303,49 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
private List<Tag> getInvoicesTags(final InternalTenantContext context) {
return tagInternalApi.getTagsForAccountType(ObjectType.INVOICE, false, context);
}
+
+ private static void checkAgainstExistingInvoiceItemState(final InvoiceItemModelDao existingInvoiceItem, final InvoiceItemModelDao inputInvoiceItem) {
+ Preconditions.checkState(existingInvoiceItem.getAccountId().equals(inputInvoiceItem.getAccountId()), String.format("Unexpected account ID '%s' for invoice item '%s'",
+ inputInvoiceItem.getAccountId(), existingInvoiceItem.getId()));
+ if (existingInvoiceItem.getChildAccountId() != null) {
+ Preconditions.checkState(existingInvoiceItem.getChildAccountId().equals(inputInvoiceItem.getChildAccountId()), String.format("Unexpected child account ID '%s' for invoice item '%s'",
+ inputInvoiceItem.getChildAccountId(), existingInvoiceItem.getId()));
+ }
+ Preconditions.checkState(existingInvoiceItem.getInvoiceId().equals(inputInvoiceItem.getInvoiceId()), String.format("Unexpected invoice ID '%s' for invoice item '%s'",
+ inputInvoiceItem.getInvoiceId(), existingInvoiceItem.getId()));
+ if (existingInvoiceItem.getBundleId() != null) {
+ Preconditions.checkState(existingInvoiceItem.getBundleId().equals(inputInvoiceItem.getBundleId()), String.format("Unexpected bundle ID '%s' for invoice item '%s'",
+ inputInvoiceItem.getBundleId(), existingInvoiceItem.getId()));
+ }
+ if (existingInvoiceItem.getSubscriptionId() != null) {
+ Preconditions.checkState(existingInvoiceItem.getSubscriptionId().equals(inputInvoiceItem.getSubscriptionId()), String.format("Unexpected subscription ID '%s' for invoice item '%s'",
+ inputInvoiceItem.getSubscriptionId(), existingInvoiceItem.getId()));
+ }
+ if (existingInvoiceItem.getPlanName() != null) {
+ Preconditions.checkState(existingInvoiceItem.getPlanName().equals(inputInvoiceItem.getPlanName()), String.format("Unexpected plan name '%s' for invoice item '%s'",
+ inputInvoiceItem.getPlanName(), existingInvoiceItem.getId()));
+ }
+ if (existingInvoiceItem.getPhaseName() != null) {
+ Preconditions.checkState(existingInvoiceItem.getPhaseName().equals(inputInvoiceItem.getPhaseName()), String.format("Unexpected phase name '%s' for invoice item '%s'",
+ inputInvoiceItem.getPhaseName(), existingInvoiceItem.getId()));
+ }
+ if (existingInvoiceItem.getUsageName() != null) {
+ Preconditions.checkState(existingInvoiceItem.getUsageName().equals(inputInvoiceItem.getUsageName()), String.format("Unexpected usage name '%s' for invoice item '%s'",
+ inputInvoiceItem.getUsageName(), existingInvoiceItem.getId()));
+ }
+ if (existingInvoiceItem.getStartDate() != null) {
+ Preconditions.checkState(existingInvoiceItem.getStartDate().equals(inputInvoiceItem.getStartDate()), String.format("Unexpected startDate '%s' for invoice item '%s'",
+ inputInvoiceItem.getStartDate(), existingInvoiceItem.getId()));
+ }
+ if (existingInvoiceItem.getEndDate() != null) {
+ Preconditions.checkState(existingInvoiceItem.getEndDate().equals(inputInvoiceItem.getEndDate()), String.format("Unexpected endDate '%s' for invoice item '%s'",
+ inputInvoiceItem.getEndDate(), existingInvoiceItem.getId()));
+ }
+
+ Preconditions.checkState(existingInvoiceItem.getCurrency() == inputInvoiceItem.getCurrency(), String.format("Unexpected currency '%s' for invoice item '%s'",
+ inputInvoiceItem.getCurrency(), existingInvoiceItem.getId()));
+ Preconditions.checkState(existingInvoiceItem.getType() == inputInvoiceItem.getType(), String.format("Unexpected item type '%s' for invoice item '%s'",
+ inputInvoiceItem.getType(), existingInvoiceItem.getId()));
+ }
+
}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceDao.java b/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceDao.java
index 3f12d60..377b150 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceDao.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceDao.java
@@ -48,8 +48,6 @@ public interface InvoiceDao extends EntityDao<InvoiceModelDao, Invoice, InvoiceA
public void setFutureAccountNotificationsForEmptyInvoice(final UUID accountId, final FutureAccountNotifications callbackDateTimePerSubscriptions,
final InternalCallContext context);
- InvoiceModelDao getEarliestDraftInvoiceByAccount(InternalTenantContext context);
-
InvoiceModelDao getByNumber(Integer number, InternalTenantContext context) throws InvoiceApiException;
List<InvoiceModelDao> getInvoicesByAccount(InternalTenantContext context);
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceSqlDao.java b/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceSqlDao.java
index 3acaab5..fe3e080 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceSqlDao.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceSqlDao.java
@@ -52,6 +52,7 @@ public interface InvoiceSqlDao extends EntitySqlDao<InvoiceModelDao, Invoice> {
@Bind("status") String status,
@SmartBindBean final InternalCallContext context);
+
@SqlQuery
InvoiceModelDao getParentDraftInvoice(@Bind("accountId") final String parentAccountId,
@SmartBindBean final InternalTenantContext context);
@@ -59,8 +60,5 @@ public interface InvoiceSqlDao extends EntitySqlDao<InvoiceModelDao, Invoice> {
@SqlQuery
List<InvoiceModelDao> getByIds(@BindIn("ids") final Collection<String> invoiceIds,
@SmartBindBean final InternalTenantContext context);
- @SqlQuery
- InvoiceModelDao getEarliestDraftInvoiceByAccount(@SmartBindBean final InternalTenantContext context);
-
}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/generator/DefaultInvoiceGenerator.java b/invoice/src/main/java/org/killbill/billing/invoice/generator/DefaultInvoiceGenerator.java
index 69bb538..2e46d79 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/generator/DefaultInvoiceGenerator.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/generator/DefaultInvoiceGenerator.java
@@ -43,7 +43,10 @@ import org.killbill.billing.util.config.definition.InvoiceConfig;
import org.killbill.clock.Clock;
import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
import com.google.inject.Inject;
public class DefaultInvoiceGenerator implements InvoiceGenerator {
@@ -68,7 +71,7 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
@Override
public InvoiceWithMetadata generateInvoice(final ImmutableAccountData account,
@Nullable final BillingEventSet events,
- @Nullable final List<Invoice> existingInvoices,
+ @Nullable final Iterable<Invoice> existingInvoices,
@Nullable final UUID targetInvoiceId,
final LocalDate targetDate,
final Currency targetCurrency,
@@ -94,6 +97,16 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
final List<InvoiceItem> usageItems = usageInvoiceItemGenerator.generateItems(account, invoice.getId(), events, existingInvoices, adjustedTargetDate, targetCurrency, perSubscriptionFutureNotificationDates, context);
invoice.addInvoiceItems(usageItems);
+ if (targetInvoiceId != null) {
+ final Invoice originalInvoice = Iterables.tryFind(existingInvoices, new Predicate<Invoice>() {
+ @Override
+ public boolean apply(final Invoice input) {
+ return input.getId().equals(targetInvoiceId);
+ }
+ }).orNull();
+ Preconditions.checkNotNull(originalInvoice, "Expecting to find an existing invoice matching the targetInvoiceId");
+ invoice.addInvoiceItems(originalInvoice.getInvoiceItems());
+ }
return new InvoiceWithMetadata(invoice.getInvoiceItems().isEmpty() ? null : invoice, perSubscriptionFutureNotificationDates);
}
@@ -106,7 +119,7 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
}
}
- private LocalDate adjustTargetDate(final List<Invoice> existingInvoices, final LocalDate targetDate) {
+ private LocalDate adjustTargetDate(final Iterable<Invoice> existingInvoices, final LocalDate targetDate) {
if (existingInvoices == null) {
return targetDate;
}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/generator/FixedAndRecurringInvoiceItemGenerator.java b/invoice/src/main/java/org/killbill/billing/invoice/generator/FixedAndRecurringInvoiceItemGenerator.java
index 6ff69c5..c73adba 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/generator/FixedAndRecurringInvoiceItemGenerator.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/generator/FixedAndRecurringInvoiceItemGenerator.java
@@ -83,7 +83,7 @@ public class FixedAndRecurringInvoiceItemGenerator extends InvoiceItemGenerator
}
public List<InvoiceItem> generateItems(final ImmutableAccountData account, final UUID invoiceId, final BillingEventSet eventSet,
- @Nullable final List<Invoice> existingInvoices, final LocalDate targetDate,
+ @Nullable final Iterable<Invoice> existingInvoices, final LocalDate targetDate,
final Currency targetCurrency, final Map<UUID, SubscriptionFutureNotificationDates> perSubscriptionFutureNotificationDate,
final InternalCallContext internalCallContext) throws InvoiceApiException {
final Multimap<UUID, LocalDate> createdItemsPerDayPerSubscription = LinkedListMultimap.<UUID, LocalDate>create();
@@ -105,7 +105,7 @@ public class FixedAndRecurringInvoiceItemGenerator extends InvoiceItemGenerator
// Generate list of proposed invoice items based on billing events from junction-- proposed items are ALL items since beginning of time
final List<InvoiceItem> proposedItems = new ArrayList<InvoiceItem>();
- processRecurringBillingEvents(invoiceId, account.getId(), eventSet, targetDate, targetCurrency, proposedItems, perSubscriptionFutureNotificationDate, existingInvoices, internalCallContext);
+ processRecurringBillingEvents(invoiceId, account.getId(), eventSet, targetDate, targetCurrency, proposedItems, perSubscriptionFutureNotificationDate, internalCallContext);
processFixedBillingEvents(invoiceId, account.getId(), eventSet, targetDate, targetCurrency, proposedItems, internalCallContext);
try {
@@ -124,7 +124,6 @@ public class FixedAndRecurringInvoiceItemGenerator extends InvoiceItemGenerator
private void processRecurringBillingEvents(final UUID invoiceId, final UUID accountId, final BillingEventSet events,
final LocalDate targetDate, final Currency currency, final List<InvoiceItem> proposedItems,
final Map<UUID, SubscriptionFutureNotificationDates> perSubscriptionFutureNotificationDate,
- @Nullable final List<Invoice> existingInvoices,
final InternalCallContext internalCallContext) throws InvoiceApiException {
if (events.isEmpty()) {
return;
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/generator/InvoiceGenerator.java b/invoice/src/main/java/org/killbill/billing/invoice/generator/InvoiceGenerator.java
index fac2799..062be76 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/generator/InvoiceGenerator.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/generator/InvoiceGenerator.java
@@ -31,6 +31,6 @@ import org.killbill.billing.invoice.api.InvoiceApiException;
import org.killbill.billing.junction.BillingEventSet;
public interface InvoiceGenerator {
- InvoiceWithMetadata generateInvoice(ImmutableAccountData account, @Nullable BillingEventSet events, @Nullable List<Invoice> existingInvoices,
+ InvoiceWithMetadata generateInvoice(ImmutableAccountData account, @Nullable BillingEventSet events, @Nullable Iterable<Invoice> existingInvoices,
final UUID targetInvoiceId, LocalDate targetDate, Currency targetCurrency, final InternalCallContext context) throws InvoiceApiException;
}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/generator/InvoiceItemGenerator.java b/invoice/src/main/java/org/killbill/billing/invoice/generator/InvoiceItemGenerator.java
index eb2ce88..826a1b5 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/generator/InvoiceItemGenerator.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/generator/InvoiceItemGenerator.java
@@ -38,7 +38,7 @@ import org.slf4j.Logger;
public abstract class InvoiceItemGenerator {
public abstract List<InvoiceItem> generateItems(final ImmutableAccountData account, final UUID invoiceId, final BillingEventSet eventSet,
- @Nullable final List<Invoice> existingInvoices, final LocalDate targetDate,
+ @Nullable final Iterable<Invoice> existingInvoices, final LocalDate targetDate,
final Currency targetCurrency, Map<UUID, SubscriptionFutureNotificationDates> perSubscriptionFutureNotificationDate,
final InternalCallContext context) throws InvoiceApiException;
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/generator/UsageInvoiceItemGenerator.java b/invoice/src/main/java/org/killbill/billing/invoice/generator/UsageInvoiceItemGenerator.java
index eb18aaa..64e6c4c 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/generator/UsageInvoiceItemGenerator.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/generator/UsageInvoiceItemGenerator.java
@@ -71,7 +71,7 @@ public class UsageInvoiceItemGenerator extends InvoiceItemGenerator {
public List<InvoiceItem> generateItems(final ImmutableAccountData account,
final UUID invoiceId,
final BillingEventSet eventSet,
- @Nullable final List<Invoice> existingInvoices,
+ @Nullable final Iterable<Invoice> existingInvoices,
final LocalDate targetDate,
final Currency targetCurrency,
final Map<UUID, SubscriptionFutureNotificationDates> perSubscriptionFutureNotificationDates,
@@ -170,8 +170,8 @@ public class UsageInvoiceItemGenerator extends InvoiceItemGenerator {
}
}
- private Map<UUID, List<InvoiceItem>> extractPerSubscriptionExistingInArrearUsageItems(final Map<String, Usage> knownUsage, @Nullable final List<Invoice> existingInvoices) {
- if (existingInvoices == null || existingInvoices.isEmpty()) {
+ private Map<UUID, List<InvoiceItem>> extractPerSubscriptionExistingInArrearUsageItems(final Map<String, Usage> knownUsage, @Nullable final Iterable<Invoice> existingInvoices) {
+ if (existingInvoices == null || Iterables.isEmpty(existingInvoices)) {
return ImmutableMap.of();
}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java b/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
index d55ebac..46d742e 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
@@ -363,20 +363,20 @@ public class InvoiceDispatcher {
}
private Invoice processAccountWithLockAndInputTargetDate(final UUID accountId, final LocalDate targetDate,
- final BillingEventSet billingEvents, final boolean isDryRun, final InternalCallContext context) throws InvoiceApiException {
+ final BillingEventSet billingEvents, final boolean isDryRun, final InternalCallContext internalCallContext) throws InvoiceApiException {
final ImmutableAccountData account;
try {
- account = accountApi.getImmutableAccountDataById(accountId, context);
+ account = accountApi.getImmutableAccountDataById(accountId, internalCallContext);
} catch (final AccountApiException e) {
log.error("Unable to generate invoice for accountId='{}', a future notification has NOT been recorded", accountId, e);
return null;
}
- final InvoiceWithMetadata invoiceWithMetadata = generateKillBillInvoice(account, targetDate, billingEvents, context);
+ final InvoiceWithMetadata invoiceWithMetadata = generateKillBillInvoice(account, targetDate, billingEvents, internalCallContext);
final DefaultInvoice invoice = invoiceWithMetadata.getInvoice();
// Compute future notifications
- final FutureAccountNotifications futureAccountNotifications = createNextFutureNotificationDate(invoiceWithMetadata, context);
+ final FutureAccountNotifications futureAccountNotifications = createNextFutureNotificationDate(invoiceWithMetadata, internalCallContext);
// If invoice comes back null, there is nothing new to generate, we can bail early
if (invoice == null) {
@@ -386,9 +386,9 @@ public class InvoiceDispatcher {
log.info("Generated null invoice for accountId='{}', targetDate='{}'", accountId, targetDate);
final BusInternalEvent event = new DefaultNullInvoiceEvent(accountId, clock.getUTCToday(),
- context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken());
+ internalCallContext.getAccountRecordId(), internalCallContext.getTenantRecordId(), internalCallContext.getUserToken());
- commitInvoiceAndSetFutureNotifications(account, null, futureAccountNotifications, context);
+ commitInvoiceAndSetFutureNotifications(account, null, futureAccountNotifications, internalCallContext);
postEvent(event);
}
return null;
@@ -397,7 +397,7 @@ public class InvoiceDispatcher {
boolean success = false;
try {
// Generate missing credit (> 0 for generation and < 0 for use) prior we call the plugin
- final InvoiceItem cbaItemPreInvoicePlugins = computeCBAOnExistingInvoice(invoice, context);
+ final InvoiceItem cbaItemPreInvoicePlugins = computeCBAOnExistingInvoice(invoice, internalCallContext);
DefaultInvoice tmpInvoiceForInvoicePlugins = invoice;
if (cbaItemPreInvoicePlugins != null) {
tmpInvoiceForInvoicePlugins = (DefaultInvoice) tmpInvoiceForInvoicePlugins.clone();
@@ -406,17 +406,31 @@ public class InvoiceDispatcher {
//
// Ask external invoice plugins if additional items (tax, etc) shall be added to the invoice
//
- final CallContext callContext = buildCallContext(context);
- final List<InvoiceItem> additionalInvoiceItemsFromPlugins = invoicePluginDispatcher.getAdditionalInvoiceItems(tmpInvoiceForInvoicePlugins, isDryRun, callContext);
+ final CallContext callContext = buildCallContext(internalCallContext);
+ final List<InvoiceItem> additionalInvoiceItemsFromPlugins = invoicePluginDispatcher.getAdditionalInvoiceItems(tmpInvoiceForInvoicePlugins, isDryRun, callContext, internalCallContext);
if (additionalInvoiceItemsFromPlugins.isEmpty()) {
// PERF: avoid re-computing the CBA if no change was made
if (cbaItemPreInvoicePlugins != null) {
invoice.addInvoiceItem(cbaItemPreInvoicePlugins);
}
} else {
- invoice.addInvoiceItems(additionalInvoiceItemsFromPlugins);
+
+ // Add or update items from generated invoice
+ for (final InvoiceItem cur : additionalInvoiceItemsFromPlugins) {
+ final InvoiceItem exitingItem = Iterables.tryFind(tmpInvoiceForInvoicePlugins.getInvoiceItems(), new Predicate<InvoiceItem>() {
+ @Override
+ public boolean apply(final InvoiceItem input) {
+ return input.getId().equals(cur.getId());
+ }
+ }).orNull();
+ if (exitingItem != null) {
+ invoice.removeInvoiceItem(exitingItem);
+ }
+ invoice.addInvoiceItem(cur);
+ }
+
// Use credit after we call the plugin (https://github.com/killbill/killbill/issues/637)
- final InvoiceItem cbaItemPostInvoicePlugins = computeCBAOnExistingInvoice(invoice, context);
+ final InvoiceItem cbaItemPostInvoicePlugins = computeCBAOnExistingInvoice(invoice, internalCallContext);
if (cbaItemPostInvoicePlugins != null) {
invoice.addInvoiceItem(cbaItemPostInvoicePlugins);
}
@@ -437,11 +451,11 @@ public class InvoiceDispatcher {
invoiceModelDao.addInvoiceItems(invoiceItemModelDaos);
// Commit invoice on disk
- commitInvoiceAndSetFutureNotifications(account, invoiceModelDao, futureAccountNotifications, context);
+ commitInvoiceAndSetFutureNotifications(account, invoiceModelDao, futureAccountNotifications, internalCallContext);
success = true;
try {
- setChargedThroughDates(invoice.getInvoiceItems(FixedPriceInvoiceItem.class), invoice.getInvoiceItems(RecurringInvoiceItem.class), context);
+ setChargedThroughDates(invoice.getInvoiceItems(FixedPriceInvoiceItem.class), invoice.getInvoiceItems(RecurringInvoiceItem.class), internalCallContext);
} catch (final SubscriptionBaseApiException e) {
log.error("Failed handling SubscriptionBase change.", e);
return null;
@@ -450,7 +464,7 @@ public class InvoiceDispatcher {
} finally {
// Make sure we always set future notifications in case of errors
if (!isDryRun && !success) {
- commitInvoiceAndSetFutureNotifications(account, null, futureAccountNotifications, context);
+ commitInvoiceAndSetFutureNotifications(account, null, futureAccountNotifications, internalCallContext);
}
}
@@ -467,17 +481,21 @@ public class InvoiceDispatcher {
return new DefaultInvoice(input);
}
}));
- final Currency targetCurrency = account.getCurrency();
-
final UUID targetInvoiceId;
+ // Filter out DRAFT invoices for computation of existing items unless Account is in AUTO_INVOICING_REUSE_DRAFT
if (billingEvents.isAccountAutoInvoiceReuseDraft()) {
- final InvoiceModelDao earliestDraftInvoice = invoiceDao.getEarliestDraftInvoiceByAccount(context);
- targetInvoiceId = earliestDraftInvoice != null ? earliestDraftInvoice.getId() : null;
+ final Invoice existingDraft = Iterables.tryFind(invoices, new Predicate<Invoice>() {
+ @Override
+ public boolean apply(final Invoice input) {
+ return input.getStatus() == InvoiceStatus.DRAFT;
+ }
+ }).orNull();
+ targetInvoiceId = existingDraft != null ? existingDraft.getId() : null;
} else {
targetInvoiceId = null;
}
- return generator.generateInvoice(account, billingEvents, invoices, targetInvoiceId, targetDate, targetCurrency, context);
+ return generator.generateInvoice(account, billingEvents, invoices, targetInvoiceId, targetDate, account.getCurrency(), context);
}
private FutureAccountNotifications createNextFutureNotificationDate(final InvoiceWithMetadata invoiceWithMetadata, final InternalCallContext context) {
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/InvoicePluginDispatcher.java b/invoice/src/main/java/org/killbill/billing/invoice/InvoicePluginDispatcher.java
index 82c62f5..45b12f8 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/InvoicePluginDispatcher.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/InvoicePluginDispatcher.java
@@ -21,10 +21,12 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
+import java.util.Set;
import javax.inject.Inject;
import org.killbill.billing.ErrorCode;
+import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.invoice.api.Invoice;
import org.killbill.billing.invoice.api.InvoiceApiException;
import org.killbill.billing.invoice.api.InvoiceItem;
@@ -34,36 +36,42 @@ import org.killbill.billing.invoice.plugin.api.InvoicePluginApi;
import org.killbill.billing.osgi.api.OSGIServiceRegistration;
import org.killbill.billing.payment.api.PluginProperty;
import org.killbill.billing.util.callcontext.CallContext;
+import org.killbill.billing.util.config.definition.InvoiceConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
public class InvoicePluginDispatcher {
private static final Logger log = LoggerFactory.getLogger(InvoicePluginDispatcher.class);
- private static final Collection<InvoiceItemType> ALLOWED_INVOICE_ITEM_TYPES = ImmutableList.<InvoiceItemType>of(InvoiceItemType.EXTERNAL_CHARGE,
+ public static final Collection<InvoiceItemType> ALLOWED_INVOICE_ITEM_TYPES = ImmutableList.<InvoiceItemType>of(InvoiceItemType.EXTERNAL_CHARGE,
InvoiceItemType.ITEM_ADJ,
InvoiceItemType.CREDIT_ADJ,
InvoiceItemType.TAX);
private final OSGIServiceRegistration<InvoicePluginApi> pluginRegistry;
+ private final InvoiceConfig invoiceConfig;
+
@Inject
- public InvoicePluginDispatcher(final OSGIServiceRegistration<InvoicePluginApi> pluginRegistry) {
+ public InvoicePluginDispatcher(final OSGIServiceRegistration<InvoicePluginApi> pluginRegistry,
+ final InvoiceConfig invoiceConfig) {
this.pluginRegistry = pluginRegistry;
+ this.invoiceConfig = invoiceConfig;
}
//
// If we have multiple plugins there is a question of plugin ordering and also a 'product' questions to decide whether
// subsequent plugins should have access to items added by previous plugins
//
- public List<InvoiceItem> getAdditionalInvoiceItems(final Invoice originalInvoice, final boolean isDryRun, final CallContext callContext) throws InvoiceApiException {
+ public List<InvoiceItem> getAdditionalInvoiceItems(final Invoice originalInvoice, final boolean isDryRun, final CallContext callContext, final InternalTenantContext tenantContext) throws InvoiceApiException {
// We clone the original invoice so plugins don't remove/add items
final Invoice clonedInvoice = (Invoice) ((DefaultInvoice) originalInvoice).clone();
final List<InvoiceItem> additionalInvoiceItems = new LinkedList<InvoiceItem>();
- final List<InvoicePluginApi> invoicePlugins = getInvoicePlugins();
+ final List<InvoicePluginApi> invoicePlugins = getInvoicePlugins(tenantContext);
for (final InvoicePluginApi invoicePlugin : invoicePlugins) {
final List<InvoiceItem> items = invoicePlugin.getAdditionalInvoiceItems(clonedInvoice, isDryRun, ImmutableList.<PluginProperty>of(), callContext);
if (items != null) {
@@ -83,11 +91,34 @@ public class InvoicePluginDispatcher {
}
}
- private List<InvoicePluginApi> getInvoicePlugins() {
+ private List<InvoicePluginApi> getInvoicePlugins(final InternalTenantContext tenantContext) {
+
+
+ final Collection<String> resultingPluginList = getResultingPluginNameList(tenantContext);
+
final List<InvoicePluginApi> invoicePlugins = new ArrayList<InvoicePluginApi>();
- for (final String name : pluginRegistry.getAllServices()) {
- invoicePlugins.add(pluginRegistry.getServiceForName(name));
+ for (final String name : resultingPluginList) {
+ final InvoicePluginApi serviceForName = pluginRegistry.getServiceForName(name);
+ invoicePlugins.add(serviceForName);
}
return invoicePlugins;
}
+
+ @VisibleForTesting
+ final Collection<String> getResultingPluginNameList(final InternalTenantContext tenantContext) {
+ final List<String> configuredPlugins = invoiceConfig.getInvoicePluginNames(tenantContext);
+ final Set<String> registeredPlugins = pluginRegistry.getAllServices();
+ // No configuration, we return undeterministic list of registered plugins
+ if (configuredPlugins == null || configuredPlugins.isEmpty()) {
+ return registeredPlugins;
+ } else {
+ final List<String> result = new ArrayList<String>(configuredPlugins.size());
+ for (final String name : configuredPlugins) {
+ if (pluginRegistry.getServiceForName(name) != null) {
+ result.add(name);
+ }
+ }
+ return result;
+ }
+ }
}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/model/DefaultInvoice.java b/invoice/src/main/java/org/killbill/billing/invoice/model/DefaultInvoice.java
index 4dcd360..bc4ccb0 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/model/DefaultInvoice.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/model/DefaultInvoice.java
@@ -142,6 +142,10 @@ public class DefaultInvoice extends EntityBase implements Invoice, Cloneable {
return invoiceItems.add(item);
}
+ public boolean removeInvoiceItem(final InvoiceItem item) {
+ return invoiceItems.remove(item);
+ }
+
@Override
public boolean addInvoiceItems(final Collection<InvoiceItem> items) {
return this.invoiceItems.addAll(items);
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/provider/DefaultNoOpInvoiceProviderPlugin.java b/invoice/src/main/java/org/killbill/billing/invoice/provider/DefaultNoOpInvoiceProviderPlugin.java
index 6b2883d..503d5e9 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/provider/DefaultNoOpInvoiceProviderPlugin.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/provider/DefaultNoOpInvoiceProviderPlugin.java
@@ -30,11 +30,8 @@ import com.google.inject.Inject;
public class DefaultNoOpInvoiceProviderPlugin implements NoOpInvoicePluginApi {
- private final Clock clock;
-
@Inject
- public DefaultNoOpInvoiceProviderPlugin(final Clock clock) {
- this.clock = clock;
+ public DefaultNoOpInvoiceProviderPlugin() {
}
@Override
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/provider/NoOpInvoiceProviderPluginProvider.java b/invoice/src/main/java/org/killbill/billing/invoice/provider/NoOpInvoiceProviderPluginProvider.java
index 1901ffb..c4444af 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/provider/NoOpInvoiceProviderPluginProvider.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/provider/NoOpInvoiceProviderPluginProvider.java
@@ -45,7 +45,7 @@ public class NoOpInvoiceProviderPluginProvider implements Provider<DefaultNoOpIn
@Override
public DefaultNoOpInvoiceProviderPlugin get() {
- final DefaultNoOpInvoiceProviderPlugin plugin = new DefaultNoOpInvoiceProviderPlugin(clock);
+ final DefaultNoOpInvoiceProviderPlugin plugin = new DefaultNoOpInvoiceProviderPlugin();
final OSGIServiceDescriptor desc = new OSGIServiceDescriptor() {
@Override
public String getPluginSymbolicName() {
diff --git a/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoiceSqlDao.sql.stg b/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoiceSqlDao.sql.stg
index 141dca0..5639dbe 100644
--- a/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoiceSqlDao.sql.stg
+++ b/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoiceSqlDao.sql.stg
@@ -71,16 +71,6 @@ getParentDraftInvoice() ::= <<
<defaultOrderBy("")>
>>
-getEarliestDraftInvoiceByAccount() ::= <<
- SELECT <allTableFields("")>
- FROM <tableName()>
- WHERE <accountRecordIdField("")> = :accountRecordId
- AND status = 'DRAFT'
- <AND_CHECK_TENANT("")>
- <defaultOrderBy("")>
- limit 1
-;
->>
getByIds(ids) ::= <<
select
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/dao/MockInvoiceDao.java b/invoice/src/test/java/org/killbill/billing/invoice/dao/MockInvoiceDao.java
index 3cf8c32..0e1ea27 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/dao/MockInvoiceDao.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/dao/MockInvoiceDao.java
@@ -81,11 +81,6 @@ public class MockInvoiceDao extends MockEntityDaoBase<InvoiceModelDao, Invoice,
}
@Override
- public InvoiceModelDao getEarliestDraftInvoiceByAccount(final InternalTenantContext context) {
- return null;
- }
-
- @Override
public List<InvoiceItemModelDao> createInvoices(final List<InvoiceModelDao> invoiceModelDaos, final InternalCallContext context) {
synchronized (monitor) {
final List<InvoiceItemModelDao> createdItems = new LinkedList<InvoiceItemModelDao>();
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/dao/TestInvoiceDao.java b/invoice/src/test/java/org/killbill/billing/invoice/dao/TestInvoiceDao.java
index 9f4ae9d..73737e0 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/dao/TestInvoiceDao.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/dao/TestInvoiceDao.java
@@ -501,41 +501,6 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
assertEquals(invoices.size(), 0);
}
- @Test(groups = "slow")
- public void testGetEarliestDraftInvoiceByAccount() throws EntityPersistenceException {
- final UUID accountId = account.getId();
-
- InvoiceModelDao result;
- result = invoiceDao.getEarliestDraftInvoiceByAccount(context);
- assertNull(result);
-
- final LocalDate targetDate1 = new LocalDate(2011, 10, 6);
- final Invoice invoice1 = new DefaultInvoice(accountId, clock.getUTCToday(), targetDate1, Currency.USD, InvoiceStatus.DRAFT);
- invoiceUtil.createInvoice(invoice1, context);
-
- result = invoiceDao.getEarliestDraftInvoiceByAccount(context);
- assertNotNull(result);
- assertEquals(result.getId(), invoice1.getId());
-
- final LocalDate targetDate2 = new LocalDate(2011, 12, 6);
- final Invoice invoice2 = new DefaultInvoice(accountId, clock.getUTCToday(), targetDate2, Currency.USD);
- invoiceUtil.createInvoice(invoice2, context);
-
- result = invoiceDao.getEarliestDraftInvoiceByAccount(context);
- assertNotNull(result);
- assertEquals(result.getId(), invoice1.getId());
-
-
- final LocalDate targetDate3 = new LocalDate(2011, 10, 6);
- final Invoice invoice3 = new DefaultInvoice(accountId, clock.getUTCToday(), targetDate3, Currency.USD, InvoiceStatus.DRAFT);
- invoiceUtil.createInvoice(invoice3, context);
-
- result = invoiceDao.getEarliestDraftInvoiceByAccount(context);
- assertNotNull(result);
- assertEquals(result.getId(), invoice1.getId());
- }
-
-
@Test(groups = "slow")
public void testAccountBalance() throws EntityPersistenceException {
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoicePluginDispatcher.java b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoicePluginDispatcher.java
new file mode 100644
index 0000000..78d1b74
--- /dev/null
+++ b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoicePluginDispatcher.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you 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 org.killbill.billing.invoice;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.killbill.billing.callcontext.InternalCallContext;
+import org.killbill.billing.invoice.plugin.api.InvoicePluginApi;
+import org.killbill.billing.invoice.provider.DefaultNoOpInvoiceProviderPlugin;
+import org.killbill.billing.osgi.api.OSGIServiceDescriptor;
+import org.killbill.billing.osgi.api.OSGIServiceRegistration;
+import org.killbill.billing.platform.api.KillbillConfigSource;
+import org.killbill.billing.tenant.api.TenantInternalApi;
+import org.mockito.Mockito;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableMap;
+import com.google.inject.Inject;
+
+import static org.testng.Assert.assertEquals;
+
+public class TestInvoicePluginDispatcher extends InvoiceTestSuiteNoDB {
+
+ private final String PLUGIN_1 = "plugin1";
+ private final String PLUGIN_2 = "plugin2";
+ private final String PLUGIN_3 = "plugin3";
+
+ @Inject
+ protected InvoicePluginDispatcher invoicePluginDispatcher;
+ @Inject
+ OSGIServiceRegistration<InvoicePluginApi> pluginRegistry;
+
+ @Inject
+ TenantInternalApi tenantInternalApi;
+
+ protected KillbillConfigSource getConfigSource() {
+ return getConfigSource("/resource.properties", ImmutableMap.<String, String>builder()
+ .put("org.killbill.invoice.plugin", Joiner.on(",").join(PLUGIN_1, PLUGIN_2))
+ .build());
+ }
+
+ @Override
+ @BeforeMethod(groups = "fast")
+ public void beforeMethod() {
+ super.beforeMethod();
+ for (final String name : pluginRegistry.getAllServices()) {
+ pluginRegistry.unregisterService(name);
+ }
+ }
+
+ @Test(groups = "fast")
+ public void testWithNoConfig() throws Exception {
+
+ // We Use the per-tenant config and specify a empty list of plugins
+ Mockito.when(tenantInternalApi.getTenantConfig(Mockito.any(InternalCallContext.class))).thenReturn("{\"org.killbill.invoice.plugin\":\"\"}");
+ // We register one plugin
+ registerPlugin(PLUGIN_1);
+
+ final Collection<String> result = invoicePluginDispatcher.getResultingPluginNameList(internalCallContext);
+ // Se expect to seee the list of registered plugins
+ assertEquals(result.size(), 1);
+ final Iterator<String> iterator = result.iterator();
+ assertEquals(iterator.next(), PLUGIN_1);
+ }
+
+ @Test(groups = "fast")
+ public void testWithNoRegistration() throws Exception {
+ // Nothing has been registered, we see nothing
+ final Collection<String> result = invoicePluginDispatcher.getResultingPluginNameList(internalCallContext);
+ assertEquals(result.size(), 0);
+ }
+
+ @Test(groups = "fast")
+ public void testWithCorrectOrder() throws Exception {
+ // 3 plugins registered in correct order but only 2 got specified in config
+ registerPlugin(PLUGIN_1);
+ registerPlugin(PLUGIN_2);
+ registerPlugin(PLUGIN_3);
+
+ final Collection<String> result = invoicePluginDispatcher.getResultingPluginNameList(internalCallContext);
+ assertEquals(result.size(), 2);
+ final Iterator<String> iterator = result.iterator();
+ assertEquals(iterator.next(), PLUGIN_1);
+ assertEquals(iterator.next(), PLUGIN_2);
+ }
+
+ @Test(groups = "fast")
+ public void testWithIncorrectCorrectOrder() throws Exception {
+
+ // 3 plugins registered in *incorrect* order and only 2 got specified in config
+ registerPlugin(PLUGIN_2);
+ registerPlugin(PLUGIN_3);
+ registerPlugin(PLUGIN_1);
+
+ final Collection<String> result = invoicePluginDispatcher.getResultingPluginNameList(internalCallContext);
+ assertEquals(result.size(), 2);
+ final Iterator<String> iterator = result.iterator();
+ assertEquals(iterator.next(), PLUGIN_1);
+ assertEquals(iterator.next(), PLUGIN_2);
+ }
+
+
+ private void registerPlugin(final String plugin) {
+ pluginRegistry.registerService(new OSGIServiceDescriptor() {
+ @Override
+ public String getPluginSymbolicName() {
+ return plugin;
+ }
+
+ @Override
+ public String getPluginName() {
+ return plugin;
+ }
+
+ @Override
+ public String getRegistrationName() {
+ return plugin;
+ }
+ }, new DefaultNoOpInvoiceProviderPlugin());
+ }
+}
\ No newline at end of file
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/NotificationJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/NotificationJson.java
index 22fe656..2f5fbbe 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/NotificationJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/NotificationJson.java
@@ -33,23 +33,27 @@ public class NotificationJson {
private final String objectType;
@ApiModelProperty(dataType = "java.util.UUID")
private final String objectId;
+ private String metaData;
@JsonCreator
public NotificationJson(@JsonProperty("eventType") final String eventType,
@JsonProperty("accountId") final String accountId,
@JsonProperty("objectType") final String objectType,
- @JsonProperty("objectId") final String objectId) {
+ @JsonProperty("objectId") final String objectId,
+ @JsonProperty("metaData") final String metaData) {
this.eventType = eventType;
this.accountId = accountId;
this.objectType = objectType;
this.objectId = objectId;
+ this.metaData = metaData;
}
public NotificationJson(final ExtBusEvent event) {
this(event.getEventType().toString(),
event.getAccountId() != null ? event.getAccountId().toString() : null,
event.getObjectType().toString(),
- event.getObjectId() != null ? event.getObjectId().toString() : null);
+ event.getObjectId() != null ? event.getObjectId().toString() : null,
+ event.getMetaData());
}
public String getEventType() {
@@ -67,4 +71,8 @@ public class NotificationJson {
public String getObjectId() {
return objectId;
}
+
+ public String getMetaData() {
+ return metaData;
+ }
}
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/TagDefinitionJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/TagDefinitionJson.java
index 453883e..779931c 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/TagDefinitionJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/TagDefinitionJson.java
@@ -17,6 +17,7 @@
package org.killbill.billing.jaxrs.json;
import java.util.List;
+import java.util.Set;
import javax.annotation.Nullable;
@@ -29,6 +30,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.Function;
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
import io.swagger.annotations.ApiModelProperty;
public class TagDefinitionJson extends JsonBase {
@@ -40,14 +42,14 @@ public class TagDefinitionJson extends JsonBase {
private final String name;
@ApiModelProperty(required = true)
private final String description;
- private final List<String> applicableObjectTypes;
+ private final Set<String> applicableObjectTypes;
@JsonCreator
public TagDefinitionJson(@JsonProperty("id") final String id,
@JsonProperty("isControlTag") final Boolean isControlTag,
@JsonProperty("name") final String name,
@JsonProperty("description") @Nullable final String description,
- @JsonProperty("applicableObjectTypes") @Nullable final List<String> applicableObjectTypes,
+ @JsonProperty("applicableObjectTypes") @Nullable final Set<String> applicableObjectTypes,
@JsonProperty("auditLogs") @Nullable final List<AuditLogJson> auditLogs) {
super(auditLogs);
this.id = id;
@@ -62,7 +64,7 @@ public class TagDefinitionJson extends JsonBase {
tagDefinition.isControlTag(),
tagDefinition.getName(),
tagDefinition.getDescription(),
- ImmutableList.<String>copyOf(Collections2.transform(tagDefinition.getApplicableObjectTypes(), new Function<ObjectType, String>() {
+ ImmutableSet.<String>copyOf(Collections2.transform(tagDefinition.getApplicableObjectTypes(), new Function<ObjectType, String>() {
@Override
public String apply(@Nullable final ObjectType input) {
if (input == null) {
@@ -92,7 +94,7 @@ public class TagDefinitionJson extends JsonBase {
return description;
}
- public List<String> getApplicableObjectTypes() {
+ public Set<String> getApplicableObjectTypes() {
return applicableObjectTypes;
}
@@ -156,4 +158,13 @@ public class TagDefinitionJson extends JsonBase {
result = 31 * result + (applicableObjectTypes != null ? applicableObjectTypes.hashCode() : 0);
return result;
}
+
+ public static Set<ObjectType> toObjectType(final Set<String> applicableObjectTypes) {
+ return ImmutableSet.copyOf(Collections2.transform(applicableObjectTypes, new Function<String, ObjectType>() {
+ @Override
+ public ObjectType apply(final String input) {
+ return ObjectType.valueOf(input);
+ }
+ }));
+ }
}
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/BundleResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/BundleResource.java
index 8f37bb6..f87438a 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/BundleResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/BundleResource.java
@@ -391,6 +391,35 @@ public class BundleResource extends JaxRsResourceBase {
return uriBuilder.buildResponse(uriInfo, BundleResource.class, "getBundle", newBundleId, request);
}
+
+ @TimedResource
+ @PUT
+ @Path("/{bundleId:" + UUID_PATTERN + "}/" + RENAME_KEY)
+ @Consumes(APPLICATION_JSON)
+ @ApiOperation(value = "Update a bundle externalKey")
+ @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid argumnent supplied"),
+ @ApiResponse(code = 404, message = "Bundle not found")})
+ public Response renameExternalKey(final BundleJson json,
+ @PathParam(ID_PARAM_NAME) final String id,
+ /* @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString, */
+ @HeaderParam(HDR_CREATED_BY) final String createdBy,
+ @HeaderParam(HDR_REASON) final String reason,
+ @HeaderParam(HDR_COMMENT) final String comment,
+ @javax.ws.rs.core.Context final UriInfo uriInfo,
+ @javax.ws.rs.core.Context final HttpServletRequest request) throws EntitlementApiException {
+
+ verifyNonNullOrEmpty(json, "BundleJson body should be specified");
+ verifyNonNullOrEmpty(json.getExternalKey(), "BundleJson externalKey needs to be set");
+
+ final UUID bundleId = UUID.fromString(id);
+
+ final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
+ subscriptionApi.updateExternalKey(bundleId, json.getExternalKey(), callContext);
+ return uriBuilder.buildResponse(uriInfo, BundleResource.class, "getBundle", bundleId, request);
+ }
+
+
+
@TimedResource
@POST
@Path("/{bundleId:" + UUID_PATTERN + "}/" + TAGS)
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/ComboPaymentResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/ComboPaymentResource.java
index 17ce949..bc87d1e 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/ComboPaymentResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/ComboPaymentResource.java
@@ -123,13 +123,4 @@ public abstract class ComboPaymentResource extends JaxRsResourceBase {
paymentData.getPluginDetail(), pluginProperties, callContext);
}
- protected Payment getPaymentByIdOrKey(@Nullable final String paymentIdStr, @Nullable final String externalKey, final Iterable<PluginProperty> pluginProperties, final TenantContext tenantContext) throws PaymentApiException {
- Preconditions.checkArgument(paymentIdStr != null || externalKey != null, "Need to set either paymentId or payment externalKey");
- if (paymentIdStr != null) {
- final UUID paymentId = UUID.fromString(paymentIdStr);
- return paymentApi.getPayment(paymentId, false, false, pluginProperties, tenantContext);
- } else {
- return paymentApi.getPaymentByExternalKey(externalKey, false, false, pluginProperties, tenantContext);
- }
- }
}
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoicePaymentResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoicePaymentResource.java
index 440d83a..45e0cb4 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoicePaymentResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoicePaymentResource.java
@@ -19,6 +19,7 @@
package org.killbill.billing.jaxrs.resources;
import java.math.BigDecimal;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
@@ -33,11 +34,13 @@ import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriInfo;
import org.killbill.billing.ObjectType;
@@ -51,6 +54,7 @@ import org.killbill.billing.jaxrs.json.CustomFieldJson;
import org.killbill.billing.jaxrs.json.InvoiceItemJson;
import org.killbill.billing.jaxrs.json.InvoicePaymentJson;
import org.killbill.billing.jaxrs.json.InvoicePaymentTransactionJson;
+import org.killbill.billing.jaxrs.json.PaymentTransactionJson;
import org.killbill.billing.jaxrs.json.TagJson;
import org.killbill.billing.jaxrs.util.Context;
import org.killbill.billing.jaxrs.util.JaxrsUriBuilder;
@@ -69,6 +73,7 @@ import org.killbill.billing.util.audit.AccountAuditLogs;
import org.killbill.billing.util.callcontext.CallContext;
import org.killbill.billing.util.callcontext.TenantContext;
import org.killbill.clock.Clock;
+import org.killbill.commons.metrics.MetricTag;
import org.killbill.commons.metrics.TimedResource;
import com.google.common.base.Predicate;
@@ -258,6 +263,62 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
return uriBuilder.buildResponse(uriInfo, InvoicePaymentResource.class, "getInvoicePayment", result.getId(), request);
}
+
+ @TimedResource(name = "completeInvoicePaymentTransaction")
+ @PUT
+ @Path("/{paymentId:" + UUID_PATTERN + "}")
+ @Consumes(APPLICATION_JSON)
+ @Produces(APPLICATION_JSON)
+ @ApiOperation(value = "Complete an existing transaction")
+ @ApiResponses(value = {@ApiResponse(code = 201, message = "Payment transaction created successfully"),
+ @ApiResponse(code = 400, message = "Invalid paymentId supplied"),
+ @ApiResponse(code = 404, message = "Account or payment not found"),
+ @ApiResponse(code = 402, message = "Transaction declined by gateway"),
+ @ApiResponse(code = 422, message = "Payment is aborted by a control plugin"),
+ @ApiResponse(code = 502, message = "Failed to submit payment transaction"),
+ @ApiResponse(code = 503, message = "Payment in unknown status, failed to receive gateway response"),
+ @ApiResponse(code = 504, message = "Payment operation timeout")})
+ public Response completeInvoicePaymentTransaction(final PaymentTransactionJson json,
+ @PathParam("paymentId") final String paymentIdStr,
+ @QueryParam(QUERY_PAYMENT_CONTROL_PLUGIN_NAME) final List<String> paymentControlPluginNames,
+ @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
+ @HeaderParam(HDR_CREATED_BY) final String createdBy,
+ @HeaderParam(HDR_REASON) final String reason,
+ @HeaderParam(HDR_COMMENT) final String comment,
+ @javax.ws.rs.core.Context final UriInfo uriInfo,
+ @javax.ws.rs.core.Context final HttpServletRequest request) throws PaymentApiException, AccountApiException {
+
+ final TenantContext tenantContext = context.createTenantContextNoAccountId(request);
+
+ final UUID paymentId = UUID.fromString(paymentIdStr);
+
+ final Payment payment = paymentApi.getPayment(paymentId, false, false, ImmutableList.<PluginProperty>of(), tenantContext);
+ final List<InvoicePayment> invoicePayments = invoicePaymentApi.getInvoicePayments(paymentId, tenantContext);
+
+ final InvoicePayment originalInvoicePaymentAttempt = Iterables.tryFind(invoicePayments, new Predicate<InvoicePayment>() {
+ @Override
+ public boolean apply(final InvoicePayment input) {
+ return input.getType() == InvoicePaymentType.ATTEMPT && !input.isSuccess();
+ }
+ }).orNull();
+
+ final UUID invoiceId = originalInvoicePaymentAttempt != null ? originalInvoicePaymentAttempt.getInvoiceId() : null;
+ if (invoiceId == null) {
+ return Response.status(Status.NOT_FOUND).build();
+ }
+
+ final PluginProperty invoiceProperty = new PluginProperty("IPCD_INVOICE_ID" /* InvoicePaymentControlPluginApi.PROP_IPCD_INVOICE_ID (contract with plugin) */,
+ invoiceId.toString(), false);
+ final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString, invoiceProperty);
+
+ final List<String> controlPluginNames = new ArrayList<String>();
+ controlPluginNames.add("__INVOICE_PAYMENT_CONTROL_PLUGIN__");
+ controlPluginNames.addAll(paymentControlPluginNames);
+
+ return completeTransactionInternal(json, payment, controlPluginNames, pluginProperties, tenantContext, createdBy, reason, comment, uriInfo, request);
+ }
+
+
@TimedResource
@GET
@Path("/{paymentId:" + UUID_PATTERN + "}/" + CUSTOM_FIELDS)
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java
index 5bb10b5..e7e6c9b 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java
@@ -143,6 +143,8 @@ public interface JaxrsResource {
public static final String QUERY_BUNDLE_TRANSFER_CANCEL_IMM = "cancelImmediately";
public static final String QUERY_BUNDLES_FILTER = "bundlesFilter";
+ public static final String QUERY_BUNDLES_RENAME_KEY_IF_EXIST_UNUSED = "renameKeyIfExistsAndUnused";
+
public static final String QUERY_DELETE_DEFAULT_PM_WITH_AUTO_PAY_OFF = "deleteDefaultPmWithAutoPayOff";
public static final String QUERY_FORCE_DEFAULT_PM_DELETION = "forceDefaultPmDeletion";
@@ -261,6 +263,7 @@ public interface JaxrsResource {
public static final String PAUSE = "pause";
public static final String RESUME = "resume";
public static final String BLOCK = "block";
+ public static final String RENAME_KEY = "renameKey";
public static final String AUTHORIZATION = "authorization";
public static final String CAPTURE = "capture";
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxRsResourceBase.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxRsResourceBase.java
index 97c9b8c..07fbc86 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxRsResourceBase.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxRsResourceBase.java
@@ -52,6 +52,7 @@ import org.killbill.billing.ObjectType;
import org.killbill.billing.account.api.Account;
import org.killbill.billing.account.api.AccountApiException;
import org.killbill.billing.account.api.AccountUserApi;
+import org.killbill.billing.catalog.api.Currency;
import org.killbill.billing.entitlement.api.BlockingState;
import org.killbill.billing.entitlement.api.BlockingStateType;
import org.killbill.billing.entitlement.api.EntitlementApiException;
@@ -64,6 +65,7 @@ import org.killbill.billing.jaxrs.json.BillingExceptionJson.StackTraceElementJso
import org.killbill.billing.jaxrs.json.BlockingStateJson;
import org.killbill.billing.jaxrs.json.CustomFieldJson;
import org.killbill.billing.jaxrs.json.JsonBase;
+import org.killbill.billing.jaxrs.json.PaymentTransactionJson;
import org.killbill.billing.jaxrs.json.PluginPropertyJson;
import org.killbill.billing.jaxrs.json.TagJson;
import org.killbill.billing.jaxrs.util.Context;
@@ -119,7 +121,6 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
// Catalog API don't quite support multiple catalogs per tenant
protected static final String catalogName = "unused";
-
protected static final ObjectMapper mapper = new ObjectMapper();
protected final JaxrsUriBuilder uriBuilder;
@@ -183,9 +184,6 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
return Response.status(Status.OK).build();
}
-
-
-
protected Response getTags(final UUID accountId, final UUID taggedObjectId, final AuditMode auditMode, final boolean includeDeleted, final TenantContext context) throws TagDefinitionApiException {
final List<Tag> tags = tagUserApi.getTagsForObject(taggedObjectId, getObjectType(), includeDeleted, context);
return createTagResponse(accountId, tags, auditMode, context);
@@ -208,7 +206,6 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
return Response.status(Response.Status.OK).entity(result).build();
}
-
protected Response createTags(final UUID id,
final String tagList,
final UriInfo uriInfo,
@@ -361,8 +358,80 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
}
}
+ protected Payment getPaymentByIdOrKey(@Nullable final String paymentIdStr, @Nullable final String externalKey, final Iterable<PluginProperty> pluginProperties, final TenantContext tenantContext) throws PaymentApiException {
+ Preconditions.checkArgument(paymentIdStr != null || externalKey != null, "Need to set either paymentId or payment externalKey");
+ if (paymentIdStr != null) {
+ final UUID paymentId = UUID.fromString(paymentIdStr);
+ return paymentApi.getPayment(paymentId, false, false, pluginProperties, tenantContext);
+ } else {
+ return paymentApi.getPaymentByExternalKey(externalKey, false, false, pluginProperties, tenantContext);
+ }
+ }
+
+
+ protected Response completeTransactionInternal(final PaymentTransactionJson json,
+ final Payment initialPayment,
+ final List<String> paymentControlPluginNames,
+ final Iterable<PluginProperty> pluginProperties,
+ final TenantContext contextNoAccountId,
+ final String createdBy,
+ final String reason,
+ final String comment,
+ final UriInfo uriInfo,
+ final HttpServletRequest request) throws PaymentApiException, AccountApiException {
+
+ final Account account = accountUserApi.getAccountById(initialPayment.getAccountId(), contextNoAccountId);
+ final BigDecimal amount = json == null ? null : json.getAmount();
+ final Currency currency = json == null || json.getCurrency() == null ? null : Currency.valueOf(json.getCurrency());
+
+ final CallContext callContext = context.createCallContextWithAccountId(account.getId(), createdBy, reason, comment, request);
+
+ final PaymentTransaction pendingOrSuccessTransaction = lookupPendingOrSuccessTransaction(initialPayment,
+ json != null ? json.getTransactionId() : null,
+ json != null ? json.getTransactionExternalKey() : null,
+ json != null ? json.getTransactionType() : null);
+ // If transaction was already completed, return early (See #626)
+ if (pendingOrSuccessTransaction.getTransactionStatus() == TransactionStatus.SUCCESS) {
+ return uriBuilder.buildResponse(uriInfo, PaymentResource.class, "getPayment", pendingOrSuccessTransaction.getPaymentId(), request);
+ }
+
+ final PaymentTransaction pendingTransaction = pendingOrSuccessTransaction;
+ final PaymentOptions paymentOptions = createControlPluginApiPaymentOptions(paymentControlPluginNames);
+ final Payment result;
+ switch (pendingTransaction.getTransactionType()) {
+ case AUTHORIZE:
+ result = paymentApi.createAuthorizationWithPaymentControl(account, initialPayment.getPaymentMethodId(), initialPayment.getId(), amount, currency,
+ initialPayment.getExternalKey(), pendingTransaction.getExternalKey(),
+ pluginProperties, paymentOptions, callContext);
+ break;
+ case CAPTURE:
+ result = paymentApi.createCaptureWithPaymentControl(account, initialPayment.getId(), amount, currency, pendingTransaction.getExternalKey(),
+ pluginProperties, paymentOptions, callContext);
+ break;
+ case PURCHASE:
+ result = paymentApi.createPurchaseWithPaymentControl(account, initialPayment.getPaymentMethodId(), initialPayment.getId(), amount, currency,
+ initialPayment.getExternalKey(), pendingTransaction.getExternalKey(),
+ pluginProperties, paymentOptions, callContext);
+ break;
+ case CREDIT:
+ result = paymentApi.createCreditWithPaymentControl(account, initialPayment.getPaymentMethodId(), initialPayment.getId(), amount, currency,
+ initialPayment.getExternalKey(), pendingTransaction.getExternalKey(),
+ pluginProperties, paymentOptions, callContext);
+ break;
+ case REFUND:
+ result = paymentApi.createRefundWithPaymentControl(account, initialPayment.getId(), amount, currency,
+ pendingTransaction.getExternalKey(), pluginProperties, paymentOptions, callContext);
+ break;
+ default:
+ return Response.status(Status.PRECONDITION_FAILED).entity("TransactionType " + pendingTransaction.getTransactionType() + " cannot be completed").build();
+ }
+ return createPaymentResponse(uriInfo, result, pendingTransaction.getTransactionType(), pendingTransaction.getExternalKey(), request);
+
+ }
+
+
protected PaymentTransaction lookupPendingOrSuccessTransaction(final Payment initialPayment, @Nullable final String transactionId, @Nullable final String transactionExternalKey, @Nullable final String transactionType) throws PaymentApiException {
- final Collection<PaymentTransaction> pendingTransaction = Collections2.filter(initialPayment.getTransactions(), new Predicate<PaymentTransaction>() {
+ final Collection<PaymentTransaction> pendingTransaction = Collections2.filter(initialPayment.getTransactions(), new Predicate<PaymentTransaction>() {
@Override
public boolean apply(final PaymentTransaction input) {
if (input.getTransactionStatus() != TransactionStatus.PENDING && input.getTransactionStatus() != TransactionStatus.SUCCESS) {
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentResource.java
index c5c98e8..bf63aaa 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentResource.java
@@ -17,7 +17,6 @@
package org.killbill.billing.jaxrs.resources;
-import java.math.BigDecimal;
import java.net.URI;
import java.util.HashMap;
import java.util.List;
@@ -59,9 +58,7 @@ import org.killbill.billing.payment.api.Payment;
import org.killbill.billing.payment.api.PaymentApi;
import org.killbill.billing.payment.api.PaymentApiException;
import org.killbill.billing.payment.api.PaymentOptions;
-import org.killbill.billing.payment.api.PaymentTransaction;
import org.killbill.billing.payment.api.PluginProperty;
-import org.killbill.billing.payment.api.TransactionStatus;
import org.killbill.billing.payment.api.TransactionType;
import org.killbill.billing.util.api.AuditUserApi;
import org.killbill.billing.util.api.CustomFieldApiException;
@@ -263,9 +260,11 @@ public class PaymentResource extends ComboPaymentResource {
@HeaderParam(HDR_COMMENT) final String comment,
@javax.ws.rs.core.Context final UriInfo uriInfo,
@javax.ws.rs.core.Context final HttpServletRequest request) throws PaymentApiException, AccountApiException {
- return completeTransactionInternal(json, paymentIdStr, paymentControlPluginNames, pluginPropertiesString, createdBy, reason, comment, uriInfo, request);
+ return completeTransactionInternalWithoutPayment(json, paymentIdStr, paymentControlPluginNames, pluginPropertiesString, createdBy, reason, comment, uriInfo, request);
}
+
+
@TimedResource(name = "completeTransaction")
@PUT
@Consumes(APPLICATION_JSON)
@@ -286,7 +285,7 @@ public class PaymentResource extends ComboPaymentResource {
@HeaderParam(HDR_COMMENT) final String comment,
@javax.ws.rs.core.Context final UriInfo uriInfo,
@javax.ws.rs.core.Context final HttpServletRequest request) throws PaymentApiException, AccountApiException {
- return completeTransactionInternal(json, null, paymentControlPluginNames, pluginPropertiesString, createdBy, reason, comment, uriInfo, request);
+ return completeTransactionInternalWithoutPayment(json, null, paymentControlPluginNames, pluginPropertiesString, createdBy, reason, comment, uriInfo, request);
}
@@ -294,71 +293,6 @@ public class PaymentResource extends ComboPaymentResource {
- private Response completeTransactionInternal(final PaymentTransactionJson json,
- @Nullable final String paymentIdStr,
- final List<String> paymentControlPluginNames,
- final Iterable<String> pluginPropertiesString,
- final String createdBy,
- final String reason,
- final String comment,
- final UriInfo uriInfo,
- final HttpServletRequest request) throws PaymentApiException, AccountApiException {
-
- final Iterable<PluginProperty> pluginPropertiesFromBody = extractPluginProperties(json.getProperties());
-
- final Iterable<PluginProperty> pluginPropertiesFromQuery = extractPluginProperties(pluginPropertiesString);
-
- final Iterable<PluginProperty> pluginProperties = Iterables.concat(pluginPropertiesFromQuery, pluginPropertiesFromBody);
-
- final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
- final Payment initialPayment = getPaymentByIdOrKey(paymentIdStr, json == null ? null : json.getPaymentExternalKey(), pluginProperties, callContext);
-
- final Account account = accountUserApi.getAccountById(initialPayment.getAccountId(), callContext);
- final BigDecimal amount = json == null ? null : json.getAmount();
- final Currency currency = json == null || json.getCurrency() == null ? null : Currency.valueOf(json.getCurrency());
-
- final PaymentTransaction pendingOrSuccessTransaction = lookupPendingOrSuccessTransaction(initialPayment,
- json != null ? json.getTransactionId() : null,
- json != null ? json.getTransactionExternalKey() : null,
- json != null ? json.getTransactionType() : null);
- // If transaction was already completed, return early (See #626)
- if (pendingOrSuccessTransaction.getTransactionStatus() == TransactionStatus.SUCCESS) {
- return uriBuilder.buildResponse(uriInfo, PaymentResource.class, "getPayment", pendingOrSuccessTransaction.getPaymentId(), request);
- }
-
-
- final PaymentTransaction pendingTransaction = pendingOrSuccessTransaction;
- final PaymentOptions paymentOptions = createControlPluginApiPaymentOptions(paymentControlPluginNames);
- final Payment result;
- switch (pendingTransaction.getTransactionType()) {
- case AUTHORIZE:
- result = paymentApi.createAuthorizationWithPaymentControl(account, initialPayment.getPaymentMethodId(), initialPayment.getId(), amount, currency,
- initialPayment.getExternalKey(), pendingTransaction.getExternalKey(),
- pluginProperties, paymentOptions, callContext);
- break;
- case CAPTURE:
- result = paymentApi.createCaptureWithPaymentControl(account, initialPayment.getId(), amount, currency, pendingTransaction.getExternalKey(),
- pluginProperties, paymentOptions, callContext);
- break;
- case PURCHASE:
- result = paymentApi.createPurchaseWithPaymentControl(account, initialPayment.getPaymentMethodId(), initialPayment.getId(), amount, currency,
- initialPayment.getExternalKey(), pendingTransaction.getExternalKey(),
- pluginProperties, paymentOptions, callContext);
- break;
- case CREDIT:
- result = paymentApi.createCreditWithPaymentControl(account, initialPayment.getPaymentMethodId(), initialPayment.getId(), amount, currency,
- initialPayment.getExternalKey(), pendingTransaction.getExternalKey(),
- pluginProperties, paymentOptions, callContext);
- break;
- case REFUND:
- result = paymentApi.createRefundWithPaymentControl(account, initialPayment.getId(), amount, currency,
- pendingTransaction.getExternalKey(), pluginProperties, paymentOptions, callContext);
- break;
- default:
- return Response.status(Status.PRECONDITION_FAILED).entity("TransactionType " + pendingTransaction.getTransactionType() + " cannot be completed").build();
- }
- return createPaymentResponse(uriInfo, result, pendingTransaction.getTransactionType(), pendingTransaction.getExternalKey(), request);
- }
@TimedResource(name = "captureAuthorization")
@POST
@@ -950,4 +884,27 @@ public class PaymentResource extends ComboPaymentResource {
protected ObjectType getObjectType() {
return ObjectType.PAYMENT;
}
+
+ private Response completeTransactionInternalWithoutPayment(final PaymentTransactionJson json,
+ @Nullable final String paymentIdStr,
+ final List<String> paymentControlPluginNames,
+ final Iterable<String> pluginPropertiesString,
+ final String createdBy,
+ final String reason,
+ final String comment,
+ final UriInfo uriInfo,
+ final HttpServletRequest request) throws PaymentApiException, AccountApiException {
+
+ final Iterable<PluginProperty> pluginPropertiesFromBody = extractPluginProperties(json.getProperties());
+
+ final Iterable<PluginProperty> pluginPropertiesFromQuery = extractPluginProperties(pluginPropertiesString);
+
+ final Iterable<PluginProperty> pluginProperties = Iterables.concat(pluginPropertiesFromQuery, pluginPropertiesFromBody);
+
+ final CallContext callContextNoAccountId = context.createCallContextNoAccountId(createdBy, reason, comment, request);
+ final Payment initialPayment = getPaymentByIdOrKey(paymentIdStr, json == null ? null : json.getPaymentExternalKey(), pluginProperties, callContextNoAccountId);
+
+ return completeTransactionInternal(json, initialPayment, paymentControlPluginNames, pluginProperties, callContextNoAccountId, createdBy, reason, comment, uriInfo, request);
+ }
+
}
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SecurityResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SecurityResource.java
index 8f3b390..60e55b5 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SecurityResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SecurityResource.java
@@ -204,4 +204,22 @@ public class SecurityResource extends JaxRsResourceBase {
securityApi.addRoleDefinition(json.getRole(), json.getPermissions(), context.createCallContextNoAccountId(createdBy, reason, comment, request));
return Response.status(Status.CREATED).build();
}
+
+
+ @TimedResource
+ @PUT
+ @Consumes(APPLICATION_JSON)
+ @Produces(APPLICATION_JSON)
+ @Path("/roles")
+ @ApiOperation(value = "Update a new role definition)")
+ public Response updateRoleDefinition(final RoleDefinitionJson json,
+ @HeaderParam(HDR_CREATED_BY) final String createdBy,
+ @HeaderParam(HDR_REASON) final String reason,
+ @HeaderParam(HDR_COMMENT) final String comment,
+ @javax.ws.rs.core.Context final HttpServletRequest request,
+ @javax.ws.rs.core.Context final UriInfo uriInfo) throws SecurityApiException {
+ securityApi.updateRoleDefinition(json.getRole(), json.getPermissions(), context.createCallContextNoAccountId(createdBy, reason, comment, request));
+ return Response.status(Status.OK).build();
+ }
+
}
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SubscriptionResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SubscriptionResource.java
index f4b0af2..d54e936 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SubscriptionResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SubscriptionResource.java
@@ -173,6 +173,7 @@ public class SubscriptionResource extends JaxRsResourceBase {
@QueryParam(QUERY_REQUESTED_DT) final String requestedDate, /* This is deprecated, only used for backward compatibility */
@QueryParam(QUERY_ENTITLEMENT_REQUESTED_DT) final String entitlementDate,
@QueryParam(QUERY_BILLING_REQUESTED_DT) final String billingDate,
+ @QueryParam(QUERY_BUNDLES_RENAME_KEY_IF_EXIST_UNUSED) @DefaultValue("true") final Boolean renameKeyIfExistsAndUnused,
@QueryParam(QUERY_MIGRATED) @DefaultValue("false") final Boolean isMigrated,
@QueryParam(QUERY_BCD) final Integer newBCD,
@QueryParam(QUERY_CALL_COMPLETION) @DefaultValue("false") final Boolean callCompletion,
@@ -218,7 +219,7 @@ public class SubscriptionResource extends JaxRsResourceBase {
final List<PlanPhasePriceOverride> overrides = PhasePriceOverrideJson.toPlanPhasePriceOverrides(entitlement.getPriceOverrides(), spec, account.getCurrency());
final Entitlement result = createAddOnEntitlement ?
entitlementApi.addEntitlement(getBundleIdForAddOnCreation(entitlement), spec, overrides, resolvedEntitlementDate, resolvedBillingDate, isMigrated, pluginProperties, callContext) :
- entitlementApi.createBaseEntitlement(account.getId(), spec, entitlement.getExternalKey(), overrides, resolvedEntitlementDate, resolvedBillingDate, isMigrated, pluginProperties, callContext);
+ entitlementApi.createBaseEntitlement(account.getId(), spec, entitlement.getExternalKey(), overrides, resolvedEntitlementDate, resolvedBillingDate, isMigrated, renameKeyIfExistsAndUnused, pluginProperties, callContext);
if (newBCD != null) {
result.updateBCD(newBCD, null, callContext);
}
@@ -262,6 +263,7 @@ public class SubscriptionResource extends JaxRsResourceBase {
@QueryParam(QUERY_ENTITLEMENT_REQUESTED_DT) final String entitlementDate,
@QueryParam(QUERY_BILLING_REQUESTED_DT) final String billingDate,
@QueryParam(QUERY_MIGRATED) @DefaultValue("false") final Boolean isMigrated,
+ @QueryParam(QUERY_BUNDLES_RENAME_KEY_IF_EXIST_UNUSED) @DefaultValue("true") final Boolean renameKeyIfExistsAndUnused,
@QueryParam(QUERY_CALL_COMPLETION) @DefaultValue("false") final Boolean callCompletion,
@QueryParam(QUERY_CALL_TIMEOUT) @DefaultValue("3") final long timeoutSec,
@QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
@@ -271,7 +273,7 @@ public class SubscriptionResource extends JaxRsResourceBase {
@javax.ws.rs.core.Context final HttpServletRequest request,
@javax.ws.rs.core.Context final UriInfo uriInfo) throws EntitlementApiException, AccountApiException, SubscriptionApiException {
final List<BulkBaseSubscriptionAndAddOnsJson> entitlementsWithAddOns = ImmutableList.of(new BulkBaseSubscriptionAndAddOnsJson(entitlements));
- return createEntitlementsWithAddOnsInternal(entitlementsWithAddOns, requestedDate, entitlementDate, billingDate, isMigrated, callCompletion, timeoutSec, pluginPropertiesString, createdBy, reason, comment, request, uriInfo, ObjectType.BUNDLE);
+ return createEntitlementsWithAddOnsInternal(entitlementsWithAddOns, requestedDate, entitlementDate, billingDate, isMigrated, renameKeyIfExistsAndUnused, callCompletion, timeoutSec, pluginPropertiesString, createdBy, reason, comment, request, uriInfo, ObjectType.BUNDLE);
}
@TimedResource
@@ -285,7 +287,8 @@ public class SubscriptionResource extends JaxRsResourceBase {
@QueryParam(QUERY_REQUESTED_DT) final String requestedDate, /* This is deprecated, only used for backward compatibility */
@QueryParam(QUERY_ENTITLEMENT_REQUESTED_DT) final String entitlementDate,
@QueryParam(QUERY_BILLING_REQUESTED_DT) final String billingDate,
- @QueryParam(QUERY_MIGRATED) @DefaultValue("false") final Boolean isMigrated,
+ @QueryParam(QUERY_BUNDLES_RENAME_KEY_IF_EXIST_UNUSED) @DefaultValue("true") final Boolean renameKeyIfExistsAndUnused,
+ @QueryParam(QUERY_MIGRATED) @DefaultValue("false") final Boolean isMigrated,
@QueryParam(QUERY_CALL_COMPLETION) @DefaultValue("false") final Boolean callCompletion,
@QueryParam(QUERY_CALL_TIMEOUT) @DefaultValue("3") final long timeoutSec,
@QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
@@ -294,7 +297,7 @@ public class SubscriptionResource extends JaxRsResourceBase {
@HeaderParam(HDR_COMMENT) final String comment,
@javax.ws.rs.core.Context final HttpServletRequest request,
@javax.ws.rs.core.Context final UriInfo uriInfo) throws EntitlementApiException, AccountApiException, SubscriptionApiException {
- return createEntitlementsWithAddOnsInternal(entitlementsWithAddOns, requestedDate, entitlementDate, billingDate, isMigrated, callCompletion, timeoutSec, pluginPropertiesString, createdBy, reason, comment, request, uriInfo, ObjectType.ACCOUNT);
+ return createEntitlementsWithAddOnsInternal(entitlementsWithAddOns, requestedDate, entitlementDate, billingDate, isMigrated, renameKeyIfExistsAndUnused, callCompletion, timeoutSec, pluginPropertiesString, createdBy, reason, comment, request, uriInfo, ObjectType.ACCOUNT);
}
@@ -302,7 +305,9 @@ public class SubscriptionResource extends JaxRsResourceBase {
final String requestedDate,
final String entitlementDate,
final String billingDate,
- final Boolean isMigrated, final Boolean callCompletion,
+ final Boolean isMigrated,
+ final Boolean renameKeyIfExistsAndUnused,
+ final Boolean callCompletion,
final long timeoutSec,
final List<String> pluginPropertiesString,
final String createdBy,
@@ -357,7 +362,7 @@ public class SubscriptionResource extends JaxRsResourceBase {
final EntitlementCallCompletionCallback<List<Entitlement>> callback = new EntitlementCallCompletionCallback<List<Entitlement>>() {
@Override
public List<Entitlement> doOperation(final CallContext ctx) throws InterruptedException, TimeoutException, EntitlementApiException, SubscriptionApiException, AccountApiException {
- return entitlementApi.createBaseEntitlementsWithAddOns(account.getId(), baseEntitlementWithAddOnsSpecifierList, pluginProperties, callContext);
+ return entitlementApi.createBaseEntitlementsWithAddOns(account.getId(), baseEntitlementWithAddOnsSpecifierList, renameKeyIfExistsAndUnused, pluginProperties, callContext);
}
@Override
public boolean isImmOperation() {
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TagDefinitionResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TagDefinitionResource.java
index d5cfaa0..efa5c24 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TagDefinitionResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TagDefinitionResource.java
@@ -52,6 +52,7 @@ import org.killbill.billing.util.tag.TagDefinition;
import org.killbill.clock.Clock;
import org.killbill.commons.metrics.TimedResource;
+import com.google.common.base.Preconditions;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import io.swagger.annotations.Api;
@@ -129,8 +130,11 @@ public class TagDefinitionResource extends JaxRsResourceBase {
verifyNonNullOrEmpty(json, "TagDefinitionJson body should be specified");
verifyNonNullOrEmpty(json.getName(), "TagDefinition name needs to be set",
json.getDescription(), "TagDefinition description needs to be set");
+ Preconditions.checkArgument(json.getApplicableObjectTypes() != null &&
+ !json.getApplicableObjectTypes().isEmpty(), "Applicable object types must be set");
- final TagDefinition createdTagDef = tagUserApi.createTagDefinition(json.getName(), json.getDescription(), context.createCallContextNoAccountId(createdBy, reason, comment, request));
+
+ final TagDefinition createdTagDef = tagUserApi.createTagDefinition(json.getName(), json.getDescription(), TagDefinitionJson.toObjectType(json.getApplicableObjectTypes()), context.createCallContextNoAccountId(createdBy, reason, comment, request));
return uriBuilder.buildResponse(uriInfo, TagDefinitionResource.class, "getTagDefinition", createdTagDef.getId(), request);
}
diff --git a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestTagDefinitionJson.java b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestTagDefinitionJson.java
index 93721d6..2a6da5e 100644
--- a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestTagDefinitionJson.java
+++ b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestTagDefinitionJson.java
@@ -24,6 +24,7 @@ import org.testng.annotations.Test;
import org.killbill.billing.jaxrs.JaxrsTestSuiteNoDB;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
public class TestTagDefinitionJson extends JaxrsTestSuiteNoDB {
@@ -33,7 +34,7 @@ public class TestTagDefinitionJson extends JaxrsTestSuiteNoDB {
final Boolean isControlTag = true;
final String name = UUID.randomUUID().toString();
final String description = UUID.randomUUID().toString();
- final ImmutableList<String> applicableObjectTypes = ImmutableList.<String>of(UUID.randomUUID().toString());
+ final ImmutableSet<String> applicableObjectTypes = ImmutableSet.<String>of(UUID.randomUUID().toString());
final TagDefinitionJson tagDefinitionJson = new TagDefinitionJson(id, isControlTag, name, description, applicableObjectTypes, null);
Assert.assertEquals(tagDefinitionJson.getId(), id);
Assert.assertEquals(tagDefinitionJson.isControlTag(), isControlTag);
diff --git a/junction/src/test/java/org/killbill/billing/junction/JunctionTestSuiteWithEmbeddedDB.java b/junction/src/test/java/org/killbill/billing/junction/JunctionTestSuiteWithEmbeddedDB.java
index 4eced64..859d024 100644
--- a/junction/src/test/java/org/killbill/billing/junction/JunctionTestSuiteWithEmbeddedDB.java
+++ b/junction/src/test/java/org/killbill/billing/junction/JunctionTestSuiteWithEmbeddedDB.java
@@ -108,16 +108,10 @@ public abstract class JunctionTestSuiteWithEmbeddedDB extends GuicyKillbillTestS
super.beforeMethod();
startTestFamework();
this.catalog = initCatalog(catalogService);
-
- // Make sure we start with a clean state
- assertListenerStatus();
}
@AfterMethod(groups = "slow")
public void afterMethod() throws Exception {
- // Make sure we finish in a clean state
- assertListenerStatus();
-
stopTestFramework();
}
@@ -219,6 +213,7 @@ public abstract class JunctionTestSuiteWithEmbeddedDB extends GuicyKillbillTestS
return account;
}
+ @Override
protected void assertListenerStatus() {
testListener.assertListenerStatus();
}
diff --git a/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestDefaultInternalBillingApi.java b/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestDefaultInternalBillingApi.java
index c8c99f1..f4a34ed 100644
--- a/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestDefaultInternalBillingApi.java
+++ b/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestDefaultInternalBillingApi.java
@@ -60,7 +60,7 @@ public class TestDefaultInternalBillingApi extends JunctionTestSuiteWithEmbedded
testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
- final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
final SubscriptionBase subscription = subscriptionInternalApi.getSubscriptionFromId(entitlement.getId(), internalCallContext);
assertListenerStatus();
@@ -205,7 +205,7 @@ public class TestDefaultInternalBillingApi extends JunctionTestSuiteWithEmbedded
testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
- final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
final SubscriptionBase subscription = subscriptionInternalApi.getSubscriptionFromId(entitlement.getId(), internalCallContext);
assertListenerStatus();
@@ -223,6 +223,7 @@ public class TestDefaultInternalBillingApi extends JunctionTestSuiteWithEmbedded
true,
block1Date);
blockingInternalApi.setBlockingState(state1, internalCallContext);
+ assertListenerStatus();
clock.addDays(1);
diff --git a/overdue/src/test/java/org/killbill/billing/overdue/notification/TestOverdueCheckNotifier.java b/overdue/src/test/java/org/killbill/billing/overdue/notification/TestOverdueCheckNotifier.java
index 744e845..8856294 100644
--- a/overdue/src/test/java/org/killbill/billing/overdue/notification/TestOverdueCheckNotifier.java
+++ b/overdue/src/test/java/org/killbill/billing/overdue/notification/TestOverdueCheckNotifier.java
@@ -69,9 +69,10 @@ public class TestOverdueCheckNotifier extends OverdueTestSuiteWithEmbeddedDB {
@Override
@BeforeMethod(groups = "slow")
public void beforeMethod() throws Exception {
- //super.beforeMethod();
// We override the parent method on purpose, because we want to register a different OverdueCheckNotifier
+ cleanupAllTables();
+
mockDispatcher = new OverdueDispatcherMock(internalCallContextFactory);
notifierForMock = new OverdueCheckNotifier(notificationQueueService, overdueProperties, internalCallContextFactory, mockDispatcher);
diff --git a/payment/src/main/java/org/killbill/billing/payment/invoice/InvoicePaymentControlPluginApi.java b/payment/src/main/java/org/killbill/billing/payment/invoice/InvoicePaymentControlPluginApi.java
index 6aa0bd6..09dda8b 100644
--- a/payment/src/main/java/org/killbill/billing/payment/invoice/InvoicePaymentControlPluginApi.java
+++ b/payment/src/main/java/org/killbill/billing/payment/invoice/InvoicePaymentControlPluginApi.java
@@ -331,11 +331,23 @@ public final class InvoicePaymentControlPluginApi implements PaymentControlPlugi
}
+ // Is remaining amount > 0 ?
final BigDecimal requestedAmount = validateAndComputePaymentAmount(invoice, paymentControlPluginContext.getAmount(), paymentControlPluginContext.isApiPayment());
+ if (requestedAmount.compareTo(BigDecimal.ZERO) <= 0) {
+ if (paymentControlPluginContext.isApiPayment()) {
+ throw new PaymentControlApiException("Abort purchase call: ", new PaymentApiException(ErrorCode.PAYMENT_PLUGIN_EXCEPTION,
+ String.format("Aborted Payment for invoice %s : invoice balance is = %s, requested payment amount is = %s",
+ invoice.getId(),
+ invoice.getBalance(),
+ paymentControlPluginContext.getAmount())));
- final boolean isAborted = requestedAmount.compareTo(BigDecimal.ZERO) == 0;
+ }
+ return new DefaultPriorPaymentControlResult(true);
+ }
- if (!isAborted && paymentControlPluginContext.getPaymentMethodId() == null) {
+
+ // Do we have a paymentMethod ?
+ if (paymentControlPluginContext.getPaymentMethodId() == null) {
log.warn("Payment for invoiceId='{}' was not triggered, accountId='{}' doesn't have a default payment method", getInvoiceId(pluginProperties), paymentControlPluginContext.getAccountId());
invoiceApi.recordPaymentAttemptCompletion(invoiceId,
paymentControlPluginContext.getAmount(),
@@ -349,35 +361,31 @@ public final class InvoicePaymentControlPluginApi implements PaymentControlPlugi
return new DefaultPriorPaymentControlResult(true);
}
- if (!isAborted && insert_AUTO_PAY_OFF_ifRequired(paymentControlPluginContext, requestedAmount)) {
+
+ // Are we in auto-payoff ?
+ if (insert_AUTO_PAY_OFF_ifRequired(paymentControlPluginContext, requestedAmount)) {
return new DefaultPriorPaymentControlResult(true);
}
- if (paymentControlPluginContext.isApiPayment() && isAborted) {
- throw new PaymentControlApiException("Abort purchase call: ", new PaymentApiException(ErrorCode.PAYMENT_PLUGIN_EXCEPTION,
- String.format("Aborted Payment for invoice %s : invoice balance is = %s, requested payment amount is = %s",
- invoice.getId(),
- invoice.getBalance(),
- paymentControlPluginContext.getAmount())));
- } else {
-
- //
- // Insert attempt row with a success = false status to implement a two-phase commit strategy and guard against scenario where payment would go through
- // but onSuccessCall callback never gets called (leaving the place for a double payment if user retries the operation)
- //
- invoiceApi.recordPaymentAttemptInit(invoice.getId(),
- MoreObjects.firstNonNull(paymentControlPluginContext.getAmount(), BigDecimal.ZERO),
- paymentControlPluginContext.getCurrency(),
- paymentControlPluginContext.getCurrency(),
- // Likely to be null, but we don't care as we use the transactionExternalKey
- // to match the operation in the checkForIncompleteInvoicePaymentAndRepair logic below
- paymentControlPluginContext.getPaymentId(),
- paymentControlPluginContext.getTransactionExternalKey(),
- paymentControlPluginContext.getCreatedDate(),
- internalContext);
-
- return new DefaultPriorPaymentControlResult(isAborted, requestedAmount);
- }
+
+ //
+ // Insert attempt row with a success = false status to implement a two-phase commit strategy and guard against scenario where payment would go through
+ // but onSuccessCall callback never gets called (leaving the place for a double payment if user retries the operation)
+ //
+ invoiceApi.recordPaymentAttemptInit(invoice.getId(),
+ MoreObjects.firstNonNull(paymentControlPluginContext.getAmount(), BigDecimal.ZERO),
+ paymentControlPluginContext.getCurrency(),
+ paymentControlPluginContext.getCurrency(),
+ // Likely to be null, but we don't care as we use the transactionExternalKey
+ // to match the operation in the checkForIncompleteInvoicePaymentAndRepair logic below
+ paymentControlPluginContext.getPaymentId(),
+ paymentControlPluginContext.getTransactionExternalKey(),
+ paymentControlPluginContext.getCreatedDate(),
+ internalContext);
+
+ return new DefaultPriorPaymentControlResult(false, requestedAmount);
+
+
} catch (final InvoiceApiException e) {
throw new PaymentControlApiException(e);
} catch (final IllegalArgumentException e) {
diff --git a/payment/src/test/java/org/killbill/billing/payment/TestJanitor.java b/payment/src/test/java/org/killbill/billing/payment/TestJanitor.java
index a124e0b..46a756e 100644
--- a/payment/src/test/java/org/killbill/billing/payment/TestJanitor.java
+++ b/payment/src/test/java/org/killbill/billing/payment/TestJanitor.java
@@ -115,6 +115,11 @@ public class TestJanitor extends PaymentTestSuiteWithEmbeddedDB {
);
}
+ @Override
+ protected void assertListenerStatus() {
+ testListener.assertListenerStatus();
+ }
+
@BeforeClass(groups = "slow")
protected void beforeClass() throws Exception {
super.beforeClass();
@@ -133,16 +138,12 @@ public class TestJanitor extends PaymentTestSuiteWithEmbeddedDB {
eventBus.register(testListener);
mockPaymentProviderPlugin.clear();
account = testHelper.createTestAccount("bobo@gmail.com", true);
-
- testListener.assertListenerStatus();
}
@AfterMethod(groups = "slow")
public void afterMethod() throws Exception {
retryService.stop();
- testListener.assertListenerStatus();
-
eventBus.unregister(handler);
eventBus.unregister(testListener);
super.afterMethod();
pom.xml 2(+1 -1)
diff --git a/pom.xml b/pom.xml
index 817b368..c5359c3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,7 +21,7 @@
<parent>
<artifactId>killbill-oss-parent</artifactId>
<groupId>org.kill-bill.billing</groupId>
- <version>0.141.4</version>
+ <version>0.141.5</version>
</parent>
<artifactId>killbill</artifactId>
<version>0.19.0-SNAPSHOT</version>
diff --git a/profiles/killbill/src/main/java/org/killbill/billing/server/notifications/PushNotificationKey.java b/profiles/killbill/src/main/java/org/killbill/billing/server/notifications/PushNotificationKey.java
index e72dec3..eb25be3 100644
--- a/profiles/killbill/src/main/java/org/killbill/billing/server/notifications/PushNotificationKey.java
+++ b/profiles/killbill/src/main/java/org/killbill/billing/server/notifications/PushNotificationKey.java
@@ -33,6 +33,7 @@ public class PushNotificationKey implements NotificationEvent {
private final UUID objectId;
private final int attemptNumber;
private final String url;
+ private final String metaData;
@JsonCreator
public PushNotificationKey(@JsonProperty("tenantId") final UUID tenantId,
@@ -41,6 +42,7 @@ public class PushNotificationKey implements NotificationEvent {
@JsonProperty("objectType") final String objectType,
@JsonProperty("objectId") final UUID objectId,
@JsonProperty("attemptNumber") final int attemptNumber,
+ @JsonProperty("metaData") final String metaData,
@JsonProperty("url") final String url) {
this.tenantId = tenantId;
this.accountId = accountId;
@@ -48,12 +50,13 @@ public class PushNotificationKey implements NotificationEvent {
this.objectType = objectType;
this.objectId = objectId;
this.attemptNumber = attemptNumber;
+ this.metaData = metaData;
this.url = url;
}
public PushNotificationKey(final PushNotificationKey key, final int attemptNumber) {
this(key.getTenantId(), key.getAccountId(), key.getEventType(), key.getObjectType(), key.getObjectId(),
- attemptNumber, key.getUrl());
+ attemptNumber, key.getMetaData(), key.getUrl());
}
public UUID getTenantId() {
@@ -84,6 +87,10 @@ public class PushNotificationKey implements NotificationEvent {
return url;
}
+ public String getMetaData() {
+ return metaData;
+ }
+
@Override
public String toString() {
return "PushNotificationKey{" +
@@ -92,6 +99,7 @@ public class PushNotificationKey implements NotificationEvent {
", eventType='" + eventType + '\'' +
", objectType='" + objectType + '\'' +
", objectId=" + objectId +
+ ", metaData=" + metaData +
", attemptNumber=" + attemptNumber +
", url='" + url + '\'' +
'}';
diff --git a/profiles/killbill/src/main/java/org/killbill/billing/server/notifications/PushNotificationListener.java b/profiles/killbill/src/main/java/org/killbill/billing/server/notifications/PushNotificationListener.java
index b598153..b9cb18c 100644
--- a/profiles/killbill/src/main/java/org/killbill/billing/server/notifications/PushNotificationListener.java
+++ b/profiles/killbill/src/main/java/org/killbill/billing/server/notifications/PushNotificationListener.java
@@ -162,7 +162,8 @@ public class PushNotificationListener {
final NotificationJson notification = new NotificationJson(key.getEventType() != null ? key.getEventType().toString() : null,
key.getAccountId() != null ? key.getAccountId().toString() : null,
key.getObjectType() != null ? key.getObjectType().toString() : null,
- key.getObjectId() != null ? key.getObjectId().toString() : null);
+ key.getObjectId() != null ? key.getObjectId().toString() : null,
+ key.getMetaData());
final String body = mapper.writeValueAsString(notification);
doPost(key.getTenantId(), key.getUrl(), body, notification, TIMEOUT_NOTIFICATION, key.getAttemptNumber());
}
@@ -173,7 +174,9 @@ public class PushNotificationListener {
notificationJson.getEventType(),
notificationJson.getObjectType(),
notificationJson.getObjectId() != null ? UUID.fromString(notificationJson.getObjectId()) : null,
- attemptRetryNumber + 1, url);
+ attemptRetryNumber + 1,
+ notificationJson.getMetaData(),
+ url);
final TenantContext tenantContext = contextFactory.createTenantContext(null, tenantId);
final DateTime nextNotificationTime = getNextNotificationTime(key.getAttemptNumber(), internalCallContextFactory.createInternalTenantContextWithoutAccountRecordId(tenantContext));
diff --git a/profiles/killbill/src/main/resources/killbill-server.properties b/profiles/killbill/src/main/resources/killbill-server.properties
index 6208aa4..2894eb4 100644
--- a/profiles/killbill/src/main/resources/killbill-server.properties
+++ b/profiles/killbill/src/main/resources/killbill-server.properties
@@ -88,3 +88,4 @@ org.killbill.payment.retry.days=1,1,1
org.killbill.notificationq.analytics.tableName=analytics_notifications
org.killbill.notificationq.analytics.historyTableName=analytics_notifications_history
+
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestEntitlement.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestEntitlement.java
index c01e757..3eb79f2 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestEntitlement.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestEntitlement.java
@@ -22,6 +22,7 @@ import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
+import java.util.regex.Pattern;
import org.joda.time.DateTime;
import org.joda.time.Interval;
@@ -258,20 +259,20 @@ public class TestEntitlement extends TestJaxrsBase {
Assert.assertEquals(subscription.getEvents().size(), 3);
Assert.assertEquals(subscription.getEvents().get(0).getEventType(), SubscriptionEventType.START_ENTITLEMENT.name());
- Assert.assertEquals(subscription.getEvents().get(0).getPlan(), "shotgun-monthly-1");
- Assert.assertEquals(subscription.getEvents().get(0).getPhase(), "shotgun-monthly-1-trial");
+ assertMatches(subscription.getEvents().get(0).getPlan(), "shotgun-monthly-[1-9]+");
+ assertMatches(subscription.getEvents().get(0).getPhase(), "shotgun-monthly-[1-9]+-trial");
Assert.assertEquals(subscription.getEvents().get(0).getPriceList(), PriceListSet.DEFAULT_PRICELIST_NAME.toString());
Assert.assertEquals(subscription.getEvents().get(0).getProduct(), "Shotgun");
Assert.assertEquals(subscription.getEvents().get(1).getEventType(), SubscriptionEventType.START_BILLING.name());
- Assert.assertEquals(subscription.getEvents().get(1).getPlan(), "shotgun-monthly-1");
- Assert.assertEquals(subscription.getEvents().get(1).getPhase(), "shotgun-monthly-1-trial");
+ assertMatches(subscription.getEvents().get(1).getPlan(), "shotgun-monthly-[1-9]+");
+ assertMatches(subscription.getEvents().get(1).getPhase(), "shotgun-monthly-[1-9]+-trial");
Assert.assertEquals(subscription.getEvents().get(1).getPriceList(), PriceListSet.DEFAULT_PRICELIST_NAME.toString());
Assert.assertEquals(subscription.getEvents().get(1).getProduct(), "Shotgun");
Assert.assertEquals(subscription.getEvents().get(2).getEventType(), SubscriptionEventType.PHASE.name());
- Assert.assertEquals(subscription.getEvents().get(2).getPlan(), "shotgun-monthly-1");
- Assert.assertEquals(subscription.getEvents().get(2).getPhase(), "shotgun-monthly-1-evergreen");
+ assertMatches(subscription.getEvents().get(2).getPlan(), "shotgun-monthly-[1-9]+");
+ assertMatches(subscription.getEvents().get(2).getPhase(), "shotgun-monthly-[1-9]+-evergreen");
Assert.assertEquals(subscription.getEvents().get(2).getPriceList(), PriceListSet.DEFAULT_PRICELIST_NAME.toString());
Assert.assertEquals(subscription.getEvents().get(2).getProduct(), "Shotgun");
@@ -297,20 +298,20 @@ public class TestEntitlement extends TestJaxrsBase {
Assert.assertEquals(subscription3.getEvents().size(), 4);
Assert.assertEquals(subscription3.getEvents().get(0).getEventType(), SubscriptionEventType.START_ENTITLEMENT.name());
- Assert.assertEquals(subscription3.getEvents().get(0).getPlan(), "shotgun-monthly-1");
- Assert.assertEquals(subscription3.getEvents().get(0).getPhase(), "shotgun-monthly-1-trial");
+ assertMatches(subscription3.getEvents().get(0).getPlan(), "shotgun-monthly-[1-9]+");
+ assertMatches(subscription3.getEvents().get(0).getPhase(), "shotgun-monthly-[1-9]+-trial");
Assert.assertEquals(subscription3.getEvents().get(0).getPriceList(), PriceListSet.DEFAULT_PRICELIST_NAME.toString());
Assert.assertEquals(subscription3.getEvents().get(0).getProduct(), "Shotgun");
Assert.assertEquals(subscription3.getEvents().get(1).getEventType(), SubscriptionEventType.START_BILLING.name());
- Assert.assertEquals(subscription3.getEvents().get(1).getPlan(), "shotgun-monthly-1");
- Assert.assertEquals(subscription3.getEvents().get(1).getPhase(), "shotgun-monthly-1-trial");
+ assertMatches(subscription3.getEvents().get(1).getPlan(), "shotgun-monthly-[1-9]+");
+ assertMatches(subscription3.getEvents().get(1).getPhase(), "shotgun-monthly-[1-9]+-trial");
Assert.assertEquals(subscription3.getEvents().get(1).getPriceList(), PriceListSet.DEFAULT_PRICELIST_NAME.toString());
Assert.assertEquals(subscription3.getEvents().get(1).getProduct(), "Shotgun");
Assert.assertEquals(subscription3.getEvents().get(2).getEventType(), SubscriptionEventType.PHASE.name());
- Assert.assertEquals(subscription3.getEvents().get(2).getPlan(), "shotgun-monthly-1");
- Assert.assertEquals(subscription3.getEvents().get(2).getPhase(), "shotgun-monthly-1-evergreen");
+ assertMatches(subscription3.getEvents().get(2).getPlan(), "shotgun-monthly-[1-9]+");
+ assertMatches(subscription3.getEvents().get(2).getPhase(), "shotgun-monthly-[1-9]+-evergreen");
Assert.assertEquals(subscription3.getEvents().get(2).getPriceList(), PriceListSet.DEFAULT_PRICELIST_NAME.toString());
Assert.assertEquals(subscription3.getEvents().get(2).getProduct(), "Shotgun");
@@ -321,6 +322,10 @@ public class TestEntitlement extends TestJaxrsBase {
Assert.assertEquals(subscription3.getEvents().get(3).getProduct(), "Pistol");
}
+ private void assertMatches(final String actual, final String regexp) {
+ Assert.assertTrue(Pattern.compile(regexp).matcher(actual).matches(), String.format("%s doesn't match pattern %s", actual, regexp));
+ }
+
@Test(groups = "slow", description = "Create a base entitlement and also addOns entitlements under the same bundle")
public void testEntitlementWithAddOnsWithWRITTEN_OFF() throws Exception {
final DateTime initialDate = new DateTime(2012, 4, 25, 0, 3, 42, 0);
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestInvoice.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestInvoice.java
index 9b8e81d..e1d9f5c 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestInvoice.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestInvoice.java
@@ -27,6 +27,7 @@ import java.util.UUID;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.LocalDate;
+import org.killbill.billing.api.FlakyRetryAnalyzer;
import org.killbill.billing.catalog.api.BillingPeriod;
import org.killbill.billing.catalog.api.ProductCategory;
import org.killbill.billing.client.KillBillClientException;
@@ -501,7 +502,8 @@ public class TestInvoice extends TestJaxrsBase {
assertEquals(killBillClient.getInvoicesForAccount(accountJson.getAccountId(), requestOptions).size(), 3);
}
- @Test(groups = "slow", description = "Can create multiple external charges with same invoice and external keys")
+ // Flaky, see https://github.com/killbill/killbill/issues/801
+ @Test(groups = "slow", description = "Can create multiple external charges with same invoice and external keys", retryAnalyzer = FlakyRetryAnalyzer.class)
public void testExternalChargesWithSameInvoiceAndExternalKeys() throws Exception {
final Account accountJson = createAccountWithPMBundleAndSubscriptionAndWaitForFirstInvoice();
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestInvoicePayment.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestInvoicePayment.java
index 661a1c6..9803ca8 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestInvoicePayment.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestInvoicePayment.java
@@ -45,6 +45,7 @@ import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.google.inject.Inject;
import static org.testng.Assert.assertEquals;
@@ -66,10 +67,36 @@ public class TestInvoicePayment extends TestJaxrsBase {
@Test(groups = "slow")
public void testRetrievePayment() throws Exception {
final InvoicePayment paymentJson = setupScenarioWithPayment();
- final Payment retrievedPaymentJson = killBillClient.getPayment(paymentJson.getPaymentId(), false);
+ final Payment retrievedPaymentJson = killBillClient.getPayment(paymentJson.getPaymentId(), false, requestOptions);
Assert.assertTrue(retrievedPaymentJson.equals((Payment) paymentJson));
}
+
+ @Test(groups = "slow")
+ public void testInvoicePaymentCompletion() throws Exception {
+ mockPaymentProviderPlugin.makeNextPaymentPending();
+
+ final InvoicePayment paymentJson = setupScenarioWithPayment();
+
+ final Payment retrievedPaymentJson = killBillClient.getPayment(paymentJson.getPaymentId(), false, requestOptions);
+ Assert.assertTrue(retrievedPaymentJson.equals((Payment) paymentJson));
+ Assert.assertEquals(retrievedPaymentJson.getTransactions().size(), 1);
+ Assert.assertEquals(retrievedPaymentJson.getTransactions().get(0).getStatus(), "PENDING");
+
+ final PaymentTransaction completeTransactionByPaymentId = new PaymentTransaction();
+ completeTransactionByPaymentId.setPaymentId(retrievedPaymentJson.getPaymentId());
+
+ final Account accountWithBalance = killBillClient.getAccount(paymentJson.getAccountId(), true, false, requestOptions);
+ Assert.assertTrue(accountWithBalance.getAccountBalance().compareTo(BigDecimal.ZERO) > 0);
+
+ final Payment completedPayment = killBillClient.completeInvoicePayment(completeTransactionByPaymentId, null, ImmutableMap.<String, String>of(), requestOptions);
+ Assert.assertEquals(completedPayment.getTransactions().get(0).getStatus(), "SUCCESS");
+
+ final Account accountWithBalance2 = killBillClient.getAccount(paymentJson.getAccountId(), true, false, requestOptions);
+ Assert.assertEquals(accountWithBalance2.getAccountBalance().compareTo(BigDecimal.ZERO), 0);
+
+ }
+
@Test(groups = "slow", description = "Can create a full refund with no adjustment")
public void testFullRefundWithNoAdjustment() throws Exception {
final InvoicePayment invoicePaymentJson = setupScenarioWithPayment();
@@ -82,7 +109,7 @@ public class TestInvoicePayment extends TestJaxrsBase {
final InvoicePaymentTransaction refund = new InvoicePaymentTransaction();
refund.setPaymentId(invoicePaymentJson.getPaymentId());
refund.setAmount(refundAmount);
- final Payment paymentAfterRefundJson = killBillClient.createInvoicePaymentRefund(refund, createdBy, reason, comment);
+ final Payment paymentAfterRefundJson = killBillClient.createInvoicePaymentRefund(refund, requestOptions);
verifyRefund(invoicePaymentJson, paymentAfterRefundJson, refundAmount);
// Verify the invoice balance
@@ -101,7 +128,7 @@ public class TestInvoicePayment extends TestJaxrsBase {
final InvoicePaymentTransaction refund = new InvoicePaymentTransaction();
refund.setPaymentId(paymentJson.getPaymentId());
refund.setAmount(refundAmount);
- final Payment paymentAfterRefundJson = killBillClient.createInvoicePaymentRefund(refund, createdBy, reason, comment);
+ final Payment paymentAfterRefundJson = killBillClient.createInvoicePaymentRefund(refund, requestOptions);
verifyRefund(paymentJson, paymentAfterRefundJson, refundAmount);
// Verify the invoice balance
@@ -113,7 +140,7 @@ public class TestInvoicePayment extends TestJaxrsBase {
final InvoicePayment paymentJson = setupScenarioWithPayment();
// Get the individual items for the invoice
- final Invoice invoice = killBillClient.getInvoice(paymentJson.getTargetInvoiceId(), true);
+ final Invoice invoice = killBillClient.getInvoice(paymentJson.getTargetInvoiceId(), true, false, requestOptions);
final InvoiceItem itemToAdjust = invoice.getItems().get(0);
// Issue a refund for the full amount
@@ -129,7 +156,7 @@ public class TestInvoicePayment extends TestJaxrsBase {
adjustment.setInvoiceItemId(itemToAdjust.getInvoiceItemId());
/* null amount means full adjustment for that item */
refund.setAdjustments(ImmutableList.<InvoiceItem>of(adjustment));
- final Payment paymentAfterRefundJson = killBillClient.createInvoicePaymentRefund(refund, createdBy, reason, comment);
+ final Payment paymentAfterRefundJson = killBillClient.createInvoicePaymentRefund(refund, requestOptions);
verifyRefund(paymentJson, paymentAfterRefundJson, refundAmount);
// Verify the invoice balance
@@ -141,7 +168,7 @@ public class TestInvoicePayment extends TestJaxrsBase {
final InvoicePayment paymentJson = setupScenarioWithPayment();
// Get the individual items for the invoice
- final Invoice invoice = killBillClient.getInvoice(paymentJson.getTargetInvoiceId(), true);
+ final Invoice invoice = killBillClient.getInvoice(paymentJson.getTargetInvoiceId(), true, false, requestOptions);
final InvoiceItem itemToAdjust = invoice.getItems().get(0);
// Issue a refund for a fraction of the amount
@@ -156,7 +183,7 @@ public class TestInvoicePayment extends TestJaxrsBase {
adjustment.setInvoiceItemId(itemToAdjust.getInvoiceItemId());
adjustment.setAmount(refundAmount);
refund.setAdjustments(ImmutableList.<InvoiceItem>of(adjustment));
- final Payment paymentAfterRefundJson = killBillClient.createInvoicePaymentRefund(refund, createdBy, reason, comment);
+ final Payment paymentAfterRefundJson = killBillClient.createInvoicePaymentRefund(refund, requestOptions);
verifyRefund(paymentJson, paymentAfterRefundJson, refundAmount);
// Verify the invoice balance
@@ -202,23 +229,23 @@ public class TestInvoicePayment extends TestJaxrsBase {
final InvoicePaymentTransaction refund = new InvoicePaymentTransaction();
refund.setPaymentId(lastPayment.getPaymentId());
refund.setAmount(lastPayment.getPurchasedAmount());
- killBillClient.createInvoicePaymentRefund(refund, createdBy, reason, comment);
+ killBillClient.createInvoicePaymentRefund(refund, requestOptions);
final InvoicePayment invoicePayment = new InvoicePayment();
invoicePayment.setPurchasedAmount(lastPayment.getPurchasedAmount());
invoicePayment.setAccountId(lastPayment.getAccountId());
invoicePayment.setTargetInvoiceId(lastPayment.getTargetInvoiceId());
- final InvoicePayment payment = killBillClient.createInvoicePayment(invoicePayment, false, createdBy, reason, comment);
+ final InvoicePayment payment = killBillClient.createInvoicePayment(invoicePayment, false, requestOptions);
lastPayment = payment;
}
- final InvoicePayments allPayments = killBillClient.getInvoicePaymentsForAccount(lastPayment.getAccountId());
+ final InvoicePayments allPayments = killBillClient.getInvoicePaymentsForAccount(lastPayment.getAccountId(), requestOptions);
Assert.assertEquals(allPayments.size(), 6);
final List<PaymentTransaction> objRefundFromJson = getPaymentTransactions(allPayments, TransactionType.REFUND.toString());
Assert.assertEquals(objRefundFromJson.size(), 5);
- Payments paymentsPage = killBillClient.getPayments(0L, 1L);
+ Payments paymentsPage = killBillClient.getPayments(0L, 1L, requestOptions);
for (int i = 0; i < 6; i++) {
Assert.assertNotNull(paymentsPage);
Assert.assertEquals(paymentsPage.size(), 1);
@@ -267,14 +294,14 @@ public class TestInvoicePayment extends TestJaxrsBase {
private InvoicePayment setupScenarioWithPayment() throws Exception {
final Account accountJson = createAccountWithPMBundleAndSubscriptionAndWaitForFirstInvoice();
- final List<InvoicePayment> paymentsForAccount = killBillClient.getInvoicePaymentsForAccount(accountJson.getAccountId());
+ final List<InvoicePayment> paymentsForAccount = killBillClient.getInvoicePaymentsForAccount(accountJson.getAccountId(), requestOptions);
Assert.assertEquals(paymentsForAccount.size(), 1);
final InvoicePayment paymentJson = paymentsForAccount.get(0);
// Check the PaymentMethod from paymentMethodId returned in the Payment object
final UUID paymentMethodId = paymentJson.getPaymentMethodId();
- final PaymentMethod paymentMethodJson = killBillClient.getPaymentMethod(paymentMethodId, true);
+ final PaymentMethod paymentMethodJson = killBillClient.getPaymentMethod(paymentMethodId, true, requestOptions);
Assert.assertEquals(paymentMethodJson.getPaymentMethodId(), paymentMethodId);
Assert.assertEquals(paymentMethodJson.getAccountId(), accountJson.getAccountId());
@@ -299,7 +326,7 @@ public class TestInvoicePayment extends TestJaxrsBase {
Assert.assertEquals(refund.getEffectiveDate().getDayOfMonth(), clock.getUTCNow().getDayOfMonth());
// Verify the refund via the payment API
- final Payment retrievedPaymentJson = killBillClient.getPayment(paymentJson.getPaymentId(), true);
+ final Payment retrievedPaymentJson = killBillClient.getPayment(paymentJson.getPaymentId(), true, requestOptions);
Assert.assertEquals(retrievedPaymentJson.getPaymentId(), paymentJson.getPaymentId());
Assert.assertEquals(retrievedPaymentJson.getPurchasedAmount().setScale(2, RoundingMode.HALF_UP), paymentJson.getPurchasedAmount().setScale(2, RoundingMode.HALF_UP));
Assert.assertEquals(retrievedPaymentJson.getAccountId(), paymentJson.getAccountId());
@@ -308,7 +335,7 @@ public class TestInvoicePayment extends TestJaxrsBase {
}
private void verifyInvoice(final InvoicePayment paymentJson, final BigDecimal expectedInvoiceBalance) throws KillBillClientException {
- final Invoice invoiceJson = killBillClient.getInvoice(paymentJson.getTargetInvoiceId());
+ final Invoice invoiceJson = killBillClient.getInvoice(paymentJson.getTargetInvoiceId(), requestOptions);
Assert.assertEquals(invoiceJson.getBalance().setScale(2, BigDecimal.ROUND_HALF_UP),
expectedInvoiceBalance.setScale(2, BigDecimal.ROUND_HALF_UP));
}
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestJaxrsBase.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestJaxrsBase.java
index 0488304..01cc712 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestJaxrsBase.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestJaxrsBase.java
@@ -18,6 +18,9 @@
package org.killbill.billing.jaxrs;
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadInfo;
+import java.lang.management.ThreadMXBean;
import java.util.EventListener;
import java.util.Iterator;
import java.util.List;
@@ -58,6 +61,8 @@ import org.killbill.billing.util.config.definition.SecurityConfig;
import org.killbill.bus.api.PersistentBus;
import org.killbill.commons.jdbi.guice.DaoConfig;
import org.skife.config.ConfigurationObjectFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.BeforeClass;
@@ -74,6 +79,12 @@ import com.google.inject.util.Modules;
public class TestJaxrsBase extends KillbillClient {
+ private static final Logger log = LoggerFactory.getLogger(TestJaxrsBase.class);
+
+ protected final int DEFAULT_CONNECT_TIMEOUT_SEC = 10;
+ protected final int DEFAULT_READ_TIMEOUT_SEC = 60;
+ protected final int DEFAULT_REQUEST_TIMEOUT_SEC = DEFAULT_READ_TIMEOUT_SEC;
+
protected static final String PLUGIN_NAME = "noop";
@Inject
@@ -161,7 +172,12 @@ public class TestJaxrsBase extends KillbillClient {
username,
password,
apiKey,
- apiSecret);
+ apiSecret,
+ null,
+ null,
+ DEFAULT_CONNECT_TIMEOUT_SEC * 1000,
+ DEFAULT_READ_TIMEOUT_SEC * 1000,
+ DEFAULT_REQUEST_TIMEOUT_SEC * 1000);
killBillClient = new KillBillClient(killBillHttpClient);
}
@@ -287,4 +303,24 @@ public class TestJaxrsBase extends KillbillClient {
})));
}
+ protected void printThreadDump() {
+ final StringBuilder dump = new StringBuilder("Thread dump:\n");
+ final ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
+ final ThreadInfo[] threadInfos = threadMXBean.getThreadInfo(threadMXBean.getAllThreadIds(), 100);
+ for (final ThreadInfo threadInfo : threadInfos) {
+ dump.append('"');
+ dump.append(threadInfo.getThreadName());
+ dump.append("\" ");
+ final Thread.State state = threadInfo.getThreadState();
+ dump.append("\n java.lang.Thread.State: ");
+ dump.append(state);
+ final StackTraceElement[] stackTraceElements = threadInfo.getStackTrace();
+ for (final StackTraceElement stackTraceElement : stackTraceElements) {
+ dump.append("\n at ");
+ dump.append(stackTraceElement);
+ }
+ dump.append("\n\n");
+ }
+ log.warn(dump.toString());
+ }
}
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPayment.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPayment.java
index 69c17a0..d7beb54 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPayment.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPayment.java
@@ -26,6 +26,7 @@ import java.util.UUID;
import javax.annotation.Nullable;
+import org.killbill.billing.ObjectType;
import org.killbill.billing.client.KillBillClientException;
import org.killbill.billing.client.RequestOptions;
import org.killbill.billing.client.model.Account;
@@ -696,7 +697,7 @@ public class TestPayment extends TestJaxrsBase {
public void testGetTagsForPaymentTransaction() throws Exception {
UUID tagDefinitionId = UUID.randomUUID();
String tagDefinitionName = "payment-transaction";
- TagDefinition tagDefinition = new TagDefinition(tagDefinitionId, false, tagDefinitionName, "description", null);
+ TagDefinition tagDefinition = new TagDefinition(tagDefinitionId, false, tagDefinitionName, "description", ImmutableList.<ObjectType>of(ObjectType.TRANSACTION));
final TagDefinition createdTagDefinition = killBillClient.createTagDefinition(tagDefinition, requestOptions);
final Account account = createAccountWithDefaultPaymentMethod();
@@ -719,7 +720,7 @@ public class TestPayment extends TestJaxrsBase {
public void testCreateTagForPaymentTransaction() throws Exception {
UUID tagDefinitionId = UUID.randomUUID();
String tagDefinitionName = "payment-transaction";
- TagDefinition tagDefinition = new TagDefinition(tagDefinitionId, false, tagDefinitionName, "description", null);
+ TagDefinition tagDefinition = new TagDefinition(tagDefinitionId, false, tagDefinitionName, "description", ImmutableList.<ObjectType>of(ObjectType.TRANSACTION));
final TagDefinition createdTagDefinition = killBillClient.createTagDefinition(tagDefinition, requestOptions);
final Account account = createAccountWithDefaultPaymentMethod();
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPushNotification.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPushNotification.java
index 1c6b542..4b32eba 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPushNotification.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPushNotification.java
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -34,6 +34,7 @@ import org.eclipse.jetty.servlet.ServletHolder;
import org.killbill.billing.client.KillBillClientException;
import org.killbill.billing.client.model.TenantKey;
import org.killbill.billing.jaxrs.json.NotificationJson;
+import org.killbill.billing.notification.plugin.api.ExtBusEventType;
import org.killbill.billing.server.notifications.PushNotificationListener;
import org.killbill.billing.tenant.api.TenantKV;
import org.slf4j.Logger;
@@ -74,8 +75,16 @@ public class TestPushNotification extends TestJaxrsBase {
callbackServer.stopServer();
}
+ private void assertAllCallbacksCompleted() throws InterruptedException {
+ final boolean waitForCallbacksToComplete = waitForCallbacksToComplete();
+ if (!waitForCallbacksToComplete) {
+ printThreadDump();
+ }
+ Assert.assertTrue(waitForCallbacksToComplete, "Fail to see push notification callbacks");
+ }
+
private boolean waitForCallbacksToComplete() throws InterruptedException {
- long remainingMs = 30000;
+ long remainingMs = DEFAULT_REQUEST_TIMEOUT_SEC * 1000;
do {
if (callbackCompleted) {
break;
@@ -107,10 +116,7 @@ public class TestPushNotification extends TestJaxrsBase {
// Create account to trigger a push notification
createAccount();
- final boolean success = waitForCallbacksToComplete();
- if (!success) {
- Assert.fail("Fail to see push notification callbacks after 5 sec");
- }
+ assertAllCallbacksCompleted();
if (callbackCompletedWithError) {
Assert.fail("Assertion during callback failed...");
@@ -136,7 +142,6 @@ public class TestPushNotification extends TestJaxrsBase {
final TenantKey result0 = killBillClient.registerCallbackNotificationForTenant(callback, requestOptions);
Assert.assertTrue(waitForCallbacksToComplete());
- Assert.assertTrue(callbackCompletedWithError); // expected true because is not an ACCOUNT_CREATION event
Assert.assertEquals(result0.getKey(), TenantKV.TenantKey.PUSH_NOTIFICATION_CB.toString());
Assert.assertEquals(result0.getValues().size(), 1);
@@ -167,7 +172,7 @@ public class TestPushNotification extends TestJaxrsBase {
// Create account to trigger a push notification
createAccount();
- Assert.assertTrue(waitForCallbacksToComplete());
+ assertAllCallbacksCompleted();
Assert.assertTrue(callbackCompletedWithError);
resetCallbackStatusProperties();
@@ -175,7 +180,7 @@ public class TestPushNotification extends TestJaxrsBase {
// move clock 15 minutes and get 1st retry
clock.addDeltaFromReality(900000);
- Assert.assertTrue(waitForCallbacksToComplete());
+ assertAllCallbacksCompleted();
Assert.assertTrue(callbackCompletedWithError);
resetCallbackStatusProperties();
@@ -183,7 +188,7 @@ public class TestPushNotification extends TestJaxrsBase {
// move clock an hour and get 2nd retry
clock.addDeltaFromReality(3600000);
- Assert.assertTrue(waitForCallbacksToComplete());
+ assertAllCallbacksCompleted();
Assert.assertTrue(callbackCompletedWithError);
resetCallbackStatusProperties();
@@ -194,7 +199,7 @@ public class TestPushNotification extends TestJaxrsBase {
// move clock a day, get 3rd retry and wait for a success push notification
clock.addDays(1);
- Assert.assertTrue(waitForCallbacksToComplete());
+ assertAllCallbacksCompleted();
Assert.assertFalse(callbackCompletedWithError);
unregisterTenantForCallback(callback);
@@ -221,7 +226,7 @@ public class TestPushNotification extends TestJaxrsBase {
// Create account to trigger a push notification
createAccount();
- Assert.assertTrue(waitForCallbacksToComplete());
+ assertAllCallbacksCompleted();
Assert.assertTrue(callbackCompletedWithError);
resetCallbackStatusProperties();
@@ -229,7 +234,7 @@ public class TestPushNotification extends TestJaxrsBase {
// move clock 15 minutes and get 1st retry
clock.addDeltaFromReality(900000);
- Assert.assertTrue(waitForCallbacksToComplete());
+ assertAllCallbacksCompleted();
Assert.assertTrue(callbackCompletedWithError);
resetCallbackStatusProperties();
@@ -237,7 +242,7 @@ public class TestPushNotification extends TestJaxrsBase {
// move clock an hour and get 2nd retry
clock.addDeltaFromReality(3600000);
- Assert.assertTrue(waitForCallbacksToComplete());
+ assertAllCallbacksCompleted();
Assert.assertTrue(callbackCompletedWithError);
resetCallbackStatusProperties();
@@ -245,7 +250,7 @@ public class TestPushNotification extends TestJaxrsBase {
// move clock a day and get 3rd retry
clock.addDays(1);
- Assert.assertTrue(waitForCallbacksToComplete());
+ assertAllCallbacksCompleted();
Assert.assertTrue(callbackCompletedWithError);
resetCallbackStatusProperties();
@@ -253,7 +258,7 @@ public class TestPushNotification extends TestJaxrsBase {
// move clock a day and get 4rd retry
clock.addDays(2);
- Assert.assertTrue(waitForCallbacksToComplete());
+ assertAllCallbacksCompleted();
Assert.assertTrue(callbackCompletedWithError);
resetCallbackStatusProperties();
@@ -316,14 +321,12 @@ public class TestPushNotification extends TestJaxrsBase {
public CallmebackServlet(final TestPushNotification test) {
this.test = test;
this.receivedCalls = new AtomicInteger(0);
- this.withError = false;
}
@Override
protected void doPost(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException {
final int current = receivedCalls.incrementAndGet();
final String body = CharStreams.toString(new InputStreamReader(request.getInputStream(), "UTF-8"));
- withError = false;
log.info("CallmebackServlet received {} calls , current = {} at {}", current, body, getClock().getUTCNow());
@@ -338,22 +341,31 @@ public class TestPushNotification extends TestJaxrsBase {
log.info("Got body {}", body);
- try {
- final NotificationJson notification = objectMapper.readValue(body, NotificationJson.class);
- Assert.assertEquals(notification.getEventType(), "ACCOUNT_CREATION");
- Assert.assertEquals(notification.getObjectType(), "ACCOUNT");
- Assert.assertNotNull(notification.getObjectId());
- Assert.assertNotNull(notification.getAccountId());
- Assert.assertEquals(notification.getObjectId(), notification.getAccountId());
-
- test.retrieveAccountWithAsserts(notification.getObjectId());
-
- Assert.assertEquals(request.getHeader(PushNotificationListener.HTTP_HEADER_CONTENT_TYPE), PushNotificationListener.CONTENT_TYPE_JSON);
- } catch (final AssertionError e) {
- withError = true;
+ final NotificationJson notification = objectMapper.readValue(body, NotificationJson.class);
+
+ final ExtBusEventType type = ExtBusEventType.valueOf(notification.getEventType());
+ switch (type) {
+ case TENANT_CONFIG_CHANGE:
+ Assert.assertEquals(notification.getEventType(), "TENANT_CONFIG_CHANGE");
+ Assert.assertEquals(notification.getObjectType(), "TENANT_KVS");
+ Assert.assertNotNull(notification.getObjectId());
+ Assert.assertNull(notification.getAccountId());
+ Assert.assertNotNull(notification.getMetaData());
+ Assert.assertEquals(notification.getMetaData(), "PUSH_NOTIFICATION_CB");
+ break;
+ case ACCOUNT_CREATION:
+ Assert.assertEquals(notification.getEventType(), "ACCOUNT_CREATION");
+ Assert.assertEquals(notification.getObjectType(), "ACCOUNT");
+ Assert.assertNotNull(notification.getObjectId());
+ Assert.assertNotNull(notification.getAccountId());
+ Assert.assertEquals(notification.getObjectId(), notification.getAccountId());
+ break;
}
- stopServerWhenComplete(current, withError);
+ test.retrieveAccountWithAsserts(notification.getObjectId());
+
+ Assert.assertEquals(request.getHeader(PushNotificationListener.HTTP_HEADER_CONTENT_TYPE), PushNotificationListener.CONTENT_TYPE_JSON);
+ stopServerWhenComplete(current, false);
}
private void stopServerWhenComplete(final int current, final boolean withError) {
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestTag.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestTag.java
index 5ba7ba8..ae69442 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestTag.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestTag.java
@@ -49,9 +49,9 @@ public class TestTag extends TestJaxrsBase {
@Test(groups = "slow", description = "Cannot add badly formatted TagDefinition")
public void testTagErrorHandling() throws Exception {
- final TagDefinition[] tagDefinitions = {new TagDefinition(null, false, null, null, null),
- new TagDefinition(null, false, "something", null, null),
- new TagDefinition(null, false, null, "something", null)};
+ final TagDefinition[] tagDefinitions = {new TagDefinition(null, false, null, null, ImmutableList.<ObjectType>of(ObjectType.ACCOUNT)),
+ new TagDefinition(null, false, "something", null, ImmutableList.<ObjectType>of(ObjectType.INVOICE)),
+ new TagDefinition(null, false, null, "something", ImmutableList.<ObjectType>of(ObjectType.TRANSACTION))};
for (final TagDefinition tagDefinition : tagDefinitions) {
try {
@@ -66,7 +66,7 @@ public class TestTag extends TestJaxrsBase {
@Test(groups = "slow", description = "Can create a TagDefinition")
public void testTagDefinitionOk() throws Exception {
- final TagDefinition input = new TagDefinition(null, false, "blue", "relaxing color", ImmutableList.<ObjectType>of());
+ final TagDefinition input = new TagDefinition(null, false, "blue", "relaxing color", ImmutableList.<ObjectType>of(ObjectType.TRANSACTION));
final TagDefinition objFromJson = killBillClient.createTagDefinition(input, requestOptions);
assertNotNull(objFromJson);
@@ -80,16 +80,16 @@ public class TestTag extends TestJaxrsBase {
final int sizeSystemTag = objFromJson.isEmpty() ? 0 : objFromJson.size();
- final TagDefinition inputBlue = new TagDefinition(null, false, "blue", "relaxing color", ImmutableList.<ObjectType>of());
+ final TagDefinition inputBlue = new TagDefinition(null, false, "blue", "relaxing color", ImmutableList.<ObjectType>of(ObjectType.TRANSACTION));
killBillClient.createTagDefinition(inputBlue, requestOptions);
- final TagDefinition inputRed = new TagDefinition(null, false, "red", "hot color", ImmutableList.<ObjectType>of());
+ final TagDefinition inputRed = new TagDefinition(null, false, "red", "hot color", ImmutableList.<ObjectType>of(ObjectType.TRANSACTION));
killBillClient.createTagDefinition(inputRed, requestOptions);
- final TagDefinition inputYellow = new TagDefinition(null, false, "yellow", "vibrant color", ImmutableList.<ObjectType>of());
+ final TagDefinition inputYellow = new TagDefinition(null, false, "yellow", "vibrant color", ImmutableList.<ObjectType>of(ObjectType.TRANSACTION));
killBillClient.createTagDefinition(inputYellow, requestOptions);
- final TagDefinition inputGreen = new TagDefinition(null, false, "green", "super relaxing color", ImmutableList.<ObjectType>of());
+ final TagDefinition inputGreen = new TagDefinition(null, false, "green", "super relaxing color", ImmutableList.<ObjectType>of(ObjectType.TRANSACTION));
killBillClient.createTagDefinition(inputGreen, requestOptions);
objFromJson = killBillClient.getTagDefinitions(requestOptions);
@@ -119,7 +119,7 @@ public class TestTag extends TestJaxrsBase {
killBillClient.createAccountTag(account.getAccountId(), controlTagType.getId(), requestOptions);
}
- final TagDefinition bundleTagDefInput = new TagDefinition(null, false, "bundletagdef", "nothing special", ImmutableList.<ObjectType>of());
+ final TagDefinition bundleTagDefInput = new TagDefinition(null, false, "bundletagdef", "nothing special", ImmutableList.<ObjectType>of(ObjectType.TRANSACTION));
final TagDefinition bundleTagDef = killBillClient.createTagDefinition(bundleTagDefInput, requestOptions);
killBillClient.createBundleTag(subscriptionJson.getBundleId(), bundleTagDef.getId(), requestOptions);
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java b/subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java
index a3a15cc..6768cec 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java
@@ -46,7 +46,6 @@ import org.killbill.billing.catalog.api.PlanPhase;
import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
import org.killbill.billing.catalog.api.PlanPhasePriceOverridesWithCallContext;
import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
-import org.killbill.billing.catalog.api.PlanSpecifier;
import org.killbill.billing.catalog.api.ProductCategory;
import org.killbill.billing.entitlement.api.BaseEntitlementWithAddOnsSpecifier;
import org.killbill.billing.entitlement.api.Entitlement.EntitlementState;
@@ -285,7 +284,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
}
@Override
- public List<SubscriptionBaseWithAddOns> createBaseSubscriptionsWithAddOns(final UUID accountId, final Iterable<BaseEntitlementWithAddOnsSpecifier> baseEntitlementWithAddOnsSpecifier, final InternalCallContext context) throws SubscriptionBaseApiException {
+ public List<SubscriptionBaseWithAddOns> createBaseSubscriptionsWithAddOns(final UUID accountId, final Iterable<BaseEntitlementWithAddOnsSpecifier> baseEntitlementWithAddOnsSpecifier, final boolean renameCancelledBundleIfExist, final InternalCallContext context) throws SubscriptionBaseApiException {
try {
final Catalog catalog = catalogInternalApi.getFullCatalog(true, true, context);
final CallContext callContext = internalCallContextFactory.createCallContext(context);
@@ -301,7 +300,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
final SubscriptionBaseBundle bundle;
if (isBaseSpecifierExists) {
- bundle = createBundleForAccount(accountId, entitlementWithAddOnsSpecifier.getExternalKey(), context);
+ bundle = createBundleForAccount(accountId, entitlementWithAddOnsSpecifier.getExternalKey(), renameCancelledBundleIfExist, context);
} else {
final List<SubscriptionBaseBundle> existingBundles = dao.getSubscriptionBundlesForKey(entitlementWithAddOnsSpecifier.getExternalKey(), context);
final SubscriptionBaseBundle tmp = getActiveBundleForKeyNotException(existingBundles, dao, clock, catalog, context);
@@ -382,7 +381,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
}
@Override
- public SubscriptionBaseBundle createBundleForAccount(final UUID accountId, final String bundleKey, final InternalCallContext context) throws SubscriptionBaseApiException {
+ public SubscriptionBaseBundle createBundleForAccount(final UUID accountId, final String bundleKey, final boolean renameCancelledBundleIfExist, final InternalCallContext context) throws SubscriptionBaseApiException {
final DateTime now = clock.getUTCNow();
final DefaultSubscriptionBaseBundle bundle = new DefaultSubscriptionBaseBundle(bundleKey, accountId, now, now, now, now);
@@ -391,7 +390,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
}
try {
final Catalog catalog = catalogInternalApi.getFullCatalog(true, true, context);
- return dao.createSubscriptionBundle(bundle, catalog, context);
+ return dao.createSubscriptionBundle(bundle, catalog, renameCancelledBundleIfExist, context);
} catch (final CatalogApiException e) {
throw new SubscriptionBaseApiException(e);
}
@@ -399,7 +398,8 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
@Override
public List<SubscriptionBaseBundle> getBundlesForAccountAndKey(final UUID accountId, final String bundleKey, final InternalTenantContext context) throws SubscriptionBaseApiException {
- return dao.getSubscriptionBundlesForAccountAndKey(accountId, bundleKey, context);
+ final SubscriptionBaseBundle subscriptionBundlesForAccountAndKey = dao.getSubscriptionBundlesForAccountAndKey(accountId, bundleKey, context);
+ return subscriptionBundlesForAccountAndKey != null ? ImmutableList.of(subscriptionBundlesForAccountAndKey) : ImmutableList.<SubscriptionBaseBundle>of();
}
@Override
@@ -424,7 +424,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
new Function<SubscriptionBundleModelDao, SubscriptionBaseBundle>() {
@Override
public SubscriptionBaseBundle apply(final SubscriptionBundleModelDao bundleModelDao) {
- return SubscriptionBundleModelDao.toSubscriptionbundle(bundleModelDao);
+ return SubscriptionBundleModelDao.toSubscriptionBundle(bundleModelDao);
}
}
);
@@ -442,7 +442,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
new Function<SubscriptionBundleModelDao, SubscriptionBaseBundle>() {
@Override
public SubscriptionBaseBundle apply(final SubscriptionBundleModelDao bundleModelDao) {
- return SubscriptionBundleModelDao.toSubscriptionbundle(bundleModelDao);
+ return SubscriptionBundleModelDao.toSubscriptionBundle(bundleModelDao);
}
}
);
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/transfer/DefaultSubscriptionBaseTransferApi.java b/subscription/src/main/java/org/killbill/billing/subscription/api/transfer/DefaultSubscriptionBaseTransferApi.java
index 61f34e9..f93883e 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/transfer/DefaultSubscriptionBaseTransferApi.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/transfer/DefaultSubscriptionBaseTransferApi.java
@@ -193,12 +193,13 @@ public class DefaultSubscriptionBaseTransferApi extends SubscriptionApiBase impl
throw new SubscriptionBaseTransferApiException(ErrorCode.SUB_TRANSFER_INVALID_EFF_DATE, effectiveTransferDate);
}
- final List<SubscriptionBaseBundle> bundlesForAccountAndKey = dao.getSubscriptionBundlesForAccountAndKey(sourceAccountId, bundleKey, fromInternalCallContext);
- final SubscriptionBaseBundle bundle = DefaultSubscriptionInternalApi.getActiveBundleForKeyNotException(bundlesForAccountAndKey, dao, clock, catalog, fromInternalCallContext);
+ final SubscriptionBaseBundle bundleForAccountAndKey = dao.getSubscriptionBundlesForAccountAndKey(sourceAccountId, bundleKey, fromInternalCallContext);
+ final SubscriptionBaseBundle bundle = DefaultSubscriptionInternalApi.getActiveBundleForKeyNotException(ImmutableList.of(bundleForAccountAndKey), dao, clock, catalog, fromInternalCallContext);
if (bundle == null) {
throw new SubscriptionBaseTransferApiException(ErrorCode.SUB_CREATE_NO_BUNDLE, bundleKey);
}
+
// Get the bundle timeline for the old account
final BundleBaseTimeline bundleBaseTimeline = timelineApi.getBundleTimeline(bundle, context);
@@ -260,7 +261,7 @@ public class DefaultSubscriptionBaseTransferApi extends SubscriptionApiBase impl
final SubscriptionTransferData curData = new SubscriptionTransferData(defaultSubscriptionBase, events, null);
subscriptionTransferDataList.add(curData);
}
- BundleTransferData bundleTransferData = new BundleTransferData(subscriptionBundleData, subscriptionTransferDataList);
+ final BundleTransferData bundleTransferData = new BundleTransferData(subscriptionBundleData, subscriptionTransferDataList);
// Atomically cancelWithRequestedDate all subscription on old account and create new bundle, subscriptions, events for new account
dao.transfer(sourceAccountId, destAccountId, bundleTransferData, transferCancelDataList, catalog, fromInternalCallContext, toInternalCallContext);
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/BundleSqlDao.java b/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/BundleSqlDao.java
index bc8f9f2..587d390 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/BundleSqlDao.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/BundleSqlDao.java
@@ -19,11 +19,6 @@ package org.killbill.billing.subscription.engine.dao;
import java.util.Date;
import java.util.List;
-import org.skife.jdbi.v2.sqlobject.Bind;
-import org.killbill.commons.jdbi.binder.SmartBindBean;
-import org.skife.jdbi.v2.sqlobject.SqlQuery;
-import org.skife.jdbi.v2.sqlobject.SqlUpdate;
-
import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.subscription.api.user.SubscriptionBaseBundle;
@@ -31,7 +26,12 @@ import org.killbill.billing.subscription.engine.dao.model.SubscriptionBundleMode
import org.killbill.billing.util.audit.ChangeType;
import org.killbill.billing.util.entity.dao.Audited;
import org.killbill.billing.util.entity.dao.EntitySqlDao;
+import org.killbill.commons.jdbi.binder.SmartBindBean;
import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
+import org.skife.jdbi.v2.sqlobject.Bind;
+import org.skife.jdbi.v2.sqlobject.SqlQuery;
+import org.skife.jdbi.v2.sqlobject.SqlUpdate;
+import org.skife.jdbi.v2.sqlobject.customizers.Define;
@KillBillSqlDaoStringTemplate
public interface BundleSqlDao extends EntitySqlDao<SubscriptionBundleModelDao, SubscriptionBaseBundle> {
@@ -44,20 +44,26 @@ public interface BundleSqlDao extends EntitySqlDao<SubscriptionBundleModelDao, S
@SqlUpdate
@Audited(ChangeType.UPDATE)
+ public void renameBundleExternalKey(@Bind("externalKey") String externalKey,
+ @Define("prefix") final String prefix,
+ @SmartBindBean final InternalCallContext context);
+
+ @SqlUpdate
+ @Audited(ChangeType.UPDATE)
public void updateBundleLastSysTime(@Bind("id") String id,
@Bind("lastSysUpdateDate") Date lastSysUpdate,
@SmartBindBean final InternalCallContext context);
@SqlQuery
- public List<SubscriptionBundleModelDao> getBundlesFromAccountAndKey(@Bind("accountId") String accountId,
- @Bind("externalKey") String externalKey,
- @SmartBindBean final InternalTenantContext context);
+ public SubscriptionBundleModelDao getBundlesFromAccountAndKey(@Bind("accountId") String accountId,
+ @Bind("externalKey") String externalKey,
+ @SmartBindBean final InternalTenantContext context);
@SqlQuery
public List<SubscriptionBundleModelDao> getBundleFromAccount(@Bind("accountId") String accountId,
@SmartBindBean final InternalTenantContext context);
@SqlQuery
- public List<SubscriptionBundleModelDao> getBundlesForKey(@Bind("externalKey") String externalKey,
- @SmartBindBean final InternalTenantContext context);
+ public List<SubscriptionBundleModelDao> getBundlesForLikeKey(@Bind("externalKey") String externalKey,
+ @SmartBindBean final InternalTenantContext context);
}
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/DefaultSubscriptionDao.java b/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/DefaultSubscriptionDao.java
index ac018a3..3c799ea 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/DefaultSubscriptionDao.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/DefaultSubscriptionDao.java
@@ -35,12 +35,10 @@ import javax.inject.Inject;
import org.joda.time.DateTime;
import org.killbill.billing.ErrorCode;
-import org.killbill.billing.ObjectType;
import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.catalog.api.Catalog;
import org.killbill.billing.catalog.api.CatalogApiException;
-import org.killbill.billing.catalog.api.CatalogInternalApi;
import org.killbill.billing.catalog.api.Plan;
import org.killbill.billing.catalog.api.ProductCategory;
import org.killbill.billing.entitlement.api.Entitlement.EntitlementState;
@@ -140,17 +138,12 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
}
@Override
- public List<SubscriptionBaseBundle> getSubscriptionBundlesForAccountAndKey(final UUID accountId, final String bundleKey, final InternalTenantContext context) {
- return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<SubscriptionBaseBundle>>() {
+ public SubscriptionBaseBundle getSubscriptionBundlesForAccountAndKey(final UUID accountId, final String bundleKey, final InternalTenantContext context) {
+ return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<SubscriptionBaseBundle>() {
@Override
- public List<SubscriptionBaseBundle> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
- final List<SubscriptionBundleModelDao> models = entitySqlDaoWrapperFactory.become(BundleSqlDao.class).getBundlesFromAccountAndKey(accountId.toString(), bundleKey, context);
- return new ArrayList<SubscriptionBaseBundle>(Collections2.transform(models, new Function<SubscriptionBundleModelDao, SubscriptionBaseBundle>() {
- @Override
- public SubscriptionBaseBundle apply(@Nullable final SubscriptionBundleModelDao input) {
- return SubscriptionBundleModelDao.toSubscriptionbundle(input);
- }
- }));
+ public SubscriptionBaseBundle inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
+ final SubscriptionBundleModelDao input = entitySqlDaoWrapperFactory.become(BundleSqlDao.class).getBundlesFromAccountAndKey(accountId.toString(), bundleKey, context);
+ return SubscriptionBundleModelDao.toSubscriptionBundle(input);
}
});
}
@@ -165,7 +158,7 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
return new ArrayList<SubscriptionBaseBundle>(Collections2.transform(models, new Function<SubscriptionBundleModelDao, SubscriptionBaseBundle>() {
@Override
public SubscriptionBaseBundle apply(@Nullable final SubscriptionBundleModelDao input) {
- return SubscriptionBundleModelDao.toSubscriptionbundle(input);
+ return SubscriptionBundleModelDao.toSubscriptionBundle(input);
}
}));
}
@@ -178,21 +171,22 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
@Override
public SubscriptionBaseBundle inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
final SubscriptionBundleModelDao model = entitySqlDaoWrapperFactory.become(BundleSqlDao.class).getById(bundleId.toString(), context);
- return SubscriptionBundleModelDao.toSubscriptionbundle(model);
+ return SubscriptionBundleModelDao.toSubscriptionBundle(model);
}
});
}
@Override
public List<SubscriptionBaseBundle> getSubscriptionBundlesForKey(final String bundleKey, final InternalTenantContext context) {
+
return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<SubscriptionBaseBundle>>() {
@Override
public List<SubscriptionBaseBundle> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
- final List<SubscriptionBundleModelDao> models = entitySqlDaoWrapperFactory.become(BundleSqlDao.class).getBundlesForKey(bundleKey, context);
+ final List<SubscriptionBundleModelDao> models = entitySqlDaoWrapperFactory.become(BundleSqlDao.class).getBundlesForLikeKey(bundleKey, context);
return new ArrayList<SubscriptionBaseBundle>(Collections2.transform(models, new Function<SubscriptionBundleModelDao, SubscriptionBaseBundle>() {
@Override
public SubscriptionBaseBundle apply(@Nullable final SubscriptionBundleModelDao input) {
- return SubscriptionBundleModelDao.toSubscriptionbundle(input);
+ return SubscriptionBundleModelDao.toSubscriptionBundle(input);
}
}));
}
@@ -226,7 +220,7 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
final BundleSqlDao bundleSqlDao = entitySqlDaoWrapperFactory.become(BundleSqlDao.class);
- final List<SubscriptionBundleModelDao> bundles = bundleSqlDao.getBundlesForKey(bundleKey, context);
+ final List<SubscriptionBundleModelDao> bundles = bundleSqlDao.getBundlesForLikeKey(bundleKey, context);
final Collection<UUID> nonAOSubscriptionIdsForKey = new LinkedList<UUID>();
final SubscriptionSqlDao subscriptionSqlDao = entitySqlDaoWrapperFactory.become(SubscriptionSqlDao.class);
@@ -257,7 +251,7 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
}
@Override
- public SubscriptionBaseBundle createSubscriptionBundle(final DefaultSubscriptionBaseBundle bundle, final Catalog catalog, final InternalCallContext context) throws SubscriptionBaseApiException {
+ public SubscriptionBaseBundle createSubscriptionBundle(final DefaultSubscriptionBaseBundle bundle, final Catalog catalog, final boolean renameCancelledBundleIfExist, final InternalCallContext context) throws SubscriptionBaseApiException {
return transactionalSqlDao.execute(SubscriptionBaseApiException.class, new EntitySqlDaoTransactionWrapper<SubscriptionBaseBundle>() {
@@ -273,8 +267,11 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
final SubscriptionBundleModelDao existingBundleForAccount = Iterables.tryFind(existingBundles, new Predicate<SubscriptionBundleModelDao>() {
@Override
public boolean apply(final SubscriptionBundleModelDao input) {
- return input.getAccountId().equals(bundle.getAccountId());
+ return input.getAccountId().equals(bundle.getAccountId()) &&
+ // We look for strict equality ignoring tsf items with keys 'kbtsf-343453:'
+ bundle.getExternalKey().equals(input.getExternalKey());
}
+
}).orNull();
// If Bundle already exists, and there is 0 Subscription associated with this bundle, we reuse
@@ -287,7 +284,7 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
return input.getBundleId().equals(existingBundleForAccount.getId());
}
})) {
- return SubscriptionBundleModelDao.toSubscriptionbundle(existingBundleForAccount);
+ return SubscriptionBundleModelDao.toSubscriptionBundle(existingBundleForAccount);
}
}
return null;
@@ -296,12 +293,13 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
@Override
public SubscriptionBaseBundle inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
- final List<SubscriptionBundleModelDao> existingBundles = entitySqlDaoWrapperFactory.become(BundleSqlDao.class).getBundlesForKey(bundle.getExternalKey(), context);
+ final List<SubscriptionBundleModelDao> existingBundles = entitySqlDaoWrapperFactory.become(BundleSqlDao.class).getBundlesForLikeKey(bundle.getExternalKey(), context);
final SubscriptionBaseBundle unusedBundle = findExistingUnusedBundleForExternalKeyAndAccount(existingBundles, entitySqlDaoWrapperFactory);
if (unusedBundle != null) {
return unusedBundle;
}
+ final BundleSqlDao bundleSqlDao = entitySqlDaoWrapperFactory.become(BundleSqlDao.class);
for (SubscriptionBundleModelDao cur : existingBundles) {
final List<SubscriptionModelDao> subscriptions = entitySqlDaoWrapperFactory.become(SubscriptionSqlDao.class).getSubscriptionsFromBundleId(cur.getId().toString(), context);
@@ -316,7 +314,13 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
final SubscriptionBase s = buildSubscription(SubscriptionModelDao.toSubscription(f, cur.getExternalKey()), catalog, context);
if (s.getState() != EntitlementState.CANCELLED) {
throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_ACTIVE_BUNDLE_KEY_EXISTS, bundle.getExternalKey());
- }
+ } else if (renameCancelledBundleIfExist) {
+ // Note that if bundle belongs to a different account, context is not the context for this target account,
+ // but the underlying sql operation does not use the account info
+ bundleSqlDao.renameBundleExternalKey(bundle.getExternalKey(), "cncl", context);
+ } /* else {
+ Code will throw SQLIntegrityConstraintViolationException because of unique constraint on externalKey; might be worth having an ErrorCode just for that
+ } */
} catch (CatalogApiException e) {
throw new SubscriptionBaseApiException(e);
}
@@ -328,9 +332,8 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
if (!existingBundles.isEmpty()) {
model.setOriginalCreatedDate(existingBundles.get(0).getCreatedDate());
}
- final BundleSqlDao bundleSqlDao = entitySqlDaoWrapperFactory.become(BundleSqlDao.class);
final SubscriptionBundleModelDao result = createAndRefresh(bundleSqlDao, model, context);
- return SubscriptionBundleModelDao.toSubscriptionbundle(result);
+ return SubscriptionBundleModelDao.toSubscriptionBundle(result);
}
});
}
@@ -1043,13 +1046,18 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
@Override
public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
- final SubscriptionEventSqlDao transactional = entitySqlDaoWrapperFactory.become(SubscriptionEventSqlDao.class);
// Cancel the subscriptions for the old bundle
for (final TransferCancelData cancel : transferCancelData) {
cancelSubscriptionFromTransaction(cancel.getSubscription(), cancel.getCancelEvent(), entitySqlDaoWrapperFactory, catalog, fromContext, 0);
}
+
+ // Rename externalKey from source bundle
+ final BundleSqlDao bundleSqlDao = entitySqlDaoWrapperFactory.become(BundleSqlDao.class);
+ bundleSqlDao.renameBundleExternalKey(bundleTransferData.getData().getExternalKey(), "tsf", fromContext);
+
+ final SubscriptionEventSqlDao transactional = entitySqlDaoWrapperFactory.become(SubscriptionEventSqlDao.class);
transferBundleDataFromTransaction(bundleTransferData, transactional, entitySqlDaoWrapperFactory, toContext);
return null;
}
@@ -1181,8 +1189,8 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
final DefaultSubscriptionBaseBundle bundleData = bundleTransferData.getData();
- final List<SubscriptionBundleModelDao> existingBundleModels = transBundleDao.getBundlesFromAccountAndKey(bundleData.getAccountId().toString(), bundleData.getExternalKey(), context);
- if (!existingBundleModels.isEmpty()) {
+ final SubscriptionBundleModelDao existingBundleForAccount = transBundleDao.getBundlesFromAccountAndKey(bundleData.getAccountId().toString(), bundleData.getExternalKey(), context);
+ if (existingBundleForAccount != null) {
log.warn("Bundle already exists for accountId='{}', bundleExternalKey='{}'", bundleData.getAccountId(), bundleData.getExternalKey());
return;
}
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/model/SubscriptionBundleModelDao.java b/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/model/SubscriptionBundleModelDao.java
index 2c9489f..e5938dc 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/model/SubscriptionBundleModelDao.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/model/SubscriptionBundleModelDao.java
@@ -17,6 +17,8 @@
package org.killbill.billing.subscription.engine.dao.model;
import java.util.UUID;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import org.joda.time.DateTime;
import org.killbill.billing.subscription.api.user.DefaultSubscriptionBaseBundle;
@@ -29,6 +31,11 @@ import com.google.common.base.MoreObjects;
public class SubscriptionBundleModelDao extends EntityModelDaoBase implements EntityModelDao<SubscriptionBaseBundle> {
+ // Any key that starts with kb<some_prefix>-<some_number>:<something> is interpreted as a <something> key that got renamed for internal purpose
+ // KB core currently only use the prefix 'tsf' for renaming such keys during bundle transfer
+ //
+ private static Pattern BUNDLE_KEY_PATTERN = Pattern.compile("kb(?:\\w+)-\\d+:(.*)");
+
private String externalKey;
private UUID accountId;
private DateTime lastSysUpdateDate;
@@ -81,11 +88,15 @@ public class SubscriptionBundleModelDao extends EntityModelDaoBase implements En
this.originalCreatedDate = originalCreatedDate;
}
- public static SubscriptionBaseBundle toSubscriptionbundle(final SubscriptionBundleModelDao src) {
+ public static SubscriptionBaseBundle toSubscriptionBundle(final SubscriptionBundleModelDao src) {
if (src == null) {
return null;
}
- return new DefaultSubscriptionBaseBundle(src.getId(), src.getExternalKey(), src.getAccountId(), src.getLastSysUpdateDate(), src.getOriginalCreatedDate(), src.getCreatedDate(), src.getUpdatedDate());
+
+ // Fix externalKey to remove internal prefix used for tsf
+ final Matcher m = BUNDLE_KEY_PATTERN.matcher(src.getExternalKey());
+ final String externalKey = m.matches() ? m.group(1) : src.getExternalKey();
+ return new DefaultSubscriptionBaseBundle(src.getId(), externalKey, src.getAccountId(), src.getLastSysUpdateDate(), src.getOriginalCreatedDate(), src.getCreatedDate(), src.getUpdatedDate());
}
@Override
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/SubscriptionDao.java b/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/SubscriptionDao.java
index ac499bf..c31b372 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/SubscriptionDao.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/SubscriptionDao.java
@@ -31,7 +31,6 @@ import org.killbill.billing.subscription.api.transfer.BundleTransferData;
import org.killbill.billing.subscription.api.transfer.TransferCancelData;
import org.killbill.billing.subscription.api.user.DefaultSubscriptionBase;
import org.killbill.billing.subscription.api.user.DefaultSubscriptionBaseBundle;
-import org.killbill.billing.subscription.api.user.DefaultSubscriptionBaseWithAddOns;
import org.killbill.billing.subscription.api.user.SubscriptionBaseApiException;
import org.killbill.billing.subscription.api.user.SubscriptionBaseBundle;
import org.killbill.billing.subscription.engine.dao.model.SubscriptionBundleModelDao;
@@ -50,11 +49,11 @@ public interface SubscriptionDao extends EntityDao<SubscriptionBundleModelDao, S
public Iterable<UUID> getNonAOSubscriptionIdsForKey(String bundleKey, InternalTenantContext context);
- public List<SubscriptionBaseBundle> getSubscriptionBundlesForAccountAndKey(UUID accountId, String bundleKey, InternalTenantContext context);
+ public SubscriptionBaseBundle getSubscriptionBundlesForAccountAndKey(UUID accountId, String bundleKey, InternalTenantContext context);
public SubscriptionBaseBundle getSubscriptionBundleFromId(UUID bundleId, InternalTenantContext context);
- public SubscriptionBaseBundle createSubscriptionBundle(DefaultSubscriptionBaseBundle bundle, final Catalog catalog, InternalCallContext context) throws SubscriptionBaseApiException;
+ public SubscriptionBaseBundle createSubscriptionBundle(DefaultSubscriptionBaseBundle bundle, final Catalog catalog, final boolean renameCancelledBundleIfExist, InternalCallContext context) throws SubscriptionBaseApiException;
public SubscriptionBase getSubscriptionFromId(UUID subscriptionId, final Catalog catalog, InternalTenantContext context) throws CatalogApiException;
diff --git a/subscription/src/main/resources/org/killbill/billing/subscription/ddl.sql b/subscription/src/main/resources/org/killbill/billing/subscription/ddl.sql
index ac3b021..0807094 100644
--- a/subscription/src/main/resources/org/killbill/billing/subscription/ddl.sql
+++ b/subscription/src/main/resources/org/killbill/billing/subscription/ddl.sql
@@ -65,7 +65,7 @@ CREATE TABLE bundles (
PRIMARY KEY(record_id)
) /*! CHARACTER SET utf8 COLLATE utf8_bin */;
CREATE UNIQUE INDEX bundles_id ON bundles(id);
-CREATE INDEX bundles_key ON bundles(external_key);
+CREATE UNIQUE INDEX bundles_external_key ON bundles(external_key, tenant_record_id);
CREATE INDEX bundles_account ON bundles(account_id);
CREATE INDEX bundles_tenant_account_record_id ON bundles(tenant_record_id, account_record_id);
diff --git a/subscription/src/main/resources/org/killbill/billing/subscription/engine/dao/BundleSqlDao.sql.stg b/subscription/src/main/resources/org/killbill/billing/subscription/engine/dao/BundleSqlDao.sql.stg
index 9a5337c..369469b 100644
--- a/subscription/src/main/resources/org/killbill/billing/subscription/engine/dao/BundleSqlDao.sql.stg
+++ b/subscription/src/main/resources/org/killbill/billing/subscription/engine/dao/BundleSqlDao.sql.stg
@@ -47,11 +47,26 @@ where id = :id
;
>>
-getBundlesForKey() ::= <<
+
+renameBundleExternalKey(prefix) ::= <<
+update bundles b
+join (select
+ record_id
+ , external_key
+ from
+ bundles
+ where external_key = :externalKey <AND_CHECK_TENANT("")>) t
+on b.record_id = t.record_id
+set b.external_key = concat('kb', '<prefix>', '-', t.record_id, ':', t.external_key)
+;
+>>
+
+getBundlesForLikeKey() ::= <<
select <allTableFields("")>
from bundles
where
external_key = :externalKey
+or external_key like concat('kb%-%:', :externalKey)
<AND_CHECK_TENANT("")>
<defaultOrderBy("")>
;
diff --git a/subscription/src/main/resources/org/killbill/billing/subscription/migration/V20170920200757__bundle_external_key.sql b/subscription/src/main/resources/org/killbill/billing/subscription/migration/V20170920200757__bundle_external_key.sql
new file mode 100644
index 0000000..c175f86
--- /dev/null
+++ b/subscription/src/main/resources/org/killbill/billing/subscription/migration/V20170920200757__bundle_external_key.sql
@@ -0,0 +1,2 @@
+drop index bundles_key on bundles;
+create unique index bundles_external_key on bundles(external_key, tenant_record_id);
\ No newline at end of file
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/api/transfer/TestTransfer.java b/subscription/src/test/java/org/killbill/billing/subscription/api/transfer/TestTransfer.java
index 3a0b350..ea1b9fa 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/api/transfer/TestTransfer.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/api/transfer/TestTransfer.java
@@ -64,7 +64,7 @@ public class TestTransfer extends SubscriptionTestSuiteWithEmbeddedDB {
final Account account2 = createAccount(accountData2);
finalNewAccountId = account2.getId();
- // internal context will be configured for newAccountId
+ // internal context will be configured for accountId
final AccountData accountData = subscriptionTestInitializer.initAccountData();
final Account account = createAccount(accountData);
newAccountId = account.getId();
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiCreate.java b/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiCreate.java
index 36167c8..143041e 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiCreate.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiCreate.java
@@ -16,6 +16,7 @@
package org.killbill.billing.subscription.api.user;
+import java.sql.SQLIntegrityConstraintViolationException;
import java.util.List;
import org.joda.time.DateTime;
@@ -33,6 +34,7 @@ import org.killbill.billing.subscription.DefaultSubscriptionTestInitializer;
import org.killbill.billing.subscription.SubscriptionTestSuiteWithEmbeddedDB;
import org.killbill.billing.subscription.events.SubscriptionBaseEvent;
import org.killbill.billing.subscription.events.phase.PhaseEvent;
+import org.mariadb.jdbc.internal.util.dao.QueryException;
import org.testng.Assert;
import org.testng.annotations.Test;
@@ -44,7 +46,7 @@ public class TestUserApiCreate extends SubscriptionTestSuiteWithEmbeddedDB {
@Test(groups = "slow")
public void testCreateBundleWithNoExternalKey() throws Exception {
- final SubscriptionBaseBundle newBundle = subscriptionInternalApi.createBundleForAccount(bundle.getAccountId(), null, internalCallContext);
+ final SubscriptionBaseBundle newBundle = subscriptionInternalApi.createBundleForAccount(bundle.getAccountId(), null, true, internalCallContext);
assertNotNull(newBundle.getExternalKey());
}
@@ -66,7 +68,7 @@ public class TestUserApiCreate extends SubscriptionTestSuiteWithEmbeddedDB {
// Verify we can't create a second bundle with the same key
try {
- subscriptionInternalApi.createBundleForAccount(bundle.getAccountId(), DefaultSubscriptionTestInitializer.DEFAULT_BUNDLE_KEY, internalCallContext);
+ subscriptionInternalApi.createBundleForAccount(bundle.getAccountId(), DefaultSubscriptionTestInitializer.DEFAULT_BUNDLE_KEY, true, internalCallContext);
Assert.fail("Should not be able to create a bundle with same externalKey");
} catch (final SubscriptionBaseApiException e) {
Assert.assertEquals(e.getCode(), ErrorCode.SUB_CREATE_ACTIVE_BUNDLE_KEY_EXISTS.getCode());
@@ -76,7 +78,14 @@ public class TestUserApiCreate extends SubscriptionTestSuiteWithEmbeddedDB {
subscription.cancelWithDate(clock.getUTCNow(), callContext);
assertListenerStatus();
- final SubscriptionBaseBundle newBundle = subscriptionInternalApi.createBundleForAccount(bundle.getAccountId(), DefaultSubscriptionTestInitializer.DEFAULT_BUNDLE_KEY, internalCallContext);
+ try {
+ subscriptionInternalApi.createBundleForAccount(bundle.getAccountId(), DefaultSubscriptionTestInitializer.DEFAULT_BUNDLE_KEY, false, internalCallContext);
+ Assert.fail("createBundleForAccount should fail because key already exists");
+ } catch (final RuntimeException e) {
+ assertTrue(e.getCause() instanceof SQLIntegrityConstraintViolationException);
+ }
+
+ final SubscriptionBaseBundle newBundle = subscriptionInternalApi.createBundleForAccount(bundle.getAccountId(), DefaultSubscriptionTestInitializer.DEFAULT_BUNDLE_KEY, true, internalCallContext);
assertNotNull(newBundle);
assertEquals(newBundle.getOriginalCreatedDate().compareTo(bundle.getCreatedDate()), 0);
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiError.java b/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiError.java
index f852cae..179d08f 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiError.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiError.java
@@ -76,7 +76,7 @@ public class TestUserApiError extends SubscriptionTestSuiteNoDB {
@Test(groups = "fast")
public void testCreateSubscriptionAddOnNotAvailable() throws SubscriptionBaseApiException {
- final SubscriptionBaseBundle aoBundle = subscriptionInternalApi.createBundleForAccount(bundle.getAccountId(), "myAOBundle", internalCallContext);
+ final SubscriptionBaseBundle aoBundle = subscriptionInternalApi.createBundleForAccount(bundle.getAccountId(), "myAOBundle", true, internalCallContext);
mockNonEntityDao.addTenantRecordIdMapping(aoBundle.getId(), internalCallContext);
mockNonEntityDao.addAccountRecordIdMapping(aoBundle.getId(), internalCallContext);
@@ -86,7 +86,7 @@ public class TestUserApiError extends SubscriptionTestSuiteNoDB {
@Test(groups = "fast")
public void testCreateSubscriptionAddOnIncluded() throws SubscriptionBaseApiException {
- final SubscriptionBaseBundle aoBundle = subscriptionInternalApi.createBundleForAccount(bundle.getAccountId(), "myAOBundle", internalCallContext);
+ final SubscriptionBaseBundle aoBundle = subscriptionInternalApi.createBundleForAccount(bundle.getAccountId(), "myAOBundle", true, internalCallContext);
mockNonEntityDao.addTenantRecordIdMapping(aoBundle.getId(), internalCallContext);
mockNonEntityDao.addAccountRecordIdMapping(aoBundle.getId(), internalCallContext);
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/DefaultSubscriptionTestInitializer.java b/subscription/src/test/java/org/killbill/billing/subscription/DefaultSubscriptionTestInitializer.java
index 0964ae8..003c00f 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/DefaultSubscriptionTestInitializer.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/DefaultSubscriptionTestInitializer.java
@@ -79,7 +79,7 @@ public class DefaultSubscriptionTestInitializer implements SubscriptionTestIniti
}
public SubscriptionBaseBundle initBundle(final UUID accountId, final SubscriptionBaseInternalApi subscriptionApi, final InternalCallContext callContext) throws Exception {
- final SubscriptionBaseBundle bundle = subscriptionApi.createBundleForAccount(accountId, DEFAULT_BUNDLE_KEY, callContext);
+ final SubscriptionBaseBundle bundle = subscriptionApi.createBundleForAccount(accountId, DEFAULT_BUNDLE_KEY, true, callContext);
assertNotNull(bundle);
return bundle;
}
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/engine/dao/MockSubscriptionDaoMemory.java b/subscription/src/test/java/org/killbill/billing/subscription/engine/dao/MockSubscriptionDaoMemory.java
index cbcb9a5..ba31884 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/engine/dao/MockSubscriptionDaoMemory.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/engine/dao/MockSubscriptionDaoMemory.java
@@ -163,18 +163,18 @@ public class MockSubscriptionDaoMemory extends MockEntityDaoBase<SubscriptionBun
}
@Override
- public List<SubscriptionBaseBundle> getSubscriptionBundlesForAccountAndKey(final UUID accountId, final String bundleKey, final InternalTenantContext context) {
+ public SubscriptionBaseBundle getSubscriptionBundlesForAccountAndKey(final UUID accountId, final String bundleKey, final InternalTenantContext context) {
final List<SubscriptionBaseBundle> results = new ArrayList<SubscriptionBaseBundle>();
for (final SubscriptionBaseBundle cur : bundles) {
if (cur.getExternalKey().equals(bundleKey) && cur.getAccountId().equals(accountId)) {
- results.add(cur);
+ return cur;
}
}
- return results;
+ return null;
}
@Override
- public SubscriptionBaseBundle createSubscriptionBundle(final DefaultSubscriptionBaseBundle bundle, final Catalog catalog, final InternalCallContext context) {
+ public SubscriptionBaseBundle createSubscriptionBundle(final DefaultSubscriptionBaseBundle bundle, final Catalog catalog, final boolean renameCancelledBundleIfExist, final InternalCallContext context) {
bundles.add(bundle);
mockNonEntityDao.addTenantRecordIdMapping(bundle.getId(), context);
return getSubscriptionBundleFromId(bundle.getId(), context);
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/engine/dao/TestSubscriptionDao.java b/subscription/src/test/java/org/killbill/billing/subscription/engine/dao/TestSubscriptionDao.java
new file mode 100644
index 0000000..0455390
--- /dev/null
+++ b/subscription/src/test/java/org/killbill/billing/subscription/engine/dao/TestSubscriptionDao.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you 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 org.killbill.billing.subscription.engine.dao;
+
+import java.util.List;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+import org.killbill.billing.ErrorCode;
+import org.killbill.billing.account.api.Account;
+import org.killbill.billing.account.api.AccountData;
+import org.killbill.billing.api.TestApiListener.NextEvent;
+import org.killbill.billing.catalog.DefaultPriceListSet;
+import org.killbill.billing.catalog.api.ProductCategory;
+import org.killbill.billing.subscription.SubscriptionTestSuiteWithEmbeddedDB;
+import org.killbill.billing.subscription.api.user.DefaultSubscriptionBase;
+import org.killbill.billing.subscription.api.user.DefaultSubscriptionBaseBundle;
+import org.killbill.billing.subscription.api.user.SubscriptionBaseApiException;
+import org.killbill.billing.subscription.api.user.SubscriptionBaseBundle;
+import org.killbill.billing.subscription.api.user.SubscriptionBuilder;
+import org.killbill.billing.subscription.events.SubscriptionBaseEvent;
+import org.killbill.billing.subscription.events.user.ApiEventBuilder;
+import org.killbill.billing.subscription.events.user.ApiEventCreate;
+import org.killbill.billing.util.UUIDs;
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+
+import static org.testng.Assert.assertEquals;
+
+public class TestSubscriptionDao extends SubscriptionTestSuiteWithEmbeddedDB {
+
+ protected UUID accountId;
+
+ @Override
+ @BeforeMethod(groups = "slow")
+ public void beforeMethod() throws Exception {
+ // Note: this will cleanup all tables
+ super.beforeMethod();
+
+ // internal context will be configured for accountId
+ final AccountData accountData = subscriptionTestInitializer.initAccountData();
+ final Account account = createAccount(accountData);
+ accountId = account.getId();
+ }
+
+ @Override // to ignore events
+ @AfterMethod(groups = "slow")
+ public void afterMethod() throws Exception {
+ subscriptionTestInitializer.stopTestFramework(testListener, busService, subscriptionBaseService);
+ }
+
+ @Test(groups = "slow")
+ public void testBundleExternalKeyReused() throws Exception {
+
+ final String externalKey = "12345";
+ final DateTime startDate = clock.getUTCNow();
+ final DateTime createdDate = startDate.plusSeconds(10);
+
+ final DefaultSubscriptionBaseBundle bundleDef = new DefaultSubscriptionBaseBundle(externalKey, accountId, startDate, startDate, createdDate, createdDate);
+ final SubscriptionBaseBundle bundle = dao.createSubscriptionBundle(bundleDef, catalog, true, internalCallContext);
+
+ final List<SubscriptionBaseBundle> result = dao.getSubscriptionBundlesForKey(externalKey, internalCallContext);
+ assertEquals(result.size(), 1);
+ assertEquals(result.get(0).getExternalKey(), bundle.getExternalKey());
+
+ // Operation succeeds but nothing new got created because bundle is empty
+ dao.createSubscriptionBundle(bundleDef, catalog, true, internalCallContext);
+ final List<SubscriptionBaseBundle> result2 = dao.getSubscriptionBundlesForKey(externalKey, internalCallContext);
+ assertEquals(result2.size(), 1);
+
+ // Create a subscription and this time operation should fail
+ final SubscriptionBuilder builder = new SubscriptionBuilder()
+ .setId(UUIDs.randomUUID())
+ .setBundleId(bundle.getId())
+ .setBundleExternalKey(bundle.getExternalKey())
+ .setCategory(ProductCategory.BASE)
+ .setBundleStartDate(startDate)
+ .setAlignStartDate(startDate)
+ .setMigrated(false);
+
+ final ApiEventBuilder createBuilder = new ApiEventBuilder()
+ .setSubscriptionId(builder.getId())
+ .setEventPlan("shotgun-monthly")
+ .setEventPlanPhase("shotgun-monthly-trial")
+ .setEventPriceList(DefaultPriceListSet.DEFAULT_PRICELIST_NAME)
+ .setEffectiveDate(startDate)
+ .setFromDisk(true);
+ final SubscriptionBaseEvent creationEvent = new ApiEventCreate(createBuilder);
+
+ final DefaultSubscriptionBase subscription = new DefaultSubscriptionBase(builder);
+ testListener.pushExpectedEvents(NextEvent.CREATE);
+ dao.createSubscription(subscription, ImmutableList.of(creationEvent), catalog, internalCallContext);
+ assertListenerStatus();
+
+ // Operation Should now fail
+ try {
+ dao.createSubscriptionBundle(bundleDef, catalog, true, internalCallContext);
+ Assert.fail("Should fail to create new subscription bundle with existing key");
+ } catch (SubscriptionBaseApiException e) {
+ assertEquals(ErrorCode.SUB_CREATE_ACTIVE_BUNDLE_KEY_EXISTS.getCode(), e.getCode());
+ }
+ }
+
+ @Test(groups = "slow")
+ public void testBundleExternalKeyTransferred() throws Exception {
+
+ final String externalKey = "2534125sdfsd";
+ final DateTime startDate = clock.getUTCNow();
+ final DateTime createdDate = startDate.plusSeconds(10);
+
+ final DefaultSubscriptionBaseBundle bundleDef = new DefaultSubscriptionBaseBundle(externalKey, accountId, startDate, startDate, createdDate, createdDate);
+ final SubscriptionBaseBundle bundle = dao.createSubscriptionBundle(bundleDef, catalog, true, internalCallContext);
+
+ final List<SubscriptionBaseBundle> result = dao.getSubscriptionBundlesForKey(externalKey, internalCallContext);
+ assertEquals(result.size(), 1);
+ assertEquals(result.get(0).getExternalKey(), bundle.getExternalKey());
+
+ // Update key to 'internal KB value 'kbtsf-12345:'
+ dao.updateBundleExternalKey(bundle.getId(), "kbtsf-12345:" + bundle.getExternalKey(), internalCallContext);
+ final List<SubscriptionBaseBundle> result2 = dao.getSubscriptionBundlesForKey(externalKey, internalCallContext);
+ assertEquals(result2.size(), 1);
+
+ // Create new bundle with original key, verify all results show original key, stripping down internal prefix
+ final DefaultSubscriptionBaseBundle bundleDef2 = new DefaultSubscriptionBaseBundle(externalKey, accountId, startDate, startDate, createdDate, createdDate);
+ final SubscriptionBaseBundle bundle2 = dao.createSubscriptionBundle(bundleDef2, catalog, true, internalCallContext);
+ final List<SubscriptionBaseBundle> result3 = dao.getSubscriptionBundlesForKey(externalKey, internalCallContext);
+ assertEquals(result3.size(), 2);
+ assertEquals(result3.get(0).getExternalKey(), bundle2.getExternalKey());
+ assertEquals(result3.get(1).getExternalKey(), bundle2.getExternalKey());
+
+ // This time we call the lower SqlDao to rename the bundle automatically and verify we still get same # results,
+ // with original key
+ dbi.onDemand(BundleSqlDao.class).renameBundleExternalKey(externalKey, "foo", internalCallContext);
+ final List<SubscriptionBaseBundle> result4 = dao.getSubscriptionBundlesForKey(externalKey, internalCallContext);
+ assertEquals(result4.size(), 2);
+ assertEquals(result4.get(0).getExternalKey(), bundle2.getExternalKey());
+ assertEquals(result4.get(1).getExternalKey(), bundle2.getExternalKey());
+
+ // Create bundle one more time
+ final DefaultSubscriptionBaseBundle bundleDef3 = new DefaultSubscriptionBaseBundle(externalKey, accountId, startDate, startDate, createdDate, createdDate);
+ final SubscriptionBaseBundle bundle3 = dao.createSubscriptionBundle(bundleDef3, catalog, true, internalCallContext);
+ final List<SubscriptionBaseBundle> result5 = dao.getSubscriptionBundlesForKey(externalKey, internalCallContext);
+ assertEquals(result5.size(), 3);
+ assertEquals(result5.get(0).getExternalKey(), bundle2.getExternalKey());
+ assertEquals(result5.get(1).getExternalKey(), bundle2.getExternalKey());
+ assertEquals(result5.get(2).getExternalKey(), bundle2.getExternalKey());
+
+
+ }
+}
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/engine/dao/TestSubscriptionModelDao.java b/subscription/src/test/java/org/killbill/billing/subscription/engine/dao/TestSubscriptionModelDao.java
new file mode 100644
index 0000000..2f6bf69
--- /dev/null
+++ b/subscription/src/test/java/org/killbill/billing/subscription/engine/dao/TestSubscriptionModelDao.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you 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 org.killbill.billing.subscription.engine.dao;
+
+import org.killbill.billing.subscription.SubscriptionTestSuiteNoDB;
+import org.killbill.billing.subscription.engine.dao.model.SubscriptionBundleModelDao;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+
+public class TestSubscriptionModelDao extends SubscriptionTestSuiteNoDB {
+
+ @Test(groups = "fast")
+ public void testBundleExternalKeyPattern1() throws Exception {
+ final SubscriptionBundleModelDao b = new SubscriptionBundleModelDao();
+ b.setExternalKey("1235");
+
+ assertEquals(SubscriptionBundleModelDao.toSubscriptionBundle(b).getExternalKey(), "1235");
+ }
+
+
+ @Test(groups = "fast")
+ public void testBundleExternalKeyPattern2() throws Exception {
+ final SubscriptionBundleModelDao b = new SubscriptionBundleModelDao();
+ b.setExternalKey("kbtsf-343453:1235");
+ assertEquals(SubscriptionBundleModelDao.toSubscriptionBundle(b).getExternalKey(), "1235");
+ }
+
+ @Test(groups = "fast")
+ public void testBundleExternalKeyPattern3() throws Exception {
+ final SubscriptionBundleModelDao b = new SubscriptionBundleModelDao();
+ b.setExternalKey("kbXXXX-343453:1235");
+ assertEquals(SubscriptionBundleModelDao.toSubscriptionBundle(b).getExternalKey(), "1235");
+ }
+
+}
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/SubscriptionTestSuiteNoDB.java b/subscription/src/test/java/org/killbill/billing/subscription/SubscriptionTestSuiteNoDB.java
index 8f1b379..0961ea1 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/SubscriptionTestSuiteNoDB.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/SubscriptionTestSuiteNoDB.java
@@ -155,6 +155,7 @@ public class SubscriptionTestSuiteNoDB extends GuicyKillbillTestSuiteNoDB {
subscriptionTestInitializer.stopTestFramework(testListener, busService, subscriptionBaseService);
}
+ @Override
protected void assertListenerStatus() {
testListener.assertListenerStatus();
}
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/SubscriptionTestSuiteWithEmbeddedDB.java b/subscription/src/test/java/org/killbill/billing/subscription/SubscriptionTestSuiteWithEmbeddedDB.java
index e97f3e0..02ce1be 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/SubscriptionTestSuiteWithEmbeddedDB.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/SubscriptionTestSuiteWithEmbeddedDB.java
@@ -115,16 +115,10 @@ public class SubscriptionTestSuiteWithEmbeddedDB extends GuicyKillbillTestSuiteW
this.accountData = subscriptionTestInitializer.initAccountData();
final Account account = createAccount(accountData);
this.bundle = subscriptionTestInitializer.initBundle(account.getId(), subscriptionInternalApi, internalCallContext);
-
- // Make sure we start with a clean state
- assertListenerStatus();
}
@AfterMethod(groups = "slow")
public void afterMethod() throws Exception {
- // Make sure we finish in a clean state
- assertListenerStatus();
-
subscriptionTestInitializer.stopTestFramework(testListener, busService, subscriptionBaseService);
}
@@ -136,6 +130,7 @@ public class SubscriptionTestSuiteWithEmbeddedDB extends GuicyKillbillTestSuiteW
return account;
}
+ @Override
protected void assertListenerStatus() {
testListener.assertListenerStatus();
}
diff --git a/tenant/src/test/java/org/killbill/billing/tenant/TenantTestSuiteWithEmbeddedDb.java b/tenant/src/test/java/org/killbill/billing/tenant/TenantTestSuiteWithEmbeddedDb.java
index 060a087..45486dc 100644
--- a/tenant/src/test/java/org/killbill/billing/tenant/TenantTestSuiteWithEmbeddedDb.java
+++ b/tenant/src/test/java/org/killbill/billing/tenant/TenantTestSuiteWithEmbeddedDb.java
@@ -58,13 +58,4 @@ public class TenantTestSuiteWithEmbeddedDb extends GuicyKillbillTestSuiteWithEmb
final Injector injector = Guice.createInjector(new TestTenantModuleWithEmbeddedDB(configSource));
injector.injectMembers(this);
}
-
- @BeforeMethod(groups = "slow")
- public void beforeMethod() throws Exception {
- super.beforeMethod();
- }
-
- @AfterMethod(groups = "slow")
- public void afterMethod() {
- }
}
diff --git a/util/src/main/java/org/killbill/billing/util/cache/CacheControllerDispatcherProvider.java b/util/src/main/java/org/killbill/billing/util/cache/CacheControllerDispatcherProvider.java
index 7d9ce76..2ce2b6f 100644
--- a/util/src/main/java/org/killbill/billing/util/cache/CacheControllerDispatcherProvider.java
+++ b/util/src/main/java/org/killbill/billing/util/cache/CacheControllerDispatcherProvider.java
@@ -31,6 +31,8 @@ import org.killbill.billing.util.cache.Cachable.CacheType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.base.Preconditions;
+
// Build the abstraction layer between EhCache and Kill Bill
public class CacheControllerDispatcherProvider implements Provider<CacheControllerDispatcher> {
@@ -57,6 +59,7 @@ public class CacheControllerDispatcherProvider implements Provider<CacheControll
logger.warn("Cache for cacheName='{}' not configured - check your ehcache.xml", cacheLoader.getCacheType().getCacheName());
continue;
}
+ Preconditions.checkState(!cache.isClosed(), "Cache '%s' should not be closed", cacheType.getCacheName());
final CacheController<Object, Object> ehCacheBasedCacheController = new EhCacheBasedCacheController<Object, Object>(cache, cacheLoader);
cacheControllers.put(cacheType, ehCacheBasedCacheController);
diff --git a/util/src/main/java/org/killbill/billing/util/config/definition/InvoiceConfig.java b/util/src/main/java/org/killbill/billing/util/config/definition/InvoiceConfig.java
index 8170bd6..7ed6ac9 100644
--- a/util/src/main/java/org/killbill/billing/util/config/definition/InvoiceConfig.java
+++ b/util/src/main/java/org/killbill/billing/util/config/definition/InvoiceConfig.java
@@ -17,6 +17,8 @@
package org.killbill.billing.util.config.definition;
+import java.util.List;
+
import org.killbill.billing.callcontext.InternalTenantContext;
import org.skife.config.Config;
import org.skife.config.Default;
@@ -81,6 +83,16 @@ public interface InvoiceConfig extends KillbillConfig {
@Description("Maximum number of times the system will retry to grab global lock (with a 100ms wait each time)")
int getMaxGlobalLockRetries();
+ @Config("org.killbill.invoice.plugin")
+ @Default("")
+ @Description("Default invoice plugin names")
+ List<String> getInvoicePluginNames();
+
+ @Config("org.killbill.invoice.plugin")
+ @Default("")
+ @Description("Default invoice plugin names")
+ List<String> getInvoicePluginNames(@Param("dummy") final InternalTenantContext tenantContext);
+
@Config("org.killbill.invoice.emailNotificationsEnabled")
@Default("false")
@Description("Whether to send email notifications on invoice creation (for configured accounts)")
diff --git a/util/src/main/java/org/killbill/billing/util/config/tenant/MultiTenantConfigBase.java b/util/src/main/java/org/killbill/billing/util/config/tenant/MultiTenantConfigBase.java
index 39562ee..10c9e38 100644
--- a/util/src/main/java/org/killbill/billing/util/config/tenant/MultiTenantConfigBase.java
+++ b/util/src/main/java/org/killbill/billing/util/config/tenant/MultiTenantConfigBase.java
@@ -108,7 +108,11 @@ public abstract class MultiTenantConfigBase {
private List<String> getTokens(final Method method, final String value) {
final Separator separator = method.getAnnotation(Separator.class);
- return ImmutableList.copyOf(value.split(separator == null ? Separator.DEFAULT : separator.value()));
+ if (value == null || value.isEmpty()) {
+ return ImmutableList.of();
+ } else {
+ return ImmutableList.copyOf(value.split(separator == null ? Separator.DEFAULT : separator.value()));
+ }
}
protected Method getConfigStaticMethod(final String methodName) {
diff --git a/util/src/main/java/org/killbill/billing/util/glue/CacheProviderBase.java b/util/src/main/java/org/killbill/billing/util/glue/CacheProviderBase.java
index 24f2dbf..222dc7f 100644
--- a/util/src/main/java/org/killbill/billing/util/glue/CacheProviderBase.java
+++ b/util/src/main/java/org/killbill/billing/util/glue/CacheProviderBase.java
@@ -32,6 +32,7 @@ import com.codahale.metrics.Metric;
import com.codahale.metrics.MetricFilter;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.jcache.JCacheGaugeSet;
+import com.google.common.base.Preconditions;
abstract class CacheProviderBase {
@@ -61,6 +62,7 @@ abstract class CacheProviderBase {
final MutableConfiguration<K, V> configuration = new MutableConfiguration<K, V>().setTypes(keyType, valueType)
.setStoreByValue(false); // Store by reference to avoid copying large objects (e.g. catalog)
final Cache<K, V> cache = cacheManager.createCache(cacheName, configuration);
+ Preconditions.checkState(!cache.isClosed(), "Cache '%s' should not be closed", cacheName);
// Re-create the metrics to support dynamically created caches (e.g. for Shiro)
metricRegistry.removeMatching(new MetricFilter() {
diff --git a/util/src/main/java/org/killbill/billing/util/glue/Eh107CacheManagerProvider.java b/util/src/main/java/org/killbill/billing/util/glue/Eh107CacheManagerProvider.java
index 005afa3..d5de5cc 100644
--- a/util/src/main/java/org/killbill/billing/util/glue/Eh107CacheManagerProvider.java
+++ b/util/src/main/java/org/killbill/billing/util/glue/Eh107CacheManagerProvider.java
@@ -27,6 +27,7 @@ import javax.cache.spi.CachingProvider;
import javax.inject.Inject;
import javax.inject.Provider;
+import org.ehcache.core.spi.store.InternalCacheManager;
import org.killbill.billing.util.cache.BaseCacheLoader;
import org.killbill.billing.util.config.definition.EhCacheConfig;
import org.slf4j.Logger;
@@ -38,6 +39,7 @@ import com.codahale.metrics.MetricRegistry;
public class Eh107CacheManagerProvider extends CacheProviderBase implements Provider<CacheManager> {
private static final Logger logger = LoggerFactory.getLogger(Eh107CacheManagerProvider.class);
+ private static final EhcacheLoggingListener ehcacheLoggingListener = new EhcacheLoggingListener();
private final Set<BaseCacheLoader> cacheLoaders;
@@ -65,6 +67,10 @@ public class Eh107CacheManagerProvider extends CacheProviderBase implements Prov
cacheManager = cachingProvider.getCacheManager();
}
+ // Make sure we start from a clean state - this is mainly useful for tests
+ cacheManager.unwrap(InternalCacheManager.class).deregisterListener(ehcacheLoggingListener);
+ cacheManager.unwrap(InternalCacheManager.class).registerListener(ehcacheLoggingListener);
+
for (final BaseCacheLoader<?, ?> cacheLoader : cacheLoaders) {
createCache(cacheManager,
cacheLoader.getCacheType().getCacheName(),
diff --git a/util/src/main/java/org/killbill/billing/util/glue/EhcacheLoggingListener.java b/util/src/main/java/org/killbill/billing/util/glue/EhcacheLoggingListener.java
new file mode 100644
index 0000000..721072e
--- /dev/null
+++ b/util/src/main/java/org/killbill/billing/util/glue/EhcacheLoggingListener.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you 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 org.killbill.billing.util.glue;
+
+import org.ehcache.Cache;
+import org.ehcache.Status;
+import org.ehcache.core.events.CacheManagerListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class EhcacheLoggingListener implements CacheManagerListener {
+
+ private static final Logger logger = LoggerFactory.getLogger(EhcacheLoggingListener.class);
+
+ @Override
+ public void cacheAdded(final String alias, final Cache<?, ?> cache) {
+ logger.info("Added Ehcache '{}'", alias);
+ }
+
+ @Override
+ public void cacheRemoved(final String alias, final Cache<?, ?> cache) {
+ logger.info("Removed Ehcache '{}'", alias);
+ }
+
+ @Override
+ public void stateTransition(final Status from, final Status to) {
+ logger.info("Transitioning Ehcache from '{}' to '{}'", from, to);
+ }
+}
diff --git a/util/src/main/java/org/killbill/billing/util/security/api/DefaultSecurityApi.java b/util/src/main/java/org/killbill/billing/util/security/api/DefaultSecurityApi.java
index 70ed26c..3d30a3c 100644
--- a/util/src/main/java/org/killbill/billing/util/security/api/DefaultSecurityApi.java
+++ b/util/src/main/java/org/killbill/billing/util/security/api/DefaultSecurityApi.java
@@ -206,6 +206,12 @@ public class DefaultSecurityApi implements SecurityApi {
}
@Override
+ public void updateRoleDefinition(final String role, final List<String> permissions, final CallContext callContext) throws SecurityApiException {
+ final List<String> sanitizedPermissions = sanitizeAndValidatePermissions(permissions);
+ userDao.updateRoleDefinition(role, sanitizedPermissions, callContext.getUserName());
+ }
+
+ @Override
public List<String> getRoleDefinition(final String role, final TenantContext tenantContext) {
final List<RolesPermissionsModelDao> permissionsModelDao = userDao.getRoleDefinition(role);
return ImmutableList.copyOf(Iterables.transform(permissionsModelDao, new Function<RolesPermissionsModelDao, String>() {
diff --git a/util/src/main/java/org/killbill/billing/util/security/shiro/dao/DefaultUserDao.java b/util/src/main/java/org/killbill/billing/util/security/shiro/dao/DefaultUserDao.java
index 013f859..1d9757d 100644
--- a/util/src/main/java/org/killbill/billing/util/security/shiro/dao/DefaultUserDao.java
+++ b/util/src/main/java/org/killbill/billing/util/security/shiro/dao/DefaultUserDao.java
@@ -17,8 +17,11 @@
package org.killbill.billing.util.security.shiro.dao;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
+import javax.annotation.Nullable;
import javax.inject.Inject;
import org.apache.shiro.crypto.RandomNumberGenerator;
@@ -113,6 +116,50 @@ public class DefaultUserDao implements UserDao {
}
@Override
+ public void updateRoleDefinition(final String role, final List<String> permissions, final String createdBy) throws SecurityApiException {
+ final DateTime createdDate = clock.getUTCNow();
+ inTransactionWithExceptionHandling(new TransactionCallback<Void>() {
+ @Override
+ public Void inTransaction(final Handle handle, final TransactionStatus status) throws Exception {
+ final RolesPermissionsSqlDao rolesPermissionsSqlDao = handle.attach(RolesPermissionsSqlDao.class);
+ final List<RolesPermissionsModelDao> existingPermissions = rolesPermissionsSqlDao.getByRoleName(role);
+ if (existingPermissions.isEmpty()) {
+ throw new SecurityApiException(ErrorCode.SECURITY_INVALID_ROLE, role);
+ }
+
+ final Iterable<RolesPermissionsModelDao> toBeDeleted = Iterables.filter(existingPermissions, new Predicate<RolesPermissionsModelDao>() {
+ @Override
+ public boolean apply(final RolesPermissionsModelDao input) {
+ return !permissions.contains(input.getPermission());
+ }
+ });
+
+ final Iterable<String> toBeAdded = Iterables.filter(permissions, new Predicate<String>() {
+ @Override
+ public boolean apply(final String input) {
+ for (RolesPermissionsModelDao e : existingPermissions) {
+ if (e.getPermission().equals(input)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ });
+
+ for (RolesPermissionsModelDao d : toBeDeleted) {
+ rolesPermissionsSqlDao.unactiveEvent(d.getRecordId(), createdDate, createdBy);
+ }
+
+ for (final String permission : toBeAdded) {
+ rolesPermissionsSqlDao.create(new RolesPermissionsModelDao(role, permission, createdDate, createdBy));
+ }
+ return null;
+ }
+ });
+
+ }
+
+ @Override
public List<RolesPermissionsModelDao> getRoleDefinition(final String role) {
return dbi.inTransaction(new TransactionCallback<List<RolesPermissionsModelDao>>() {
@Override
diff --git a/util/src/main/java/org/killbill/billing/util/security/shiro/dao/RolesPermissionsSqlDao.java b/util/src/main/java/org/killbill/billing/util/security/shiro/dao/RolesPermissionsSqlDao.java
index dccee99..ad4187f 100644
--- a/util/src/main/java/org/killbill/billing/util/security/shiro/dao/RolesPermissionsSqlDao.java
+++ b/util/src/main/java/org/killbill/billing/util/security/shiro/dao/RolesPermissionsSqlDao.java
@@ -19,6 +19,10 @@ package org.killbill.billing.util.security.shiro.dao;
import java.util.List;
+import org.joda.time.DateTime;
+import org.killbill.billing.callcontext.InternalCallContext;
+import org.killbill.billing.util.audit.ChangeType;
+import org.killbill.billing.util.entity.dao.Audited;
import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
import org.killbill.commons.jdbi.binder.SmartBindBean;
import org.skife.jdbi.v2.sqlobject.Bind;
@@ -37,4 +41,12 @@ public interface RolesPermissionsSqlDao extends Transactional<RolesPermissionsSq
@SqlUpdate
public void create(@SmartBindBean final RolesPermissionsModelDao rolesPermissions);
+
+ @SqlUpdate
+ @Audited(ChangeType.UPDATE)
+ public void unactiveEvent(@Bind("recordId") final Long recordId,
+ @Bind("createdDate") final DateTime createdDate,
+ @Bind("createdBy") final String createdBy);
+
+
}
diff --git a/util/src/main/java/org/killbill/billing/util/security/shiro/dao/UserDao.java b/util/src/main/java/org/killbill/billing/util/security/shiro/dao/UserDao.java
index 142e13d..f0b4427 100644
--- a/util/src/main/java/org/killbill/billing/util/security/shiro/dao/UserDao.java
+++ b/util/src/main/java/org/killbill/billing/util/security/shiro/dao/UserDao.java
@@ -29,6 +29,8 @@ public interface UserDao {
public void addRoleDefinition(String role, List<String> permissions, String createdBy) throws SecurityApiException;
+ public void updateRoleDefinition(String role, List<String> permissions, String createdBy) throws SecurityApiException;
+
public List<RolesPermissionsModelDao> getRoleDefinition(String role);
public void updateUserPassword(String username, String password, String createdBy) throws SecurityApiException;
diff --git a/util/src/main/java/org/killbill/billing/util/tag/api/DefaultTagUserApi.java b/util/src/main/java/org/killbill/billing/util/tag/api/DefaultTagUserApi.java
index 55314d1..eb81b50 100644
--- a/util/src/main/java/org/killbill/billing/util/tag/api/DefaultTagUserApi.java
+++ b/util/src/main/java/org/killbill/billing/util/tag/api/DefaultTagUserApi.java
@@ -18,6 +18,7 @@ package org.killbill.billing.util.tag.api;
import java.util.Collection;
import java.util.List;
+import java.util.Set;
import java.util.UUID;
import org.killbill.billing.ErrorCode;
@@ -45,6 +46,7 @@ import org.killbill.billing.util.tag.dao.TagModelDao;
import org.killbill.billing.util.tag.dao.TagModelDaoHelper;
import com.google.common.base.Function;
+import com.google.common.base.Joiner;
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableList;
import com.google.inject.Inject;
@@ -53,6 +55,8 @@ import static org.killbill.billing.util.entity.dao.DefaultPaginationHelper.getEn
public class DefaultTagUserApi implements TagUserApi {
+ private static final Joiner JOINER = Joiner.on(",");
+
private static final Function<TagModelDao, Tag> TAG_MODEL_DAO_TAG_FUNCTION = new Function<TagModelDao, Tag>() {
@Override
public Tag apply(final TagModelDao input) {
@@ -85,11 +89,11 @@ public class DefaultTagUserApi implements TagUserApi {
}
@Override
- public TagDefinition createTagDefinition(final String definitionName, final String description, final CallContext context) throws TagDefinitionApiException {
+ public TagDefinition createTagDefinition(final String definitionName, final String description, final Set<ObjectType> applicableObjectTypes, final CallContext context) throws TagDefinitionApiException {
if (definitionName.matches(".*[A-Z].*")) {
throw new TagDefinitionApiException(ErrorCode.TAG_DEFINITION_HAS_UPPERCASE, definitionName);
}
- final TagDefinitionModelDao tagDefinitionModelDao = tagDefinitionDao.create(definitionName, description, internalCallContextFactory.createInternalCallContextWithoutAccountRecordId(context));
+ final TagDefinitionModelDao tagDefinitionModelDao = tagDefinitionDao.create(definitionName, description, JOINER.join(applicableObjectTypes), internalCallContextFactory.createInternalCallContextWithoutAccountRecordId(context));
return new DefaultTagDefinition(tagDefinitionModelDao, TagModelDaoHelper.isControlTag(tagDefinitionModelDao.getName()));
}
diff --git a/util/src/main/java/org/killbill/billing/util/tag/dao/DefaultTagDefinitionDao.java b/util/src/main/java/org/killbill/billing/util/tag/dao/DefaultTagDefinitionDao.java
index 90d2d75..dfa1331 100644
--- a/util/src/main/java/org/killbill/billing/util/tag/dao/DefaultTagDefinitionDao.java
+++ b/util/src/main/java/org/killbill/billing/util/tag/dao/DefaultTagDefinitionDao.java
@@ -22,6 +22,7 @@ import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
+import java.util.Set;
import java.util.UUID;
import org.killbill.billing.BillingExceptionBase;
@@ -59,6 +60,7 @@ public class DefaultTagDefinitionDao extends EntityDaoBase<TagDefinitionModelDao
private final TagEventBuilder tagEventBuilder;
private final PersistentBus bus;
+
@Inject
public DefaultTagDefinitionDao(final IDBI dbi, final TagEventBuilder tagEventBuilder, final PersistentBus bus, final Clock clock,
final CacheControllerDispatcher controllerDispatcher, final NonEntityDao nonEntityDao, final InternalCallContextFactory internalCallContextFactory) {
@@ -134,7 +136,7 @@ public class DefaultTagDefinitionDao extends EntityDaoBase<TagDefinitionModelDao
}
@Override
- public TagDefinitionModelDao create(final String definitionName, final String description,
+ public TagDefinitionModelDao create(final String definitionName, final String description, final String tagDefinitionObjectTypes,
final InternalCallContext context) throws TagDefinitionApiException {
// Make sure a invoice tag with this name don't already exist
if (TagModelDaoHelper.isControlTag(definitionName)) {
@@ -154,7 +156,7 @@ public class DefaultTagDefinitionDao extends EntityDaoBase<TagDefinitionModelDao
}
// Create it
- final TagDefinitionModelDao tagDefinition = new TagDefinitionModelDao(context.getCreatedDate(), definitionName, description);
+ final TagDefinitionModelDao tagDefinition = new TagDefinitionModelDao(context.getCreatedDate(), definitionName, description, tagDefinitionObjectTypes);
createAndRefresh(tagDefinitionSqlDao, tagDefinition, context);
// Post an event to the bus
diff --git a/util/src/main/java/org/killbill/billing/util/tag/dao/SystemTags.java b/util/src/main/java/org/killbill/billing/util/tag/dao/SystemTags.java
index 5879654..61ae17e 100644
--- a/util/src/main/java/org/killbill/billing/util/tag/dao/SystemTags.java
+++ b/util/src/main/java/org/killbill/billing/util/tag/dao/SystemTags.java
@@ -24,6 +24,7 @@ import java.util.UUID;
import javax.annotation.Nullable;
+import org.killbill.billing.ObjectType;
import org.killbill.billing.util.tag.ControlTagType;
import com.google.common.base.Predicate;
@@ -37,7 +38,7 @@ public class SystemTags {
public static final String PARK_TAG_DEFINITION_NAME = "__PARK__";
// Note! TagSqlDao.sql.stg needs to be kept in sync (see userAndSystemTagDefinitions)
- private static final List<TagDefinitionModelDao> SYSTEM_DEFINED_TAG_DEFINITIONS = ImmutableList.<TagDefinitionModelDao>of(new TagDefinitionModelDao(PARK_TAG_DEFINITION_ID, null, null, PARK_TAG_DEFINITION_NAME, "Accounts with invalid invoicing state"));
+ private static final List<TagDefinitionModelDao> SYSTEM_DEFINED_TAG_DEFINITIONS = ImmutableList.<TagDefinitionModelDao>of(new TagDefinitionModelDao(PARK_TAG_DEFINITION_ID, null, null, PARK_TAG_DEFINITION_NAME, "Accounts with invalid invoicing state", ObjectType.ACCOUNT.name()));
public static Collection<TagDefinitionModelDao> get(final boolean includeSystemTags) {
final Collection<TagDefinitionModelDao> all = includeSystemTags ?
diff --git a/util/src/main/java/org/killbill/billing/util/tag/dao/TagDefinitionDao.java b/util/src/main/java/org/killbill/billing/util/tag/dao/TagDefinitionDao.java
index 84f3bed..e409c89 100644
--- a/util/src/main/java/org/killbill/billing/util/tag/dao/TagDefinitionDao.java
+++ b/util/src/main/java/org/killbill/billing/util/tag/dao/TagDefinitionDao.java
@@ -34,7 +34,7 @@ public interface TagDefinitionDao extends EntityDao<TagDefinitionModelDao, TagDe
public List<TagDefinitionModelDao> getByIds(Collection<UUID> definitionIds, InternalTenantContext context);
- public TagDefinitionModelDao create(String definitionName, String description, InternalCallContext context) throws TagDefinitionApiException;
+ public TagDefinitionModelDao create(String definitionName, String description, String tagDefinitionObjectTypes, InternalCallContext context) throws TagDefinitionApiException;
public void deleteById(UUID definitionId, InternalCallContext context) throws TagDefinitionApiException;
}
diff --git a/util/src/main/java/org/killbill/billing/util/tag/dao/TagDefinitionModelDao.java b/util/src/main/java/org/killbill/billing/util/tag/dao/TagDefinitionModelDao.java
index 337afbc..b5ba4bd 100644
--- a/util/src/main/java/org/killbill/billing/util/tag/dao/TagDefinitionModelDao.java
+++ b/util/src/main/java/org/killbill/billing/util/tag/dao/TagDefinitionModelDao.java
@@ -27,32 +27,38 @@ import org.killbill.billing.util.entity.dao.EntityModelDaoBase;
import org.killbill.billing.util.tag.ControlTagType;
import org.killbill.billing.util.tag.TagDefinition;
+import com.google.common.base.Joiner;
+
public class TagDefinitionModelDao extends EntityModelDaoBase implements EntityModelDao<TagDefinition> {
+ private static final Joiner JOINER = Joiner.on(",");
private String name;
+ private String applicableObjectTypes;
private String description;
private Boolean isActive;
public TagDefinitionModelDao() { /* For the DAO mapper */ }
- public TagDefinitionModelDao(final UUID id, final DateTime createdDate, final DateTime updatedDate, final String name, final String description) {
+ public TagDefinitionModelDao(final UUID id, final DateTime createdDate, final DateTime updatedDate, final String name, final String description, String applicableObjectTypes) {
super(id, createdDate, updatedDate);
this.name = name;
this.description = description;
this.isActive = true;
+ this.applicableObjectTypes = applicableObjectTypes;
}
public TagDefinitionModelDao(final ControlTagType tag) {
- this(tag.getId(), null, null, tag.name(), tag.getDescription());
+ this(tag.getId(), null, null, tag.name(), tag.getDescription(), JOINER.join(tag.getApplicableObjectTypes()));
}
- public TagDefinitionModelDao(final DateTime createdDate, final String name, final String description) {
- this(UUIDs.randomUUID(), createdDate, createdDate, name, description);
+ public TagDefinitionModelDao(final DateTime createdDate, final String name, final String description, String applicableObjectTypes) {
+ this(UUIDs.randomUUID(), createdDate, createdDate, name, description, applicableObjectTypes);
}
+
public TagDefinitionModelDao(final TagDefinition tagDefinition) {
this(tagDefinition.getId(), tagDefinition.getCreatedDate(), tagDefinition.getUpdatedDate(), tagDefinition.getName(),
- tagDefinition.getDescription());
+ tagDefinition.getDescription(), JOINER.join(tagDefinition.getApplicableObjectTypes()));
}
public String getName() {
@@ -67,6 +73,14 @@ public class TagDefinitionModelDao extends EntityModelDaoBase implements EntityM
return isActive;
}
+ public String getApplicableObjectTypes() {
+ return applicableObjectTypes;
+ }
+
+ public void setApplicableObjectTypes(final String applicableObjectTypes) {
+ this.applicableObjectTypes = applicableObjectTypes;
+ }
+
public void setName(final String name) {
this.name = name;
}
@@ -85,6 +99,7 @@ public class TagDefinitionModelDao extends EntityModelDaoBase implements EntityM
sb.append("TagDefinitionModelDao");
sb.append("{name='").append(name).append('\'');
sb.append(", description='").append(description).append('\'');
+ sb.append(", applicableObjectTypes='").append(applicableObjectTypes).append('\'');
sb.append(", isActive=").append(isActive);
sb.append('}');
return sb.toString();
@@ -110,6 +125,9 @@ public class TagDefinitionModelDao extends EntityModelDaoBase implements EntityM
if (isActive != null ? !isActive.equals(that.isActive) : that.isActive != null) {
return false;
}
+ if (applicableObjectTypes != null ? !applicableObjectTypes.equals(that.applicableObjectTypes) : that.applicableObjectTypes != null) {
+ return false;
+ }
if (name != null ? !name.equals(that.name) : that.name != null) {
return false;
}
@@ -123,6 +141,7 @@ public class TagDefinitionModelDao extends EntityModelDaoBase implements EntityM
result = 31 * result + (name != null ? name.hashCode() : 0);
result = 31 * result + (description != null ? description.hashCode() : 0);
result = 31 * result + (isActive != null ? isActive.hashCode() : 0);
+ result = 31 * result + (applicableObjectTypes != null ? applicableObjectTypes.hashCode() : 0);
return result;
}
diff --git a/util/src/main/java/org/killbill/billing/util/tag/DefaultTagDefinition.java b/util/src/main/java/org/killbill/billing/util/tag/DefaultTagDefinition.java
index 05ca6b4..77db66f 100644
--- a/util/src/main/java/org/killbill/billing/util/tag/DefaultTagDefinition.java
+++ b/util/src/main/java/org/killbill/billing/util/tag/DefaultTagDefinition.java
@@ -19,6 +19,8 @@ package org.killbill.billing.util.tag;
import java.util.List;
import java.util.UUID;
+import javax.annotation.Nullable;
+
import org.killbill.billing.ObjectType;
import org.killbill.billing.entity.EntityBase;
import org.killbill.billing.util.UUIDs;
@@ -26,32 +28,41 @@ import org.killbill.billing.util.tag.dao.TagDefinitionModelDao;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.Function;
+import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
public class DefaultTagDefinition extends EntityBase implements TagDefinition {
+ private static final Splitter SPLITTER = Splitter.on(',').omitEmptyStrings().trimResults();
+
private final String name;
private final String description;
private final Boolean controlTag;
private final List<ObjectType> applicableObjectTypes;
+
public DefaultTagDefinition(final TagDefinitionModelDao tagDefinitionModelDao, final boolean isControlTag) {
- this(tagDefinitionModelDao.getId(), tagDefinitionModelDao.getName(), tagDefinitionModelDao.getDescription(), isControlTag);
+ this(tagDefinitionModelDao.getId(), tagDefinitionModelDao.getName(), tagDefinitionModelDao.getDescription(), isControlTag, toObjectTypes(tagDefinitionModelDao.getApplicableObjectTypes()));
}
+
+ public DefaultTagDefinition(final ControlTagType controlTag) {
+ this(controlTag.getId(), controlTag.toString(), controlTag.getDescription(), true, controlTag.getApplicableObjectTypes());
+ }
+
+ // Test only
public DefaultTagDefinition(final String name, final String description, final Boolean isControlTag) {
this(UUIDs.randomUUID(), name, description, isControlTag);
}
+ // Test only
public DefaultTagDefinition(final UUID id, final String name, final String description, final Boolean isControlTag) {
this(id, name, description, isControlTag, getApplicableObjectTypes(id, isControlTag));
}
- public DefaultTagDefinition(final ControlTagType controlTag) {
- this(controlTag.getId(), controlTag.toString(), controlTag.getDescription(), true, controlTag.getApplicableObjectTypes());
- }
-
-
@JsonCreator
public DefaultTagDefinition(@JsonProperty("id") final UUID id,
@JsonProperty("name") final String name,
@@ -144,4 +155,14 @@ public class DefaultTagDefinition extends EntityBase implements TagDefinition {
}
throw new IllegalStateException(String.format("ControlTag id %s does not seem to exist", id));
}
+
+ private static List<ObjectType> toObjectTypes(final String input) {
+ return ImmutableList.copyOf(Iterables.transform(SPLITTER.splitToList(input), new Function<String, ObjectType>() {
+ @Override
+ public ObjectType apply(final String input) {
+ return ObjectType.valueOf(input);
+ }
+ }));
+ }
+
}
diff --git a/util/src/main/resources/org/killbill/billing/util/ddl.sql b/util/src/main/resources/org/killbill/billing/util/ddl.sql
index 552f8dd..5523655 100644
--- a/util/src/main/resources/org/killbill/billing/util/ddl.sql
+++ b/util/src/main/resources/org/killbill/billing/util/ddl.sql
@@ -49,6 +49,7 @@ CREATE TABLE tag_definitions (
record_id serial unique,
id varchar(36) NOT NULL,
name varchar(20) NOT NULL,
+ applicable_object_types varchar(500),
description varchar(200) NOT NULL,
is_active boolean default true,
created_by varchar(50) NOT NULL,
@@ -67,6 +68,7 @@ CREATE TABLE tag_definition_history (
id varchar(36) NOT NULL,
target_record_id bigint /*! unsigned */ not null,
name varchar(30) NOT NULL,
+ applicable_object_types varchar(500),
description varchar(200),
is_active boolean default true,
change_type varchar(6) NOT NULL,
diff --git a/util/src/main/resources/org/killbill/billing/util/migration/V20171011170256__tag_definition_object_types.sql b/util/src/main/resources/org/killbill/billing/util/migration/V20171011170256__tag_definition_object_types.sql
new file mode 100644
index 0000000..09b02bd
--- /dev/null
+++ b/util/src/main/resources/org/killbill/billing/util/migration/V20171011170256__tag_definition_object_types.sql
@@ -0,0 +1,2 @@
+alter table tag_definitions add column applicable_object_types varchar(500) after name;
+alter table tag_definition_history add column applicable_object_types varchar(500) after name;
diff --git a/util/src/main/resources/org/killbill/billing/util/security/shiro/dao/RolesPermissionsSqlDao.sql.stg b/util/src/main/resources/org/killbill/billing/util/security/shiro/dao/RolesPermissionsSqlDao.sql.stg
index febc7ee..1d13de4 100644
--- a/util/src/main/resources/org/killbill/billing/util/security/shiro/dao/RolesPermissionsSqlDao.sql.stg
+++ b/util/src/main/resources/org/killbill/billing/util/security/shiro/dao/RolesPermissionsSqlDao.sql.stg
@@ -58,3 +58,16 @@ where role_name = :roleName
and is_active
;
>>
+
+unactiveEvent() ::= <<
+update <tableName()>
+set
+is_active = false
+, updated_by = :createdBy
+, updated_date = :createdDate
+where
+record_id = :recordId
+<AND_CHECK_TENANT("")>
+;
+>>
+
diff --git a/util/src/main/resources/org/killbill/billing/util/tag/dao/TagDefinitionSqlDao.sql.stg b/util/src/main/resources/org/killbill/billing/util/tag/dao/TagDefinitionSqlDao.sql.stg
index cc1f546..3b16041 100644
--- a/util/src/main/resources/org/killbill/billing/util/tag/dao/TagDefinitionSqlDao.sql.stg
+++ b/util/src/main/resources/org/killbill/billing/util/tag/dao/TagDefinitionSqlDao.sql.stg
@@ -6,6 +6,7 @@ andCheckSoftDeletionWithComma(prefix) ::= "and <prefix>is_active"
tableFields(prefix) ::= <<
<prefix>name
+, <prefix>applicable_object_types
, <prefix>description
, <prefix>is_active
, <prefix>created_by
@@ -16,6 +17,7 @@ tableFields(prefix) ::= <<
tableValues() ::= <<
:name
+, :applicableObjectTypes
, :description
, :isActive
, :createdBy
diff --git a/util/src/test/java/org/killbill/billing/api/FlakyInvokedMethodListener.java b/util/src/test/java/org/killbill/billing/api/FlakyInvokedMethodListener.java
new file mode 100644
index 0000000..80ad169
--- /dev/null
+++ b/util/src/test/java/org/killbill/billing/api/FlakyInvokedMethodListener.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you 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 org.killbill.billing.api;
+
+import org.testng.IInvokedMethod;
+import org.testng.IInvokedMethodListener;
+import org.testng.IRetryAnalyzer;
+import org.testng.ITestResult;
+import org.testng.Reporter;
+
+public class FlakyInvokedMethodListener implements IInvokedMethodListener {
+
+ @Override
+ public void beforeInvocation(final IInvokedMethod method, final ITestResult testResult) {
+ }
+
+ @Override
+ public void afterInvocation(final IInvokedMethod method, final ITestResult testResult) {
+ if (testResult.getStatus() != ITestResult.FAILURE) {
+ return;
+ }
+
+ final IRetryAnalyzer retryAnalyzer = testResult.getMethod().getRetryAnalyzer();
+ if (retryAnalyzer != null &&
+ retryAnalyzer instanceof FlakyRetryAnalyzer &&
+ !((FlakyRetryAnalyzer) retryAnalyzer).shouldRetry()) {
+ // Don't fail the build (flaky test), mark it as SKIPPED
+ testResult.setStatus(ITestResult.SKIP);
+ Reporter.setCurrentTestResult(testResult);
+ }
+ }
+}
diff --git a/util/src/test/java/org/killbill/billing/api/FlakyRetryAnalyzer.java b/util/src/test/java/org/killbill/billing/api/FlakyRetryAnalyzer.java
new file mode 100644
index 0000000..9cacc19
--- /dev/null
+++ b/util/src/test/java/org/killbill/billing/api/FlakyRetryAnalyzer.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you 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 org.killbill.billing.api;
+
+import org.testng.IRetryAnalyzer;
+import org.testng.ITestResult;
+
+public class FlakyRetryAnalyzer implements IRetryAnalyzer {
+
+ private static final int MAX_RETRIES = 3;
+
+ private int count = 0;
+
+ @Override
+ public boolean retry(final ITestResult iTestResult) {
+ if (iTestResult.isSuccess()) {
+ return false;
+ }
+
+ if (shouldRetry()) {
+ count++;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public boolean shouldRetry() {
+ return count < MAX_RETRIES;
+ }
+}
diff --git a/util/src/test/java/org/killbill/billing/api/TestApiListener.java b/util/src/test/java/org/killbill/billing/api/TestApiListener.java
index 886dd99..fd0bc8c 100644
--- a/util/src/test/java/org/killbill/billing/api/TestApiListener.java
+++ b/util/src/test/java/org/killbill/billing/api/TestApiListener.java
@@ -63,7 +63,7 @@ public class TestApiListener {
private static final Joiner SPACE_JOINER = Joiner.on(" ");
- private static final long DELAY = 25000;
+ private static final long DELAY = 60000;
private final List<NextEvent> nextExpectedEvent;
private final IDBI idbi;
diff --git a/util/src/test/java/org/killbill/billing/DBTestingHelper.java b/util/src/test/java/org/killbill/billing/DBTestingHelper.java
index 7046879..de0640b 100644
--- a/util/src/test/java/org/killbill/billing/DBTestingHelper.java
+++ b/util/src/test/java/org/killbill/billing/DBTestingHelper.java
@@ -79,14 +79,16 @@ public class DBTestingHelper extends PlatformDBTestingHelper {
"CREATE TABLE accounts (\n" +
" record_id serial unique,\n" +
" id varchar(36) NOT NULL,\n" +
- " external_key varchar(128) NULL,\n" +
- " email varchar(128) NOT NULL,\n" +
- " name varchar(100) NOT NULL,\n" +
- " first_name_length int NOT NULL,\n" +
+ " external_key varchar(255) NULL,\n" +
+ " email varchar(128) DEFAULT NULL,\n" +
+ " name varchar(100) DEFAULT NULL,\n" +
+ " first_name_length int DEFAULT NULL,\n" +
" currency varchar(3) DEFAULT NULL,\n" +
" billing_cycle_day_local int DEFAULT NULL,\n" +
+ " parent_account_id varchar(36) DEFAULT NULL,\n" +
+ " is_payment_delegated_to_parent boolean DEFAULT FALSE,\n" +
" payment_method_id varchar(36) DEFAULT NULL,\n" +
- " time_zone varchar(50) DEFAULT NULL,\n" +
+ " time_zone varchar(50) NOT NULL,\n" +
" locale varchar(5) DEFAULT NULL,\n" +
" address1 varchar(100) DEFAULT NULL,\n" +
" address2 varchar(100) DEFAULT NULL,\n" +
@@ -96,6 +98,7 @@ public class DBTestingHelper extends PlatformDBTestingHelper {
" country varchar(50) DEFAULT NULL,\n" +
" postal_code varchar(16) DEFAULT NULL,\n" +
" phone varchar(25) DEFAULT NULL,\n" +
+ " notes varchar(4096) DEFAULT NULL,\n" +
" migrated boolean default false,\n" +
" is_notified_for_invoices boolean NOT NULL,\n" +
" created_date datetime NOT NULL,\n" +
@@ -109,7 +112,7 @@ public class DBTestingHelper extends PlatformDBTestingHelper {
"CREATE TABLE tenants (\n" +
" record_id serial unique,\n" +
" id varchar(36) NOT NULL,\n" +
- " external_key varchar(128) NULL,\n" +
+ " external_key varchar(255) NULL,\n" +
" api_key varchar(128) NULL,\n" +
" api_secret varchar(128) NULL,\n" +
" api_salt varchar(128) NULL,\n" +
@@ -125,9 +128,10 @@ public class DBTestingHelper extends PlatformDBTestingHelper {
"CREATE TABLE bundles (\n" +
" record_id serial unique,\n" +
" id varchar(36) NOT NULL,\n" +
- " external_key varchar(64) NOT NULL,\n" +
+ " external_key varchar(255) NOT NULL,\n" +
" account_id varchar(36) NOT NULL,\n" +
" last_sys_update_date datetime,\n" +
+ " original_created_date datetime NOT NULL,\n" +
" created_by varchar(50) NOT NULL,\n" +
" created_date datetime NOT NULL,\n" +
" updated_by varchar(50) NOT NULL,\n" +
@@ -144,9 +148,8 @@ public class DBTestingHelper extends PlatformDBTestingHelper {
" category varchar(32) NOT NULL,\n" +
" start_date datetime NOT NULL,\n" +
" bundle_start_date datetime NOT NULL,\n" +
- " active_version int DEFAULT 1,\n" +
" charged_through_date datetime DEFAULT NULL,\n" +
- " paid_through_date datetime DEFAULT NULL,\n" +
+ " migrated bool NOT NULL default FALSE,\n" +
" created_by varchar(50) NOT NULL,\n" +
" created_date datetime NOT NULL,\n" +
" updated_by varchar(50) NOT NULL,\n" +
@@ -162,12 +165,10 @@ public class DBTestingHelper extends PlatformDBTestingHelper {
" record_id serial unique,\n" +
" id varchar(36) NOT NULL,\n" +
" account_id varchar(36) NOT NULL,\n" +
- " invoice_id varchar(36) NOT NULL,\n" +
" payment_method_id varchar(36) NOT NULL,\n" +
- " amount numeric(15,9),\n" +
- " currency varchar(3),\n" +
- " effective_date datetime,\n" +
- " payment_status varchar(50),\n" +
+ " external_key varchar(255) NOT NULL,\n" +
+ " state_name varchar(64) DEFAULT NULL,\n" +
+ " last_success_state_name varchar(64) DEFAULT NULL,\n" +
" created_by varchar(50) NOT NULL,\n" +
" created_date datetime NOT NULL,\n" +
" updated_by varchar(50) NOT NULL,\n" +
diff --git a/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuite.java b/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuite.java
index c7ba40e..79008a6 100644
--- a/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuite.java
+++ b/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuite.java
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2016 Groupon, Inc
- * Copyright 2014-2016 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -23,6 +23,7 @@ import java.util.UUID;
import javax.inject.Inject;
+import org.killbill.billing.api.FlakyInvokedMethodListener;
import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.callcontext.MutableInternalCallContext;
import org.killbill.billing.platform.api.KillbillConfigSource;
@@ -35,13 +36,17 @@ import org.killbill.clock.ClockMock;
import org.skife.config.ConfigSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.testng.IHookCallBack;
+import org.testng.IHookable;
import org.testng.ITestResult;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Listeners;
import com.google.common.collect.ImmutableMap;
-public class GuicyKillbillTestSuite {
+@Listeners(FlakyInvokedMethodListener.class)
+public class GuicyKillbillTestSuite implements IHookable {
// Use the simple name here to save screen real estate
protected static final Logger log = LoggerFactory.getLogger(KillbillTestSuite.class.getSimpleName());
@@ -143,6 +148,24 @@ public class GuicyKillbillTestSuite {
}
}
+ // Note: assertions should not be run in before / after hooks, as the associated test result won't be correctly updated.
+ // Use this wrapper instead.
+ @Override
+ public void run(final IHookCallBack callBack, final ITestResult testResult) {
+ // Make sure we start with a clean state
+ assertListenerStatus();
+
+ // Run the actual test
+ callBack.runTestMethod(testResult);
+
+ // Make sure we finish in a clean state
+ assertListenerStatus();
+ }
+
+ protected void assertListenerStatus() {
+ // No-op
+ }
+
public boolean hasFailed() {
return hasFailed;
}
diff --git a/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuiteWithEmbeddedDB.java b/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuiteWithEmbeddedDB.java
index 565027e..757b8d4 100644
--- a/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuiteWithEmbeddedDB.java
+++ b/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuiteWithEmbeddedDB.java
@@ -24,6 +24,7 @@ import org.killbill.commons.embeddeddb.EmbeddedDB;
import org.skife.jdbi.v2.IDBI;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.testng.Assert;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.BeforeSuite;
@@ -52,11 +53,16 @@ public class GuicyKillbillTestSuiteWithEmbeddedDB extends GuicyKillbillTestSuite
@BeforeMethod(groups = "slow")
public void beforeMethod() throws Exception {
+ cleanupAllTables();
+ controlCacheDispatcher.clearAll();
+ }
+
+ protected void cleanupAllTables() {
try {
DBTestingHelper.get().getInstance().cleanupAllTables();
- } catch (final Exception ignored) {
+ } catch (final Exception e) {
+ Assert.fail("Unable to clean database", e);
}
- controlCacheDispatcher.clearAll();
}
@AfterSuite(groups = "slow")
diff --git a/util/src/test/java/org/killbill/billing/util/audit/dao/TestDefaultAuditDao.java b/util/src/test/java/org/killbill/billing/util/audit/dao/TestDefaultAuditDao.java
index 4249b18..9251e98 100644
--- a/util/src/test/java/org/killbill/billing/util/audit/dao/TestDefaultAuditDao.java
+++ b/util/src/test/java/org/killbill/billing/util/audit/dao/TestDefaultAuditDao.java
@@ -96,6 +96,7 @@ public class TestDefaultAuditDao extends UtilTestSuiteWithEmbeddedDB {
eventsListener.pushExpectedEvent(NextEvent.TAG_DEFINITION);
final TagDefinitionModelDao tagDefinition = tagDefinitionDao.create(UUID.randomUUID().toString().substring(0, 5),
UUID.randomUUID().toString().substring(0, 5),
+ ObjectType.ACCOUNT.name(),
internalCallContext);
assertListenerStatus();
diff --git a/util/src/test/java/org/killbill/billing/util/callcontext/TestInternalCallContextFactory.java b/util/src/test/java/org/killbill/billing/util/callcontext/TestInternalCallContextFactory.java
index 40e940e..c13db83 100644
--- a/util/src/test/java/org/killbill/billing/util/callcontext/TestInternalCallContextFactory.java
+++ b/util/src/test/java/org/killbill/billing/util/callcontext/TestInternalCallContextFactory.java
@@ -53,9 +53,11 @@ public class TestInternalCallContextFactory extends UtilTestSuiteWithEmbeddedDB
" id varchar(36) NOT NULL,\n" +
" account_id varchar(36) NOT NULL,\n" +
" invoice_date date NOT NULL,\n" +
- " target_date date NOT NULL,\n" +
+ " target_date date,\n" +
" currency varchar(3) NOT NULL,\n" +
+ " status varchar(15) NOT NULL DEFAULT 'COMMITTED',\n" +
" migrated bool NOT NULL,\n" +
+ " parent_invoice bool NOT NULL DEFAULT FALSE,\n" +
" created_by varchar(50) NOT NULL,\n" +
" created_date datetime NOT NULL,\n" +
" account_record_id bigint /*! unsigned */ not null,\n" +
@@ -86,8 +88,8 @@ public class TestInternalCallContextFactory extends UtilTestSuiteWithEmbeddedDB
@Override
public Void withHandle(final Handle handle) throws Exception {
// Note: we always create an accounts table, see MysqlTestingHelper
- handle.execute("insert into accounts (record_id, id, email, name, first_name_length, is_notified_for_invoices, created_date, created_by, updated_date, updated_by) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
- accountRecordId, accountId.toString(), "yo@t.com", "toto", 4, false, new Date(), "i", new Date(), "j");
+ handle.execute("insert into accounts (record_id, id, email, name, first_name_length, time_zone, is_notified_for_invoices, created_date, created_by, updated_date, updated_by) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
+ accountRecordId, accountId.toString(), "yo@t.com", "toto", 4, "UTC", false, new Date(), "i", new Date(), "j");
return null;
}
});
diff --git a/util/src/test/java/org/killbill/billing/util/customfield/api/TestDefaultCustomFieldUserApi.java b/util/src/test/java/org/killbill/billing/util/customfield/api/TestDefaultCustomFieldUserApi.java
index ffe76e3..fcddf41 100644
--- a/util/src/test/java/org/killbill/billing/util/customfield/api/TestDefaultCustomFieldUserApi.java
+++ b/util/src/test/java/org/killbill/billing/util/customfield/api/TestDefaultCustomFieldUserApi.java
@@ -53,8 +53,8 @@ public class TestDefaultCustomFieldUserApi extends UtilTestSuiteWithEmbeddedDB {
@Override
public Void withHandle(final Handle handle) throws Exception {
// Note: we always create an accounts table, see MysqlTestingHelper
- handle.execute("insert into accounts (record_id, id, email, name, first_name_length, is_notified_for_invoices, created_date, created_by, updated_date, updated_by) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
- accountRecordId, accountId.toString(), "yo@t.com", "toto", 4, false, new Date(), "i", new Date(), "j");
+ handle.execute("insert into accounts (record_id, id, email, name, first_name_length, time_zone, is_notified_for_invoices, created_date, created_by, updated_date, updated_by) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
+ accountRecordId, accountId.toString(), "yo@t.com", "toto", 4, "UTC", false, new Date(), "i", new Date(), "j");
return null;
}
diff --git a/util/src/test/java/org/killbill/billing/util/dao/TestNonEntityDao.java b/util/src/test/java/org/killbill/billing/util/dao/TestNonEntityDao.java
index 8b9c231..2319573 100644
--- a/util/src/test/java/org/killbill/billing/util/dao/TestNonEntityDao.java
+++ b/util/src/test/java/org/killbill/billing/util/dao/TestNonEntityDao.java
@@ -96,8 +96,8 @@ public class TestNonEntityDao extends UtilTestSuiteWithEmbeddedDB {
@Override
public Void withHandle(final Handle handle) throws Exception {
// Note: we always create an accounts table, see MysqlTestingHelper
- handle.execute("insert into accounts (record_id, id, email, name, first_name_length, is_notified_for_invoices, created_date, created_by, updated_date, updated_by, tenant_record_id) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
- accountRecordId, accountId.toString(), "zozo@tt.com", "zozo", 4, false, new Date(), "i", new Date(), "j", tenantRecordId);
+ handle.execute("insert into accounts (record_id, id, email, name, first_name_length, time_zone, is_notified_for_invoices, created_date, created_by, updated_date, updated_by, tenant_record_id) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
+ accountRecordId, accountId.toString(), "zozo@tt.com", "zozo", 4, "UTC", false, new Date(), "i", new Date(), "j", tenantRecordId);
return null;
}
});
@@ -108,8 +108,8 @@ public class TestNonEntityDao extends UtilTestSuiteWithEmbeddedDB {
@Override
public Void withHandle(final Handle handle) throws Exception {
// Note: we always create an accounts table, see MysqlTestingHelper
- handle.execute("insert into account_history (record_id, id, email, name, first_name_length, is_notified_for_invoices, created_date, created_by, updated_date, updated_by, tenant_record_id) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
- accountRecordId, accountId.toString(), "zozo@tt.com", "zozo", 4, false, new Date(), "i", new Date(), "j", tenantRecordId);
+ handle.execute("insert into account_history (record_id, id, email, name, first_name_length, time_zone, is_notified_for_invoices, created_date, created_by, updated_date, updated_by, tenant_record_id) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
+ accountRecordId, accountId.toString(), "zozo@tt.com", "zozo", 4, "UTC", false, new Date(), "i", new Date(), "j", tenantRecordId);
return null;
}
});
diff --git a/util/src/test/java/org/killbill/billing/util/dao/TestPagination.java b/util/src/test/java/org/killbill/billing/util/dao/TestPagination.java
index 107585e..72dcfc7 100644
--- a/util/src/test/java/org/killbill/billing/util/dao/TestPagination.java
+++ b/util/src/test/java/org/killbill/billing/util/dao/TestPagination.java
@@ -18,6 +18,7 @@ package org.killbill.billing.util.dao;
import java.util.List;
+import org.killbill.billing.ObjectType;
import org.testng.Assert;
import org.testng.annotations.Test;
@@ -38,7 +39,7 @@ public class TestPagination extends UtilTestSuiteWithEmbeddedDB {
final String definitionName = "name-" + i;
final String description = "description-" + i;
eventsListener.pushExpectedEvent(NextEvent.TAG_DEFINITION);
- tagDefinitionDao.create(definitionName, description, internalCallContext);
+ tagDefinitionDao.create(definitionName, description, ObjectType.ACCOUNT.name(), internalCallContext);
assertListenerStatus();
}
diff --git a/util/src/test/java/org/killbill/billing/util/export/dao/TestDatabaseExportDao.java b/util/src/test/java/org/killbill/billing/util/export/dao/TestDatabaseExportDao.java
index 01fe087..8c26cbe 100644
--- a/util/src/test/java/org/killbill/billing/util/export/dao/TestDatabaseExportDao.java
+++ b/util/src/test/java/org/killbill/billing/util/export/dao/TestDatabaseExportDao.java
@@ -46,6 +46,7 @@ public class TestDatabaseExportDao extends UtilTestSuiteWithEmbeddedDB {
final String accountEmail = UUID.randomUUID().toString().substring(0, 4) + '@' + UUID.randomUUID().toString().substring(0, 4);
final String accountName = UUID.randomUUID().toString().substring(0, 4);
final int firstNameLength = 4;
+ final String timeZone = "UTC";
final boolean isNotifiedForInvoices = false;
final Date createdDate = new Date(12421982000L);
final String createdBy = UUID.randomUUID().toString().substring(0, 4);
@@ -77,17 +78,17 @@ public class TestDatabaseExportDao extends UtilTestSuiteWithEmbeddedDB {
internalCallContext.getAccountRecordId(), internalCallContext.getTenantRecordId());
// Add row in accounts table
- handle.execute("insert into accounts (record_id, id, email, name, first_name_length, is_notified_for_invoices, created_date, created_by, updated_date, updated_by, tenant_record_id) " +
- "values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
- internalCallContext.getAccountRecordId(), accountId, accountEmail, accountName, firstNameLength, isNotifiedForInvoices, createdDate, createdBy, updatedDate, updatedBy, internalCallContext.getTenantRecordId());
+ handle.execute("insert into accounts (record_id, id, email, name, first_name_length, time_zone, is_notified_for_invoices, created_date, created_by, updated_date, updated_by, tenant_record_id) " +
+ "values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
+ internalCallContext.getAccountRecordId(), accountId, accountEmail, accountName, firstNameLength, timeZone, isNotifiedForInvoices, createdDate, createdBy, updatedDate, updatedBy, internalCallContext.getTenantRecordId());
return null;
}
});
// Verify new dump
final String newDump = getDump();
- Assert.assertEquals(newDump, "-- accounts record_id|id|external_key|email|name|first_name_length|currency|billing_cycle_day_local|payment_method_id|time_zone|locale|address1|address2|company_name|city|state_or_province|country|postal_code|phone|migrated|is_notified_for_invoices|created_date|created_by|updated_date|updated_by|tenant_record_id\n" +
- String.format("%s|%s||%s|%s|%s||||||||||||||false|%s|%s|%s|%s|%s|%s", internalCallContext.getAccountRecordId(), accountId, accountEmail, accountName, firstNameLength,
+ Assert.assertEquals(newDump, "-- accounts record_id|id|external_key|email|name|first_name_length|currency|billing_cycle_day_local|parent_account_id|is_payment_delegated_to_parent|payment_method_id|time_zone|locale|address1|address2|company_name|city|state_or_province|country|postal_code|phone|notes|migrated|is_notified_for_invoices|created_date|created_by|updated_date|updated_by|tenant_record_id\n" +
+ String.format("%s|%s||%s|%s|%s||||false||%s|||||||||||false|%s|%s|%s|%s|%s|%s", internalCallContext.getAccountRecordId(), accountId, accountEmail, accountName, firstNameLength, timeZone,
isNotifiedForInvoices, "1970-05-24T18:33:02.000+0000", createdBy, "1982-02-18T20:03:42.000+0000", updatedBy, internalCallContext.getTenantRecordId()) + "\n" +
"-- " + tableNameA + " record_id|a_column|blob_column|account_record_id|tenant_record_id\n" +
"1|a|WlYAAARjYWZl|" + internalCallContext.getAccountRecordId() + "|" + internalCallContext.getTenantRecordId() + "\n" +
diff --git a/util/src/test/java/org/killbill/billing/util/security/shiro/realm/TestKillBillJdbcRealm.java b/util/src/test/java/org/killbill/billing/util/security/shiro/realm/TestKillBillJdbcRealm.java
index 30f90af..5e89611 100644
--- a/util/src/test/java/org/killbill/billing/util/security/shiro/realm/TestKillBillJdbcRealm.java
+++ b/util/src/test/java/org/killbill/billing/util/security/shiro/realm/TestKillBillJdbcRealm.java
@@ -178,6 +178,33 @@ public class TestKillBillJdbcRealm extends UtilTestSuiteWithEmbeddedDB {
Assert.fail("Subject should not have rights to create tag definitions");
} catch (AuthorizationException e) {
}
+ }
+
+ @Test(groups = "slow")
+ public void testUpdateRoleDefinition() throws SecurityApiException {
+
+ final String username = "siskiyou";
+ final String password = "siskiyou33";
+
+ securityApi.addRoleDefinition("original", ImmutableList.of("account:*", "invoice", "tag:create_tag_definition"), callContext);
+ securityApi.addUserRoles(username, password, ImmutableList.of("restricted"), callContext);
+
+ final AuthenticationToken goodToken = new UsernamePasswordToken(username, password);
+
+ final List<String> roleDefinition = securityApi.getRoleDefinition("original", callContext);
+ Assert.assertEquals(roleDefinition.size(), 3);
+ Assert.assertTrue(roleDefinition.contains("account:*"));
+ Assert.assertTrue(roleDefinition.contains("invoice:*"));
+ Assert.assertTrue(roleDefinition.contains("tag:create_tag_definition"));
+
+ securityApi.updateRoleDefinition("original", ImmutableList.of("account:*", "payment", "tag:create_tag_definition", "entitlement:create"), callContext);
+
+ final List<String> updatedRoleDefinition = securityApi.getRoleDefinition("original", callContext);
+ Assert.assertEquals(updatedRoleDefinition.size(), 4);
+ Assert.assertTrue(updatedRoleDefinition.contains("account:*"));
+ Assert.assertTrue(updatedRoleDefinition.contains("payment:*"));
+ Assert.assertTrue(updatedRoleDefinition.contains("tag:create_tag_definition"));
+ Assert.assertTrue(updatedRoleDefinition.contains("entitlement:create"));
}
diff --git a/util/src/test/java/org/killbill/billing/util/tag/api/TestDefaultTagUserApi.java b/util/src/test/java/org/killbill/billing/util/tag/api/TestDefaultTagUserApi.java
index bbdfb0f..290a472 100644
--- a/util/src/test/java/org/killbill/billing/util/tag/api/TestDefaultTagUserApi.java
+++ b/util/src/test/java/org/killbill/billing/util/tag/api/TestDefaultTagUserApi.java
@@ -52,8 +52,8 @@ public class TestDefaultTagUserApi extends UtilTestSuiteWithEmbeddedDB {
@Override
public Void withHandle(final Handle handle) throws Exception {
// Note: we always create an accounts table, see MysqlTestingHelper
- handle.execute("insert into accounts (record_id, id, email, name, first_name_length, is_notified_for_invoices, created_date, created_by, updated_date, updated_by) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
- accountRecordId, accountId.toString(), "yo@t.com", "toto", 4, false, new Date(), "i", new Date(), "j");
+ handle.execute("insert into accounts (record_id, id, email, name, first_name_length, time_zone, is_notified_for_invoices, created_date, created_by, updated_date, updated_by) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
+ accountRecordId, accountId.toString(), "yo@t.com", "toto", 4, "UTC", false, new Date(), "i", new Date(), "j");
return null;
}
diff --git a/util/src/test/java/org/killbill/billing/util/tag/api/TestDefaultTagUserApiWithMockDao.java b/util/src/test/java/org/killbill/billing/util/tag/api/TestDefaultTagUserApiWithMockDao.java
index fd7b6a1..7dba212 100644
--- a/util/src/test/java/org/killbill/billing/util/tag/api/TestDefaultTagUserApiWithMockDao.java
+++ b/util/src/test/java/org/killbill/billing/util/tag/api/TestDefaultTagUserApiWithMockDao.java
@@ -17,6 +17,7 @@
package org.killbill.billing.util.tag.api;
+import org.killbill.billing.ObjectType;
import org.killbill.billing.callcontext.DefaultCallContext;
import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.util.UtilTestSuiteNoDB;
@@ -31,6 +32,8 @@ import org.mockito.Mockito;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
+import com.google.common.collect.ImmutableSet;
+
import static org.testng.Assert.assertEquals;
public class TestDefaultTagUserApiWithMockDao extends UtilTestSuiteNoDB {
@@ -50,17 +53,17 @@ public class TestDefaultTagUserApiWithMockDao extends UtilTestSuiteNoDB {
@Test(groups = "fast", expectedExceptions = TagDefinitionApiException.class, expectedExceptionsMessageRegExp = "The tag definition name must be in lowercase .*")
public void testCreateTagDefinitionWithMiddleUpperCase() throws Exception {
- tagUserApi.createTagDefinition("inVaLid", "description", context);
+ tagUserApi.createTagDefinition("inVaLid", "description", ImmutableSet.<ObjectType>of(ObjectType.ACCOUNT), context);
}
@Test(groups = "fast", expectedExceptions = TagDefinitionApiException.class, expectedExceptionsMessageRegExp = "The tag definition name must be in lowercase .*")
public void testCreateTagDefinitionWithFrontUpperCase() throws Exception {
- tagUserApi.createTagDefinition("Invalid", "description", context);
+ tagUserApi.createTagDefinition("Invalid", "description", ImmutableSet.<ObjectType>of(ObjectType.ACCOUNT), context);
}
@Test(groups = "fast", expectedExceptions = TagDefinitionApiException.class, expectedExceptionsMessageRegExp = "The tag definition name must be in lowercase .*")
public void testCreateTagDefinitionWithBackUpperCase() throws Exception {
- tagUserApi.createTagDefinition("invaliD", "description", context);
+ tagUserApi.createTagDefinition("invaliD", "description", ImmutableSet.<ObjectType>of(ObjectType.ACCOUNT), context);
}
@Test(groups = "fast")
@@ -68,8 +71,9 @@ public class TestDefaultTagUserApiWithMockDao extends UtilTestSuiteNoDB {
final String tagDefinitionName = "lowercase";
final TagDefinitionModelDao tagDefinitionModelDao = new TagDefinitionModelDao();
tagDefinitionModelDao.setName(tagDefinitionName);
- Mockito.when(tagDefinitionDao.create(Mockito.anyString(), Mockito.anyString(), Mockito.any(InternalCallContext.class))).thenReturn(tagDefinitionModelDao);
- final TagDefinition tagDefinition = tagUserApi.createTagDefinition(tagDefinitionName, "description", context);
+ tagDefinitionModelDao.setApplicableObjectTypes(ObjectType.ACCOUNT.name());
+ Mockito.when(tagDefinitionDao.create(Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.any(InternalCallContext.class))).thenReturn(tagDefinitionModelDao);
+ final TagDefinition tagDefinition = tagUserApi.createTagDefinition(tagDefinitionName, "description", ImmutableSet.<ObjectType>of(ObjectType.ACCOUNT), context);
assertEquals(tagDefinitionName, tagDefinition.getName());
}
}
diff --git a/util/src/test/java/org/killbill/billing/util/tag/dao/MockTagDefinitionDao.java b/util/src/test/java/org/killbill/billing/util/tag/dao/MockTagDefinitionDao.java
index f382b4f..8ae3ab6 100644
--- a/util/src/test/java/org/killbill/billing/util/tag/dao/MockTagDefinitionDao.java
+++ b/util/src/test/java/org/killbill/billing/util/tag/dao/MockTagDefinitionDao.java
@@ -29,6 +29,8 @@ import org.killbill.billing.util.api.TagDefinitionApiException;
import org.killbill.billing.util.entity.dao.MockEntityDaoBase;
import org.killbill.billing.util.tag.TagDefinition;
+import com.google.common.collect.ImmutableList;
+
public class MockTagDefinitionDao extends MockEntityDaoBase<TagDefinitionModelDao, TagDefinition, TagDefinitionApiException> implements TagDefinitionDao {
private final Map<String, TagDefinitionModelDao> tags = new ConcurrentHashMap<String, TagDefinitionModelDao>();
@@ -44,9 +46,9 @@ public class MockTagDefinitionDao extends MockEntityDaoBase<TagDefinitionModelDa
}
@Override
- public TagDefinitionModelDao create(final String definitionName, final String description,
+ public TagDefinitionModelDao create(final String definitionName, final String description, final String tagDefinitionObjectTypes,
final InternalCallContext context) throws TagDefinitionApiException {
- final TagDefinitionModelDao tag = new TagDefinitionModelDao(null, definitionName, description);
+ final TagDefinitionModelDao tag = new TagDefinitionModelDao(null, definitionName, description, tagDefinitionObjectTypes);
tags.put(tag.getId().toString(), tag);
return tag;
diff --git a/util/src/test/java/org/killbill/billing/util/tag/dao/TestDefaultTagDao.java b/util/src/test/java/org/killbill/billing/util/tag/dao/TestDefaultTagDao.java
index d648fcd..e3f019c 100644
--- a/util/src/test/java/org/killbill/billing/util/tag/dao/TestDefaultTagDao.java
+++ b/util/src/test/java/org/killbill/billing/util/tag/dao/TestDefaultTagDao.java
@@ -46,17 +46,17 @@ public class TestDefaultTagDao extends UtilTestSuiteWithEmbeddedDB {
assertEquals(result.size(), 0);
eventsListener.pushExpectedEvent(NextEvent.TAG_DEFINITION);
- final TagDefinitionModelDao defYo = tagDefinitionDao.create(UUID.randomUUID().toString().substring(0, 5), "defintion yo", internalCallContext);
+ final TagDefinitionModelDao defYo = tagDefinitionDao.create(UUID.randomUUID().toString().substring(0, 5), "defintion yo", ObjectType.ACCOUNT.name(), internalCallContext);
assertListenerStatus();
uuids.add(defYo.getId());
eventsListener.pushExpectedEvent(NextEvent.TAG_DEFINITION);
- final TagDefinitionModelDao defBah = tagDefinitionDao.create(UUID.randomUUID().toString().substring(0, 5), "defintion bah", internalCallContext);
+ final TagDefinitionModelDao defBah = tagDefinitionDao.create(UUID.randomUUID().toString().substring(0, 5), "defintion bah", ObjectType.ACCOUNT.name(), internalCallContext);
assertListenerStatus();
uuids.add(defBah.getId());
eventsListener.pushExpectedEvent(NextEvent.TAG_DEFINITION);
- final TagDefinitionModelDao defZoo = tagDefinitionDao.create(UUID.randomUUID().toString().substring(0, 5), "defintion zoo", internalCallContext);
+ final TagDefinitionModelDao defZoo = tagDefinitionDao.create(UUID.randomUUID().toString().substring(0, 5), "defintion zoo", ObjectType.ACCOUNT.name(), internalCallContext);
assertListenerStatus();
uuids.add(defZoo.getId());
@@ -76,7 +76,7 @@ public class TestDefaultTagDao extends UtilTestSuiteWithEmbeddedDB {
public void testGetById() throws TagDefinitionApiException {
// User Tag
eventsListener.pushExpectedEvent(NextEvent.TAG_DEFINITION);
- final TagDefinitionModelDao defYo = tagDefinitionDao.create(UUID.randomUUID().toString().substring(0, 5), "defintion yo", internalCallContext);
+ final TagDefinitionModelDao defYo = tagDefinitionDao.create(UUID.randomUUID().toString().substring(0, 5), "defintion yo", ObjectType.ACCOUNT.name(),internalCallContext);
assertListenerStatus();
final TagDefinitionModelDao resDefYo = tagDefinitionDao.getById(defYo.getId(), internalCallContext);
@@ -84,7 +84,7 @@ public class TestDefaultTagDao extends UtilTestSuiteWithEmbeddedDB {
// Control Tag
try {
- tagDefinitionDao.create(ControlTagType.AUTO_INVOICING_OFF.name(), ControlTagType.AUTO_INVOICING_OFF.name(), internalCallContext);
+ tagDefinitionDao.create(ControlTagType.AUTO_INVOICING_OFF.name(), ControlTagType.AUTO_INVOICING_OFF.name(), ObjectType.ACCOUNT.name(),internalCallContext);
Assert.fail("Should not be able to create a invoice tag");
} catch (TagDefinitionApiException ignore) {
}
@@ -98,7 +98,7 @@ public class TestDefaultTagDao extends UtilTestSuiteWithEmbeddedDB {
public void testGetByName() throws TagDefinitionApiException {
// User Tag
eventsListener.pushExpectedEvent(NextEvent.TAG_DEFINITION);
- final TagDefinitionModelDao defYo = tagDefinitionDao.create(UUID.randomUUID().toString().substring(0, 5), "defintion yo", internalCallContext);
+ final TagDefinitionModelDao defYo = tagDefinitionDao.create(UUID.randomUUID().toString().substring(0, 5), "defintion yo", ObjectType.ACCOUNT.name(),internalCallContext);
assertListenerStatus();
final TagDefinitionModelDao resDefYo = tagDefinitionDao.getByName(defYo.getName(), internalCallContext);
@@ -106,7 +106,7 @@ public class TestDefaultTagDao extends UtilTestSuiteWithEmbeddedDB {
// Control Tag
try {
- tagDefinitionDao.create(ControlTagType.AUTO_PAY_OFF.name(), ControlTagType.AUTO_INVOICING_OFF.name(), internalCallContext);
+ tagDefinitionDao.create(ControlTagType.AUTO_PAY_OFF.name(), ControlTagType.AUTO_INVOICING_OFF.name(), ObjectType.ACCOUNT.name(), internalCallContext);
Assert.fail("Should not be able to create a invoice tag");
} catch (TagDefinitionApiException ignore) {
}
@@ -125,7 +125,7 @@ public class TestDefaultTagDao extends UtilTestSuiteWithEmbeddedDB {
// Create a tag definition
eventsListener.pushExpectedEvent(NextEvent.TAG_DEFINITION);
- final TagDefinitionModelDao createdTagDefinition = tagDefinitionDao.create(definitionName, description, internalCallContext);
+ final TagDefinitionModelDao createdTagDefinition = tagDefinitionDao.create(definitionName, description, ObjectType.ACCOUNT.name(), internalCallContext);
Assert.assertEquals(createdTagDefinition.getName(), definitionName);
Assert.assertEquals(createdTagDefinition.getDescription(), description);
assertListenerStatus();
diff --git a/util/src/test/java/org/killbill/billing/util/tag/dao/TestDefaultTagDefinitionDao.java b/util/src/test/java/org/killbill/billing/util/tag/dao/TestDefaultTagDefinitionDao.java
index a24ba3e..1e5d3cf 100644
--- a/util/src/test/java/org/killbill/billing/util/tag/dao/TestDefaultTagDefinitionDao.java
+++ b/util/src/test/java/org/killbill/billing/util/tag/dao/TestDefaultTagDefinitionDao.java
@@ -16,10 +16,12 @@
package org.killbill.billing.util.tag.dao;
+import java.io.ObjectOutput;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
+import org.killbill.billing.ObjectType;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
@@ -42,9 +44,10 @@ public class TestDefaultTagDefinitionDao extends UtilTestSuiteWithEmbeddedDB {
// Make sure we can create a tag definition
eventsListener.pushExpectedEvent(NextEvent.TAG_DEFINITION);
- final TagDefinitionModelDao createdTagDefinition = tagDefinitionDao.create(definitionName, description, internalCallContext);
+ final TagDefinitionModelDao createdTagDefinition = tagDefinitionDao.create(definitionName, description, ObjectType.ACCOUNT.name(), internalCallContext);
Assert.assertEquals(createdTagDefinition.getName(), definitionName);
Assert.assertEquals(createdTagDefinition.getDescription(), description);
+ Assert.assertEquals(createdTagDefinition.getApplicableObjectTypes(), ObjectType.ACCOUNT.name());
assertListenerStatus();
// Make sure we can retrieve it via the DAO
diff --git a/util/src/test/java/org/killbill/billing/util/tag/TestTagStore.java b/util/src/test/java/org/killbill/billing/util/tag/TestTagStore.java
index 8de750a..d9bd318 100644
--- a/util/src/test/java/org/killbill/billing/util/tag/TestTagStore.java
+++ b/util/src/test/java/org/killbill/billing/util/tag/TestTagStore.java
@@ -41,11 +41,11 @@ public class TestTagStore extends UtilTestSuiteWithEmbeddedDB {
final UUID accountId = UUID.randomUUID();
eventsListener.pushExpectedEvent(NextEvent.TAG_DEFINITION);
- tagDefinitionDao.create("tag1", "First tag", internalCallContext);
+ tagDefinitionDao.create("tag1", "First tag", ObjectType.ACCOUNT.name(), internalCallContext);
assertListenerStatus();
eventsListener.pushExpectedEvent(NextEvent.TAG_DEFINITION);
- final TagDefinitionModelDao testTagDefinition = tagDefinitionDao.create("testTagDefinition", "Second tag", internalCallContext);
+ final TagDefinitionModelDao testTagDefinition = tagDefinitionDao.create("testTagDefinition", "Second tag", ObjectType.ACCOUNT.name(), internalCallContext);
assertListenerStatus();
final Tag tag = new DescriptiveTag(testTagDefinition.getId(), ObjectType.ACCOUNT, accountId, clock.getUTCNow());
@@ -76,14 +76,14 @@ public class TestTagStore extends UtilTestSuiteWithEmbeddedDB {
@Test(groups = "slow", expectedExceptions = TagDefinitionApiException.class)
public void testTagDefinitionCreationWithControlTagName() throws TagDefinitionApiException {
final String definitionName = ControlTagType.AUTO_PAY_OFF.toString();
- tagDefinitionDao.create(definitionName, "This should break", internalCallContext);
+ tagDefinitionDao.create(definitionName, "This should break", ObjectType.ACCOUNT.name(), internalCallContext);
}
@Test(groups = "slow")
public void testTagDefinitionDeletionForUnusedDefinition() throws TagDefinitionApiException {
final String definitionName = "TestTag1234";
eventsListener.pushExpectedEvent(NextEvent.TAG_DEFINITION);
- tagDefinitionDao.create(definitionName, "Some test tag", internalCallContext);
+ tagDefinitionDao.create(definitionName, "Some test tag", ObjectType.ACCOUNT.name(), internalCallContext);
assertListenerStatus();
TagDefinitionModelDao tagDefinition = tagDefinitionDao.getByName(definitionName, internalCallContext);
@@ -101,7 +101,7 @@ public class TestTagStore extends UtilTestSuiteWithEmbeddedDB {
public void testTagDefinitionDeletionForDefinitionInUse() throws TagDefinitionApiException, TagApiException {
final String definitionName = "TestTag12345";
eventsListener.pushExpectedEvent(NextEvent.TAG_DEFINITION);
- tagDefinitionDao.create(definitionName, "Some test tag", internalCallContext);
+ tagDefinitionDao.create(definitionName, "Some test tag", ObjectType.ACCOUNT.name(), internalCallContext);
assertListenerStatus();
final TagDefinitionModelDao tagDefinition = tagDefinitionDao.getByName(definitionName, internalCallContext);
@@ -120,7 +120,7 @@ public class TestTagStore extends UtilTestSuiteWithEmbeddedDB {
public void testDeleteTagBeforeDeleteTagDefinition() throws TagDefinitionApiException, TagApiException {
final String definitionName = "TestTag1234567";
eventsListener.pushExpectedEvent(NextEvent.TAG_DEFINITION);
- tagDefinitionDao.create(definitionName, "Some test tag", internalCallContext);
+ tagDefinitionDao.create(definitionName, "Some test tag", ObjectType.ACCOUNT.name(), internalCallContext);
assertListenerStatus();
final TagDefinitionModelDao tagDefinition = tagDefinitionDao.getByName(definitionName, internalCallContext);
diff --git a/util/src/test/java/org/killbill/billing/util/UtilTestSuiteWithEmbeddedDB.java b/util/src/test/java/org/killbill/billing/util/UtilTestSuiteWithEmbeddedDB.java
index 503a229..0569958 100644
--- a/util/src/test/java/org/killbill/billing/util/UtilTestSuiteWithEmbeddedDB.java
+++ b/util/src/test/java/org/killbill/billing/util/UtilTestSuiteWithEmbeddedDB.java
@@ -123,20 +123,15 @@ public abstract class UtilTestSuiteWithEmbeddedDB extends GuicyKillbillTestSuite
eventBus.start();
eventBus.register(eventsListener);
-
- // Make sure we start with a clean state
- assertListenerStatus();
}
@AfterMethod(groups = "slow")
public void afterMethod() throws Exception {
- // Make sure we finish in a clean state
- assertListenerStatus();
-
eventBus.unregister(eventsListener);
eventBus.stop();
}
+ @Override
protected void assertListenerStatus() {
eventsListener.assertListenerStatus();
}