How to pact test an SSE endpoint (GET, "Content-Type": "text/event-stream") - server-sent-events

My current application includes an SSE endpoint to allow streaming access to events occurring internally. That all works well, but we're like to do contract testing using pack for all endpoint and I can't find a way to define a pact for the stream event data, which looks like this:
data: {"foo": "bar"}
data: {"bar": "foo"}
...
in curl results.
Can anyone point me to an example of a pact for SSE contract validation?

Pact has a concept referred to as Message Pact. Message pact support asynchronous calls, and abstracts away the specific protocol.
Which language do you need?
For example, here is the docs for Pact JS: https://github.com/pact-foundation/pact-js/#asynchronous-api-testing
An example consumer test for a product event would look as follows:
describe("receive product event", () => {
it("accepts a product", () => {
return (
messagePact
.given("product created")
.expectsToReceive("a product created event")
.withContent({
id: like(1),
name: like("pizza"),
})
.withMetadata({
"content-type": "application/json",
})
.verify(synchronousBodyHandler(productApiHandler))
)
})
})

Related

Are concurrent queries via same endpoint possible using useLazyQueryHook in Redux Toolkit

The problem: When doing multiple requests to the same endpoint, useLazyQueryHook will return a response only with the latest query with status set to 'fulfilled' and response data, while other requests made before are stuck with status 'pending' and without response data.
Desired functionality: The lazy query hook does not overwrite the previous returns (if overwrite is the case) but returns data from each query which can be accessed in a useEffect hook f.ex. Is this possibly not the correct approach for this use case when using RTK?
I have the following endpoint within createAPI...
getLoggerCheck: builder.query<any, any>({
query: ({ loggerId }) => ({
url: '/scan/check',
params: {
logger: loggerId,
}
}),
transformResponse(data: any) {
console.log(data); // <---- Correct data for each request is logged out here
return data;
}
})
... but when using the generated useLazyGetLoggerCheckQuery hook like so and making approx 5 requests / sec with runLoggerChecks({loggerId: XXXXX}) only the most recent query is returned with data and status 'fulfilled'.
const [runLoggerCheck, loggerCheckResponse] = useLazyGetLoggerCheckQuery();
useEffect(() => {
console.log(loggerCheckResponse)
}, [loggerCheckResponse]);

WireMock To Use As Proxy For SOAP Service

Here is the scenario I'm trying to work on:
I'm writing Contract Driven Tests using Spring Cloud Contract. The tests for inter-communication between the microservices works fine.
Some microservices are calling SOAP-based services. As part of integration tests, I'm trying to use
WireMock as a proxy for the SOAP-based services. Basically, the WireMock should intercept the call, then call the target live environment with the same request, return the same response to the test as a stub.
Unfortunately, I couldn't find any examples how to proceed with that. These services use the HTTP protocol. Any examples of how or any pointers to achieve this would be great. Thanks!
Firstly you need to point your SOAP client to the WireMock base URL, so e.g. if you're using a Spring properties file you might have something like this:
soap.api.host=wiremock-host.internal
soap.api.port=8888
Then you need to configure the WireMock server with a low-priority, broad matching proxy stub. Here's an example of how that would look in JSON form:
{
"priority": 8,
"response": {
"proxyBaseUrl" : "http://target.soap.endpoint"
}
}
Then finally, you would create additional stubs (at the default priority) for each request you want to intercept e.g.
{
"request": {
"method": "POST",
"urlPath": "/v1/some/thing",
"headers": {
"SOAPAction": {
"contains": "MyAction"
}
}
},
"response": {
"status": 200,
"body": "<soap:Envelope ..."
}
}

How do I delete user analytics data from Firebase using userDeletionRequests:upsert?

