I can't get a functional test working, so I ran a var_dump on the $crawler object to see what was going on.
I noticed the $uri of the crawler is set to http://localhost/items - I believe this is the issue. I have set the path to be /items so that is okay, but my web app is not installed at localhost (it is at http://localhost/myapp/ - I also have an alias http://myapp.local/).
How do I configure PHPUnit (I am using Symfony2 if that makes a difference) so it points to either http://localhost/myapp/items or http://myapp.local/items for this functional test?
If anyone is ever curious how I fixed this, in your $client you can set it like this:
$client = static::createClient(array(), array(
'HTTP_HOST' => 'myapp.local',
....
Related
This may involve way too many specific technologies for anyone to be able to answer, but I thought I'd give it a shot. I've ready SO Many tutorials and feel like I'm SO close...there's maybe just one thing I'm missing.
My goal here is multi-part, and as far as I know my issue is only really with one part at this point
Take a simple Symfony app (it happens to be using version 5) with a single controller, put it up on Amazon AWS as an API Gateway. I've accomplished this with the help of bref
(https://bref.sh/) and requiring it in my Symfony project. I have a serverless.yml file for which I can use the serverless deploy command to upload it as an API Gateway to AWS. It even tests out in a browser, no problem.
Take that API Gateway and link it to an AWS Lambda function, to eventually be used as a Lambda function for an event to be triggered upon sign-in etc. using Amazon Cognito. I've achieved this using tutorials, I can see it linked to the API Gateway when I go into my Lambda function that was uploaded during step 1 using bref.
Take this Lambda and link it to the Cognito Lambda trigger for Pre sign-up. I've done this, it's a very simple setting.
Now in the single file PHP examples for how to use bref with AWS, you get something as follows:
require __DIR__.'/vendor/autoload.php';
lambda(function ($event) {
return $event;
});
I have uploaded this as a different lambda (nothing to do with Symfony here), set that to be the trigger on Cognito's Pre-sign-up event, and it works fine. It does nothing granted, but it passes the information along correctly to where it does not cause any errors of any kind.
Now when I try this same thing with a Symfony app, I have IndexController.php in my src/Controller directory, that looks like this:
<?php
namespace App\Controller;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Aws\CloudWatchLogs\CloudWatchLogsClient;
use Maxbanton\Cwh\Handler\CloudWatch;
use Monolog\Logger;
use Monolog\Formatter\JsonFormatter;
class IndexController extends AbstractController
{
/**
* #Route("/", name="index")
*/
public function index(Request $request, LoggerInterface $logger)
{
$this->awsLogger($request);
return new JsonResponse(json_encode($request->query->all()));
}
private function awsLogger(Request $request)
{
/**
* This is only here for now because I couldn't get CloudWatch logging working any better way.
*/
$sdkParams = [
'region' => 'us-east-2',
'version' => 'latest',
'credentials' => [
'key' => 'AKIAIGFNOM3BKSE6HQ6A',
'secret' => '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',
]
];
// Instantiate AWS SDK CloudWatch Logs Client
$client = new CloudWatchLogsClient($sdkParams);
// Log group name, will be created if none
$groupName = 'lambda_symfony_test';
// Log stream name, will be created if none
$streamName = 'dev';
// Days to keep logs, 14 by default. Set to `null` to allow indefinite retention.
$retentionDays = 30;
// Instantiate handler (tags are optional)
$handler = new CloudWatch($client, $groupName, $streamName, $retentionDays, 10000, ['tag' => 'lambda']);
// Optionally set the JsonFormatter to be able to access your log messages in a structured way
$handler->setFormatter(new JsonFormatter());
// Create a log channel
$log = new Logger('channel');
// Set handler
$log->pushHandler($handler);
// Add records to the log
$log->debug(print_r($request->query->all(), true));
}
}
I completely understand this will cause an error as a lambda, because the JsonResponse is not what Cognito is expecting to see back. However I was at least hoping that I'd hit the call to the logger so I could see what my request object looked like, and I could see what I was working with in terms of what Cognito is passing into this Lambda. This will help me eventually figure out what I need to return. And as far as I know I can't just use the "lambda" wrapper around a controller method like what was done in the simple example I mentioned I had working. However it's not even getting this far, instead the following is what appears in my logs on CloudWatch:
21:34:58
Fatal error: Uncaught Exception: The lambda was not invoked via HTTP through API Gateway: this is not supported by this runtime in /var/task/vendor/bref/bref/src/Runtime/PhpFpm.php:120
So my question is what am I missing here? This API works completely fine through a browser when I just pass it something as a GET request. What am I missing in my configurations? Here is my serverless.yml file for the Symfony app:
service: lambda-test-symfony
provider:
name: aws
region: us-east-2
runtime: provided
environment:
# Symfony environment variables
APP_ENV: prod
plugins:
- ./vendor/bref/bref
package:
exclude:
- node_modules/**
- tests/**
functions:
lambdatest:
handler: public/index.php
layers:
- ${bref:layer.php-72-fpm}
events:
- http: 'ANY /'
- http: 'ANY /{proxy+}'
Here are also some screenshots from my Lambda configurations on AWS:
https://i.stack.imgur.com/TDMZj.png
https://i.stack.imgur.com/ciehT.png
And here are some from the setup of the API Gateway:
https://i.stack.imgur.com/RL7D9.png
https://i.stack.imgur.com/LPcsh.png
https://i.stack.imgur.com/RVNwN.png
https://i.stack.imgur.com/4bs0u.png
I'm still fairly new to the whole AWS/serverless thing, so I could be missing something really obvious here. I'm not 100% sure whether the issue is with my code or my configuration though. Any help would be appreciated!
I have C#/ASP.NET web service which is running on a remote server and uses WSDL. It worked fine up until recently when it was moved to another server. However this means I had to change the database connection string, which was hard coded, so the code needed to be rebuilt on my development machine and uploaded to the server.
The service is called from a PHP script running on another web server using SOAP.
For some reason, from what I can tell, it's trying to run the old code, even though I've modified it.
e.g. if I change my web service function to just return, for example, "Hello, World", it seems to still try to connect to the database, etc. (but failing because that database no longer exists, I believe it's still trying to use the old connection string)
If I remove the function, it tells me that the function doesn't exist. (So it is looking in the right place)
If I add a new function and try to call it from the php script, I get the error
The server did not recognize the value of HTTP Header SOAPAction
If I try and test it on the actual server using the http://localhost/Myservice/Myservice.asmx everything works fine!
Here is the code I am using to call:
ini_set("soap.wsdl_cache_enabled", 0);
$client = new SoapClient("http://1.2.3.4:8083/MyService/MyService.asmx?WSDL&revision=1", array('cache_wsdl' => WSDL_CACHE_NONE));
$input = new stdClass;
$input->inputvals = '15707F';
echo "Functions: |";
print_r($client->__getFunctions()); // Lists all functions including new ones
echo "|\n\n";
$Response = $client->checkPrice($input);
print_r($Response);
To deploy the code this is what I'm doing - on local development machine, I Publish the solution to File System (for some reason I can't get IIS working on this machine). Then stop IIS on server machine, "Remove Application" in IIS, copy my files in, "Convert to Application", then restart IIS.
The server seems to get a wrong SOAPAction HTTP-Head attribute (which is part of the SOAP-standard) from your SOAP-Client. Check the wsdl for the expected one (wsdl:binding section) and make sure that you're sending it with the expected value.
OK, I'm not completely satisfied with this solution but here is how I got it working.
I don't know enough about WSDL to know why or how this happens, but the WSDL xml file had the following lines in it (as per my comment on my own original post).
<wsdl:service name="Myservice">
<wsdl:port name="MyserviceSoap" binding="tns:MyserviceSoap">
<soap:address location="http://1.2.3.4/Myservice/Myservice.asmx" />
</wsdl:port>
.
.
.
</wsdl:service>
Note the lack of the :8083 port on the location. Originally I had moved the service from 1.2.3.4 to 1.2.3.4:8083 in order to keep it running during the transition - the router then uses NAT to forward it to the correct server on their internal network. When the owners of the server had said they turned off, all they had turned off was the MS SQL server on that computer, so my old web service was still working away. (I had kind of taken their word for it when they said they had turned off the server)
To work around this, I overrode the __doRequest() function in the SoapClient class in my PHP client script to manually add the :8083 to the URL of the location.
class SoapClient8083 extends SoapClient
{
public function __doRequest($request, $location, $action, $version, $one_way = 0) {
$location_parts = explode("//", $location);
if (count($location_parts) == 2) {
$location_url_parts = explode("/", $location_parts[1]);
$location_url_parts[0] .= ":8083";
$new_location = $location_parts[0] . "//" . implode("/", $location_url_parts);
}
if (isset($new_location) && $new_location)
$location = $new_location;
return parent::__doRequest($request, $location, $action, $version, $one_way);
}
}
So it was getting the function list from the correct place which was why it was correctly recognising when I removed the function, but then contacting the wrong place to actually implement the functions.
... 8 hours of trying to debug later ...
Anyway, I'd rather not stick with this solution and instead figure out why the WSDL doesn't put the port number on the <soap:address location... />
Thanks for the responses - they did encourage me to look in the right direction...
I am testing a RESTful API and need to test that the application parses incoming data properly. The type of incoming data can be in either XML or JSON format. The application looks at the Content-Type value in the header to determine how the data will be treated.
The applicatoin works well but I am not able to write a proper functional test for it in Symfony2 as I seem to be unable to set the Content-Type when calling the URL.
I am doing something like this:
$crawler = $client->request('PUT','/api/record/, array("data" => $xmlData), array(), array("Content-Type" => "text/xml"));
While it is not throwing any errors, my application is unable to pick it up. I successfully tested my script with Firefox's "Poster" plugin as well as cUrl.
Any help/idea would be greatly appreciated.
From what I can see on the Symfony2 testing section (which uses Crawler and Client to interact with the application), you are suppose to have it as 'CONTENT_TYPE' => 'application/xml'. So you should try the following:
$crawler = $client->request('PUT','/api/record/', array("data" => $xmlData), array(), array('CONTENT_TYPE' => 'application/xml'));
Note that I changed it from text/xml to application/xml, but both should work.
I'm trying the above code to set a message and redirect to a different location like this
and i'm redirecting from
example.com/somewere/index.php
to
example.com
My problem is when i get to example.com drupal doesen't keep the session,
and the message is not shown.
Any idea will be much appreciated.
chdir('../');
require_once './includes/bootstrap.inc';
require_once './includes/common.inc';
require_once './includes/module.inc';
$url = "http://".$_SERVER['SERVER_NAME'];
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
drupal_set_message(t('Your message has been sent'), 'status', TRUE);
drupal_goto($url);
i'm taking a form and some other elements of the page and putting it outside drupal in a bootstrap that has session enable.
in
example.com/somewere/
my message is there
but on example.com/
i dont get the message
the server open me a diffrent session
can it be because i use a diffrent htaccess file in example.com/somewere/
i know messages are session based
is there a way to bypass the problem because there on the same domain and same drupal just different access position ?
I would run session_get_cookie_params to see whether the path is just /. It might be that PHP sets the path to /somewhere for the session cookie and so the Drupal install in your install doesnt have a session cookie after that.
You really don't need to go to these lengths to redirect a Drupal page, something as simple as this in a custom module will do it:
function mymodule_init() {
if ($_GET['q'] == 'index.php') {
$url = "http://".$_SERVER['SERVER_NAME'];
drupal_set_message(t('Your message has been sent'), 'status', TRUE);
drupal_goto($url);
}
}
I'm not entirely sure why you would do this is though, from your message I gather this in response to a form submission? If so you'd be better off setting $form_state['redirect'] = $url in a submission handler for the form.
I'm writing a simple REST service in Node.js (just experimenting), trying to figure out if Node has matured enough yet. I'm also using NodeUnit for my unit testing.
Now, NodeUnit works fine as a testing framework for testing GET-requests, using the HttpUtils, however, testing POST-requests doesn't seem to be obvious.
Testing GET looks like this:
exports.testHelloWorld = function(test) {
test.expect(1);
httputil(app.cgi(), function(server, client) {
client.fetch('GET', '/', {}, function (resp) {
test.equals('hello world'), resp.body);
test.done();
});
});
}
But how do I test POST-requests? I can change 'GET' to 'POST' and try to write something to 'client', however this doesn't work before .fetch is called because there's no connection yet. And it doesn't work in the .fetch callback function either, because at that time the request has already been executed.
I've looked into the nodeunit code, and there doesn't seem to be support for POSTing data at the moment. So here's my questions:
What does it take to test POST-requests?
Should I even test POST-requests in a unit test, or does that fall under an integration test and I should use another approach?
You could try this library instead of nodeunit: https://github.com/masylum/testosterone
It's built specifically to test web apps over http.
I've just written this library for testing HTTP servers with nodeunit:
https://github.com/powmedia/nodeunit-httpclient