Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief Test Tool 48 - basically call service and test for cache data
0003  *
0004  * @file testtool48.c
0005  */
0006 /* -----------------------------------------------------------------------------
0007  * Enduro/X Middleware Platform for Distributed Transaction Processing
0008  * Copyright (C) 2009-2016, ATR Baltic, Ltd. All Rights Reserved.
0009  * Copyright (C) 2017-2023, Mavimax, Ltd. All Rights Reserved.
0010  * This software is released under one of the following licenses:
0011  * AGPL (with Java and Go exceptions) or Mavimax's license for commercial use.
0012  * See LICENSE file for full text.
0013  * -----------------------------------------------------------------------------
0014  * AGPL license:
0015  *
0016  * This program is free software; you can redistribute it and/or modify it under
0017  * the terms of the GNU Affero General Public License, version 3 as published
0018  * by the Free Software Foundation;
0019  *
0020  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0021  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0022  * PARTICULAR PURPOSE. See the GNU Affero General Public License, version 3
0023  * for more details.
0024  *
0025  * You should have received a copy of the GNU Affero General Public License along 
0026  * with this program; if not, write to the Free Software Foundation, Inc.,
0027  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0028  *
0029  * -----------------------------------------------------------------------------
0030  * A commercial use license is available from Mavimax, Ltd
0031  * contact@mavimax.com
0032  * -----------------------------------------------------------------------------
0033  */
0034 #include <string.h>
0035 #include <stdio.h>
0036 #include <stdlib.h>
0037 #include <memory.h>
0038 #include <math.h>
0039 
0040 #include <ctype.h>
0041 #include <unistd.h>
0042 
0043 #include <atmi.h>
0044 #include <ubf.h>
0045 #include <ndebug.h>
0046 #include <test.fd.h>
0047 #include <ndrstandard.h>
0048 #include <nstopwatch.h>
0049 #include <fcntl.h>
0050 #include <unistd.h>
0051 #include <nstdutil.h>
0052 #include <ubf_int.h>
0053 #include <ubfutil.h>
0054 #include "test48.h"
0055 #include "exsha1.h"
0056 /*---------------------------Externs------------------------------------*/
0057 /*---------------------------Macros-------------------------------------*/
0058 #define BUFS_EXTRA  1024*16
0059 /*---------------------------Enums--------------------------------------*/
0060 /*---------------------------Typedefs-----------------------------------*/
0061 /*---------------------------Globals------------------------------------*/
0062 /*---------------------------Statics------------------------------------*/
0063 
0064 exprivate char M_svcnm[MAXTIDENT+1] = {EXEOS};
0065 exprivate UBFH *M_p_ub = NULL;
0066 exprivate UBFH *M_p_ub_cmp_cache = NULL; /* compare with cache results  */
0067 exprivate int M_result_must_from_cache = EXTRUE;
0068 exprivate int M_numcalls = 1;
0069 exprivate long M_tpurcode = 0;
0070 exprivate int M_tperrno = 0;
0071 exprivate int M_first_goes_to_cache = EXTRUE; /* first call goes to cache (basically from svc) */
0072 exprivate long M_tpcall_flags = 0; /* Additional tpcall flags */
0073 exprivate int M_threads = 1; /* Number of threads */
0074 exprivate int M_failed = EXFALSE; /* Set to true by failed thread */
0075 exprivate int M_bigmsg = EXFALSE;   /* should we test big message ~ 5K? */
0076 exprivate char M_bigmsg_buf[BUFS_EXTRA]; /* extra buffer for big msg, random */
0077 /*---------------------------Prototypes---------------------------------*/
0078 
0079 /**
0080  * Perform the testing
0081  * @return 
0082  */
0083 exprivate int main_loop(void *ptr)
0084 {
0085     int ret = EXSUCCEED;
0086     long i;
0087     UBFH *p_ub = NULL;
0088     UBFH *p_ub2;
0089     UBFH *p_free_later;
0090     long t;
0091     long tusec;
0092     
0093     int err;
0094     
0095     long t_svc;
0096     long tusec_svc;
0097     
0098     long olen;
0099     int data_from_cache;
0100     
0101     /* take a copy from UBF */
0102     
0103     for (i=0; i<M_numcalls; i++)
0104     {
0105         p_ub2 = NULL;
0106         p_free_later = NULL;
0107         NDRX_LOG(log_debug, "into loop %ld", i);
0108         
0109         if (NULL==(p_ub = (UBFH *)tpalloc("UBF", NULL, Bsizeof(M_p_ub)+1024+BUFS_EXTRA)))
0110         {
0111             NDRX_LOG(log_error, "Failed to allocate test buffer: %s", 
0112                     tpstrerror(tperrno));
0113             EXFAIL_OUT(ret);
0114         }
0115         
0116         if (EXSUCCEED!=Bcpy(p_ub, M_p_ub))
0117         {
0118             NDRX_LOG(log_error, "Failed to copy test buffer: %s", 
0119                     Bstrerror(Berror));
0120             EXFAIL_OUT(ret);
0121         }
0122 
0123         /* get tstamp here... */
0124         ndrx_utc_tstamp2(&t, &tusec);
0125         
0126         /* call services */
0127         
0128         ndrx_debug_dump_UBF(log_debug, "Sending buffer", p_ub);
0129         
0130         /* Bug #436 */
0131         ret=tpcall(M_svcnm, (char *)p_ub, 0L, (char **)&p_ub2, &olen, M_tpcall_flags);
0132         
0133         if (p_ub==p_ub2)
0134         {
0135             NDRX_LOG(log_error, "TESTERROR: Buffers not reallocated!");
0136             EXFAIL_OUT(ret);
0137         }
0138         
0139         /* check that bufs are still valid */
0140         
0141         if (!Bisubf(p_ub))
0142         {
0143             NDRX_LOG(log_error, "TESTERROR: p_ub invalid!");
0144             EXFAIL_OUT(ret);
0145         }
0146         
0147         p_free_later = p_ub;
0148         p_ub = p_ub2;
0149         
0150         err = tperrno;
0151                 
0152         ndrx_debug_dump_UBF(log_debug, "Received buffer", p_ub);
0153         
0154         if (M_tperrno!=0)
0155         {
0156             if (tperrno!=err)
0157             {
0158                 NDRX_LOG(log_error, "TESTERROR: Expected tperrno=%d got %d", 
0159                         M_tperrno, err);
0160                 EXFAIL_OUT(ret);
0161             }
0162             
0163             ret = EXSUCCEED;
0164         }
0165         else if (EXSUCCEED!=ret)
0166         {
0167             NDRX_LOG(log_error, "TESTERROR: service call shall SUCCEED, but FAILED!");
0168             EXFAIL_OUT(ret);
0169         }
0170         
0171         if (M_tpurcode!=tpurcode)
0172         {
0173             NDRX_LOG(log_error, "TESTERROR: Expected tpurcode=%ld got %ld", 
0174                     M_tpurcode, tpurcode);
0175             EXFAIL_OUT(ret);
0176         }
0177         
0178         /* if tstamp from service >= tstamp, then data comes from service and
0179          * not from cache
0180          * Store stamps here:
0181          * T_LONG_2_FLD[0] -> sec
0182          * T_LONG_2_FLD[1] -> usec
0183          */
0184         
0185         if (EXSUCCEED!=Bget(p_ub, T_LONG_2_FLD, 0, (char *)&t_svc, 0L)
0186                 || EXSUCCEED!=Bget(p_ub, T_LONG_2_FLD, 1, (char *)&tusec_svc, 0L))
0187         {
0188             
0189             if (TPENOENT!=err)
0190             {
0191                 NDRX_LOG(log_error, "TESTERROR: Failed to get timestamp "
0192                         "fields from service!");
0193                 EXFAIL_OUT(ret);
0194             }
0195         }
0196         else if (TPENOENT==err)
0197         {
0198             NDRX_LOG(log_error, "TESTERROR: Service call failed but timestamp present!");
0199             EXFAIL_OUT(ret);
0200         }
0201         
0202         NDRX_LOG(log_info, "timestamp from service %ld.%ld local tstamp %ld.%ld",
0203                 t_svc, tusec_svc, t, tusec);
0204         
0205         
0206         if (TPENOENT!=err)
0207         {
0208             /* so if, tsvc < t, then data is from cache */
0209             if (-1 == ndrx_utc_cmp(&t_svc, &tusec_svc, &t, &tusec))
0210             {
0211                 NDRX_LOG(log_debug, "Data from cache");
0212                 data_from_cache = EXTRUE;
0213             }
0214             else
0215             {
0216                 NDRX_LOG(log_debug, "Data from service");
0217                 data_from_cache = EXFALSE;
0218             }
0219 
0220             if (i==0 && M_first_goes_to_cache && data_from_cache)
0221             {
0222                 NDRX_LOG(log_error, "TESTERROR (%ld), record must be new for loop 0, "
0223                         "but got from cache!", i);
0224                 EXFAIL_OUT(ret);
0225             }
0226             else if (i==0 && M_first_goes_to_cache && !data_from_cache)
0227             {
0228                 /* ok... */
0229                 NDRX_LOG(log_debug, "OK, first new rec.");
0230             }
0231             else if (M_result_must_from_cache && !data_from_cache)
0232             {
0233                 NDRX_LOG(log_error, "TESTERROR (%ld), record must be from cache, "
0234                         "but got new!", i);
0235                 EXFAIL_OUT(ret);
0236             }
0237             else if (!M_result_must_from_cache && data_from_cache)
0238             {
0239                 NDRX_LOG(log_error, "TESTERROR(%ld) , record must be new but got "
0240                         "from cache!", i);
0241                 EXFAIL_OUT(ret);
0242             }
0243             
0244             /* Compare the buffer if given */
0245             
0246             if (NULL!=M_p_ub_cmp_cache && data_from_cache)
0247             {
0248                 /* strip time fields off */
0249                 Bdel(p_ub, T_LONG_2_FLD, 1);
0250                 Bdel(p_ub, T_LONG_2_FLD, 0);
0251                 
0252                 if (0!=Bcmp(p_ub, M_p_ub_cmp_cache))
0253                 {
0254                     NDRX_LOG(log_error, "TESTERROR ! Failed to compare UBF buffer: %s", 
0255                                         Bstrerror(Berror));
0256                     
0257                     ndrx_debug_dump_UBF(log_debug, "Received for compare", p_ub);
0258                     
0259                     ndrx_debug_dump_UBF(log_debug, "Received vs -m", 
0260                             M_p_ub_cmp_cache);
0261                     EXFAIL_OUT(ret);
0262                 }
0263             }
0264             
0265         }
0266         
0267         tpfree((char *)p_ub);
0268         p_ub = NULL;
0269         
0270         tpfree((char *)p_free_later);
0271         p_free_later = NULL;
0272         
0273         
0274         usleep(2000); /* sleep 2ms for new timestamp */
0275     }
0276     
0277 out:
0278 
0279     if (NULL!=p_ub)
0280     {
0281         tpfree((char *)p_ub);
0282     }
0283 
0284     if (NULL!=p_free_later)
0285     {
0286         tpfree((char *)p_free_later);
0287     }
0288 
0289     if (EXSUCCEED!=ret)
0290     {
0291         M_failed=EXTRUE;
0292     }
0293 
0294     tpterm();
0295 
0296     return ret;
0297 }
0298 
0299 /**
0300  * Run cache processing in multiple threads.
0301  * @return 
0302  */
0303 int run_threads(void)
0304 {
0305     pthread_t thread1, thread2, thread3, thread4, thread5;  /* thread variables */
0306     pthread_attr_t pthread_custom_attr;
0307     pthread_attr_init(&pthread_custom_attr);
0308     
0309     
0310     /* create threads 1 and 2 */    
0311     pthread_create (&thread1, &pthread_custom_attr, (void *) &main_loop, NULL);
0312     pthread_create (&thread2, &pthread_custom_attr, (void *) &main_loop, NULL);
0313     /*sleep(1);  Have some async works... WHY? */
0314     pthread_create (&thread3, &pthread_custom_attr, (void *) &main_loop, NULL);
0315     pthread_create (&thread4, &pthread_custom_attr, (void *) &main_loop, NULL);
0316     pthread_create (&thread5, &pthread_custom_attr, (void *) &main_loop, NULL);
0317 
0318     /* Main block now waits for both threads to terminate, before it exits
0319        If main block exits, both threads exit, even if the threads have not
0320        finished their work */ 
0321     pthread_join(thread1, NULL);
0322     pthread_join(thread2, NULL);
0323     pthread_join(thread3, NULL);
0324     pthread_join(thread4, NULL);
0325     pthread_join(thread5, NULL);
0326    
0327     if (M_failed)
0328     {
0329         return EXFAIL;
0330     }
0331     
0332     return EXSUCCEED;
0333 }
0334 
0335 /**
0336  * We shall load arguments like:
0337  * -s service_name
0338  * -b "json2ubf buffer"
0339  * -m "compare with cache reseults"
0340  * [-c Y|N - should result be out from cache or newly allocated?, default TRUE]
0341  * [-n <number of calls>, dflt 1]
0342  * [-r <tpurcode expected>, dflt 0]
0343  * [-e <error code expected>, dftl 0]
0344  * [-f <first_should_cache Y|N, if -n > 1 >, dftl Y]
0345  * [-l <look in cache flag>, TPNOCACHELOOK tpcall flag]
0346  * [-x <do not add to cache>, TPNOCACHEADD tpcall flag]
0347  * [-t <number of threads>]
0348  * [-r, perform fork ops]
0349  */
0350 int main(int argc, char** argv)
0351 {
0352     int ret = EXSUCCEED;
0353     int c;
0354     
0355     opterr = 0;
0356     
0357     if (NULL==(M_p_ub = (UBFH *)tpalloc("UBF", NULL, 56000)))
0358     {
0359         NDRX_LOG(log_error, "Failed to allocate UBF: %s", tpstrerror(tperrno));
0360         EXFAIL_OUT(ret);
0361     }
0362 
0363     while ((c = getopt (argc, argv, "s:b:t:c:n:r:e:f:lxm:dB")) != EXFAIL)
0364     {
0365         NDRX_LOG(log_debug, "got %c", (char)c);
0366         
0367         switch (c)
0368         {
0369             case 'B':
0370                 /* test big messages */
0371                 M_bigmsg = EXTRUE;
0372                 break;
0373             case 's':
0374                 NDRX_STRCPY_SAFE(M_svcnm, optarg);
0375                 break;
0376             case 'b':
0377                 /* JSON buffer, build UBF... */
0378 
0379                 NDRX_LOG(log_debug, "Parsing: [%s]", optarg);
0380 
0381                 if (EXSUCCEED!=tpjsontoubf(M_p_ub, optarg))
0382                 {
0383                     NDRX_LOG(log_error, "Failed to parse [%s]", optarg);
0384                     EXFAIL_OUT(ret);
0385                 }
0386 
0387                 break;
0388             case 'm':
0389                 /* JSON buffer, build UBF... */
0390                 if (NULL==(M_p_ub_cmp_cache = (UBFH *)tpalloc("UBF", NULL, 56000)))
0391                 {
0392                     NDRX_LOG(log_error, "Failed to allocate UBF (2): %s", 
0393                             tpstrerror(tperrno));
0394                     EXFAIL_OUT(ret);
0395                 }
0396 
0397                 NDRX_LOG(log_debug, "Parsing: [%s]", optarg);
0398 
0399                 if (EXSUCCEED!=tpjsontoubf(M_p_ub_cmp_cache, optarg))
0400                 {
0401                     NDRX_LOG(log_error, "Failed to parse [%s]", optarg);
0402                     EXFAIL_OUT(ret);
0403                 }
0404                 
0405                 break;
0406             case 'c':
0407 
0408                 if ('Y'==optarg[0] || 'y'==optarg[0])
0409                 {
0410                     M_result_must_from_cache=EXTRUE;
0411                 }
0412                 else
0413                 {
0414                     M_result_must_from_cache=EXFALSE;
0415                 }
0416 
0417                 break;
0418             case 'n':
0419                 M_numcalls = atoi(optarg);
0420                 break;
0421             case 'r':
0422                 M_tpurcode = atol(optarg);
0423                 break;
0424             case 'e':
0425                 M_tperrno = atoi(optarg);
0426                 break;
0427             case 't':
0428                 M_threads = atoi(optarg);
0429                 break;
0430             case 'f':
0431                 
0432                 if ('Y'==optarg[0] || 'y'==optarg[0])
0433                 {
0434                     M_first_goes_to_cache=EXTRUE;
0435                 }
0436                 else
0437                 {
0438                     M_first_goes_to_cache=EXFALSE;
0439                 }
0440                 
0441                 break;
0442             case 'd':
0443                 M_tpcall_flags|=TPNOCACHEDDATA;
0444                 break;
0445             case 'l':
0446                 M_tpcall_flags|=TPNOCACHELOOK;
0447                 break;
0448             case 'x':
0449                 M_tpcall_flags|=TPNOCACHEADD;
0450                 break;
0451             case '?':
0452                 if (optopt == 'c')
0453                 {
0454                     fprintf (stderr, "Option -%c requires an argument.\n", optopt);
0455                     EXFAIL_OUT(ret);
0456                 }
0457                 else if (isprint (optopt))
0458                 {
0459                     fprintf (stderr, "Unknown option `-%c'.\n", optopt);
0460                     EXFAIL_OUT(ret);
0461                 }
0462                 else
0463                 {
0464                     fprintf (stderr,
0465                         "Unknown option character `\\x%x'.\n",
0466                         optopt);
0467                     EXFAIL_OUT(ret);
0468                 }
0469                 return 1;
0470             default:
0471                 abort ();
0472         }
0473     }
0474     
0475     /* validate config! */    
0476     
0477     NDRX_LOG(log_debug, "M_svcnm = [%s]", M_svcnm);
0478     NDRX_LOG(log_debug, "M_p_ub = %p", M_p_ub);
0479     NDRX_LOG(log_debug, "M_p_ub_cmp_cache = %p", M_p_ub_cmp_cache);
0480     NDRX_LOG(log_debug, "M_result_must_from_cache=%d", M_result_must_from_cache);
0481     NDRX_LOG(log_debug, "M_numcalls=%d", M_numcalls);
0482     NDRX_LOG(log_debug, "M_tpurcode=ld", M_tpurcode);
0483     NDRX_LOG(log_debug, "M_errcode=%d", M_tperrno);
0484     NDRX_LOG(log_debug, "M_first_goes_to_cache=%d", M_first_goes_to_cache);
0485     NDRX_LOG(log_debug, "M_tpcall_flags %ld", M_tpcall_flags);
0486     
0487     
0488     ndrx_debug_dump_UBF(log_debug, "Send buffer", M_p_ub);
0489     
0490     if (NULL!=M_p_ub_cmp_cache)
0491     {
0492         ndrx_debug_dump_UBF(log_debug, "Cache compare buffer", M_p_ub_cmp_cache);
0493     }
0494     
0495     if (EXEOS==M_svcnm[0])
0496     {
0497         NDRX_LOG(log_error, "-s: Service name cannot be empty!");
0498         EXFAIL_OUT(ret);
0499     }
0500     
0501     if (NULL==M_p_ub)
0502     {
0503         NDRX_LOG(log_error, "-b: Mandatory!");
0504         EXFAIL_OUT(ret);
0505     }
0506     
0507     if (M_numcalls <= 0)
0508     {
0509         NDRX_LOG(log_error, "-n: Number of call must be possitive!");
0510         EXFAIL_OUT(ret);
0511     }
0512     
0513     if (M_bigmsg)
0514     {
0515         /* prepare compare buffer - add */
0516 
0517         if (EXSUCCEED!=Bchg(M_p_ub, T_CARRAY_3_FLD, 0, M_bigmsg_buf, 
0518                 sizeof(M_bigmsg_buf)))
0519         {
0520             NDRX_LOG(log_error, "Failed to add T_CARRAY_3_FLD (bigmsg) to M_p_ub: %s", 
0521                 Bstrerror(Berror));
0522             EXFAIL_OUT(ret);
0523         }
0524         
0525         if (EXSUCCEED!=Bchg(M_p_ub_cmp_cache, T_CARRAY_3_FLD, 0, M_bigmsg_buf, 
0526                 sizeof(M_bigmsg_buf)))
0527         {
0528             NDRX_LOG(log_error, "Failed to add T_CARRAY_3_FLD (bigmsg) to M_p_ub_cmp_cache: %s", 
0529                 Bstrerror(Berror));
0530             EXFAIL_OUT(ret);
0531         }
0532     }
0533     
0534     /* loop over */
0535     if (M_threads > 1)
0536     {
0537         if (EXSUCCEED!=run_threads())
0538         {
0539             EXFAIL_OUT(ret);
0540         }
0541     }
0542     else 
0543     {
0544         if (EXSUCCEED!=main_loop(NULL))
0545         {
0546             EXFAIL_OUT(ret);
0547         }
0548     }
0549     
0550 out:
0551                 
0552     if (NULL!=M_p_ub)
0553     {
0554         tpfree((char *)M_p_ub);
0555     }
0556 
0557     if (NULL!=M_p_ub_cmp_cache)
0558     {
0559         tpfree((char *)M_p_ub_cmp_cache);
0560     }
0561 
0562     if (EXSUCCEED!=ret)
0563     {
0564         NDRX_LOG(log_error, "TESTERROR!");
0565     }
0566 
0567     tpterm();
0568     fprintf(stderr, "Exit with %d\n", ret);
0569     
0570     return ret;
0571 }
0572 /* vim: set ts=4 sw=4 et smartindent: */