Skip to content

Commit

Permalink
Merge pull request #280 from ostelco/develop
Browse files Browse the repository at this point in the history
Merge of develop to master
  • Loading branch information
Kjell M. Myksvoll authored Sep 13, 2018
2 parents 314e8a5 + c5723d1 commit 63df277
Show file tree
Hide file tree
Showing 119 changed files with 5,299 additions and 786 deletions.
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ Mono Repository for core protocols and services around a OCS/BSS for packet data
* [diameter-stack](./diameter-stack/README.md)
* [diameter-test](./diameter-test/README.md)
* [exporter](./exporter/README.md)
* [ext-pgw](./ext-pgw/README.md)
* [ocs-api](./ocs-api/README.md)
* [ocsgw](./ocsgw/README.md)
* [ostelco-lib](./ostelco-lib/README.md)
Expand Down
1 change: 1 addition & 0 deletions acceptance-tests/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ RUN apt-get update \
&& apt-get install -y --no-install-recommends netcat \
&& rm -rf /var/lib/apt/lists/*

COPY config/ /secret/
COPY src/main/resources/ /
COPY script/wait.sh /wait.sh
COPY build/libs/acceptance-tests-uber.jar /acceptance-tests.jar
Expand Down
4 changes: 3 additions & 1 deletion acceptance-tests/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ dependencies {
implementation project(":prime-client-api")
implementation project(':diameter-test')

implementation "com.stripe:stripe-java:6.8.0"
implementation 'com.google.firebase:firebase-admin:6.4.0'

implementation "com.stripe:stripe-java:$stripeVersion"
implementation 'io.jsonwebtoken:jjwt:0.9.1'
// tests fail when updated to 2.27
implementation "org.glassfish.jersey.media:jersey-media-json-jackson:2.25.1"
Expand Down
1 change: 1 addition & 0 deletions acceptance-tests/config/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pantel-prod.json
2 changes: 2 additions & 0 deletions acceptance-tests/script/wait.sh
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,14 @@ java -cp '/acceptance-tests.jar' org.junit.runner.JUnitCore \
org.ostelco.at.okhttp.GetPseudonymsTest \
org.ostelco.at.okhttp.GetProductsTest \
org.ostelco.at.okhttp.GetSubscriptionStatusTest \
org.ostelco.at.okhttp.SourceTest \
org.ostelco.at.okhttp.PurchaseTest \
org.ostelco.at.okhttp.ConsentTest \
org.ostelco.at.okhttp.ProfileTest \
org.ostelco.at.jersey.GetPseudonymsTest \
org.ostelco.at.jersey.GetProductsTest \
org.ostelco.at.jersey.GetSubscriptionStatusTest \
org.ostelco.at.jersey.SourceTest \
org.ostelco.at.jersey.PurchaseTest \
org.ostelco.at.jersey.AnalyticsTest \
org.ostelco.at.jersey.ConsentTest \
Expand Down
41 changes: 41 additions & 0 deletions acceptance-tests/src/main/kotlin/org/ostelco/at/common/Firebase.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package org.ostelco.at.common

import com.google.auth.oauth2.GoogleCredentials
import com.google.firebase.FirebaseApp
import com.google.firebase.FirebaseOptions
import com.google.firebase.database.FirebaseDatabase
import java.io.FileInputStream
import java.nio.file.Files
import java.nio.file.Paths

object Firebase {

private fun setupFirebaseInstance(): FirebaseDatabase {

try {
FirebaseApp.getInstance()
} catch (e: Exception) {
val databaseName = "pantel-2decb"
val configFile = System.getenv("GOOGLE_APPLICATION_CREDENTIALS") ?: "config/pantel-prod.json"

val credentials: GoogleCredentials = if (Files.exists(Paths.get(configFile))) {
FileInputStream(configFile).use { serviceAccount -> GoogleCredentials.fromStream(serviceAccount) }
} else {
throw Exception()
}

val options = FirebaseOptions.Builder()
.setCredentials(credentials)
.setDatabaseUrl("https://$databaseName.firebaseio.com/")
.build()

FirebaseApp.initializeApp(options)
}

return FirebaseDatabase.getInstance()
}

fun deleteAllPaymentCustomers() {
setupFirebaseInstance().getReference("test/paymentId").removeValueAsync().get()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ package org.ostelco.at.common

import com.stripe.Stripe
import com.stripe.model.Customer
import com.stripe.model.Source
import com.stripe.model.Token

object StripePayment {
fun createPaymentSourceId(): String {

fun createPaymentTokenId(): String {

// https://stripe.com/docs/api/java#create_card_token
Stripe.apiKey = System.getenv("STRIPE_API_KEY")
Expand All @@ -21,6 +23,53 @@ object StripePayment {
return token.id
}

fun createPaymentSourceId(): String {

// https://stripe.com/docs/api/java#create_source
Stripe.apiKey = System.getenv("STRIPE_API_KEY")

// TODO martin: set valid map values
val sourceMap = mapOf<String,Any>()
val source = Source.create(sourceMap)
return source.id
}

fun getCardIdForTokenId(tokenId: String) : String {

// https://stripe.com/docs/api/java#create_source
Stripe.apiKey = System.getenv("STRIPE_API_KEY")

val token = Token.retrieve(tokenId)
return token.card.id
}

/**
* Obtains 'default source' directly from Stripe. Use in tests to
* verify that the correspondng 'setDefaultSource' API works as
* intended.
*/
fun getDefaultSourceForCustomer(customerId: String) : String {

// https://stripe.com/docs/api/java#create_source
Stripe.apiKey = System.getenv("STRIPE_API_KEY")

val customer = Customer.retrieve(customerId)
return customer.defaultSource
}

