Check HTTP status in cycle. Behat + Mink, Goutte driver - behat

I try to check HTTP status in cycle:
foreach ($arrayOfLinks as $link) {
$this->getMainContext()->getSubcontext('mink')->visit($link);
$statusCode = $this->getSession()->getStatusCode();
if ($statusCode < 200 || $statusCode > 299) {
print 'Broken link ' . $href . ' status code is ' . $statusCode . "\n";
}
}
In the cycle it does not work consistently. It successfully checks about 20-40 links and then fails with error
The current node list is empty.
How can I fix it and what means this error?

I resolved problem. When I looking for all links on page and check status in the same foreach - I get error. When I split cycle into two cycles - it works

Related

E_WARNING[2]: fread(): Length parameter must be greater than 0 at

First of all sorry for my noobness, i just started learning and trying to dive right in the rabbit hole.
I am updating old php code so it will work on 7.5 i already fixed loads of errors but am stuck (even after help from this thread Warning: fread(): Length parameter must be greater than 0
I get the error (in title) on this code
$data = fread($fp = fopen($this->_cacheFile, 'r'), filesize($this->_cacheFile));
fclose($fp);
With help from the thread above i started recoding to this
$handle = fopen($this->_cacheFile, 'r');
$data = '';
if(filesize($this->_cacheFile) > 0)
$data = fread($handle,filesize($this->_cacheFile, 'r'));
echo $data;
fclose($handle);
Unfortunately that did not do the trick it just returns an empty page:( error is gone though:)
Anyone?
The solution from the thread mentionen

Rancid/ Looking Glass perl script hitting an odd error: $router unavailable

I am attempting to set up a small test environment (homelab) using CentOS 6.6, Rancid 3.1, Looking Glass, and some Cisco Switches/Routers, with httpd acting as the handler. I have picked up a little perl by means of this endeavor, but python (more 2 than 3) is my background. Right now, everything on the rancid side of things works without issue: bin/clogin successfully logs into all of the equipment in the router.db file, and logging of the configs is working as expected. All switches/routers to be accessed are available and online, verified by ssh connection to devices as well as using bin/clogin.
Right now, I have placed the lg.cgi and lgform.cgi files into var/www/cgi-bin/ which allows the forms to be run as cgi scripts. I had to modify the files to split on ';' instead of ':' due to the change in the .db file in Rancid 3.1:#record = split('\:', $_); was replaced with: #record = split('\;', $_); etc. Once that change was made, I was able to load the lgform.cgi with the proper router.db parsing. At this point, it seemed like everything should be good to go. When I attempt to ping from one of those devices out to 8.8.8.8, the file correctly redirects to lg.cgi, and the page loads, but with
main is unavailable. Try again later.
as the error, where 'main' is the router hostname. Using this output, I was able to find the function responsible for this output. Here it is before I added anything:
sub DoRsh
{
my ($router, $mfg, $cmd, $arg) = #_;
my($ctime) = time();
my($val);
my($lckobj) = LockFile::Simple->make(-delay => $lock_int,
-max => $max_lock_wait, -hold => $max_lock_hold);
if ($pingcmd =~ /\d$/) {
`$pingcmd $router`;
} else {
`$pingcmd $router 56 1`;
}
if ($?) {
print "$router is unreachable. Try again later.\n";
return(-1);
}
if ($LG_SINGLE) {
if (! $lckobj->lock("$cache_dir/$router")) {
print "$router is busy. Try again later.\n";
return(-1);
}
}
$val = &DoCmd($router, $mfg, $cmd, $arg);
if ($LG_SINGLE) {
$lckobj->unlock("$cache_dir/$router");
}
return($val);
}
In order to dig in a little deeper, I peppered that function with several print statements. Here is the modified function, followed by the output from the loaded lg.cgi page:
sub DoRsh
{
my ($router, $mfg, $cmd, $arg) = #_;
my($ctime) = time();
my($val);
my($lckobj) = LockFile::Simple->make(-delay => $lock_int,
-max => $max_lock_wait, -hold => $max_lock_hold);
if ($pingcmd =~ /\d$/) {
`$pingcmd $router`;
} else {
`$pingcmd $router 56 1`;
}
print "About to test the ($?) branch.\n";
print "Also who is the remote_user?:' $remote_user'\n";
print "What about the ENV{REMOTE_USER} '$ENV{REMOTE_USER}'\n";
print "Here is the ENV{HOME}: '$ENV{HOME}'\n";
if ($?) {
print "$lckobj is the lock object.\n";
print "#_ something else to look at.\n";
print "$? whatever this is suppose to be....\n";
print "Some variables:\n";
print "$mfg is the mfg.\n";
print "$cmd was the command passed in with $arg as the argument.\n";
print "$pingcmd $router\n";
print "$cloginrc - Is the cloginrc pointing correctly?\n";
print "$LG_SINGLE the next value to be tested.\n";
print "$router is unreachable. Try again later.\n";
return(-1);
}
if ($LG_SINGLE) {
if (! $lckobj->lock("$cache_dir/$router")) {
print "$router is busy. Try again later.\n";
return(-1);
}
}
$val = &DoCmd($router, $mfg, $cmd, $arg);
if ($LG_SINGLE) {
$lckobj->unlock("$cache_dir/$router");
}
return($val);
}
OUTPUT:
About to test the (512) branch.
Also who is the remote_user?:' '
What about the ENV{REMOTE_USER} ''
Here is the ENV{HOME}: '.'
LockFile::Simple=HASH(0x1a13650) is the lock object.
main cisco ping 8.8.8.8 something else to look at.
512 whatever this is suppose to be....
Some variables:
cisco is the mfg.
ping was the command passed in with 8.8.8.8 as the argument.
/bin/ping -c 1 main
./.cloginrc - Is the cloginrc pointing correctly?
1 the next value to be tested.
main is unreachable. Try again later.
I can provide the code for when DoRsh is called, if necessary, but it looks mostly like this:&DoRsh($router, $mfg, $cmd, $arg);.
From what I can tell the '$?' special variable (or at least according to
this reference it is a special var) is returning the 512 value, which is causing that fork to test true. The problem is I don't know what that 512 means, nor where it is coming from. Using the ref site's description ("The status returned by the last pipe close, backtick (``) command, or system operator.") and the formation of the conditional tree above, I can see that it is some error of some kind, but I don't know how else to proceed with this inspection. I'm wondering if maybe it is in response to some permission issue, since the remote_user variable is null, when I didn't expect it to be. Any guidance anyone may be able to provide would be helpful. Furthermore, if there is any information that I may have skipped over, that I didn't think to include, or that may prove helpful, please ask, and I will provide to the best of my ability
May be you put in something like
my $pingret=$pingcmd ...;
print 'Ping result was:'.$pingret;
And check the returned strings?

Rename screenshots taken on failure in PHPUnit Selenium

PHPUnit has an option to take a screenshot upon a Selenium test case failure. However, the screenshot filename generated is a hash of something - I don't know what exactly. While the test result report allows me to match a particular failed test case with a screenshot filename, this is troublesome to use.
If I could rename the screenshot to use the message from the failed assert as well as a timestamp for instance, it makes the screenshots much easier to cross-reference. Is there any way to rename the generated screenshot filename at all?
You could try something like this (it's works with selenium2):
protected function tearDown() {
$status = $this->getStatus();
if ($status == \PHPUnit_Runner_BaseTestRunner::STATUS_ERROR || $status == \PHPUnit_Runner_BaseTestRunner::STATUS_FAILURE) {
$file_name = sys_get_temp_dir() . '/' . get_class($this) . ':' . $this->getName() . '_' . date('Y-m-d_H:i:s') . '.png';
file_put_contents($file_name, $this->currentScreenshot());
}
}
Also uncheck
protected $captureScreenshotOnFailure = FALSE;
I ended up using a modified version of #sectus' answer:
public function onNotSuccessfulTest(Exception $e) {
$file_name = '/' . date('Y-m-d_H-i-s') . ' ' . $this->getName() . '.png';
file_put_contents($this->screenshotPath . $file_name, base64_decode($this->captureEntirePageScreenshotToString()));
parent::onNotSuccessfulTest($e);
}
Although the conditional check in tearDown() works fine, based on Extending phpunit error message, I decided to go with onNotSuccessfulTest() as it seemed cleaner.
The filename could not accept colons :, or I would get an error message from file_get_contents: failed to open stream: Protocol error
The function currentScreenshot also did not exist, so I ended up taking the screenshot in a different way according to http://www.devinzuczek.com/2011/08/taking-a-screenshot-with-phpunit-and-selenium-rc/.
Another method I played around with, as I still wanted to use $this->screenshotUrl and $this->screenshotPath for convenient configuration:
I overwrote takeScreenshot from https://github.com/sebastianbergmann/phpunit-selenium/blob/master/PHPUnit/Extensions/SeleniumTestCase.php
protected function takeScreenshot() {
if (!empty($this->screenshotPath) &&
!empty($this->screenshotUrl)) {
$file_name = '/' . date('Y-m-d_H-i-s') . ' ' . $this->getName() . '.png';
file_put_contents($this->screenshotPath . $file_name, base64_decode($this->captureEntirePageScreenshotToString()));
return 'Screenshot: ' . $this->screenshotUrl . '/' . $file_name . ".png\n";
} else {
return '';
}
}

LDAP bind with Win Server 2008 R2 Standard AD fails

The environment is a single server running Win Server 2008 R2 Standard with SP1 with Apache 2.2 and PHP 5.3.19.
I have a PHP script that attempts to do an LDAP bind to the Win Server 2008 R2 Active Directory and fails no matter what variations I try. I put in a lot of echos to see the results at each step, and I've discovered that ldap_connect ALWAYS connects. I can put total garbage in the URL and it never fails. The latest iteration of my PHP script does an anonymous bind, then does an ldap_search, which fails.
Here's the script (actual domain, user & pswd changed):
<?php
define(LDAP_OPT_DIAGNOSTIC_MESSAGE, 0x0032);
ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, 7);
echo "<br>LDAP set debug level: " . ldap_errno($ad) . ' ' . ldap_error($ad);
$LDAPhost = 'ldap://myDomain.com';
$LDAPport = '3268';
$ad = ldap_connect($LDAPhost, $LDAPport);
echo "<br>LDAP connect to $LDAPhost: " . ldap_errno($ad) . ' ' . ldap_error($ad);
if ($ad) {
ldap_set_option($ad, LDAP_OPT_PROTOCOL_VERSION, 3);
echo "<br>LDAP set protocol to version 3: " . ldap_errno($ad) . ' ' . ldap_error($ad);
ldap_set_option($ad, LDAP_OPT_REFERRALS, 0);
echo "<br>LDAP set referrals to 0: " . ldap_errno($ad) . ' ' . ldap_error($ad);
$bind = ldap_bind($ad);
echo "<br>LDAP bind: " . ldap_errno($ad) . ' ' . ldap_error($ad);
$baseDN = 'CN=Users,DC=myDomain,DC=com';
$filter = '(objectClass=*)';
$search = ldap_search($ad, $baseDN, $filter);
echo "<br>LDAP search $baseDN $filter: " . ldap_errno($ad) . ' ' . ldap_error($ad);
if ($rec = ldap_get_entries($ad, $search)) {
echo "<br>LDAP get entries: " . ldap_errno($ad) . ' ' . ldap_error($ad);
for ($i = 0; $i < $rec["count"]; $i++) {
echo "<br>$rec[0]['uid'][0]";
echo "<br>$rec[0]['givenname'][0]";
}
} else {
echo '<br>Record not found.';
}
ldap_close($ad);
} else {
echo '<br><br>Could not connect.';
}
?>
The displayed results are:
LDAP set debug level:
LDAP connect to ldap://myDomain.com: 0 Success
LDAP set protocol to version 3: 0 Success
LDAP set referrals to 0: 0 Success
LDAP bind: 0 Success
LDAP search CN=Users,DC=myDomain,DC=com (objectClass=*): 1 Operations error
Record not found.
Using the Windows LDP.exe utility, I am able to bind with the same user/pswd credentials used in the test.
I would love to know exactly what to put as the base DN, i.e. what is ldap_bind comparing these values to? Something in Active Directory? Something in the registry? Something else?
Searching for this stuff turns up lots of examples, but none that work for me. Any ideas?
The Base DN you need is a valid DN in your AD. How do you find a base DN? Well you need to look at the rootDSE, to see what the namingContexts attribute says.
If you have a Unix box with ldapsearch, you can do an
ldapsearch -x -h mydomain.com -p3268 | less to see what namingContexts values are.
AD usually has 4 namingContexts values as I recall by default. (Don't have an AD box to do a quick test against). Many GUI LDAP tools can let you connect and look at the rootDSE or else have a GUI way to see it.
One thing to note is if the base DN doesn't seem to work and you are sure of everything, try using the 2003 format for the username: user#domain instead of the DN. There seems to be an issue where a domain that was migrated from a 2003 controller to a 2008 controller might have issues binding using PHP LDAP functions. I don't have the full details as I'm still exploring it but the 2003 format works on a 2008 R2 domain controller. Below is a sample basic function used in testing.
# $ldapconn = a valid connection
# $username = a username in the format 'username#domain'
# #password = the password for the above user
function ad_auth($ldapconn,$username,$password){
ldap_set_option ($ldapconn, LDAP_OPT_REFERRALS, 0);
ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);
try {
$ldap_bind = ldap_bind($ldapconn, $username, $password);
} catch (Exception $e){
# Your error code
}
return $ldap_bind;
}
Usage: $rs = ad_auth($ldapconn,$username,$password);
If I figure out the cause I'll post it.

401 Error "oauth_problem=nonce_used" Adding Products To Magento w/ Rest API

Getting a 401 status with "oauth_problem=nonce_used" message return when attempting to add products to Magento using the rest api. Oddly, the products are still get imported but it's really throwing me off because I'm not getting the product id's back in which to update the stock info.
Magento install is brand new (crucialwebhost installer) 1.7.0.2 and the code I'm using is pretty much copied and pasted from magento site...
$callbackUrl = '****';
$temporaryCredentialsRequestUrl = "*****/oauth/initiate?oauth_callback=".urlencode($callbackUrl);
$adminAuthorizationUrl = '*****/admin/oauth_authorize';
$accessTokenRequestUrl = '*****/oauth/token';
$apiUrl = '*****/api/rest';
$consumerKey = '*****';
$consumerSecret = '******';
try
{
$authType = ($_SESSION['state'] == 2) ? OAUTH_AUTH_TYPE_AUTHORIZATION : OAUTH_AUTH_TYPE_URI;
$oauthClient = new OAuth($consumerKey, $consumerSecret, OAUTH_SIG_METHOD_HMACSHA1, $authType);
$oauthClient->enableDebug();
if(!isset($_GET['oauth_token']) && !$_SESSION['state'])
{
$requestToken = $oauthClient->getRequestToken($temporaryCredentialsRequestUrl);
$_SESSION['secret'] = $requestToken['oauth_token_secret'];
$_SESSION['state'] = 1;
header('Location: '.$adminAuthorizationUrl.'?oauth_token='.$requestToken['oauth_token']);
exit;
} else if($_SESSION['state'] == 1)
{
$oauthClient->setToken($_GET['oauth_token'], $_SESSION['secret']);
$accessToken = $oauthClient->getAccessToken($accessTokenRequestUrl);
$_SESSION['state'] = 2;
$_SESSION['token'] = $accessToken['oauth_token'];
$_SESSION['secret'] = $accessToken['oauth_token_secret'];
header('Location: '.$callbackUrl);
exit;
} else
{
$oauthClient->setToken($_SESSION['token'], $_SESSION['secret']);
$resourceUrl = "$apiUrl/products";
$productData = json_encode(array(
'type_id' => 'simple',
'attribute_set_id' => 4,
'sku' => $local_product['sku'],
'weight' => 1,
'status' => 1,
'visibility' => 4,
'name' => $local_product['name'],
'description' => $local_product['description'],
'short_description' => $local_product['description'],
'price' => $local_product['price'],
'tax_class_id' => 0,
));
$headers = array('Content-Type' => 'application/json');
$oauthClient->fetch($resourceUrl, $productData, OAUTH_HTTP_METHOD_POST, $headers);
$respHeader = $oauthClient->getLastResponseHeaders();
}
} catch(OAuthException $e)
{
print_r($e);
}
}
session_destroy();
Exact error: {"messages":{"error":[{"code":401,"message":"oauth_problem=nonce_used"}]}}
In Mage_Api2_Model_Resource, about line 227, locate
$this->getResponse()->setHeader('Location', $newItemLocation);
and insert just after this:
$this->getResponse()->setHttpResponseCode(202);
Ref: Wikipedia "HTTP Location":
The HTTP Location header field is returned in responses from an HTTP
server under two circumstances:
To ask a web browser to load a different web page. In this
circumstance, the Location header should be sent with an HTTP status
code of 3xx.
To provide information about the location of a newly
created resource. In this circumstance, the Location header should
be sent with an HTTP status code of 201 or 202
I had exactly the same problem and spend weeks tracking down the problem. It seems to be a strange combination of Apache with PHP and Rewriting. In the end I created a clean installation and the problem was gone. I also tried to create a second installation where the problem could be observed but failed - the error appeared only in my production system, not in any of test installations...
I looked at this and from what I see in the code, it looks like OAuth register all your calls and if it find out that the exact same nonce was actually used with the exact same timestamp as some previous call, it will just discard it with this very specific oauth_problem=nonce_used error.
Code from app/code/core/Mage/Oauth/Model/Server.php
/**
* Validate nonce request data
*
* #param string $nonce Nonce string
* #param string|int $timestamp UNIX Timestamp
*/
protected function _validateNonce($nonce, $timestamp)
{
$timestamp = (int) $timestamp;
if ($timestamp <= 0 || $timestamp > (time() + self::TIME_DEVIATION)) {
$this->_throwException('', self::ERR_TIMESTAMP_REFUSED);
}
/** #var $nonceObj Mage_Oauth_Model_Nonce */
$nonceObj = Mage::getModel('oauth/nonce');
$nonceObj->load($nonce, 'nonce');
if ($nonceObj->getTimestamp() == $timestamp) {
$this->_throwException('', self::ERR_NONCE_USED);
}
$nonceObj->setNonce($nonce)
->setTimestamp($timestamp)
->save();
}
So I would say, when you do calls through Magento API in REST you should take extra care that each and every request you make have its own unique generated combinaison timestamp / nonce value.
Also see
oauth_nonce. A random value, uniquely generated by the application.
oauth_timestamp. A positive integer, expressed in the number of seconds since January 1, 1970 00:00:00 GMT.
And
nonce_used: The nonce-timestamp combination has already been used.
From this source : http://devdocs.magento.com/guides/v2.0/get-started/authentication/gs-authentication-oauth.html
I had the exact same problem and to solve it I looked at the mod_rewrite apache module and turned on logging for this module which is done by adding this to your apache httpd.conf file (this is for apache 2.4x , 2.2x needs to be done differently
<IfModule mod_rewrite.c>
LogLevel mod_rewrite.c:trace8
</IfModule>
The errors are then logged out to the apache standard error_log
When I looked at the rewrite here I could see that my post request was being rewritten twice, the first time it add the products to magento and the second time it failed to add the product again as the nonce was used, obviously.
I could see that the rewrite rule that was causing this in the .htaccess was the one
## workaround for HTTP authorization
## in CGI environment
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
I check my configuration and I was indeed running fast cgi php and I checked this by checking the value of Server API from a php info script. I had spent so long trying to solve this that I knowing the root cause I simply changed PHP from CGI php to an apache module and hey preto my post request now is only rewritten once and returns that all elusive 200 response code.
Work Around:
Use SOAP API.
Reason for not using it before:
SOAP API didn't provide ability to at custom product attributes or product quantity increment fields.
Fix:
Add any field you want to the product using the SOAP api by first creating an array of objects for them like this (last 4 lines of code below repeated for each field added):
$additionalAttrs = array();
$per_item = new stdClass();
$per_item->key = 'price_per_item';
$per_item->value = $local_product['price'];
$additionalAttrs['single_data'][] = $per_item;
And then adding it to your product array with the key "additional_attributes" like:
'additional_attributes' => $additionalAttrs,
I know this work around only helps people that were avoiding the SOAP API for the same reason I was but hopefully it helps some of you. That error we're seeing where it tries to add a product twice seems to be server configuration specific and very hard to track down.