From 209a8a23ac831cb21db65e0d9915502ab6096afb Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 27 Jul 2022 12:03:48 -0700 Subject: [PATCH 1/9] Add CartService e2e Tests --- docker-compose.yml | 2 +- test/data.json | 7 +++++++ test/test.js | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index a0100e95ac..91d256e919 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -64,7 +64,7 @@ services: context: ./ dockerfile: ./src/cartservice/src/Dockerfile ports: - - "${CART_SERVICE_PORT}" + - "${CART_SERVICE_PORT}:${CART_SERVICE_PORT}" environment: - CART_SERVICE_PORT - REDIS_ADDR diff --git a/test/data.json b/test/data.json index c38ae4331d..d0f43a1bdd 100644 --- a/test/data.json +++ b/test/data.json @@ -1,4 +1,11 @@ { + "cart": { + "userId": "1234", + "item": { + "productId": "OLJCESPC7Z", + "quantity": 1 + } + }, "charge": { "amount": { "currencyCode": "USD", diff --git a/test/test.js b/test/test.js index 399f7f6dc2..b154670193 100644 --- a/test/test.js +++ b/test/test.js @@ -15,7 +15,10 @@ const deepCopy = obj => JSON.parse(JSON.stringify(obj)) const arrayIntersection = (a, b) => a.filter(x => b.indexOf(x) !== -1) +const isEmpty = obj => Object.keys(obj).length === 0 + // Main +let cartAdd = null, cartGet = null, cartEmpty = null let charge = null let recommend = null @@ -24,6 +27,11 @@ test.before(() => { const hipstershop = grpc.loadPackageDefinition(protoLoader.loadSync('../pb/demo.proto')).hipstershop + const cartClient = new hipstershop.CartService(`0.0.0.0:${process.env.CART_SERVICE_PORT}`, grpc.credentials.createInsecure()) + cartAdd = promisify(cartClient.addItem).bind(cartClient) + cartGet = promisify(cartClient.getCart).bind(cartClient) + cartEmpty = promisify(cartClient.emptyCart).bind(cartClient) + const paymentClient = new hipstershop.PaymentService(`0.0.0.0:${process.env.PAYMENT_SERVICE_PORT}`, grpc.credentials.createInsecure()) charge = promisify(paymentClient.charge).bind(paymentClient) @@ -31,6 +39,35 @@ test.before(() => { recommend = promisify(recommendationClient.listRecommendations).bind(recommendationClient) }) +// --------------- Cart Service --------------- + +test('cart: all', async t => { + const request = data.cart + const userIdRequest = { userId: request.userId } + + // Empty Cart + const emptyRes1 = await cartEmpty(userIdRequest) + t.truthy(isEmpty(emptyRes1)) + + // Add to Cart + const addRes = await cartAdd(request) + t.truthy(isEmpty(addRes)) + + // Check Cart Content + const getRes1 = await cartGet(userIdRequest) + t.is(getRes1.items.length, 1) + t.is(getRes1.items[0].productId, request.item.productId) + t.is(getRes1.items[0].quantity, request.item.quantity) + + // Empty Cart + const emptyRes2 = await cartEmpty(userIdRequest) + t.truthy(isEmpty(emptyRes2)) + + // Check Cart Content + const getRes2 = await cartGet(userIdRequest) + t.truthy(isEmpty(getRes2)) +}) + // --------------- Payment Service --------------- test('payment: valid credit card', t => { From 6de0efb8c0dc04780aa242dd640024205b5c5b98 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 27 Jul 2022 12:09:27 -0700 Subject: [PATCH 2/9] simpler --- test/test.js | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/test/test.js b/test/test.js index b154670193..50e4adcd79 100644 --- a/test/test.js +++ b/test/test.js @@ -42,30 +42,31 @@ test.before(() => { // --------------- Cart Service --------------- test('cart: all', async t => { + let res = null const request = data.cart const userIdRequest = { userId: request.userId } // Empty Cart - const emptyRes1 = await cartEmpty(userIdRequest) - t.truthy(isEmpty(emptyRes1)) + res = await cartEmpty(userIdRequest) + t.truthy(isEmpty(res)) // Add to Cart - const addRes = await cartAdd(request) - t.truthy(isEmpty(addRes)) + res = await cartAdd(request) + t.truthy(isEmpty(res)) // Check Cart Content - const getRes1 = await cartGet(userIdRequest) - t.is(getRes1.items.length, 1) - t.is(getRes1.items[0].productId, request.item.productId) - t.is(getRes1.items[0].quantity, request.item.quantity) + res = await cartGet(userIdRequest) + t.is(res.items.length, 1) + t.is(res.items[0].productId, request.item.productId) + t.is(res.items[0].quantity, request.item.quantity) // Empty Cart - const emptyRes2 = await cartEmpty(userIdRequest) - t.truthy(isEmpty(emptyRes2)) + res = await cartEmpty(userIdRequest) + t.truthy(isEmpty(res)) // Check Cart Content - const getRes2 = await cartGet(userIdRequest) - t.truthy(isEmpty(getRes2)) + res = await cartGet(userIdRequest) + t.truthy(isEmpty(res)) }) // --------------- Payment Service --------------- From 985b66d05afc8644d502c257ac0ae6564bc0ac42 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 27 Jul 2022 13:36:30 -0700 Subject: [PATCH 3/9] Product Service e2e Tests --- docker-compose.yml | 2 +- test/test.js | 32 ++++++++++++++++++++++++++++++-- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 91d256e919..877aa62244 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -192,7 +192,7 @@ services: context: ./ dockerfile: ./src/productcatalogservice/Dockerfile ports: - - "${PRODUCT_CATALOG_SERVICE_PORT}" + - "${PRODUCT_CATALOG_SERVICE_PORT}:${PRODUCT_CATALOG_SERVICE_PORT}" environment: - PRODUCT_CATALOG_SERVICE_PORT - OTEL_EXPORTER_OTLP_TRACES_ENDPOINT diff --git a/test/test.js b/test/test.js index 50e4adcd79..e98e748b0c 100644 --- a/test/test.js +++ b/test/test.js @@ -21,6 +21,7 @@ const isEmpty = obj => Object.keys(obj).length === 0 let cartAdd = null, cartGet = null, cartEmpty = null let charge = null let recommend = null +let productList = null, productGet = null, productSearch = null test.before(() => { dotenv.config({ path: '../.env' }) @@ -35,6 +36,11 @@ test.before(() => { const paymentClient = new hipstershop.PaymentService(`0.0.0.0:${process.env.PAYMENT_SERVICE_PORT}`, grpc.credentials.createInsecure()) charge = promisify(paymentClient.charge).bind(paymentClient) + const productCatalogClient = new hipstershop.ProductCatalogService(`0.0.0.0:${process.env.PRODUCT_CATALOG_SERVICE_PORT}`, grpc.credentials.createInsecure()) + productList = promisify(productCatalogClient.listProducts).bind(productCatalogClient) + productGet = promisify(productCatalogClient.getProduct).bind(productCatalogClient) + productSearch = promisify(productCatalogClient.searchProducts).bind(productCatalogClient) + const recommendationClient = new hipstershop.RecommendationService(`0.0.0.0:${process.env.RECOMMENDATION_SERVICE_PORT}`, grpc.credentials.createInsecure()) recommend = promisify(recommendationClient.listRecommendations).bind(recommendationClient) }) @@ -42,12 +48,11 @@ test.before(() => { // --------------- Cart Service --------------- test('cart: all', async t => { - let res = null const request = data.cart const userIdRequest = { userId: request.userId } // Empty Cart - res = await cartEmpty(userIdRequest) + let res = await cartEmpty(userIdRequest) t.truthy(isEmpty(res)) // Add to Cart @@ -106,6 +111,29 @@ test('payment: expired credit card', t => { }) }) +// --------------- Product Catalog Service --------------- + +test('product: list', async t => { + const res = await productList({}) + t.is(res.products.length, 9) +}) + +test('product: get', async t => { + const res = await productGet({ id: 'OLJCESPC7Z' }) + t.is(res.name, 'Sunglasses') + t.truthy(res.description) + t.truthy(res.picture) + t.truthy(res.priceUsd) + t.truthy(res.categories) +}) + +test('product: search', async t => { + const res = await productSearch({ query: 'hold' }) + t.is(res.results.length, 2) + t.is(res.results[0].name, 'Candle Holder') + t.is(res.results[1].name, 'Bamboo Glass Jar') +}) + // --------------- Recommendation Service --------------- test('recommendation: list products', t => { From 91982d037d909dd272a562558ec71bdc5da53be6 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 27 Jul 2022 15:39:28 -0700 Subject: [PATCH 4/9] Shipping Service e2e Tests --- docker-compose.yml | 2 +- test/data.json | 15 +++++++++++++++ test/test.js | 31 +++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 877aa62244..0186541544 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -227,7 +227,7 @@ services: context: ./ dockerfile: ./src/shippingservice/Dockerfile ports: - - "${SHIPPING_SERVICE_PORT}" + - "${SHIPPING_SERVICE_PORT}:${SHIPPING_SERVICE_PORT}" environment: - PORT=${SHIPPING_SERVICE_PORT} - OTEL_EXPORTER_OTLP_TRACES_ENDPOINT diff --git a/test/data.json b/test/data.json index d0f43a1bdd..c7abc9908d 100644 --- a/test/data.json +++ b/test/data.json @@ -22,5 +22,20 @@ "recommend": { "userId": "1234", "productIds": [ "OLJCESPC7Z", "66VCHSJNUP", "1YMWWN1N4O", "L9ECAV7KIM", "2ZYFJ3GM2N" ] + }, + "shipping": { + "address": { + "steetAddress": "One Microsoft Way", + "city": "Redmond", + "state": "Washington", + "country": "United States", + "zipCode": 98052 + }, + "items": [ + { + "productId": "66VCHSJNUP", + "quantity": 2 + } + ] } } diff --git a/test/test.js b/test/test.js index e98e748b0c..a65fa6256e 100644 --- a/test/test.js +++ b/test/test.js @@ -22,6 +22,7 @@ let cartAdd = null, cartGet = null, cartEmpty = null let charge = null let recommend = null let productList = null, productGet = null, productSearch = null +let shippingQuote = null, shippingOrder = null test.before(() => { dotenv.config({ path: '../.env' }) @@ -43,6 +44,10 @@ test.before(() => { const recommendationClient = new hipstershop.RecommendationService(`0.0.0.0:${process.env.RECOMMENDATION_SERVICE_PORT}`, grpc.credentials.createInsecure()) recommend = promisify(recommendationClient.listRecommendations).bind(recommendationClient) + + const shippingClient = new hipstershop.ShippingService(`0.0.0.0:${process.env.SHIPPING_SERVICE_PORT}`, grpc.credentials.createInsecure()) + shippingQuote = promisify(shippingClient.getQuote).bind(shippingClient) + shippingOrder = promisify(shippingClient.shipOrder).bind(shippingClient) }) // --------------- Cart Service --------------- @@ -144,3 +149,29 @@ test('recommendation: list products', t => { t.is(arrayIntersection(res.productIds, request.productIds).length, 0) }) }) + +// --------------- Shipping Service --------------- + +test('shipping: quote', async t => { + const request = data.shipping + + const res = await shippingQuote(request) + t.is(res.costUsd.units, 17) + t.is(res.costUsd.nanos, 980000000) +}) + +test('shipping: empty quote', async t => { + const request = deepCopy(data.shipping) + request.items = [] + + const res = await shippingQuote(request) + t.falsy(res.costUsd.units) + t.falsy(res.costUsd.nanos) +}) + +test('shipping: order', async t => { + const request = data.shipping + + const res = await shippingOrder(request) + t.truthy(res.trackingId) +}) From 1ec12d4a74043863f38131e2f3571ee8271b29ea Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 27 Jul 2022 16:25:10 -0700 Subject: [PATCH 5/9] Currency Service e2e Tests --- docker-compose.yml | 2 +- test/data.json | 10 +++++++++- test/test.js | 30 +++++++++++++++++++++++++----- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 0186541544..32642f765b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -113,7 +113,7 @@ services: - GRPC_VERSION=1.46.0 - OPENTELEMETRY_VERSION=1.4.0 ports: - - "${CURRENCY_SERVICE_PORT}" + - "${CURRENCY_SERVICE_PORT}:${CURRENCY_SERVICE_PORT}" environment: - PORT=${CURRENCY_SERVICE_PORT} - OTEL_EXPORTER_OTLP_TRACES_ENDPOINT diff --git a/test/data.json b/test/data.json index c7abc9908d..851d8a1d9e 100644 --- a/test/data.json +++ b/test/data.json @@ -6,6 +6,14 @@ "quantity": 1 } }, + "currency": { + "from": { + "currencyCode": "USD", + "units": 330, + "nanos": 750000000 + }, + "toCode": "CAD" + }, "charge": { "amount": { "currencyCode": "USD", @@ -25,7 +33,7 @@ }, "shipping": { "address": { - "steetAddress": "One Microsoft Way", + "streetAddress": "One Microsoft Way", "city": "Redmond", "state": "Washington", "country": "United States", diff --git a/test/test.js b/test/test.js index a65fa6256e..fdc2d3e6b5 100644 --- a/test/test.js +++ b/test/test.js @@ -19,6 +19,7 @@ const isEmpty = obj => Object.keys(obj).length === 0 // Main let cartAdd = null, cartGet = null, cartEmpty = null +let currencySupported = null, currencyConvert = null let charge = null let recommend = null let productList = null, productGet = null, productSearch = null @@ -34,6 +35,10 @@ test.before(() => { cartGet = promisify(cartClient.getCart).bind(cartClient) cartEmpty = promisify(cartClient.emptyCart).bind(cartClient) + const currencyClient = new hipstershop.CurrencyService(`0.0.0.0:${process.env.CURRENCY_SERVICE_PORT}`, grpc.credentials.createInsecure()) + currencySupported = promisify(currencyClient.getSupportedCurrencies).bind(currencyClient) + currencyConvert = promisify(currencyClient.convert).bind(currencyClient) + const paymentClient = new hipstershop.PaymentService(`0.0.0.0:${process.env.PAYMENT_SERVICE_PORT}`, grpc.credentials.createInsecure()) charge = promisify(paymentClient.charge).bind(paymentClient) @@ -79,6 +84,22 @@ test('cart: all', async t => { t.truthy(isEmpty(res)) }) +// --------------- Currency Service --------------- + +test('currency: supported', async t => { + const res = await currencySupported({}) + t.is(res.currencyCodes.length, 33) +}) + +test('currency: convert', async t => { + const request = data.currency + + const res = await currencyConvert(request) + t.is(res.currencyCode, "CAD") + t.is(res.units, 442) + t.is(res.nanos, 599380805) +}) + // --------------- Payment Service --------------- test('payment: valid credit card', t => { @@ -141,13 +162,12 @@ test('product: search', async t => { // --------------- Recommendation Service --------------- -test('recommendation: list products', t => { +test('recommendation: list products', async t => { const request = deepCopy(data.recommend) - return recommend(request).then(res => { - t.is(res.productIds.length, 4) - t.is(arrayIntersection(res.productIds, request.productIds).length, 0) - }) + const res = await recommend(request) + t.is(res.productIds.length, 4) + t.is(arrayIntersection(res.productIds, request.productIds).length, 0) }) // --------------- Shipping Service --------------- From c5317ec9b1ecb4707366ee64ae11d8eec835b90c Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Thu, 28 Jul 2022 11:15:15 -0700 Subject: [PATCH 6/9] Add e2e tests to Checkout Service + boilerplate for email service --- .env | 2 +- docker-compose.yml | 4 +- src/shippingservice/src/main.rs | 2 +- test/data.json | 50 +++++++++++++++++ test/package-lock.json | 68 ++++++++++++++++++++++- test/package.json | 3 +- test/test.js | 97 +++++++++++++++++++++------------ 7 files changed, 186 insertions(+), 40 deletions(-) diff --git a/.env b/.env index 9eaefeab53..7f8a100a41 100644 --- a/.env +++ b/.env @@ -45,7 +45,7 @@ PRODUCT_CATALOG_SERVICE_ADDR=productcatalogservice:${PRODUCT_CATALOG_SERVICE_POR RECOMMENDATION_SERVICE_PORT=9001 RECOMMENDATION_SERVICE_ADDR=recommendationservice:${RECOMMENDATION_SERVICE_PORT} -SHIPPING_SERVICE_PORT=50051 +SHIPPING_SERVICE_PORT=50052 SHIPPING_SERVICE_ADDR=shippingservice:${SHIPPING_SERVICE_PORT} FEATURE_FLAG_SERVICE_PORT=50052 diff --git a/docker-compose.yml b/docker-compose.yml index 32642f765b..407919e80d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -83,7 +83,7 @@ services: context: ./ dockerfile: ./src/checkoutservice/Dockerfile ports: - - "${CHECKOUT_SERVICE_PORT}" + - "${CHECKOUT_SERVICE_PORT}:${CHECKOUT_SERVICE_PORT}" environment: - CHECKOUT_SERVICE_PORT - CART_SERVICE_ADDR @@ -128,7 +128,7 @@ services: build: context: ./src/emailservice ports: - - "${EMAIL_SERVICE_PORT}" + - "${EMAIL_SERVICE_PORT}:${EMAIL_SERVICE_PORT}" environment: - APP_ENV=production - PORT=${EMAIL_SERVICE_PORT} diff --git a/src/shippingservice/src/main.rs b/src/shippingservice/src/main.rs index b7b954145f..514aafd5a9 100644 --- a/src/shippingservice/src/main.rs +++ b/src/shippingservice/src/main.rs @@ -53,7 +53,7 @@ async fn main() -> Result<(), Box> { init_logger()?; init_tracer()?; info!("OTel pipeline created"); - let port = env::var("PORT").unwrap_or_else(|_| "50051".to_string()); + let port = env::var("PORT").unwrap_or_else(|_| "50052".to_string()); let addr = format!("0.0.0.0:{}", port).parse()?; info!("listening on {}", addr); let shipper = ShippingServer::default(); diff --git a/test/data.json b/test/data.json index 851d8a1d9e..1cc8ce5bbc 100644 --- a/test/data.json +++ b/test/data.json @@ -6,6 +6,24 @@ "quantity": 1 } }, + "checkout": { + "userId": "1997", + "userCurrency": "USD", + "address": { + "streetAddress": "410 Terry Ave. North", + "city": "Seattle", + "state": "Washington", + "country": "United States", + "zipCode": 98109 + }, + "email": "amazon@example.com", + "creditCard": { + "creditCardNumber": "4117-7059-6121-5486", + "creditCardCvv": 346, + "creditCardExpirationYear": 2025, + "creditCardExpirationMonth": 3 + } + }, "currency": { "from": { "currencyCode": "USD", @@ -14,6 +32,38 @@ }, "toCode": "CAD" }, + "email": { + "email": "google@example.com", + "order": { + "orderId": "505", + "shippingTrackingId": "dead-beef", + "shippingCost": { + "currencyCode": "USD", + "units": 17, + "nanos": 980000000 + }, + "shippingAddress": { + "streetAddress": "1600 Amphitheatre Parkway", + "city": "Mountain View", + "state": "California", + "country": "United States", + "zipCode": 94043 + }, + "items": [ + { + "item": { + "productId": "1YMWWN1N4O", + "quantity": 5 + }, + "cost": { + "currencyCode": "USD", + "units": 100, + "nanos": 0 + } + } + ] + } + }, "charge": { "amount": { "currencyCode": "USD", diff --git a/test/package-lock.json b/test/package-lock.json index 9759a7d757..a401bd4237 100644 --- a/test/package-lock.json +++ b/test/package-lock.json @@ -10,7 +10,8 @@ "license": "ISC", "dependencies": { "@grpc/grpc-js": "1.6.7", - "dotenv": "16.0.1" + "dotenv": "16.0.1", + "node-fetch": "^2.6.7" }, "devDependencies": { "ava": "4.3.0" @@ -1577,6 +1578,25 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/nofilter": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-3.1.0.tgz", @@ -2096,6 +2116,11 @@ "node": ">=8.0" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, "node_modules/type-fest": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", @@ -2108,6 +2133,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, "node_modules/well-known-symbols": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/well-known-symbols/-/well-known-symbols-2.0.0.tgz", @@ -2117,6 +2147,15 @@ "node": ">=6" } }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -3304,6 +3343,14 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, "nofilter": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-3.1.0.tgz", @@ -3635,18 +3682,37 @@ "is-number": "^7.0.0" } }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, "type-fest": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", "dev": true }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, "well-known-symbols": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/well-known-symbols/-/well-known-symbols-2.0.0.tgz", "integrity": "sha512-ZMjC3ho+KXo0BfJb7JgtQ5IBuvnShdlACNkKkdsqBmYw3bPAaJfPeYUo6tLUaT5tG/Gkh7xkpBhKRQ9e7pyg9Q==", "dev": true }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", diff --git a/test/package.json b/test/package.json index a516a6459b..4e968bdadf 100644 --- a/test/package.json +++ b/test/package.json @@ -13,6 +13,7 @@ }, "dependencies": { "@grpc/grpc-js": "1.6.7", - "dotenv": "16.0.1" + "dotenv": "16.0.1", + "node-fetch": "2.6.7" } } diff --git a/test/test.js b/test/test.js index fdc2d3e6b5..63774ba79c 100644 --- a/test/test.js +++ b/test/test.js @@ -6,19 +6,19 @@ const test = require('ava') const dotenv = require('dotenv') const grpc = require('@grpc/grpc-js') const protoLoader = require('@grpc/proto-loader') +const fetch = require('node-fetch') // Local const data = require('./data.json') // Functions const deepCopy = obj => JSON.parse(JSON.stringify(obj)) - const arrayIntersection = (a, b) => a.filter(x => b.indexOf(x) !== -1) - const isEmpty = obj => Object.keys(obj).length === 0 // Main let cartAdd = null, cartGet = null, cartEmpty = null +let checkoutOrder = null let currencySupported = null, currencyConvert = null let charge = null let recommend = null @@ -35,6 +35,9 @@ test.before(() => { cartGet = promisify(cartClient.getCart).bind(cartClient) cartEmpty = promisify(cartClient.emptyCart).bind(cartClient) + const checkoutClient = new hipstershop.CheckoutService(`0.0.0.0:${process.env.CHECKOUT_SERVICE_PORT}`, grpc.credentials.createInsecure()) + checkoutOrder = promisify(checkoutClient.placeOrder).bind(checkoutClient) + const currencyClient = new hipstershop.CurrencyService(`0.0.0.0:${process.env.CURRENCY_SERVICE_PORT}`, grpc.credentials.createInsecure()) currencySupported = promisify(currencyClient.getSupportedCurrencies).bind(currencyClient) currencyConvert = promisify(currencyClient.convert).bind(currencyClient) @@ -58,29 +61,29 @@ test.before(() => { // --------------- Cart Service --------------- test('cart: all', async t => { - const request = data.cart - const userIdRequest = { userId: request.userId } + const req = data.cart + const userIdReq = { userId: req.userId } // Empty Cart - let res = await cartEmpty(userIdRequest) + let res = await cartEmpty(userIdReq) t.truthy(isEmpty(res)) // Add to Cart - res = await cartAdd(request) + res = await cartAdd(req) t.truthy(isEmpty(res)) // Check Cart Content - res = await cartGet(userIdRequest) + res = await cartGet(userIdReq) t.is(res.items.length, 1) - t.is(res.items[0].productId, request.item.productId) - t.is(res.items[0].quantity, request.item.quantity) + t.is(res.items[0].productId, req.item.productId) + t.is(res.items[0].quantity, req.item.quantity) // Empty Cart - res = await cartEmpty(userIdRequest) + res = await cartEmpty(userIdReq) t.truthy(isEmpty(res)) // Check Cart Content - res = await cartGet(userIdRequest) + res = await cartGet(userIdReq) t.truthy(isEmpty(res)) }) @@ -92,47 +95,73 @@ test('currency: supported', async t => { }) test('currency: convert', async t => { - const request = data.currency + const req = data.currency - const res = await currencyConvert(request) + const res = await currencyConvert(req) t.is(res.currencyCode, "CAD") t.is(res.units, 442) t.is(res.nanos, 599380805) }) +// --------------- Checkout Service --------------- + +test('checkout: place order', async t => { + const req = data.checkout + const res = await checkoutOrder(req) + + t.truthy(res.order.orderId) + t.truthy(res.order.shippingTrackingId) + t.truthy(res.order.shippingAddress) + t.is(res.order.shippingCost.currencyCode, 'USD') +}) + +// --------------- Email Service --------------- + +// TODO +test('email: confirmation', async t => { + const req = data.email + + const res = await fetch( + `http://0.0.0.0:${process.env.EMAIL_SERVICE_PORT}/send_order_confirmation`, + { method: 'POST', body: JSON.stringify(req), headers: { 'Contenty-Type': 'application/json' } } + ) + + t.truthy(true) +}) + // --------------- Payment Service --------------- test('payment: valid credit card', t => { - const request = data.charge + const req = data.charge - return charge(request).then(res => { + return charge(req).then(res => { t.truthy(res.transactionId) }) }) test('payment: invalid credit card', t => { - const request = deepCopy(data.charge) - request.creditCard.creditCardNumber = '0000-0000-0000-0000' + const req = deepCopy(data.charge) + req.creditCard.creditCardNumber = '0000-0000-0000-0000' - return charge(request).catch(err => { + return charge(req).catch(err => { t.is(err.details, 'Credit card info is invalid.') }) }) test('payment: amex credit card not allowed', t => { - const request = deepCopy(data.charge) - request.creditCard.creditCardNumber = '3714 496353 98431' + const req = deepCopy(data.charge) + req.creditCard.creditCardNumber = '3714 496353 98431' - return charge(request).catch(err => { + return charge(req).catch(err => { t.is(err.details, 'Sorry, we cannot process amex credit cards. Only VISA or MasterCard is accepted.') }) }) test('payment: expired credit card', t => { - const request = deepCopy(data.charge) - request.creditCard.creditCardExpirationYear = 2021 + const req = deepCopy(data.charge) + req.creditCard.creditCardExpirationYear = 2021 - return charge(request).catch(err => { + return charge(req).catch(err => { t.is(err.details, 'The credit card (ending 0454) expired on 1/2021.') }) }) @@ -163,35 +192,35 @@ test('product: search', async t => { // --------------- Recommendation Service --------------- test('recommendation: list products', async t => { - const request = deepCopy(data.recommend) + const req = deepCopy(data.recommend) - const res = await recommend(request) + const res = await recommend(req) t.is(res.productIds.length, 4) - t.is(arrayIntersection(res.productIds, request.productIds).length, 0) + t.is(arrayIntersection(res.productIds, req.productIds).length, 0) }) // --------------- Shipping Service --------------- test('shipping: quote', async t => { - const request = data.shipping + const req = data.shipping - const res = await shippingQuote(request) + const res = await shippingQuote(req) t.is(res.costUsd.units, 17) t.is(res.costUsd.nanos, 980000000) }) test('shipping: empty quote', async t => { - const request = deepCopy(data.shipping) - request.items = [] + const req = deepCopy(data.shipping) + req.items = [] - const res = await shippingQuote(request) + const res = await shippingQuote(req) t.falsy(res.costUsd.units) t.falsy(res.costUsd.nanos) }) test('shipping: order', async t => { - const request = data.shipping + const req = data.shipping - const res = await shippingOrder(request) + const res = await shippingOrder(req) t.truthy(res.trackingId) }) From 83c221f6fb1a8fa75f546e70167fa936d92f378c Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Thu, 28 Jul 2022 11:23:07 -0700 Subject: [PATCH 7/9] Add e2e tests to Ad Service --- docker-compose.yml | 2 +- src/shippingservice/Dockerfile | 4 ++-- test/data.json | 3 +++ test/test.js | 17 +++++++++++++++++ 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 407919e80d..84a71623f6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -48,7 +48,7 @@ services: context: ./ dockerfile: ./src/adservice/Dockerfile ports: - - "${AD_SERVICE_PORT}" + - "${AD_SERVICE_PORT}:${AD_SERVICE_PORT}" environment: - AD_SERVICE_PORT - OTEL_EXPORTER_OTLP_TRACES_ENDPOINT diff --git a/src/shippingservice/Dockerfile b/src/shippingservice/Dockerfile index bf6f5fa102..eabde95342 100644 --- a/src/shippingservice/Dockerfile +++ b/src/shippingservice/Dockerfile @@ -16,7 +16,7 @@ RUN GRPC_HEALTH_PROBE_VERSION=v0.4.7 && \ chmod +x /bin/grpc_health_probe WORKDIR /app COPY --from=builder /app/target/release/shippingservice /shippingservice -ENV PORT=50051 +ENV PORT=50052 -EXPOSE 50051 +EXPOSE 50052 ENTRYPOINT ["/shippingservice"] diff --git a/test/data.json b/test/data.json index 1cc8ce5bbc..85db134e2c 100644 --- a/test/data.json +++ b/test/data.json @@ -1,4 +1,7 @@ { + "ad": { + "contextKeys": [ "galaxy", "telescope" ] + }, "cart": { "userId": "1234", "item": { diff --git a/test/test.js b/test/test.js index 63774ba79c..e9088ac918 100644 --- a/test/test.js +++ b/test/test.js @@ -17,6 +17,7 @@ const arrayIntersection = (a, b) => a.filter(x => b.indexOf(x) !== -1) const isEmpty = obj => Object.keys(obj).length === 0 // Main +let adsGet = null let cartAdd = null, cartGet = null, cartEmpty = null let checkoutOrder = null let currencySupported = null, currencyConvert = null @@ -30,6 +31,9 @@ test.before(() => { const hipstershop = grpc.loadPackageDefinition(protoLoader.loadSync('../pb/demo.proto')).hipstershop + const adClient = new hipstershop.AdService(`0.0.0.0:${process.env.AD_SERVICE_PORT}`, grpc.credentials.createInsecure()) + adsGet = promisify(adClient.getAds).bind(adClient) + const cartClient = new hipstershop.CartService(`0.0.0.0:${process.env.CART_SERVICE_PORT}`, grpc.credentials.createInsecure()) cartAdd = promisify(cartClient.addItem).bind(cartClient) cartGet = promisify(cartClient.getCart).bind(cartClient) @@ -58,6 +62,19 @@ test.before(() => { shippingOrder = promisify(shippingClient.shipOrder).bind(shippingClient) }) +// --------------- Ad Service --------------- + +test('ad: get', async t => { + const req = data.ad + const res = await adsGet(req) + + t.is(res.ads.length, 2) + t.truthy(res.ads[0].redirectUrl) + t.truthy(res.ads[1].redirectUrl) + t.truthy(res.ads[0].text) + t.truthy(res.ads[1].text) +}) + // --------------- Cart Service --------------- test('cart: all', async t => { From ddd8349f2c7ef3fca7d2d32b9d06ca6262bc78e4 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Thu, 28 Jul 2022 11:31:54 -0700 Subject: [PATCH 8/9] fix port conflict + changelog --- CHANGELOG.md | 2 ++ src/emailservice/Dockerfile | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee0eba8147..521b548fbb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,3 +41,5 @@ significant modifications will be credited to OpenTelemetry Authors. ([#189](https://github.com/open-telemetry/opentelemetry-demo/pull/189)) * Simplified repo name and dropped the '-webstore' suffix in every place ([#225](https://github.com/open-telemetry/opentelemetry-demo/pull/225)) +* Added end-to-end tests to each individual service +([#242](https://github.com/open-telemetry/opentelemetry-demo/pull/242)) diff --git a/src/emailservice/Dockerfile b/src/emailservice/Dockerfile index 07500157bf..1b6d1d8cd4 100644 --- a/src/emailservice/Dockerfile +++ b/src/emailservice/Dockerfile @@ -24,5 +24,5 @@ WORKDIR /email_server COPY . . -EXPOSE 8080 +EXPOSE ${EMAIL_SERVICE_PORT} ENTRYPOINT ["bundle", "exec", "ruby", "email_server.rb"] From 7354b0db2b47114d4a0275d9d1f7f43998e52453 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Tue, 2 Aug 2022 08:36:49 -0700 Subject: [PATCH 9/9] port fix --- .env | 4 ++-- src/shippingservice/src/main.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.env b/.env index 7f8a100a41..985582299c 100644 --- a/.env +++ b/.env @@ -33,7 +33,7 @@ CHECKOUT_SERVICE_ADDR=checkoutservice:${CHECKOUT_SERVICE_PORT} CURRENCY_SERVICE_PORT=7000 CURRENCY_SERVICE_ADDR=currencyservice:${CURRENCY_SERVICE_PORT} -EMAIL_SERVICE_PORT=8080 +EMAIL_SERVICE_PORT=6060 EMAIL_SERVICE_ADDR=http://emailservice:${EMAIL_SERVICE_PORT} PAYMENT_SERVICE_PORT=50051 @@ -45,7 +45,7 @@ PRODUCT_CATALOG_SERVICE_ADDR=productcatalogservice:${PRODUCT_CATALOG_SERVICE_POR RECOMMENDATION_SERVICE_PORT=9001 RECOMMENDATION_SERVICE_ADDR=recommendationservice:${RECOMMENDATION_SERVICE_PORT} -SHIPPING_SERVICE_PORT=50052 +SHIPPING_SERVICE_PORT=50050 SHIPPING_SERVICE_ADDR=shippingservice:${SHIPPING_SERVICE_PORT} FEATURE_FLAG_SERVICE_PORT=50052 diff --git a/src/shippingservice/src/main.rs b/src/shippingservice/src/main.rs index 514aafd5a9..b4d913a23a 100644 --- a/src/shippingservice/src/main.rs +++ b/src/shippingservice/src/main.rs @@ -53,7 +53,7 @@ async fn main() -> Result<(), Box> { init_logger()?; init_tracer()?; info!("OTel pipeline created"); - let port = env::var("PORT").unwrap_or_else(|_| "50052".to_string()); + let port = env::var("PORT").unwrap_or_else(|_| "50050".to_string()); let addr = format!("0.0.0.0:{}", port).parse()?; info!("listening on {}", addr); let shipper = ShippingServer::default();