/**
* Obtains the Stripe 'customerId' directly from Stripe.
*/
fun getCustomerIdForEmail(email: String) : String {

// https://stripe.com/docs/api/java#create_card_token
Stripe.apiKey = System.getenv("STRIPE_API_KEY")

val customers = Customer.list(emptyMap()).data

return customers.filter { it.email.equals(email) }.first().id
}

fun deleteAllCustomers() {
// https://stripe.com/docs/api/java#create_card_token
Stripe.apiKey = System.getenv("STRIPE_API_KEY")
Expand Down
188 changes: 186 additions & 2 deletions acceptance-tests/src/main/kotlin/org/ostelco/at/jersey/Tests.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.ostelco.at.jersey

import org.junit.Test
import org.ostelco.at.common.Firebase
import org.ostelco.at.common.StripePayment
import org.ostelco.at.common.createProfile
import org.ostelco.at.common.createSubscription
Expand All @@ -10,6 +11,8 @@ import org.ostelco.at.common.randomInt
import org.ostelco.prime.client.model.ActivePseudonyms
import org.ostelco.prime.client.model.ApplicationToken
import org.ostelco.prime.client.model.Consent
import org.ostelco.prime.client.model.PaymentSource
import org.ostelco.prime.client.model.PaymentSourceList
import org.ostelco.prime.client.model.Person
import org.ostelco.prime.client.model.Price
import org.ostelco.prime.client.model.Product
Expand Down Expand Up @@ -223,12 +226,140 @@ class GetProductsTest {
}
}

