Test java and C applications with python
This is a modal window.
The media could not be loaded, either because the server or network failed or because the format is not supported.
Formal Metadata
Title |
| |
Title of Series | ||
Number of Parts | 131 | |
Author | ||
Contributors | ||
License | CC Attribution - NonCommercial - ShareAlike 3.0 Unported: You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this | |
Identifiers | 10.5446/69507 (DOI) | |
Publisher | ||
Release Date | ||
Language |
Content Metadata
Subject Area | ||
Genre | ||
Abstract |
|
00:00
Ordinary differential equationLocal GroupSinguläres IntegralDigital signalProcess (computing)Statistical hypothesis testingFunction (mathematics)CodeLibrary (computing)2 (number)Design of experimentsLogicSlide ruleComputer networkString (computer science)Physical systemStatistical hypothesis testingJava appletSineParametrische ErregungJava appletCodeStatistical hypothesis testingSoftware developerSoftwareVirtual machineTime zoneMereologyCartesian coordinate systemData storage deviceIP addressCASE <Informatik>Statistical hypothesis testingDigitizingDifferent (Kate Ryan album)Functional (mathematics)Sound effectSoftware frameworkLibrary (computing)Cloud computingType theorySlide ruleTelecommunicationHuman migrationProtein foldingSocial classShared memoryBoltzmann equationQuicksortLine (geometry)Formal languageGoodness of fitInterface (computing)Video gameInteractive televisionComputer configurationMoment (mathematics)Electric generatorInformation securityPoint cloudINTEGRALFunction (mathematics)LogicProcess (computing)BytecodeInstallation artVirtualizationMultiplication signDigital signal processingSinc functionService (economics)Standard deviationAddress spaceComputer animation
06:59
Java appletParametrische ErregungCodeStatistical hypothesis testingStatistical hypothesis testingError messageFunction (mathematics)System callSoftware developerBuildingLibrary (computing)FlagIndependence (probability theory)Position operatorCore dumpCorrelation and dependence2 (number)Statistical hypothesis testingCodeBuffer solutionSoftware developerCartesian coordinate systemIntegerWritingSoftware bugCASE <Informatik>Network socketJava appletStatistical hypothesis testingIP addressNumberDampingObject (grammar)BitMereologySocial classString (computer science)outputLibrary (computing)Error messageFunctional (mathematics)InformationType theorySequenceDistribution (mathematics)DecimalData structureField (computer science)Independence (probability theory)FlagStandard deviationModule (mathematics)PreprocessorComputer fileParsingFormal languageSystem callComplex numberVapor barrierComputer animation
13:58
Core dumpCodeFunction (mathematics)HypothesisCanadian Light SourceData structureIn-System-ProgrammierungProcess (computing)DisintegrationEvent horizonMountain passStatistical hypothesis testingJava appletComputer networkSoftware developerReduction of orderSoftwareImage resolutionJava appletNumberFunctional (mathematics)Ring (mathematics)ChainCartesian coordinate systemComputer fileStatistical hypothesis testingFrame problemLine (geometry)CoprocessorCodeIntegerInformationSocial classType theoryData structureBuffer solutionLibrary (computing)Statistical hypothesis testingSelf-referenceEmailLogicResultantValidity (statistics)MereologyINTEGRALFunction (mathematics)String (computer science)Pointer (computer programming)Software developerCore dumpEvent horizon2 (number)AuthenticationPoint (geometry)Dependent and independent variablesCASE <Informatik>ParsingPreprocessorNormal (geometry)Message passingComputer animation
20:58
Density of statesIntrusion detection systemDesign of experimentsFinite-state machineCloud computingArithmetic logic unitConservation of energyComputer fileData structureOnline helpRoundness (object)CASE <Informatik>Denial-of-service attackSkeleton (computer programming)Streaming mediaProjective planeResultantPresentation of a groupMicrocontrollerComputer architectureMobile appBytecodeSoftware developerComplex (psychology)MiniDiscMultiplication signType theoryMereologyLevel (video gaming)Product (business)Statistical hypothesis testingCartesian coordinate systemSoftwareOperator (mathematics)CompilerCodeDirection (geometry)ChainStatistical hypothesis testingLatent heatSingle-precision floating-point formatCore dumpBitSystem administratorPhysical systemCompilation albumRevision controlStaff (military)InformationSlide ruleLecture/Conference
Transcript: English(auto-generated)
00:04
I speak about testing JAWS application. But, well, I am Roberto Bolli. I work in Patek that is an Italian IT security and cloud company. I work on designing secure resilient infrastructure based
00:23
on cloud platform and I spent the last five years working for the Italian digital department, digital transformation department. So, this is a tale of a daily experience where Python saved the day, doesn't promote any best practice,
00:44
something that works and can save your day too. So, at first we would start telling why testing application written in foreign languages and essentially because Python is a very good testing glue. We will see then how to test Java code, how to test C code
01:05
and finally, well, conclusions. So, not that deep dive on C types, foreign function interface, Jpipe, not suggesting to replace native testing with Python.
01:23
So, we don't live anyway in a perfect world and so in our life we might need to reduce technical depth and we have no strategic advantage in writing C code, for example, or we are running out of C developers.
01:41
Maybe we want to migrate an application and we need to ensure that functionalities are preserved during the migration and the test case that we write in Python can be reused after the migration or we want to consolidate integration tests when application are tested only in isolation.
02:01
So, Java application with Java test, C application with C test and we don't have integration tests or integration tests are low, we have network, we have latencies, we have C application that go in segmentation folds or they require infrastructural setups.
02:21
So, shortly we can test foreign application with Python to reliably evolve service without spending a lot of money. We can write better tests, we can write them faster, run them faster and share the work of Q&A with more people
02:41
since C developers are really running out. So, when it came to cost effectiveness, Python is great, we have a lot of framework for generating and managing test data, we have network libraries baked in the Python standard library and it is very easy to execute foreign code,
03:03
thanks to libraries like C types, J type and CFFI. So, these slides shows a Python test that generates data and pass them to C function.
03:20
Everything that is important here is that all happens inside the Python test process. We have no network communication going in and out and this practice allows us to test single part of a complete application. This is faster and more flexible.
03:42
For example, we can use Python tools to generate HTTP requests, pack them as bytes and send them to a C function that is compiled. We can even store test output to create more test cases.
04:06
So, we can then apply this logic of calling foreign function from Python to different code segments and generate test data for each step. So, I feed the Java function with test data,
04:24
then I cherry-pick the Java function I want to test and spawn this generated test data to other function. And what I found that speed sub-testing is that you can skip network interaction in many cases.
04:42
So, let's test how to test Java code. This is quite simple. We just need to install jpeg one. Clearly, we need a Java virtual machine installed. I set up the virtual machine, import the classes, okay?
05:01
And then those four lines are simply Java code without semicolons actually and braces. Well, that's straight forward. So, here we're running a real test.
05:22
I like pytest, so we can use fixture. It simply set up a JVM. We can pass our Java options. We can set up the classpad. The nice thing here is that I can iterate with different Java options.
05:41
So, test, for example, if my Java function works correctly, even if I change the time zone, for example, if I don't set the time zone, I add the Java classes I want to test. And then I run the test. That's the else stuff.
06:00
We'll see in a moment. And then shut down the JVM. Now run the test. As you can see, I get the Java class and I invoke the toLowerCase method and check that works. It actually executes Java bytecode. So, JVM allows us to automatically import Java classes,
06:21
but, well, tools may complain. I sort of can remove one line and PyFlix can complain because, well, Java language is not a package. Yeah, it's not a package. It just work around. But it's faster to write code. And we could even delegate writing Python tests
06:41
for Java application to Java developers. So, this snippet shows how to test. Guava is a Google Java library. There is this init address class
07:01
that validates IP addresses. I feed the test function with all the fixtures. Then I load the Java class and check whether it is valid. Well, the nice thing here is that jpy allows passing Python strings.
07:23
That's the one we have in feed by pytest, to a Java method that takes a Java language string input. But this is not always the case.
07:41
For example, if we use the big decimal class, that is a class that implements precision, barrier precision numbers in Java, I have a Python float. I instantiate Java object that is a big decimal.
08:02
But if I want to add a big decimal number to a Java object, I cannot pass a Python float. I need to instantiate a Java object and then it will work.
08:22
And this is generally the correct thing to do. But again, it's very easy and allows you to delegate writing tests to other people. And it works even interactively if you have a Python.
08:44
So it's just like having an RAPL in Java. So testing SQL, it's a bit more complex. I don't go very deep on this part,
09:04
but well, if it's not clear, you can reach out to me. So the real part here is that we may want to offload C developers.
09:23
So there are C applications, maybe you haven't read it and you need to maintain a C application that have been written by other folks. And you don't have that many C developers
09:41
so you can write tests in Python. You may not want to write legacy C code because that application is legacy and you don't want to continue maintaining it. And there are some cases where that makes sense, but it may not always make sense.
10:03
Or maybe you want to test some C library and you don't know how it works and you want to play with it. And that's a good way to do it because you can do it with IPython. And another use case is troubleshooting errors in isolated function calls.
10:22
Because when you run a C application, if you just make an end-to-end test, you send stuff through TrustSocket and you get stuff on the other side, always TrustSocket, for example. And it's very hard to identify a small function inside that C application that you want to test,
10:43
but this allows you to do it. For example, you have segmentation false and this means that you need to start a write test in C. You can isolate the functions and then try to fix the code without continuously restarts.
11:03
So imagine, well, this is a very simple C file. Imagine we want to test the parse person C function. It takes a semicolon separated string, puts the value in a person's structure, just like that.
11:24
To access the function from Python, we need to create a shared library first. This is done compiling the file with the position independent code flag and then linking it as a shared library. So that is the function. We have a struct.
11:41
We have to compile with the position independent code and create the shared library. Now we can load this function from Python. Note that we have these libx.so shared library. We can use the C types standard library module
12:01
to load it and access its function through the CDLL class. So in the LE variable, I load the shared library. And then before using it,
12:22
I need to provide to Python all the information that is lost after build, such as types, the structure and preprocessor stripped data. And for example, we need to define the person class
12:41
using the structure class from C types, specifying the fields and their types, just like we did in the C code. Then I can test the function. I pass it a byte sequence.
13:02
And then with the biref magic, it puts all the information in the person like it was C structure. Okay, this is a very simple way to test a C function.
13:23
Another thing I could have passed instead of the person class, buffer, a C buffer, and then I should have controlled every single byte. So the first bytes were four bytes for the integer and 20 bytes for the name.
13:44
But Python can do it by itself. And another thing, the function had a lot of bugs. And I can test whether my function is not safe and this triggers a segmentation fault.
14:02
But instead testing and debugging it into the old C application that ran that function, I can just gdb on Python and going to the right frame, I can see the issue. So line is null
14:21
and I'm using a scanf on and out. And it's very straightforward and I can debug like that with every single function where I have problem. So real code requires more steps.
14:42
Here I have libc.json that is a real library. It has a lot of defines. Those are replaced by the C preprocessor. I have a structure that has self-references, okay? And this needs some tweaks.
15:02
And finally, I have a function under test that returns a structure and not a simple integer. How can I do it? So in the Python code, I need to provide all the information that are strict. So all the defines.
15:22
I need to define just a bare class. So I can reuse it here and avoid circular references in the C JSON class. Then I load the library,
15:41
point to the function under test and tell to Python that the response type of that function is a pointer to the C JSON function, to a C JSON structure. Some tweaks clearly.
16:00
And then I can just use a parameterized test to see how that library works. I get the bytes. I pass the bytes to C JSON parse and I check that the type is correct. So it's always a number.
16:23
And then for example, I discovered that I pass one on the line, three zeros to the C JSON library. I don't get 1,000 like it happens for example in Python, but I get 1.0.
16:44
So not everything is something behave like we may think. So the benefits. Normally I would do with an integration test what happens above. I paste data to a C application
17:02
that goes throughout the network, invokes my function, get a result that is passed to a Java application that process it and then I validate it. Usually integration tests are written in Python so data generator and the validator are in Python
17:23
in my case. But if I run it inside a pyfest, I have everything on Python. Clearly it doesn't test that network is behaving correctly. It doesn't test everything that is around
17:43
the log function and the event parse function. But clearly those are other tests that you need to do. But at first if the test below works, probably testing with the network is simple.
18:05
And here we have a simple but complete example. I have an event processor class in Java. I process an event that returns an output string in JSON and before sending it to C types,
18:23
I check that the output is correct for Python and I can add all the intermediate checks that I want. Then I create a string buffer from this JSON document and pass it, yeah Java output, it should be JSON document
18:43
and pass it to C JSON parse and check that the type is correct. Here I can add other function, make tests more simple or more complex but that's generally the idea.
19:01
And well, we are almost done. Conclusions, writing Python tests for Java in C application solves organizational and technical problems. Usually if you are very good,
19:22
you can solve technical problems. It's hard to solve organizational problems. For example, hiring C developers or widening the number of teammates that is able to support the testing work of your team.
19:47
So ensure quality even if you're running out of C developers, reduce the effort of writing C code, speeding test execution since when you skip networking and infrastructural setup,
20:01
you could, for example, take one log file, identify the core business chain between Java, C or other foreign code and dump all the log through this selected chain and run tests.
20:22
For me, I was able to run maybe 1000 to 5000 tests a bunch of seconds. Imagine sending all this stuff in network, applying authentication and so on.
20:40
C authentication, Java authentication. You can get rid of it if you want just to test application logic. And well, I think I finished. Have I been fast? Really hope that it was clear
21:01
but if there are some steps that weren't clear, I can step back to the slides. Okay, thank you, Roberto. So we will probably leave it for Q&A session that we can go back as well. So do we have any questions from the audience?
21:21
There's a mic in the middle. Please step there. Hello, thank you for the nice presentation. One thing I was wondering, especially about the part of C code is that it seems that you have to replicate the types of the C code in the Python code.
21:43
Do you know if there is any tools that can aid on that? Oh, okay. I saw it coming. So there are some tools. You can use CFFI for this code because it has some ability.
22:02
If you pass an .h file, he has the ability to extract information from .h file where you have structures and so on. In my case, it didn't help that much because I had one special use case.
22:23
I had to stream. The structure was streamed over network and it weren't aligned to four bytes. But when you use C types or CFFI, in general, compilers align to four bytes structure.
22:47
Two or four bytes should be four. And you have special directives in C such as PECT, the PECT directive in GCC that tells the compiler not to pack bytes,
23:03
to pack bytes and don't align to four bytes. As of now, but this may change, when you generate structure, Python structures from .h file, directives such PECT are not respected
23:25
because they're compiler specific. So my structure were misaligned. But probably if there is some Python core developers here,
23:41
can share some hints on that. But yes, you can use with CFFI .h file. In this case, it was simple because it was just two fields. Okay, thank you. Thank you, thanks for your question.
24:01
Okay, do we have any other questions from the audience? Don't be shy. In the meantime, I will ask one. Is it a complex practice or anyone with a system level kind of knowledge of development can do it easily? Well, my experience is that I was able
24:20
to delegate writing tests for C application to general system administrators or operation colleagues that had clearly Python knowledge.
24:41
So once I set up the skeleton of the Python stuff, they were able to write and improve tests autonomously. And for me, this was a great achievement because for that application,
25:00
I was starting to become a bottleneck. And of flooding stuff to other people means you can even get better results because they have more time and they can spend and understand better. And so they can contribute better to the projects.
25:22
So this was a real organizational goal of all this stuff. Okay, thank you very much for that. I got, oh, finally question from the public. Hi, thank you for very nice presentation. Have you ever had experience with microcontrollers and testing the C code for microcontrollers
25:44
that you can generate by deploying on an agent and compiling in there? And then doing some testing with Python code on compile? My experience was just playing with my son with Arduino.
26:04
But I think that if the byte code is compatible, the byte code you compile on the microcontroller is compatible with the Python version
26:21
you are using. And if the Python for the microcontroller has the C types support, probably you can do it or maybe you can make a tool chain to compile your microcontroller code single on AMD 64 bytes bits architecture.
26:47
But it's interesting question because it could simplify a lot of stuff, but I never tried. Thank you. If you do it, let me know.
27:01
Thank you, well, that was also my prepared question so it goes away. Okay, I can't see any more questions here or online, but I will ask one last. Wouldn't it be better to write the original app directly in Python? Well, that depends in some cases, yes.
27:23
For example, we started moving some code from C to Python when we have, for example, network bottlenecks or disk bottlenecks. When there are some specific requirements
27:44
it's not easy because you have to demonstrate that you are not creating something that can break in production because Python always work very well in prototyping,
28:05
but in production, I always like to test Python application better since I'm a Python advocate. So I prefer to fall fast, but if it's possible not to fail.
28:21
But yes, in some cases, we are migrating, since there is asyncio, we are migrating stuff from C to Python. Brilliant, thank you very much for that. Big round of applause for Roberto. Thank you.