Problem Description
My Android app collects data via Google Analytics for Firebase. For privacy reasons, users must be able to wipe their data off the Firebase servers, should they choose to do so.
The app requests a deletion by forwarding its Firebase APP_INSTANCE_ID to my own server. This server has been prepared in advance with credentials, from my personal Google account (via oauth2), for managing the Firebase project. The server authenticates with www.googleapis.com, and, using the supplied APP_INSTANCE_ID, invokes the upsert.
As noted by the documentation, the generic Google Analytics API is appropriate for this task.
After some initial trouble (b/c I didn't have the correct auth scope, and the Analytics API wasn't properly enabled), googleapis.com now returns HTTP 200 for each upsert request. (As an aside, even if you supply a bogus APP_INSTANCE_ID, it returns 200.)
Here is a sample response from the upsert, which shows nothing amiss:
{ kind: 'analytics#userDeletionRequest',
id:
{ type: 'APP_INSTANCE_ID',
userId: (REDACTED 32-char hexidecimal string) },
firebaseProjectId: (REDACTED),
deletionRequestTime: '2018-08-28T12:46:30.874Z' }
I know the firebaseProjectId is correct, because if I alter it, I get an error. I have verified that the APP_INSTANCE_ID is correct, and stable up until the moment it is reset with resetAnalyticsData().
Test Procedure
To test the deletions, I populated Firebase with several custom events, using the procedure below (Nexus 5X emulator, no Google Play, no Google accounts configured, but that shouldn't make any difference):
Install the app
Fire off some custom events (FirebaseAnalytics.logEvent)
Observe those events appear on the Firebase console
(About a minute later:) Make the upsert call, observe HTTP 200, and note the "deletionRequestTime"
Immediately call FirebaseAnalytics.resetAnalyticsData (to clear any event data cached on the device)
Uninstall the app
Rinse & repeat 7 or 8 times
However, even 24 hours later, 100% of the Firebase events are still present in the events table. No discernable state change has taken place on the Firebase server as a result of the upserts.
Question
So, what am I doing wrong? how do I successfully delete user data from Google Analytics for Firebase?
EDIT
Here's the code I'm using to make a request (from node.js):
const request = require( 'request' );
...
_deletePersonalData( data )
{
return new Promise( (resolve, reject) => {
request.post({
url: 'https://www.googleapis.com/analytics/v3/userDeletion/userDeletionRequests:upsert',
body: {
kind: 'analytics#userDeletionRequest',
id: {
type: 'APP_INSTANCE_ID',
userId: data.firebaseAppInstanceId
},
firebaseProjectId: (REDACTED)
},
headers: {
Authorization: 'Bearer ' + iap.getCurAccessToken()
},
json: true
}, (err, res, body) => {
console.log( 'user-deletion POST complete' );
console.log( 'Error ' + err );
console.log( 'Body ', body );
if( err )
{
reject( err );
return;
}
if( body.error )
{
reject( new Error( 'The Google service returned an error: ' + body.error.message + ' (' + body.error.code + ')' ) );
return;
}
resolve({ deletionRequestTime: body.deletionRequestTime });
});
});
}
Here's a sample request body:
{
kind: 'analytics#userDeletionRequest',
id: {
type: 'APP_INSTANCE_ID',
userId: (REDACTED 32-char hexidecimal string)
},
firebaseProjectId: (REDACTED)
}
And here's the console output for that same request (same userId and everything):
user-deletion POST complete
Error: null
Body: { kind: 'analytics#userDeletionRequest',
id:
{ type: 'APP_INSTANCE_ID',
userId: (REDACTED 32-char hexidecimal string) },
firebaseProjectId: (REDACTED),
deletionRequestTime: '2018-08-29T17:32:06.949Z' }
Firebase support just got back to me, and I quote:
Upsert method deletes any individual user data we have logged, but aggregate metrics are not recomputed. This means that you might not see any changes in the events tab in your Analytics console.
So, basically my mistake was expecting the events to disappear from the console.
This, of course, raises the question of how one determines that the API is actually working... but maybe the HTTP 200 is enough.

Managing API calls with default error handling in react-redux application

I've completed my application and I'm now integrating the real api calls for each async action. I use redux-thunk which returns a promise from an axios instance.
Currently I'm repeating so much of the same logic in my actions that I'm sure I'm missing something.
API response example
{
"ok": true,
"warnings": [],
"errors": [],
"response": {/* stuff */}
}
The Idea is that I need the same error handling if either the axios call fails (so another response status then 2xx). Additionally I need to also do the same thing when the api response returns "ok": false.
Preferably I would like to dispatch an action which shows a notification to users so they also know when something goes wrong. Aside from that I want to log the api response's warnings and error entities. This is mainly because I'll use sentry for monitoring.
Any Ideas on how to do this without doing a .catch() with the same logic on each api call in any of my action creators?
I've thought about using the onError of axios but that can't dispatch an action as far as I know.
You could use a response interceptor to dispatch appropriate actions. Just wire them up after you create the store
const store = createStore(...)
axios.interceptors.response.use((response) => {
if (!response.data.ok) {
store.dispatch({ type: "RESPONSE_NOT_OK", response }
}
return response
}, (error) => {
store.dispatch({ type: "RESPONSE_HAD_ERROR", error }
return Promise.reject(error)
})
Obviously, you can handle the response how ever you want, this was just for demonstration purposes.

How to call external rest api using metero HTTP module

I am currently new to Meteor and Angular2 and I built an application with same.
I want to make External API call inside Meteor Server using Meteor HTTP Module.
Could you please give an example code in "Typescript" how to do this? Thanks in advance.
Use HTTP.call() for external invoking API. You can call both Get and post requests with this. See the documentation link for details.
Here is a simple example
HTTP.call('POST', 'http://api.twitter.com/xyz', {
data: { some: 'json', stuff: 1 }
}, () => (error, result) {
if (!error) {
Session.set('twizzled', true);
}
});

Resources