class SourceTest {

@Test
fun `jersey test - POST source create`() {

StripePayment.deleteAllCustomers()
Firebase.deleteAllPaymentCustomers()

val email = "purchase-${randomInt()}@test.com"
createProfile(name = "Test Payment Source", email = email)

val tokenId = StripePayment.createPaymentTokenId()

// Ties source with user profile both local and with Stripe
post<PaymentSource> {
path = "/paymentSources"
subscriberId = email
queryParams = mapOf("sourceId" to tokenId)
}

Thread.sleep(200)

val sources: PaymentSourceList = get {
path = "/paymentSources"
subscriberId = email
}
assert(sources.isNotEmpty()) { "Expected at least one payment source for profile $email" }

val cardId = StripePayment.getCardIdForTokenId(tokenId)
assertNotNull(sources.first { it.id == cardId }, "Expected card $cardId in list of payment sources for profile $email")
}

@Test
fun `okhttp test - GET list sources`() {

StripePayment.deleteAllCustomers()
Firebase.deleteAllPaymentCustomers()

val email = "purchase-${randomInt()}@test.com"
createProfile(name = "Test Payment Source", email = email)

val tokenId = StripePayment.createPaymentTokenId()
val cardId = StripePayment.getCardIdForTokenId(tokenId)

// Ties source with user profile both local and with Stripe
post<PaymentSource> {
path = "/paymentSources"
subscriberId = email
queryParams = mapOf("sourceId" to tokenId)
}

Thread.sleep(200)

val newTokenId = StripePayment.createPaymentTokenId()
val newCardId = StripePayment.getCardIdForTokenId(newTokenId)

post<PaymentSource> {
path = "/paymentSources"
subscriberId = email
queryParams = mapOf("sourceId" to newTokenId)
}

val sources : PaymentSourceList = get {
path = "/paymentSources"
subscriberId = email
}

assert(sources.isNotEmpty()) { "Expected at least one payment source for profile $email" }
assert(sources.map{ it.id }.containsAll(listOf(cardId, newCardId)))
{ "Expected to find both $cardId and $newCardId in list of sources for profile $email" }

sources.forEach {
assert(it.details.id.isNotEmpty()) { "Expected 'id' to be set in source account details for profile $email" }
assertEquals("card", it.details.accountType,
"Unexpected source account type ${it.details.accountType} for profile $email")
}
}

@Test
fun `jersey test - PUT source set default`() {

StripePayment.deleteAllCustomers()
Firebase.deleteAllPaymentCustomers()

val email = "purchase-${randomInt()}@test.com"
createProfile(name = "Test Payment Source", email = email)

val tokenId = StripePayment.createPaymentTokenId()
val cardId = StripePayment.getCardIdForTokenId(tokenId)

// Ties source with user profile both local and with Stripe
post<PaymentSource> {
path = "/paymentSources"
subscriberId = email
queryParams = mapOf("sourceId" to tokenId)
}

Thread.sleep(200)

val newTokenId = StripePayment.createPaymentTokenId()
val newCardId = StripePayment.getCardIdForTokenId(newTokenId)

post<PaymentSource> {
path = "/paymentSources"
subscriberId = email
queryParams = mapOf("sourceId" to newTokenId)
}

// TODO: Update to fetch the Stripe customerId from 'admin' API when ready.
val customerId = StripePayment.getCustomerIdForEmail(email)

// Verify that original 'sourceId/card' is default.
assertEquals(cardId, StripePayment.getDefaultSourceForCustomer(customerId),
"Expected $cardId to be default source for $customerId")

// Set new default card.
put<PaymentSource> {
path = "/paymentSources"
subscriberId = email
queryParams = mapOf("sourceId" to newCardId)
}

assertEquals(newCardId, StripePayment.getDefaultSourceForCustomer(customerId),
"Expected $newCardId to be default source for $customerId")
}
}

class PurchaseTest {

@Test
fun `jersey test - POST products purchase`() {

StripePayment.deleteAllCustomers()
Firebase.deleteAllPaymentCustomers()

val email = "purchase-${randomInt()}@test.com"
createProfile(name = "Test Purchase User", email = email)
Expand All @@ -240,12 +371,65 @@ class PurchaseTest {
val balanceBefore = subscriptionStatusBefore.remaining

val productSku = "1GB_249NOK"
val sourceId = StripePayment.createPaymentSourceId()
val sourceId = StripePayment.createPaymentTokenId()

post<String> {
path = "/products/$productSku/purchase"
subscriberId = email
queryParams = mapOf("sourceId" to sourceId)
}

Thread.sleep(100) // wait for 100 ms for balance to be updated in db

val subscriptionStatusAfter: SubscriptionStatus = get {
path = "/subscription/status"
subscriberId = email
}
val balanceAfter = subscriptionStatusAfter.remaining

assertEquals(1_000_000_000, balanceAfter - balanceBefore, "Balance did not increased by 1GB after Purchase")

val purchaseRecords: PurchaseRecordList = get {
path = "/purchases"
subscriberId = email
}

purchaseRecords.sortBy { it.timestamp }

assert(Instant.now().toEpochMilli() - purchaseRecords.last().timestamp < 10_000) { "Missing Purchase Record" }
assertEquals(expectedProducts().first(), purchaseRecords.last().product, "Incorrect 'Product' in purchase record")
}

@Test
fun `jersey test - POST products purchase using default source`() {

StripePayment.deleteAllCustomers()
Firebase.deleteAllPaymentCustomers()

val email = "purchase-${randomInt()}@test.com"
createProfile(name = "Test Purchase User with Default Payment Source", email = email)

val sourceId = StripePayment.createPaymentTokenId()

val paymentSource: PaymentSource = post {
path = "/paymentSources"
subscriberId = email
queryParams = mapOf("sourceId" to sourceId)
}

assertNotNull(paymentSource.id, message = "Failed to create payment source")

val subscriptionStatusBefore: SubscriptionStatus = get {
path = "/subscription/status"
subscriberId = email
}
val balanceBefore = subscriptionStatusBefore.remaining

val productSku = "1GB_249NOK"

post<String> {
path = "/products/$productSku/purchase"
subscriberId = email
queryParams = mapOf( "sourceId" to sourceId)
}

Thread.sleep(100) // wait for 100 ms for balance to be updated in db
Expand Down
Loading

0 comments on commit 63df277

Please sign in to comment.