phpUnit - Functions in test class that aren't tests - php

I'm doing some speed comparisons between reports in phpunit, as I am trying to figure out an optimization problem.
I have a couple of functions that aren't necessarily tests, but don't belong in the functionality of the project either. I am using them in order to make my tests small and readable. The function I am using does a cUrl operation with the parameters I pass to it.
So, I am running two Urls (two versions of a project, one in its original form, and one with the optimization) and seeing if they return text equal to each other. I would not do this within the app itself. I'm doing this because its quicker than trying to figure out the correct function calls because the project is a bit messy.
So I have a test like this:
public function testOne(){
$results = $this->testRange(13,1,2013,16,1,2013);
$this->assertEquals($results['opt'], $results['non_opt']);
}//tests
And my two non test functions:
protected function testRange($fromDay,
$fromMonth,
$fromYear,
$toDay,
$toMonth,
$toYear){
$this->params['periodFromDay'] = $fromDay;
$this->params['periodFromMonth'] = $fromMonth;
$this->params['periodFromYear'] = $fromYear;
$this->params['periodToDay'] = $toDay;
$this->params['periodToMonth'] = $toMonth;
$this->params['periodToYear'] = $toYear;
$this->data['from']=$fromDay."-".$fromMonth."-".$fromYear;
$this->data['to']=$toDay."-".$toMonth."-".$toYear;;
return $this->testRunner();
}//testOneDay
protected function testRunner(){
//include"test_bootstrap.php";
$response = array();
foreach($this->types as $key=>$type){
$params = http_build_query($this->params);
$url=$this->paths[$type];
$curl_url = $url."?".$params;
$ch = curl_init($curl_url);
$cookieFile = "tmp/cookie.txt";
if(!file_exists($cookieFile))
{
$fh = fopen($cookieFile, "w");
fwrite($fh, "");
fclose($fh);
}//if
curl_setopt($ch,CURLOPT_COOKIEFILE,$cookieFile);
curl_setopt($ch,CURLOPT_COOKIEJAR,$cookieFile);
curl_setopt($ch,CURLOPT_FOLLOWLOCATION,1);
curl_setopt($ch,CURLOPT_HEADER,0);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
$result[$type] = curl_exec($ch);
$dump = "logs/report_results/".
$this->data['from']."_".
$this->data['to']."_".
$type.".txt";
$fh = fopen($dump, "w");
fwrite($fh, $result[$type]);
fclose($fh);
}//foreach
return $result;
}//testRunner
I'm wondering if
A: it is possible to write functions in the test file, and have phpunit ignore them, or if there is a more appropriate place to put them.
B: there is a more sensible way to handle this sort of thing. I like this approach, but I am open to suggestions.

PHPUnit will ignore any method whose name does not start with "test*" and do not have a #Test annotation so feel free to put stuff in private helper functions.

Related

Cakephp 2.x Security::cipher not providing results across two apps

