2013-05-10 21:14:40 +04:00
/*
* Copyright ( C ) 2013 Red Hat , Inc .
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library ; If not , see
* < http : //www.gnu.org/licenses/>.
*/
# include <config.h>
# include <fcntl.h>
# include "testutils.h"
2017-03-07 12:34:47 +03:00
# include "virfdstream.h"
2013-05-10 21:14:40 +04:00
# include "datatypes.h"
# include "virerror.h"
# include "viralloc.h"
# include "virlog.h"
# include "virstring.h"
# include "virfile.h"
# include "virutil.h"
# define VIR_FROM_THIS VIR_FROM_NONE
2014-02-28 16:16:17 +04:00
VIR_LOG_INIT ( " tests.fdstreamtest " ) ;
2013-05-10 21:14:40 +04:00
# define PATTERN_LEN 256
static int testFDStreamReadCommon ( const char * scratchdir , bool blocking )
{
int fd = - 1 ;
2013-05-13 23:38:18 +04:00
char * file = NULL ;
2013-05-10 21:14:40 +04:00
int ret = - 1 ;
char * pattern = NULL ;
char * buf = NULL ;
virStreamPtr st = NULL ;
size_t i ;
virConnectPtr conn = NULL ;
int flags = 0 ;
if ( ! blocking )
flags | = VIR_STREAM_NONBLOCK ;
if ( ! ( conn = virConnectOpen ( " test:///default " ) ) )
goto cleanup ;
if ( VIR_ALLOC_N ( pattern , PATTERN_LEN ) < 0 | |
VIR_ALLOC_N ( buf , PATTERN_LEN ) < 0 )
goto cleanup ;
2013-05-21 11:53:48 +04:00
for ( i = 0 ; i < PATTERN_LEN ; i + + )
2013-05-10 21:14:40 +04:00
pattern [ i ] = i ;
2013-05-13 23:38:18 +04:00
if ( virAsprintf ( & file , " %s/input.data " , scratchdir ) < 0 )
2013-05-10 21:14:40 +04:00
goto cleanup ;
2013-05-13 23:38:18 +04:00
if ( ( fd = open ( file , O_CREAT | O_WRONLY | O_EXCL , 0600 ) ) < 0 )
2013-05-10 21:14:40 +04:00
goto cleanup ;
2013-05-21 11:53:48 +04:00
for ( i = 0 ; i < 10 ; i + + ) {
2013-05-10 21:14:40 +04:00
if ( safewrite ( fd , pattern , PATTERN_LEN ) ! = PATTERN_LEN )
goto cleanup ;
}
if ( VIR_CLOSE ( fd ) < 0 )
goto cleanup ;
if ( ! ( st = virStreamNew ( conn , flags ) ) )
goto cleanup ;
/* Start reading 1/2 way through first pattern
* and end 1 / 2 way through last pattern
*/
2013-05-13 23:38:18 +04:00
if ( virFDStreamOpenFile ( st , file ,
2013-05-10 21:14:40 +04:00
PATTERN_LEN / 2 , PATTERN_LEN * 9 ,
O_RDONLY ) < 0 )
goto cleanup ;
2013-05-21 11:53:48 +04:00
for ( i = 0 ; i < 10 ; i + + ) {
2013-05-10 21:14:40 +04:00
size_t offset = 0 ;
size_t want ;
if ( i = = 0 )
want = PATTERN_LEN / 2 ;
else
want = PATTERN_LEN ;
while ( want > 0 ) {
int got ;
reread :
got = st - > driver - > streamRecv ( st , buf + offset , want ) ;
if ( got < 0 ) {
if ( got = = - 2 & & ! blocking ) {
usleep ( 20 * 1000 ) ;
goto reread ;
}
2013-05-17 18:11:24 +04:00
virFilePrintf ( stderr , " Failed to read stream: %s \n " ,
virGetLastErrorMessage ( ) ) ;
2013-05-10 21:14:40 +04:00
goto cleanup ;
}
if ( got = = 0 ) {
/* Expect EOF 1/2 through last pattern */
if ( i = = 9 & & want = = ( PATTERN_LEN / 2 ) )
break ;
2013-05-17 18:11:24 +04:00
virFilePrintf ( stderr , " Unexpected EOF block %zu want %zu \n " ,
i , want ) ;
2013-05-10 21:14:40 +04:00
goto cleanup ;
}
offset + = got ;
want - = got ;
}
if ( i = = 0 ) {
if ( memcmp ( buf , pattern + ( PATTERN_LEN / 2 ) , PATTERN_LEN / 2 ) ! = 0 ) {
2013-05-17 18:11:24 +04:00
virFilePrintf ( stderr , " Mismatched pattern data iteration %zu \n " , i ) ;
2013-05-10 21:14:40 +04:00
goto cleanup ;
}
} else if ( i = = 9 ) {
if ( memcmp ( buf , pattern , PATTERN_LEN / 2 ) ! = 0 ) {
2013-05-17 18:11:24 +04:00
virFilePrintf ( stderr , " Mismatched pattern data iteration %zu \n " , i ) ;
2013-05-10 21:14:40 +04:00
goto cleanup ;
}
} else {
if ( memcmp ( buf , pattern , PATTERN_LEN ) ! = 0 ) {
2013-05-17 18:11:24 +04:00
virFilePrintf ( stderr , " Mismatched pattern data iteration %zu \n " , i ) ;
2013-05-10 21:14:40 +04:00
goto cleanup ;
}
}
}
if ( st - > driver - > streamFinish ( st ) ! = 0 ) {
2013-05-17 18:11:24 +04:00
virFilePrintf ( stderr , " Failed to finish stream: %s \n " ,
virGetLastErrorMessage ( ) ) ;
2013-05-10 21:14:40 +04:00
goto cleanup ;
}
ret = 0 ;
2014-03-25 10:53:44 +04:00
cleanup :
2013-05-10 21:14:40 +04:00
if ( st )
virStreamFree ( st ) ;
VIR_FORCE_CLOSE ( fd ) ;
2013-05-13 23:38:18 +04:00
if ( file ! = NULL )
unlink ( file ) ;
2013-05-10 21:14:40 +04:00
if ( conn )
virConnectClose ( conn ) ;
2013-05-13 23:38:18 +04:00
VIR_FREE ( file ) ;
2013-05-10 21:14:40 +04:00
VIR_FREE ( pattern ) ;
VIR_FREE ( buf ) ;
return ret ;
}
static int testFDStreamReadBlock ( const void * data )
{
return testFDStreamReadCommon ( data , true ) ;
}
static int testFDStreamReadNonblock ( const void * data )
{
return testFDStreamReadCommon ( data , false ) ;
}
static int testFDStreamWriteCommon ( const char * scratchdir , bool blocking )
{
int fd = - 1 ;
2013-05-13 23:38:18 +04:00
char * file = NULL ;
2013-05-10 21:14:40 +04:00
int ret = - 1 ;
char * pattern = NULL ;
char * buf = NULL ;
virStreamPtr st = NULL ;
size_t i ;
virConnectPtr conn = NULL ;
int flags = 0 ;
if ( ! blocking )
flags | = VIR_STREAM_NONBLOCK ;
if ( ! ( conn = virConnectOpen ( " test:///default " ) ) )
goto cleanup ;
if ( VIR_ALLOC_N ( pattern , PATTERN_LEN ) < 0 | |
VIR_ALLOC_N ( buf , PATTERN_LEN ) < 0 )
goto cleanup ;
2013-05-21 11:53:48 +04:00
for ( i = 0 ; i < PATTERN_LEN ; i + + )
2013-05-10 21:14:40 +04:00
pattern [ i ] = i ;
2013-05-13 23:38:18 +04:00
if ( virAsprintf ( & file , " %s/input.data " , scratchdir ) < 0 )
2013-05-10 21:14:40 +04:00
goto cleanup ;
if ( ! ( st = virStreamNew ( conn , flags ) ) )
goto cleanup ;
/* Start writing 1/2 way through first pattern
* and end 1 / 2 way through last pattern
*/
2013-05-13 23:38:18 +04:00
if ( virFDStreamCreateFile ( st , file ,
2013-05-10 21:14:40 +04:00
PATTERN_LEN / 2 , PATTERN_LEN * 9 ,
O_WRONLY , 0600 ) < 0 )
goto cleanup ;
2013-05-21 11:53:48 +04:00
for ( i = 0 ; i < 10 ; i + + ) {
2013-05-10 21:14:40 +04:00
size_t offset = 0 ;
size_t want ;
if ( i = = 0 )
want = PATTERN_LEN / 2 ;
else
want = PATTERN_LEN ;
while ( want > 0 ) {
int got ;
rewrite :
got = st - > driver - > streamSend ( st , pattern + offset , want ) ;
if ( got < 0 ) {
if ( got = = - 2 & & ! blocking ) {
usleep ( 20 * 1000 ) ;
goto rewrite ;
}
if ( i = = 9 & &
want = = ( PATTERN_LEN / 2 ) )
break ;
2013-05-17 18:11:24 +04:00
virFilePrintf ( stderr , " Failed to write stream: %s \n " ,
virGetLastErrorMessage ( ) ) ;
2013-05-10 21:14:40 +04:00
goto cleanup ;
}
offset + = got ;
want - = got ;
}
}
if ( st - > driver - > streamFinish ( st ) ! = 0 ) {
2013-05-17 18:11:24 +04:00
virFilePrintf ( stderr , " Failed to finish stream: %s \n " ,
virGetLastErrorMessage ( ) ) ;
2013-05-10 21:14:40 +04:00
goto cleanup ;
}
2013-05-13 23:38:18 +04:00
if ( ( fd = open ( file , O_RDONLY ) ) < 0 )
2013-05-10 21:14:40 +04:00
goto cleanup ;
2013-05-21 11:53:48 +04:00
for ( i = 0 ; i < 10 ; i + + ) {
2017-04-11 10:51:41 +03:00
size_t want , got ;
2013-05-10 21:14:40 +04:00
if ( i = = 9 )
want = PATTERN_LEN / 2 ;
else
want = PATTERN_LEN ;
2017-04-11 10:51:41 +03:00
if ( ( got = saferead ( fd , buf , want ) ) ! = want ) {
virFilePrintf ( stderr ,
" Short read from data, i=%zu got=%zu want=%zu \n " ,
i , got , want ) ;
2013-05-10 21:14:40 +04:00
goto cleanup ;
}
if ( i = = 0 ) {
size_t j ;
2013-05-21 11:53:48 +04:00
for ( j = 0 ; j < ( PATTERN_LEN / 2 ) ; j + + ) {
2013-05-10 21:14:40 +04:00
if ( buf [ j ] ! = 0 ) {
2013-05-17 18:11:24 +04:00
virFilePrintf ( stderr , " Mismatched pattern data iteration %zu \n " , i ) ;
2013-05-10 21:14:40 +04:00
goto cleanup ;
}
}
if ( memcmp ( buf + ( PATTERN_LEN / 2 ) , pattern , PATTERN_LEN / 2 ) ! = 0 ) {
2013-05-17 18:11:24 +04:00
virFilePrintf ( stderr , " Mismatched pattern data iteration %zu \n " , i ) ;
2013-05-10 21:14:40 +04:00
goto cleanup ;
}
} else if ( i = = 9 ) {
if ( memcmp ( buf , pattern , PATTERN_LEN / 2 ) ! = 0 ) {
2013-05-17 18:11:24 +04:00
virFilePrintf ( stderr , " Mismatched pattern data iteration %zu \n " , i ) ;
2013-05-10 21:14:40 +04:00
goto cleanup ;
}
} else {
if ( memcmp ( buf , pattern , PATTERN_LEN ) ! = 0 ) {
2013-05-17 18:11:24 +04:00
virFilePrintf ( stderr , " Mismatched pattern data iteration %zu \n " , i ) ;
2013-05-10 21:14:40 +04:00
goto cleanup ;
}
}
}
if ( VIR_CLOSE ( fd ) < 0 )
goto cleanup ;
ret = 0 ;
2014-03-25 10:53:44 +04:00
cleanup :
2013-05-10 21:14:40 +04:00
if ( st )
virStreamFree ( st ) ;
VIR_FORCE_CLOSE ( fd ) ;
2013-05-13 23:38:18 +04:00
if ( file ! = NULL )
unlink ( file ) ;
2013-05-10 21:14:40 +04:00
if ( conn )
virConnectClose ( conn ) ;
2013-05-13 23:38:18 +04:00
VIR_FREE ( file ) ;
2013-05-10 21:14:40 +04:00
VIR_FREE ( pattern ) ;
VIR_FREE ( buf ) ;
return ret ;
}
static int testFDStreamWriteBlock ( const void * data )
{
return testFDStreamWriteCommon ( data , true ) ;
}
static int testFDStreamWriteNonblock ( const void * data )
{
return testFDStreamWriteCommon ( data , false ) ;
}
2017-04-11 10:50:26 +03:00
# define SCRATCHDIRTEMPLATE abs_builddir " / fdstreamdir-XXXXXX"
2013-05-10 21:14:40 +04:00
static int
mymain ( void )
{
char scratchdir [ ] = SCRATCHDIRTEMPLATE ;
int ret = 0 ;
if ( ! mkdtemp ( scratchdir ) ) {
2017-04-11 10:50:26 +03:00
virFilePrintf ( stderr , " Cannot create fdstreamdir " ) ;
2013-05-10 21:14:40 +04:00
abort ( ) ;
}
2016-05-26 18:01:50 +03:00
if ( virTestRun ( " Stream read blocking " , testFDStreamReadBlock , scratchdir ) < 0 )
2013-05-10 21:14:40 +04:00
ret = - 1 ;
2016-05-26 18:01:50 +03:00
if ( virTestRun ( " Stream read non-blocking " , testFDStreamReadNonblock , scratchdir ) < 0 )
2013-05-10 21:14:40 +04:00
ret = - 1 ;
2016-05-26 18:01:50 +03:00
if ( virTestRun ( " Stream write blocking " , testFDStreamWriteBlock , scratchdir ) < 0 )
2013-05-10 21:14:40 +04:00
ret = - 1 ;
2016-05-26 18:01:50 +03:00
if ( virTestRun ( " Stream write non-blocking " , testFDStreamWriteNonblock , scratchdir ) < 0 )
2013-05-10 21:14:40 +04:00
ret = - 1 ;
if ( getenv ( " LIBVIRT_SKIP_CLEANUP " ) = = NULL )
virFileDeleteTree ( scratchdir ) ;
return ret = = 0 ? EXIT_SUCCESS : EXIT_FAILURE ;
}
2017-03-29 17:45:42 +03:00
VIR_TEST_MAIN ( mymain )