mvn pact:verify does not execute provider state but #State code is executed from IDE - maven

When I execute my provider test from IDE #State method is executed, but mvn pact:verify command does not execute the #State of the provider
Provider test class:
#RunWith(PactRunner.class)
#Provider("wProvider")
#PactFolder("/home/username/workspace/automation/pactProject/pacts/")
public class WpproviderTest {
#State("wProvider will create new stuff")
public void providerState(){
System.out.println("execute the the provider state");
//some code...
System.out.println("your new stuff response is: " + jsonResponse)
}
#TestTarget
public final Target target = new HttpTarget(url, true);
#TargetRequestFilter
public void updateAuthHeaders(HttpRequest request) {
request.addHeader("some auth headers")
}
}
my pom.xml file:
<plugin>
<groupId>au.com.dius</groupId>
<artifactId>pact-jvm-provider-maven_2.12</artifactId>
<version>3.6.7</version>
<configuration>
<serviceProviders>
<serviceProvider>
<name>wProvider</name>
<requestFilter>
request.addHeader('Authorization', 'auth value')
</requestFilter>
<stateChangeRequestFilter>
request.addHeader('Authorization', 'auth value')
</stateChangeRequestFilter>
<stateChangeUrl>http://mywebsite.com/myservice/myaction
</stateChangeUrl>
<stateChangeUsesBody>true</stateChangeUsesBody>
<protocol>http</protocol>
<host>http://localhost</host>
<path></path>
<port>443</port>
<pactBroker>
<url>https://mypactbroker</url>
<authentication>
<username>my_usrname</username>
<password>my_pwd</password>
</authentication>
</pactBroker>
<insecure>true</insecure>
</serviceProvider>
</serviceProviders>
</plugin>
my pact file:
{
"provider": {
"name": "wProvider"
},
"consumer": {
"name": "tConsumer"
},
"interactions": [
{
"description": "A new interaction with wProvider",
"request": {
"method": "POST",
"path": "/somePath",
"headers": {
"Content-Type": "application/json"
},
"body": ""
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/json"
},
"body": " ",
"matchingRules": {
"body": {
// some matching rules
}
}
},
"providerStates": [
{
"name": "wProvider will create new stuff"
}
]
}
],
"metadata": {
"pactSpecification": {
"version": "3.0.0"
},
"pact-jvm": {
"version": "3.6.7"
}
}
}
When I execute mvn pact:verify -X command I see in console:
Given Wprovider will generate new stuff
[DEBUG] Invoked state change http://mywebsite.com/myservice/myaction
-> HTTP/1.1 200 OK [DEBUG] State Change: "ProviderState(name=http://mywebsite.com/myservice/myaction,
params={})" -> Ok(value={})
I am missing some settings related to #State with mvn pact:verify?

It looks like the #State annotation isn't supported for the Maven plugin (unlike the JUnit setup).
The docs have the following to say about this:
For each provider you can specify a state change URL to use to switch the state of the provider. This URL will receive the providerState description and parameters from the pact file before each interaction via a POST.
So you may need to add a dynamic endpoint (e.g. /_pact/state) that can take the request and setup the given state.

The Maven plugin (as well as the Gradle one) execute the Pact verification against a running provider when you execute pact:verify. The #State method you have defined is for a JUnit test. The Maven plugin does not execute JUnit tests, you run them as part of the test Maven phase which is executed by the Maven Surefire plugin.
The documentation link that Matt provided above will let you know how to execute state changes with pact:verify, but if you have written a JUnit test you don't need to use that.

Related

How to get Spring Actuator build information locally?

When accessing my Spring Actuator /info endpoint I receive the following information:
{
"git": {
"branch": "8743b52063cd84097a65d1633f5c74f5",
"commit": {
"id": "b3j2924",
"time": "05.07.2021 # 10:00:00 UTC"
}
},
"build": {
"encoding": {
"source": "UTF-8"
},
"version": "1.0",
"artifact": "my-artifact",
"name": "my-app",
"time": 0451570333.122000000,
"group": "my.group"
}
}
My project does not maintain a META-INF/build-info.properties file.
I now wanted to write a unit-test for that exact output but get the following error:
java.lang.AssertionError:
Expecting actual:
"{"git":{"branch":"8743b52063cd84097a65d1633f5c74f5","commit":{"id":"b3j2924","time":"05.07.2021 # 10:00:00 UTC"}}}"
to contain:
"build"
The whole build block is missing in the output.
My questions are the following:
What needs to be done to access the build information during a local unit-test run without providing a META-INF/build-info.properties.
From where does Spring Actuator retrieve the actual build information when my project does not has a META-INF/build-info.properties file so it gives me the output from above?
The build-info.properties file is typically generated at build time by Spring Boot's Maven or Gradle plugins.

.NET 6 System.Drawing.Common Runtime Switch