I have 2 apps communicating with each other. The 1st app is the one who do the transactions and the other app is a settings app to control the 1st app's system settings.
Upon on reaching the login page of the first app, I'm calling a WebService through curl inside the config.php and it will communicate to the 2nd app and it will return corresponding values. Now, my problem is, the value was encrypted using the Security::cipher() function and it was encrypted using a module inside of the settings app. When I try to decrypt it, there is no error prompted and even no error is logged in the error logs file. I suspect that when I decrypt from WebServicesController it doesn't read the Security component. I tried to put App::uses('Security','Utility') on the top of the codes. Here's how I code it:
1st app
curl_setopt($ch, CURLOPT_URL, Configure::read('TMSWebServices.Url').'getSystemSetting.json');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
$result_json = curl_exec($ch);
curl_close($ch);
$result = json_decode($result_json, true);
debug($result); exit;
2nd app
App::uses('AuthComponent', 'Controller/Component');
App::uses('UsersController', 'Controller');
App::uses('Security','Utility');
class WebServicesController extends AppController {
public $name = 'WebServices';
public $uses = array('Tenant', 'TbNextId', 'ReportMaster' );
public $components = array('RequestHandler');
public function getSystemSetting(){
$this->loadModel('SystemSetting');
$results = $this->SystemSetting->find($type, $params);
$return_value = array();
$return_value = $results['SystemSetting'];
foreach($return_value['Config'] as $key=>$value){
if ($value['ENCRYPT_IND'] == 'Y'){
$encryptedValue = $return_value['Config'][$key]['SYSTEM_SETTING_VALUE'];
//decrypt the value
$decryptedValue = Security::cipher($encryptedValue,
Configure::read('Security.salt')); // the problem starts here
$return_value['Config'][$key]['SYSTEM_SETTING_VALUE'] = $decryptedValue;
}
}
}
}
$this->set(array(
'return_value' => $return_value,
'_serialize' => array('return_value')
));
When I try to just put simple value on the $return_value, the communication works. But if I use the Security::cipher to decrypt, it doesn't work and give me a null value.
I would look at two problems:
The Security.salt value is usually not the same across two CakePHP apps. From your error message I think that it's either empty or not set (i.e. null). Unless you set Security.salt to the same value in both apps, cipher will not work giving you either null or some incorrect value.
As #ndm mentioned in the comment, you are creating a flat array (not an associative array) so I wonder how it is that your code even enters the foreach loop.
Look at the following code and my comments:
// ...
$return_value = array(); // we have ourselves an empty array
$return_value[] = $results['SystemSetting']; // we assign a value to $return_value[0]
foreach($return_value['Config'] as $key=>$value){ // no such key 'Config' in the array
// loop code follows, but execution flow shouldn't enter here...
While we are at it, I strongly encourage you to not use Security.salt because it is just a weak XOR cipher, try to use Security.encrypt() and Security.decrypt()

How to store values globally, permantly?

I want to store some counter and want to increment as desired.
This counters are not related to any client, so i cant use session or cookies.
I tried $GLOBALS but, its not what i want.
I want something like, let say i have 3 php files, each will do some counter manuplation.
init.php
$_GLOBAL_VARIABLE['cntr1'] = 0;
file1.php
$_GLOBAL_VARIABLE['cntr1'] = $_GLOBAL_VARIABLE['cntr1'] + 7;
file2.php
$_GLOBAL_VARIABLE['cntr1'] = $_GLOBAL_VARIABLE['cntr1'] + ($_GLOBAL_VARIABLE['cntr1'] * 0.90);
file3.php
echo $_GLOBAL_VARIABLE['cntr1'];
All three files (except init.php) will called randomly without ant relation and init will called once.
I dont want to try database transaction coz counter manuplation is very frequent, and file i/o is one and the same. I am looking for some way to store my data on server till the time its up and running, somewhat like global class and variables in c#.
If you want the store globally accessible value in the server without the use of database, cookie or session then memcache could be a solution for you. Its a daemon which allows you to store data and use it across different connection requests. If you have frequent visits you will have to somehow handle concurrency within you application.
I think this will work
global $cntr1;
If not then you can make one .inc.php and include this file to all pages.
This will resolve your issue.
im sure this is NOT what you wanted, but i've used fileread/filewrite to store my globals in a file on the drive, which can be read from, written to with updated values etc. This allows for you to set MANY global variables as int's, I've modified my globals code to work as a iterator, counting up or counting down by what ever value you pass.
its a simple quick class i made to handle the request :
<?php
class my_global{
protected $name;
protected $value;
static protected $path = './globals/';
public function __construct()
{
if(!is_dir(self::$path))
mkdir(self::$path);
}
public function change($name, $value)
{
$current = $this->get($name);
$this->set($name,$current+$value);
return $current+$value;
}
protected function set($name, $value)
{
$this->name = $name;
$this->value = $value;
$this->write();
}
protected function get($name)
{
if(file_exists(self::$path.$name))
{
$myFile = self::$path.$name;
$fh = fopen($myFile, 'r');
$value = fread($fh, filesize($myFile));
fclose($fh);
}
else
$value = 0;
$this->name = $name;
$this->value = $value;
return $value;
}
protected function write(){
$myFile = self::$path.$this->name;
$fh = fopen($myFile, 'w') or die("can't open file");
fwrite($fh, $this->value);
fclose($fh);
}
}
$my_global = new my_global();
?>
You can then just call the $my_global->change() method to increase or decrease the counter
<?php
echo $my_global->change('new_global',5).'<br>';
echo $my_global->change('anotherglobal',-2).'<br>';
echo $my_global->change('forme',7).'<br>';
?>
this is more food for thought than anything, but could be used tweaked to work as you need it.

How to lock file in PHP?

I'm trying to create a PHP file, which wouldn't run if it's already running. Here's the code I'm using:
<?php
class Test {
private $tmpfile;
public function action_run() {
$this->die_if_running();
$this->run();
}
private function die_if_running() {
$this->tmpfile = #fopen('.refresher2.pid', "w");
$locked = #flock($this->tmpfile, LOCK_EX|LOCK_NB);
if (! $locked) {
#fclose($this->tmpfile);
die("Running 2");
}
}
private function run() {
echo "NOT RUNNNING";
sleep(100);
}
}
$test = new Test();
$test->action_run();
The problem is, when I run this from console, it works great. But when I try to run it from browser, many instances can run simultaneously. This is on Windows 7, XAMPP, PHP 5.3.2. I guess OS is thinking that it's the same process and thus the functionality falls. Is there a cross-platform way to create a PHP script of this type?
Not really anything to promising. You can't use flock for that like this.
You could use system() to start another (php) process that does the locking for you. But drawbacks:
You need to do interprocess communication. Think about a way how to tell the other program when to release the lock etc. You can use stdin for messenging und use 3 constants or something. In this case it's still rather simple
It's bad for performance because you keep creating processes which is expensive.
Another way would be to start another program that runs all the time. You connect to it using some means of IPC (probably just use a tcp channel because it's cross-platform) and allow this program to manage file acces. That program could be a php script in an endless loop as well, but it will probably be simpler to code this in Java or another language that has multithreading support.
Another way would be to leverage existing ressources. Create a dummy database table for locks, create an entry for the file and then do table-row-locking.
Another way would be not to use files, but a database.
I had a similar problem a while ago.
I needed to have a counter where the number returned was unique.
I used a lock-file and only if this instance was able to create the lock-file was it allowed to read the file with the current number.
Instead of counting up perhaps you can allow the script to run.
The trick is to let try a few times (like 5) with a small wait/sleep in between.
function GetNextNumber()
{
$lockFile = "lockFile.txt";
$lfh = #fopen($lockFile, "x");
if (!$lfh)
{
$lockOkay = false;
$count = 0;
$countMax = 5;
// Try ones every second in 5 seconds
while (!$lockOkay & $count < $countMax)
{
$lfh = #fopen($lockFile, "x");
if ($lfh)
{
$lockOkay = true;
}
else
{
$count++;
sleep(1);
}
}
}
if ($lfh)
{
$fh = fopen($myFile, 'r+') or die("Too many users. ");
flock($fh, LOCK_EX);
$O_nextNumber = fread($fh, 15);
$O_nextNumber = $O_nextNumber + 1;
rewind($fh);
fwrite($fh, $O_knr);
flock($fh, LOCK_UN);
fclose($fh);
unlink($lockFile); // Sletter lockfilen
}
return $O_nextNumber;
}

Why some variables are parameters and others aren't?

What could be the reason for having this:
public function __construct($host, $port, $timeout = 5){
$errnum = 0;
$errstr = '';
Instead of this:
public function __construct($host, $port, $errnum = 0, $errstr = '', $timeout = 5){
?
Why some are params and others aren't ?
Thanks a lot,
MEM
A function definition defines a contract between the function itself and the code that calls it.
A variable should only be a parameter if the caller should specify it's value. Otherwise if a variable is only used internally by the function, there is no need to specify it as a parameter.
the errors are set by the function, and there is no point passing those in
If they would be params, the user could pass them in during the creation of the object. A call like
$a = new MyObject($myhost, $myport, 40000, 'Failed.', $mytimeout);
would initialize your object with an error already in its memory... In the case of an error number or string, that is rather unwanted. The user shouldn't be able to poke a random error into your object.
Normally you define a function in a way that it only accepts parameters/data that it definitely needs in order to run.
In you example, $errnum and $errstr seem to be variables that the function uses internally. If you design that function you have to decide whether you want to give the user the possibility to override those or not.
Maybe you want to call the constructor with more than 3 parameters, depending on what the constructor/class do. The parameter list is not the place to initialize local variables. Check the API of the class you are reading what the parameters are for (looks like they are for the fsockopen function, so read this documentation first).
$timeout is a default parameter that can be overwritten when calling the function.
$errnum and $errstr cannot be overwritten when calling the function.
Observe:
public function goodConstruct($host, $port, $timeout = 5){
$errnum = 0;
$errstr = '';
}
goodConstruct('hostname',8443,60);
By doing this, I can overwrite the default timeout.
public function badConstruct($host, $port, $errnum = 0, $errstr = '', $timeout = 5)
{
//code
}
badConstruct('hostname',8443,99,'hey look at this silly error!!!!',900);
Now I can also overwrite the error code (assuming that's the purpose of errnum, it's even worse if that's some sort of a counter) and the error string. Do you really want to be able to control this from your function call? Probably not... I assume that you'd want that to be fixed.

how do I override php://input when doing unit tests

I'm trying to write a unit test for a controller using Zend and PHPUnit
In the code I get data from php://input
$req = new Zend_Controller_Request_Http();
$data = $req->getRawBody();
My code works fine when I test the real application, but unless I can supply data as a raw http post, $data will always be blank. The getRawBody() method basically calls file_get_contents('php://input'), but how do I override this in order to supply the test data to my application.
I had the same problem and the way I fixed it was to have the 'php://input' string as a variable that is settable at run time. I know this does not really apply directly to this question as it would require modifying the Zend Framework. But all the same it may be helpful to someone.
For example:
<?php
class Foo {
public function read() {
return file_get_contents('php://input');
}
}
would become
<?php
class Foo {
public $_fileIn = 'php://input';
public function read() {
return file_get_contents($this->_fileIn);
}
}
Then in my unit test I can do:
<?php
$obj = new Foo();
$obj->_fileIn = 'my_input_data.dat';
assertTrue('foo=bar', $obj->read());
You could try mocking the object in your unit tests. Something like this:
$req = $this->getMock('Zend_Controller_Request_Http', array('getRawBody'));
$req->method('getRawBody')
->will($this->returnValue('raw_post_data_to_return'));
Provided the $req->getRawBody() is, as you say, the same as file_get_contents('php://input')...
$test = true; /* Set to TRUE when using Unit Tests */
$req = new Zend_Controller_Request_Http();
if( $test )
$data = file_get_contents( 'testfile.txt' );
else
$data = $req->getRawBody();
Not a perfect solution, but similar to what I have used in the past when designing scripts to handle piped emails with great success.
Zend_Controller_Request_HttpTestCase contains methods for setting and getting various http request/responses.
For example:
$req = new Zend_Controller_Request_HttpTestCase;
$req->setCookie('cookie', 'TRUE');
$test = $this->controller->cookieAction($req);
$this->assertSame($test, TRUE);

Categories