Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief Protocol converter unit tests
0003  *
0004  * @file atmiunit0_exproto.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 
0035 #include <stdio.h>
0036 #include <stdlib.h>
0037 #include <unistd.h>
0038 #include <cgreen/cgreen.h>
0039 #include <ubf.h>
0040 #include <ndrstandard.h>
0041 #include <string.h>
0042 #include "test.fd.h"
0043 #include "ndebug.h"
0044 #include "xatmi.h"
0045 #include "atmi_int.h"
0046 #include <fdatatype.h>
0047 #include <nstdutil.h>
0048 #include <typed_buf.h>
0049 #include <extest.h>
0050 #include <atmi_int.h>
0051 #include <exproto.h>
0052 #include <atmi_tls.h>
0053 #include <exassert.h>
0054 #include <nstd_shm.h>
0055 /**
0056  * Basic preparation before the test
0057  */
0058 exprivate void basic_setup(void)
0059 {
0060     
0061 }
0062 
0063 exprivate void basic_teardown(void)
0064 {
0065     
0066 }
0067 
0068 /**
0069  * Perform network call (wrapper from c->net->c)
0070  * Function is used to validate transportation of different kind of ATMI buffers
0071  * @param req_buf input ATMI buffer
0072  * @param req_len input len
0073  * @param obuf output buffer ATMI
0074  * @param olen output buffer len
0075  * @param mbufsz mutli-buffer size (output tlv)
0076  * @param netbufsz network output buffer size
0077  * @param cback_size C buffer size when parsing msg in (from net)
0078  * @return EXSUCCEED/EXFAIL
0079  */
0080 exprivate int netcallconv(char *req_buf, long req_len, char **obuf, long *olen, 
0081         long mbufsz, long netbufsz, long cback_size)
0082 {
0083     int ret = EXSUCCEED;
0084     tp_command_call_t *call=NULL;
0085     tp_command_call_t *callpars=NULL;
0086     char smallbuf[sizeof(cmd_br_net_call_t) + sizeof(char *)];
0087     cmd_br_net_call_t *netcall = (cmd_br_net_call_t *)smallbuf;
0088     long call_len_org;
0089     long netcall_len_org;
0090     long proto_len;
0091     char *proto_out=NULL;
0092     char *cbuf_back = NULL;
0093     long max_struct = 0;
0094     ndrx_stopwatch_t w;
0095     time_t t;
0096     /* prepare call, dynamic buffer */
0097     call = (tp_command_call_t *)NDRX_MALLOC(mbufsz);
0098     
0099     if (NULL==call)
0100     {
0101         NDRX_LOG(log_error, "Failed to malloc call: %s", strerror(errno));
0102         EXFAIL_OUT(ret);
0103     }
0104     
0105     memset(call, 0, sizeof(*call));
0106     /* netcall buf bytes are set to dynamic call buffer */
0107     memcpy(netcall->buf, &call, sizeof(char *));
0108     
0109     call->data_len=mbufsz-sizeof(*call);
0110     
0111     /* prepare MBUF for output */
0112     if (EXSUCCEED!=ndrx_mbuf_prepare_outgoing (req_buf, req_len, call->data, 
0113             &call->data_len, 0, 0))
0114     {
0115         NDRX_LOG(log_error, "Failed to prepare outgoing data: %s", 
0116                 tpstrerror(tperrno));
0117         EXFAIL_OUT(ret);
0118     }
0119     
0120     call_len_org=call->data_len;
0121     netcall_len_org = netcall->len=sizeof(*call)+call_len_org;
0122     
0123     if (NULL==(proto_out=NDRX_MALLOC(netbufsz)))
0124     {
0125         NDRX_LOG(log_error, "Failed to malloc %ld bytes: %s", netbufsz, strerror(errno));
0126         EXFAIL_OUT(ret);
0127     }
0128     
0129     /* setup some minimum constant values: */
0130     
0131     ndrx_stopwatch_reset(&w);
0132     t=time(NULL);
0133     
0134     call->timer = w;
0135     call->cd = 999;
0136     call->timestamp = t;
0137     call->command_id=ATMI_COMMAND_TPCALL;
0138     NDRX_STRCPY_SAFE(call->name, "HELLOSVC");
0139     
0140     netcall->br_magic=BR_NET_CALL_MAGIC;
0141     netcall->command_id=ATMI_COMMAND_TPCALL;
0142     netcall->msg_type=BR_NET_CALL_MSG_TYPE_ATMI;
0143     
0144     proto_len=0;
0145     if (EXSUCCEED!=exproto_ex2proto((char *)netcall, sizeof(*call)+call->data_len, 
0146     proto_out, &proto_len, netbufsz))
0147     {
0148         NDRX_LOG(log_error, "Failed to convert to convert to net-proto");
0149         EXFAIL_OUT(ret);
0150     }
0151     
0152     cbuf_back = NDRX_MALLOC(cback_size);
0153     
0154     if (NULL==cbuf_back)
0155     {
0156         NDRX_LOG(log_error, "Failed to malloc back parse buffer: %s", strerror(errno));
0157         EXFAIL_OUT(ret);
0158     }
0159     
0160     memset(cbuf_back, 0, sizeof(cmd_br_net_call_t) + sizeof(tp_command_call_t));
0161     netcall = (cmd_br_net_call_t *)cbuf_back;
0162             
0163     callpars = (tp_command_call_t *)(cbuf_back + sizeof(cmd_br_net_call_t));
0164     
0165     if (EXFAIL==exproto_proto2ex(proto_out, proto_len, 
0166         cbuf_back, &max_struct, cback_size))
0167     {
0168         NDRX_LOG(log_error, "Failed to convert proto -> EX");
0169         EXFAIL_OUT(ret);
0170     }
0171     
0172     if (EXSUCCEED!=ndrx_mbuf_prepare_incoming (call->data, call->data_len, obuf, olen, 
0173             0, 0))
0174     {
0175         NDRX_LOG(log_error, "Failed to prepare incoming buffers");
0176         EXFAIL_OUT(ret);
0177     }
0178     
0179     /* minimalistic verification: */
0180     NDRX_ASSERT_VAL_OUT((netcall->br_magic==BR_NET_CALL_MAGIC), "Invalid netcall->br_magic %ld vs %ld", 
0181             netcall->br_magic, BR_NET_CALL_MAGIC);
0182     
0183     NDRX_ASSERT_VAL_OUT((netcall->command_id==ATMI_COMMAND_TPCALL), "%d vs %d", 
0184             netcall->command_id, ATMI_COMMAND_TPCALL);
0185     NDRX_ASSERT_VAL_OUT((netcall->msg_type==BR_NET_CALL_MSG_TYPE_ATMI), "%x vs %x", 
0186             (int)netcall->command_id, (int)ATMI_COMMAND_TPCALL);
0187     
0188     NDRX_ASSERT_VAL_OUT((netcall->len==netcall_len_org), "%ld vs %ld", 
0189             netcall->len, netcall_len_org);
0190     NDRX_ASSERT_VAL_OUT((callpars->data_len==call_len_org), "%ld vs %ld", 
0191             callpars->data_len, call_len_org);
0192     
0193     NDRX_ASSERT_VAL_OUT((callpars->cd==999), "%d vs %d", callpars->cd, 999);
0194     NDRX_ASSERT_VAL_OUT((0==strcmp(callpars->name, "HELLOSVC")), "%s vs %s", callpars->name, "HELLOSVC");
0195     
0196     NDRX_ASSERT_VAL_OUT((callpars->command_id==ATMI_COMMAND_TPCALL), "%hd vs %hd", 
0197             callpars->command_id, (short)ATMI_COMMAND_TPCALL);
0198     
0199     NDRX_ASSERT_VAL_OUT((callpars->timer.t.tv_nsec==call->timer.t.tv_nsec), "%ld vs %ld", 
0200             (long)callpars->timer.t.tv_nsec, (long)call->timer.t.tv_nsec);
0201     
0202     NDRX_ASSERT_VAL_OUT((callpars->timer.t.tv_sec==call->timer.t.tv_sec), "%ld vs %ld",
0203             (long)callpars->timer.t.tv_sec, (long)call->timer.t.tv_sec);
0204     
0205     NDRX_ASSERT_VAL_OUT((callpars->timestamp==call->timestamp), "%ld vs %ld",
0206             (long)callpars->timestamp, (long)call->timestamp);
0207     
0208 out:
0209     
0210     if (NULL!=call)
0211     {
0212         NDRX_FREE(call);
0213     }
0214 
0215     if (NULL!=proto_out)
0216     {
0217         NDRX_FREE(proto_out);
0218     }
0219 
0220     if (NULL!=cbuf_back)
0221     {
0222         NDRX_FREE(cbuf_back);
0223     }
0224 
0225     return ret;    
0226 }
0227 
0228 /**
0229  * Convert UBF call two way
0230  */
0231 Ensure(test_proto_ubfcall)
0232 {
0233     UBFH *p_ub = (UBFH *)tpalloc("UBF", 0, 2024);
0234     UBFH *p_ci = (UBFH *)tpalloc("UBF", 0, 2024);
0235     UBFH *p_ub5 = NULL;
0236     UBFH *p_ci5 = NULL;
0237     struct UBTESTVIEW1 *vptr;
0238     struct UBTESTVIEW1 *vptr5;
0239     char *vptr_2;
0240     char *vptr5_2;
0241     long olen;
0242     
0243     assert_not_equal(p_ub, NULL);
0244     
0245     /* have some ptr to VIEW... */
0246     
0247     ATMI_TLS_ENTRY;
0248     
0249     vptr=(struct UBTESTVIEW1 *)tpalloc("VIEW", "UBTESTVIEW1", sizeof(struct UBTESTVIEW1));
0250     assert_not_equal(vptr, NULL);
0251     
0252     vptr_2=tpalloc("CARRAY", NULL, 567);
0253     assert_not_equal(vptr_2, NULL);
0254     
0255     memset(vptr_2, 'Z', 567);
0256     vptr_2[0]='A';
0257     vptr_2[499]='A';
0258     
0259     extest_init_UBTESTVIEW1(vptr);
0260     
0261     /* set call infos */
0262     assert_equal(Bchg(p_ci, T_STRING_6_FLD, 4, "HELLO CALL INFO", 0), EXSUCCEED);
0263     
0264     /* load primary data.., including sub-ubf buf */
0265     extest_ubf_set_up_dummy_data(p_ub, EXTEST_PROC_UBF | EXTEST_PROC_VIEW);
0266     
0267     assert_equal(tpsetcallinfo((char *)p_ub, p_ci, 0), EXSUCCEED);
0268     
0269     
0270     /* Load view ptr..., at pos 0 we will have NULL buffer ... */
0271     assert_equal(Bchg(p_ub, T_PTR_FLD, 1, (char *)&vptr, 0), EXSUCCEED);
0272     assert_equal(Bchg(p_ub, T_PTR_FLD, 2, (char *)&vptr_2, 0), EXSUCCEED);
0273     
0274     Bprint(p_ub);
0275     
0276     olen=0;
0277     assert_equal(netcallconv((char *)p_ub, 0, (char **)&p_ub5, &olen, 9000, 9000, 9000), EXSUCCEED);
0278             
0279     Bprint(p_ub5);
0280     
0281     /* read ptr */
0282     assert_equal(Bget(p_ub5, T_PTR_FLD, 1, (char *)&vptr5, 0), EXSUCCEED);
0283     assert_equal(Bget(p_ub5, T_PTR_FLD, 2, (char *)&vptr5_2, 0), EXSUCCEED);
0284     
0285     /* ptr, as it will be different */
0286     Bdel(p_ub, T_PTR_FLD, 2);
0287     Bdel(p_ub5, T_PTR_FLD, 2);
0288     Bdel(p_ub, T_PTR_FLD, 1);
0289     Bdel(p_ub5, T_PTR_FLD, 1);
0290     
0291     
0292     assert_equal(Bcmp(p_ub, p_ub5), 0);
0293     
0294     
0295     Bvprint((char *)vptr, "UBTESTVIEW1");
0296     
0297     Bvprint((char *)vptr5, "UBTESTVIEW1");
0298     
0299     assert_equal(Bvcmp((char *)vptr, "UBTESTVIEW1", (char *)vptr5, "UBTESTVIEW1"), 0);
0300     
0301     
0302     assert_equal(memcmp(vptr_2, vptr5_2, 567), 0);
0303     
0304     /* read the call infos ! */
0305     assert_equal(tpgetcallinfo((char *)p_ub5, &p_ci5, 0), EXSUCCEED);
0306     assert_equal(Bcmp(p_ci, p_ci5), 0);
0307     
0308 
0309     tpfree((char *)p_ub);
0310     tpfree((char *)p_ub5);
0311     
0312     tpfree((char *)p_ci);
0313     tpfree((char *)p_ci5);
0314  
0315 }
0316 
0317 Ensure(test_proto_nullcall)
0318 {
0319     char *null_buf = NULL;
0320     long olen = 0;
0321     char *null_out = NULL;
0322     ATMI_TLS_ENTRY;
0323     
0324     assert_equal(netcallconv(null_buf, 0, (char **)&null_out, &olen, 1024, 1024, 1024), 
0325             EXSUCCEED);
0326     
0327     assert_equal(null_buf, NULL);
0328     assert_equal(null_out, NULL);
0329     assert_equal(olen, 0);
0330     
0331 }
0332 
0333 Ensure(test_proto_carraycall)
0334 {
0335     char *carray_buf = NULL;
0336     long olen = 0;
0337     char *carray_out = NULL;
0338     char rndbuf[1028];
0339     
0340     ATMI_TLS_ENTRY; /* otherwise mbuf cannot work with NULL buffers */
0341     
0342     carray_buf=tpalloc("CARRAY", NULL, 1028);
0343     
0344     memcpy(carray_buf, rndbuf, sizeof(rndbuf));
0345     
0346     assert_equal(netcallconv(carray_buf, 1028, (char **)&carray_out, &olen, 2000, 2000, 2000), 
0347             EXSUCCEED);
0348     assert_equal(memcmp(carray_buf, carray_out, sizeof(rndbuf)), 0);
0349     
0350     tpfree(carray_buf);
0351     tpfree(carray_out);
0352 }
0353 
0354 /**
0355  * Perform no-space tests (i.e. buffer too for the operation)
0356  * Check that any of converting parts go over the allocated memory...
0357  */
0358 Ensure(test_proto_nospace)
0359 {
0360     int i,j,k;
0361     UBFH *p_ub = (UBFH *)tpalloc("UBF", 0, 2048);
0362     UBFH *buf_out;
0363     long olen;
0364     int ret = EXSUCCEED;
0365     int callsize=sizeof(cmd_br_net_call_t)+sizeof(tp_command_call_t);
0366     
0367     assert_not_equal(p_ub, NULL);
0368 
0369     extest_ubf_set_up_dummy_data(p_ub, EXTEST_PROC_UBF | EXTEST_PROC_VIEW);
0370     
0371     for (i=callsize; i<3000; i+=56)
0372         for (j=callsize; j<3000; j+=56)
0373             for (k=callsize; k<3000; k+=56)
0374             {
0375                 /* try 3x combinations... */
0376                 olen=0;
0377                 buf_out=NULL;
0378                 netcallconv((char *)p_ub, 0, (char **)&buf_out, &olen, i, j, k);
0379                 
0380                 if (NULL!=buf_out)
0381                 {
0382                     NDRX_ASSERT_UBF_OUT((0==Bcmp(p_ub, buf_out)), "Buffer does not match");
0383                     
0384                     tpfree((char *)buf_out);
0385                 }
0386                 
0387             }
0388     
0389 out:
0390             
0391     assert_equal(ret, EXSUCCEED);
0392             
0393 }
0394 
0395 #define LEVEL_MAX   100
0396 ndrx_shm_t M_testmem;
0397 
0398 
0399 int brute_force_protocol(int level)
0400 {
0401     int ret = EXSUCCEED;
0402     int i;
0403     
0404     if (LEVEL_MAX==level)
0405     {
0406         char obuf[1024];
0407         long len;
0408         
0409         /* just run the asan... */
0410         exproto_proto2ex((char *)M_testmem.mem, LEVEL_MAX, obuf, &len, 1024);
0411     }
0412     else for (i=M_testmem.mem[level]; i<255; i++)
0413     {
0414         M_testmem.mem[level]=(char) (i & 0xff);
0415         brute_force_protocol(level+1);
0416     }
0417 
0418 out:
0419     return ret;
0420 }
0421 
0422 /**
0423  * Needs to have shm, so that we can restart when looped with out
0424  * log files.
0425  */
0426 Ensure(test_proto_rndparse)
0427 {
0428     int i;
0429     
0430     memset(&M_testmem, 0, sizeof(M_testmem));
0431     M_testmem.size=LEVEL_MAX;
0432     M_testmem.key = 0x00aabbcc;
0433     
0434     NDRX_STRCPY_SAFE(M_testmem.path, "/test");
0435     
0436     
0437     if (EXSUCCEED==ndrx_shm_open(&M_testmem, EXFALSE))
0438     {
0439         /* start here... */
0440         fprintf(stderr, "Creating new...\n");
0441         memset(M_testmem.mem, 0, LEVEL_MAX);
0442     }
0443     else
0444     {
0445         fprintf(stderr, "Continuing...\n");
0446         assert_equal(ndrx_shm_open(&M_testmem, EXTRUE), EXSUCCEED);
0447     }
0448             
0449     assert_equal(brute_force_protocol(0), EXSUCCEED);
0450 }
0451 
0452 /**
0453  * Check the time sync conv operations
0454  */
0455 Ensure(test_proto_timesync)
0456 {
0457     cmd_br_time_sync_t *ptr_tmsg;
0458     char smallbuf[sizeof(cmd_br_net_call_t) + sizeof(cmd_br_time_sync_t)];
0459     cmd_br_net_call_t *netcall = (cmd_br_net_call_t *)smallbuf;
0460     char proto_out[1024];
0461     long proto_len;
0462     long max_struct = 0;
0463     cmd_br_time_sync_t *tmsg_back;
0464     cmd_br_time_sync_t tmsg;
0465     char *tmp_ptr;
0466 
0467     memset(&tmsg, 0, sizeof(tmsg));
0468     
0469     tmsg.call.msg_type=NDRXD_CALL_TYPE_BRBCLOCK;
0470     tmsg.call.command = NDRXD_COM_BRCLOCK_RQ;
0471     tmsg.call.caller_nodeid=1;
0472     tmsg.call.msg_src = NDRXD_SRC_ADMIN;
0473     tmsg.call.magic=NDRX_MAGIC;
0474     
0475     NDRX_STRCPY_SAFE(tmsg.call.reply_queue, "Helloqueue");
0476     
0477     /* set local time */
0478     ndrx_stopwatch_reset(&tmsg.time);
0479     
0480     netcall->br_magic=BR_NET_CALL_MAGIC;
0481     netcall->command_id=NDRXD_COM_BRCLOCK_RQ;
0482     netcall->msg_type=BR_NET_CALL_MSG_TYPE_NDRXD;
0483         
0484     tmp_ptr = (char *)&tmsg;
0485     memcpy(netcall->buf, &tmp_ptr, sizeof(char *));
0486     assert_not_equal(&tmsg, NULL);
0487     assert_equal(*(cmd_br_time_sync_t **)netcall->buf, &tmsg);
0488     
0489     ptr_tmsg = *((cmd_br_time_sync_t **)netcall->buf);
0490     
0491     assert_equal(ptr_tmsg, &tmsg);
0492     assert_equal(ptr_tmsg->call.command, tmsg.call.command);
0493     
0494     proto_len=0;
0495     assert_not_equal(exproto_ex2proto((char *)netcall, 0, proto_out, &proto_len, 
0496             sizeof(proto_out)), EXFAIL);
0497     
0498     memset(smallbuf, 0, sizeof(smallbuf));
0499     assert_not_equal(exproto_proto2ex(proto_out, proto_len, smallbuf, 
0500             &max_struct, sizeof(smallbuf)), EXFAIL);
0501     
0502     /* OK check the fields... */
0503     tmsg_back = (cmd_br_time_sync_t *)netcall->buf;
0504     
0505     assert_equal(netcall->br_magic, BR_NET_CALL_MAGIC);
0506     assert_equal(netcall->command_id, NDRXD_COM_BRCLOCK_RQ);
0507     assert_equal(netcall->msg_type, BR_NET_CALL_MSG_TYPE_NDRXD);
0508     
0509     /* check call fields*/
0510     assert_equal(tmsg_back->call.command, NDRXD_COM_BRCLOCK_RQ);
0511     assert_equal(tmsg_back->call.caller_nodeid, 1);
0512     assert_equal(tmsg_back->call.msg_type, NDRXD_CALL_TYPE_BRBCLOCK);
0513     assert_equal(tmsg_back->call.msg_src, NDRXD_SRC_ADMIN);
0514     assert_equal(tmsg_back->call.magic, NDRX_MAGIC);
0515     assert_string_equal(tmsg_back->call.reply_queue, "Helloqueue");
0516     
0517     /* finally check the payload */
0518     assert_equal(ndrx_stopwatch_diff(&tmsg.time, &tmsg_back->time), 0);
0519     
0520 }
0521 
0522 /**
0523  * Standard library tests
0524  * @return
0525  */
0526 TestSuite *atmiunit0_exproto(void)
0527 {
0528     TestSuite *suite = create_test_suite();
0529 
0530     add_test(suite, test_proto_ubfcall);
0531     add_test(suite, test_proto_nullcall);
0532     add_test(suite, test_proto_carraycall);
0533     add_test(suite, test_proto_nospace);
0534     /* add_test(suite, test_proto_rndparse); - too long...*/
0535     
0536     add_test(suite, test_proto_timesync);
0537     
0538     return suite;
0539 }
0540 
0541 /* vim: set ts=4 sw=4 et smartindent: */