According to https://learn.microsoft.com/en-us/dotnet/core/compatibility/core-libraries/6.0/system-drawing-common-windows-only System.Drawing.Common is no longer supported under on non-windows OS UNLESS a runtime configuration switch is set. I've setup runtimeconfig.template.json and see the switch:
"runtimeOptions": {
"configProperties": {
"System.Drawing.EnableUnixSupport": true
}
}
inside the file .runtimeconfig.json in bin/Debug/net6.0
However when I run the app in a linux box using dotnet exec app.dll I still get PlatformNotSupportedException
The following worked for me.
Adding the following line to the .csproj file in a PropertyGroup section:
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
Next create a file named runtimeconfig.template.json in the same directory as your project file containing:
{
"configProperties": {
"System.Drawing.EnableUnixSupport": true
}
}
I used the dotnet publish command, which created a [YourAppNameHere].runtimeconfig.json file in the output directory I supplied to the dotnet publish command.
For my asp.net project, the publish resulted in the following [YourAppNameHere].runtimeconfig.jsonfile:
{
"runtimeOptions": {
"tfm": "net6.0",
"includedFrameworks": [
{
"name": "Microsoft.NETCore.App",
"version": "6.0.1"
},
{
"name": "Microsoft.AspNetCore.App",
"version": "6.0.1"
}
],
"configProperties": {
"System.Drawing.EnableUnixSupport": true,
"System.GC.Server": true,
"System.Reflection.Metadata.MetadataUpdater.IsSupported": false,
"System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false
}
}
}
This worked, where trying to follow the documentation on the page linked to in the question did not. I think this is because I was adding the "runtimeOptions" section in the runtimeconfig.template.json file, but the dotnet publish command was also adding a section named "runtimeOptions", which seems to have prevented the runtime from seeing the "System.Drawing.EnableUnixSupport" option.
For this reason, I excluded the "runTimeOptions" section in my runtimeconfig.template.json file as the publish resulted in the following file that did not work:
{
"runtimeOptions": {
"tfm": "net6.0",
"includedFrameworks": [
{
"name": "Microsoft.NETCore.App",
"version": "6.0.1"
},
{
"name": "Microsoft.AspNetCore.App",
"version": "6.0.1"
}
],
"runtimeOptions": {
"configProperties": {
"System.Drawing.EnableUnixSupport": true
}
},
"configProperties": {
"System.GC.Server": true,
"System.Reflection.Metadata.MetadataUpdater.IsSupported": false,
"System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false
}
}
}
Note the nested "runtimeOptions", which I believe was causing it to fail when trying to follow the documentation in the link from the question.
One more way is to use set switch in the code:
AppContext.SetSwitch("System.Drawing.EnableUnixSupport", true);

How to run tests programmatically in Nightwatch.js?

I'm using Nightwatch.js and trying to run E2E tests using the programmatic API as described here.
Here is my nightwatch.json file:
{
"src_folders": ["tests"],
"webdriver": {
"start_process": true,
"server_path": "node_modules/.bin/chromedriver",
"port": 9515
},
"test_settings": {
"default": {
"desiredCapabilities": {
"browserName": "chrome"
}
}
}
}
and index.js script:
const Nightwatch = require('nightwatch');
Nightwatch.runTests(require('./nightwatch.json')).then(() => {
console.log('All tests has been passed!');
}).catch(err => {
console.log(err);
});
When I run the script I get the error:
Error: An error occurred while retrieving a new session: "Connection refused to 127.0.0.1:9515". If the Webdriver/Selenium service is managed by Nightwatch, check if "start_process" is set to "true".
I feel it needs some configuration but the documentation isn't very helpful here.

How do I use CloudFormation resources in a Lambda function?

