I am trying to use pact for validating the spring boot microservices. I have generated the pact file from consumer and verified it in the provider side using pact broker.
I have another use case where I need to execute some code before validating the pact file against actual service response. I read about state change URL and state change with closure to achieve it but couldnt get an example of how to achieve this. Can someone help?
My specific situation is: I have created a contract to update customer with id 1234 (First Name: test Last Name: user).
If this customer doesnt exist, then i would need to insert this data into DB by reading the first name, last name, id from the update request in pact file and additional info (city, state, phone number) through state change code.
So my question is, can i read the request data from pact file through state change instead of configuring the first name,last name and id in the verification side?
The state change URL is a hook you create on the provider to allow Pact to tell the provider what state it should be in at the start of the test. Before each test runs, the mock consumer taps the state change URL on your provider, and tells it the name of the state the test expects.
You need to do two things:
Configure a state change URL
Implement the state change endpoint on the provider
Configuring the state change URL
You can configure the state change URL in the provider verification settings. For example, using the the maven plugin:
<serviceProvider>
<name>provider1</name>
<stateChangeUrl>http://localhost:8080/tasks/pactStateChange</stateChangeUrl>
...
Or using the Gradle provider plugin:
hasPactWith('consumer1') {
stateChangeUrl = url('http://localhost:8080/tasks/pactStateChange')
...
Both of these tell the mock consumer to use localhost:8080/tasks/pactStateChange to change the state of the provider before each test.
Implementing the state change endpoint
The documentation linked above tells us that by default, the format of the request is a POST request of your state string and any parameters:
{ "state" : "a provider state description", "params": { "a": "1", "b": "2" } }
To use this, you implement something like the following untested code on the provider :
#RequestMapping(value = "tasks/pactStateChange", method = RequestMethod.POST)
ResponseEntity<?> stateChange(#RequestBody ProviderState state) {
if (state.state == "no database") {
// Set up state for the "no database" case here
} else if state.state == "Some other state" {
// Set up state here
} else if ... // Other states go here
...
}
return ResponseEntity.ok().build()
}
Please excuse any spring boot errors in that example - I'm not a spring boot person, but you can see the general principle.
With the state change URL, pact doesn't tell the provider any setup details. It just tells the provider the pre-agreed state string that you used in your test. This could be something like "foo exists". Then, when implementing the handler for the state change URL, you detect "foo exists", and do any explicit setup there.
if (state.state == "foo exists") {
// do whatever you need to set up so that foo exists
repository.clear()
repository.insert(new Foo("arguments that foo needs",12))
}
If you'd like to know more about the intent of provider states, have a read of the wiki page on provider states.
How to do this in your specific case
You asked:
Can i read the request data from pact file through state change instead of configuring the first name,last name and id in the verification side?
You might be confused about the intention of the contract tests - each test is a combination of state and request.
So instead of using one test to say:
My test is to request a customer update. If the customer exists, then I expect X response, and if it doesn't, then I expect Y response
you use two tests to say:
When I submit an update to the customer record (in the state when the customer exists), then I expect X response.
When I submit an update to the customer record (in the state where the customer does NOT exist), then I expect Y response.
These tests are two separate items in your Pact contract.
The intention is not to include details of the setup in the contract. On the consumer side, your state is just a string that says something like "Customer with id=1234 exists".
On the Provider side, your state change endpoint detects that URL and creates the state as appropriate. This is usually done in a hard-coded way:
if (state == "Customer with id=1234 exists") {
Database.Clear()
Database.Insert(new Customer(1234, "John","Smith"))
} else if (state == "No customers exist") {
Database.Clear()
}
You don't want to do this in a parameterised way by parsing the state string, because then you're creating a new complex contract between the test consumer and the provider.
The consumer tests shouldn't know anything about how to set provider state, they should just know what state is required by the test (by name only). Similarly, the provider doesn't need to know what's being tested, it just needs to know how to turn state names into actual state.
Related
Before adding a new user to Firebase Authentication should the name be qualified first:
The name must not be null
The name must not be empty
The name must contain one D character at least
Examples:
"Frank van Puffelen" => It is unacceptable because there is no D character
"Doug Stevenson" => It is acceptable
"Alex Mamo" => It is unacceptable because there is no D character
"Renaud Tarnec" => It is acceptable
"" => It is unacceptable because it is empty value
NULL => It is unacceptable because it is a null value
On the client side before adding a new user I check if the name follows the above qualifiers or not but the problem is if someone modifies the code.
The client side is not safe and I should check again on the server side if the name follows the rules or not.
So the question is why there is no Rules tab inside Firebase Authentication?
Since you want to check that the user name (the displayName I guess) follows the set of constraints listed at the top of your question you can take advantage of the new blocking Cloud Functions that "let you execute custom code that modifies the result of a user signing in to your app".
For example:
exports.checkDisplayName = functions.auth.user().beforeCreate((user, context) => {
if (!user.displayName || !user.displayName.toUpperCase().includes('D')) {
throw new functions.auth.HttpsError(
'invalid-argument', `displayName is invalid`); // adapt as follows
}
});
More details in the specific section of the doc, and in particular on how to catch and handle the error in your front-end.
The security rules concept is used to prevent unauthorized access to your Firebase resources such as database and storage. The displayName property is optional irrespective of which authentication method you chose.
If you require users to have a displayName then you can:
Check if user has displayName set every time they login. If not, then redirect them to a screen where they can set a name.
Disable sign-ups directly from Firebase client SDKs and use Firebase Cloud Functions with the Admin SDK to create user. No one else can reverse engineer the functions code so the validation on server side will ensure a user has displayName.
exports.createUser = functions.https.onCall((data, context) => {
const { displayName, email, password } = data;
// check if displayName is valid
// if not return error
// create user using Admin SDK if all data provided is valid
return { message: "User created" };
});
Then you can login your user with the Client SDK using signInWithEmailAndPassword()
In case you are using any Auth providers e.g. Google, Facebook and the display name is unavailable for some reason, then you'll need some custom logic as explain in method 1 above.
Either of the solution does not prevent users from using updateProfile() APIs so make sure have some validation on client end as well and report such events somewhere in the database where you can monitor it.
I have to create calendar push notification but didn't undersatnd how to create channel subscription ?
private void perormWatch(Calendar service, String user) throws Exception {
Channel content = new Channel();
content.setId("abcd#gmail.com");
content.setType("web_hook");
content.setAddress("http://localhost:8888/calendarNotiication");
com.google.api.services.calendar.Calendar.CalendarList.Watch cal = service.calendarList().watch(content);
}
I assume that you want to set up a channel with CalendarList.watch(). To do so you must satisfy three minimum requirements:
An id that uniquely identifies this new channel within your project.
The type property set on web_hook
An address over HTTPS where you want to receive the notifications.
By keeping that in mind, you only have to update your script to match the requirements. First of all the address is set to an invalid URL in the example. It must start with https, not http. Please be aware that only valid SSL certificates are acceptable (i.e. not selfsigned certificates, revoked or badly formed). Also please check that the id is truly unique within your project. Those small modifications should suffice in the example code, but feel free to update your question and leave a comment if you need further solutions.
The default behavior for a Pact test is to not fail when the provider adds fields to a message that the contract of the consumer does not specify, eg:
Consumer expects:
{
"foo": "bar"
}
Provider provides:
{
"foo": "bar",
"hello": "world"
}
A Pact contract-test using the above noted messages would succeed. Is there a way to make them fail? Some "strict"-mode for example that requires exact matches of messages?
No, that's not possible according to the pact docs:
You cannot expect a field to not be present in a response
Following Postel's law, the provider may return fields that the consumer will just ignore. The provider may have a pact with another consumer that requires those fields, so your consumer cannot tell the provider what it should not do. It can only specify what it should do.
I customized the tutorial http://assets.spring.io/wp/WebSocketBlogPost.html into my application . When sending message from the application to the server using SimpMessageSendingOperations.convertAndSendToUser("fabrice","/stayawakews2/shakebaby", "mano") the log show :
/stayawakews2/shakebaby*-userltmei5cm* .I dont know why it add the value -userltmei5cm .
thanks
this is explained in the reference docs, see the section on user destinations and also these slides.
ltmei5cm - this is a websocket session id. This value generates on client side.
One logined user can have some websocket sessions.
For each webscocket connection(session) spring create individual queue.
If you send message to specific user, message will be added to some queues.
For this reason, the user name is replaced with the webcoket session id.
From JavaDoc comment to DefaultUserDestinationResolver.java:
When a user attempts to subscribe to "/user/queue/position-updates",
the "/user" prefix is removed and a unique suffix added, resulting in
something like "/queue/position-updates-useri9oqdfzo" where the suffix
is based on the user's session and ensures it does not collide with
any other users attempting to subscribe to
"/user/queue/position-updates". When a message is sent to a user
with a destination such as "/user/{username}/queue/position-updates",
the "/user/{username}" prefix is removed and the suffix added,
resulting in something like "/queue/position-updates-useri9oqdfzo".
How can check, on server side route, if user is logged?
I would add check on 'before', but Metor.user() don't work here.
thanks in advance.
p.s. I have found How to get Meteor.user() to return on the server side?, but not work on iron-router
I'm afraid that this is not possible. I guess that the problem comes from the fact that you're trying to connect to the server with two different protocols - both literally and in logically - so there is no obvious way to relate this two actions.
There is, however, a pretty simple solution that may suit your needs. You'll need to develop a simple system of privileges tokens, or secret keys, or whatever you call them. First, create a server method
var Secrets = new Meteor.Collection("secrets"); // only on server!!!
Meteor.methods({
getSecretKey: function () {
if (!this.userId)
// check if the user has privileges
throw Meteor.Error(403);
return Secrets.insert({_id: Random.id(), user: this.userId});
},
});
Then, you can now use it on the client to get the secretKey which attach to your AJAX request (or something), either within the HTTP header or in the URL itself. Fear not!
They will all be encrypted if you're using HTTPS.
On the server side you can now retrieve the secretKey from the incoming request and check if it is present in the Secrets collection. You'll know then if the user is granted certain privileges or not.
Also you may want to remove your secret keys from the collection after some time for safety reasons.
If what you're looking to do is to authenticate the Meteor.user making the request, I'm currently doing this within the context of IronRouter.route(). The request must be made with a valid user ID and auth token in the header. I call this function from within Router.route(), which then gives me access to this.user:
###
Verify the request is being made by an actively logged in user
#context: IronRouter.Router.route()
###
authenticate = ->
# Get the auth info from header
userId = this.request.headers['x-user-id']
loginToken = this.request.headers['x-auth-token']
# Get the user from the database
if userId and loginToken
user = Meteor.users.findOne {'_id': userId, 'services.resume.loginTokens.token': loginToken}
# Return an error if the login token does not match any belonging to the user
if not user
respond.call this, {success: false, message: "You must be logged in to do this."}, 401
# Attach the user to the context so they can be accessed at this.user within route
this.user = user
###
Respond to an HTTP request
#context: IronRouter.Router.route()
###
respond = (body, statusCode=200, headers={'Content-Type':'text/json'}) ->
this.response.writeHead statusCode, headers
this.response.write(JSON.stringify(body))
this.response.end()
This code was heavily inspired by RestStop and RestStop2. It's part of a meteor package for writing REST APIs in Meteor 0.9.0+ (built on top of Iron Router). You can check out the complete source code here:
https://github.com/krose72205/meteor-restivus