I have added a Redis ElastiCache section to my s-resource-cf.json (a CloudFormation template), and selected its hostname as an output.
"Resources": {
...snip...
"Redis": {
"Type": "AWS::ElastiCache::CacheCluster",
"Properties": {
"AutoMinorVersionUpgrade": "true",
"AZMode": "single-az",
"CacheNodeType": "cache.t2.micro",
"Engine": "redis",
"EngineVersion": "2.8.24",
"NumCacheNodes": "1",
"PreferredAvailabilityZone": "eu-west-1a",
"PreferredMaintenanceWindow": "tue:00:30-tue:01:30",
"CacheSubnetGroupName": {
"Ref": "cachesubnetdefault"
},
"VpcSecurityGroupIds": [
{
"Fn::GetAtt": [
"sgdefault",
"GroupId"
]
}
]
}
}
},
"Outputs": {
"IamRoleArnLambda": {
"Description": "ARN of the lambda IAM role",
"Value": {
"Fn::GetAtt": [
"IamRoleLambda",
"Arn"
]
}
},
"RedisEndpointAddress": {
"Description": "Redis server host",
"Value": {
"Fn::GetAtt": [
"Redis",
"Address"
]
}
}
}
I can get CloudFormation to output the Redis server host when running sls resources deploy, but how can I access that output from within a Lambda function?
There is nothing in this starter project template that refers to that IamRoleArnLambda, which came with the example project. According to the docs, templates are only usable for project configuration, they are not accessible from Lambda functions:
Templates & Variables are for Configuration Only
Templates and variables are used for configuration of the project only. This information is not usable in your lambda functions. To set variables which can be used by your lambda functions, use environment variables.
So, then how do I set an environment variable to the hostname of the ElastiCache server after it has been created?
You can set environment variables in the environment section of a function's s-function.json file. Furthermore, if you want to prevent those variables from being put into version control (for example, if your code will be posted to a public GitHub repo), you can put them in the appropriate files in your _meta/variables directory and then reference those from your s-function.json files. Just make sure you add a _meta line to your .gitignore file.
For example, in my latest project I needed to connect to a Redis Cloud server, but didn't want to commit the connection details to version control. I put variables into my _meta/variables/s-variables-[stage]-[region].json file, like so:
{
"redisUrl": "...",
"redisPort": "...",
"redisPass": "..."
}
…and referenced the connection settings variables in that function's s-function.json file:
"environment": {
"REDIS_URL": "${redisUrl}",
"REDIS_PORT": "${redisPort}",
"REDIS_PASS": "${redisPass}"
}
I then put this redis.js file in my functions/lib directory:
module.exports = () => {
const redis = require('redis')
const jsonify = require('redis-jsonify')
const redisOptions = {
host: process.env.REDIS_URL,
port: process.env.REDIS_PORT,
password: process.env.REDIS_PASS
}
return jsonify(redis.createClient(redisOptions))
}
Then, in any function that needed to connect to that Redis database, I imported redis.js:
redis = require('../lib/redis')()
(For more details on my Serverless/Redis setup and some of the challenges I faced in getting it to work, see this question I posted yesterday.)
update
CloudFormation usage has been streamlined somewhat since that comment was posted in the issue tracker. I have submitted a documentation update to http://docs.serverless.com/docs/templates-variables, and posted a shortened version of my configuration in a gist.
It is possible to refer to a CloudFormation output in a s-function.json Lambda configuration file, in order to make those outputs available as environment variables.
s-resource-cf.json output section:
"Outputs": {
"redisHost": {
"Description": "Redis host URI",
"Value": {
"Fn::GetAtt": [
"RedisCluster",
"RedisEndpoint.Address"
]
}
}
}
s-function.json environment section:
"environment": {
"REDIS_HOST": "${redisHost}"
},
Usage in a Lambda function:
exports.handler = function(event, context) {
console.log("Redis host: ", process.env.REDIS_HOST);
};
old answer
Looks like a solution was found / implemented in the Serverless issue tracker (link). To quote HyperBrain:
CF Output variables
To have your lambda access the CF output variables you have to give it the cloudformation:describeStacks access rights in the lambda IAM role.
The CF.loadVars() promise will add all CF output variables to the process'
environment as SERVERLESS_CF_OutVar name. It will add a few ms to the
startup time of your lambda.
Change your lambda handler as follows:
// Require Serverless ENV vars
var ServerlessHelpers = require('serverless-helpers-js');
ServerlessHelpers.loadEnv();
// Require Logic
var lib = require('../lib');
// Lambda Handler
module.exports.handler = function(event, context) {
ServerlessHelpers.CF.loadVars()
.then(function() {
lib.respond(event, function(error, response) {
return context.done(error, response);
});
})
};

Protractor proxy settings configuration is not passed to Saucelabs

To enable saucelabs proxy to work in older version of protractor, we were overriding sendRequest method by setting host and port in below index.js:
protractor\node_modules\selenium-webdriver\http\index.js
Now protractor allows you set the proxy through capabilities object (as shown below) which should be passed to index.js sendRequest new parameter called 'opt_proxy'.
capabilities: {
"browserName": "chrome",
'proxy': {
'proxyType': 'manual',
'httpProxy': 'appproxy.web.abc.com:84'
},
"chromeOptions": {
"args": [
"--disable-extensions",
"--test-type"
]
},
"customData": {
"usageBracket" : "1",
"displayName" : "Chrome",
"id" : "CH"
}
}
However, when I am still getting null for opt_proxy. Is there anything I am doing wrong? I even tried passing through CLI using --proxy="" but it still get null.
I have gotten my proxy configuration to work with Sauce Labs using the sauceAgent util provided within Protractor. Here is a code snippet from my protractor config file.
var HttpsProxyAgent = require("https-proxy-agent");
var agent = new HttpsProxyAgent('http://localhost:56193'); //Insert your proxy info here
exports.config = {
sauceUser: process.env.SAUCE_USERNAME,
sauceKey: process.env.SAUCE_ACCESS_KEY,
sauceAgent: agent,
capabilities: {
browserName: 'chrome',
chromeOptions: {
args: [
'--proxy-server=socks5://host:port',
]
},
},

Resources