Pegasus Enhancement Proposal (PEP)
PEP #: 121
Title: Test
Enhancements for Pegasus
Version: 1.3
Created: 18 Dec.
2003
Authors: Subodh Soni
Status: Final
Version History:
Version |
Date |
Author |
Change Description |
1.0 |
18 Dec 2003 |
Subodh Soni |
Initial Submission |
1.1 |
13 Jan 2004 |
Subodh Soni |
Minor editorial changes based on comments by David
Dillard |
1.2
|
02 Feb 2004
|
Subodh Soni
|
Priorities of the proposed
test enhancements added.
|
1.3
|
05 Feb 2004
|
Subodh Soni
|
Final Version uploaded to "Recent Documents"
|
Abstract: This
PEP aims to deliver test enhancements for Pegasus CIMOM. These enhancements
introduce some specific conditions in the CIMOM and check its behavior.
These conditions or test scenarios are the ones that are not tested in
the current implementation of Pegasus and consists of some of the real-life
issues faced by the developers and users (working with various configurations
and machine setups) of Pegasus . The different test cases are present in
the form of either sample providers or shell scripts and are independent of
the existing test programs present in the Pegasus CVS tree.The complete package
containing these test cases can be easily integrated with the existing source
tree and no special knowledge is required to execute these tests.
Definition
of the Problem
There are many scenarios
where the cimom behavior is not known as of the current pegasus stable
source tree. This PEP is an attempt to identify some of these scenarios
and develop test programs to check the behavior exhibited by pegasus when
subjected to these conditions.
The problems are defined
below: [These are various situations in which the cimserver behavior is
not known/ or inconsistent]
1. Single provider responsible
for loading multiple classes and running multiple clients simultaneously
using the classes loaded by this provider.
2. Behavior of Pegasus is different depending on whether the exception
thrown is a CIMException, Pegasus::Exception, or "unknown" exception such
as int. exceptions on initialize, after processing(), etc.
3. What happens if the
provider method does a fork() and creates subprocess from within itself.
What are the handles (or file descriptors) it inherits from the parent.
These conditions occur frequently when an actual provider interacts with
the system through various system calls.
4. What is the behavior
on linux when providers manipulate signals from within their methods.
How is threading and signal handling taken care by pegasus ?
5. Checking for timing-related
issues in the Pegasus common code. Memory testing involving significant
exercising of multiple providers with strange timings, and clients timed
to both stress provider subsystems and pause long enough to exercise the
provider unload logic.
6. The provider calling
the CIMOMHandle sets a UserIdentity into the OperationContext. It is possible
for a provider to call the CIMOMHandle with a user name that is different
than the end-user on the client who sent in the original request. For
example, a provider could set "root" into the UserIdentity, effectively
promoting itself to root authority when calling the CIMOMHandle.
7. Testing the behavior
of Pegasus when the classes it has implemented return a large amount of
data. (For example: a sample provider in which the enumInstances
returns 10000 instances of the class implemented by the provider.
8. Checking the XML parser and generator
programs when malformed strings are passed through the providers
Priority
The priorities of the
above mentioned test enhancements can be assigned based on the areas in the
pegasus code that require more testing.
Based on the above serial nos. the order of the tests can be: 2,
1, 5, 7, 3, 4, 8, 6
Proposed
Solution
An attempt is made
to address the issues/problems/scenarios described in the problem definition
above by writing sample providers, test client programs and various shell
scripts. The sample providers follow the same structure in all the test
programs.
Each sample provider is made atleast of the following files :
<ProviderName>.cpp
|
Implementing
the provider methods |
<ProviderName>.h
|
Header
for the provider implemented |
<ProviderNameMain.cpp>
|
The
main() function calling the PegasusCreateProvider API |
<Provider.mof>
|
The
Sample Class MOF |
<ProviderR.mof>
|
Provider
Registration MOF. |
The solution consists of test providers and test programs for the
following specific conditions: [some parts of the actual code developed
are also provided with the proposed solution for each of the specific
scenarios]
a.) Single Provider implementing
Multiple Classes
This test program containing a sample provider is used
to test the provider for loading multiple classes with various combinations
of the test client to fetch the classes. Various complex client loading scenarios
are introduced in order to achieve this.
The following source programs are implemented for this test case:
1. TestProvider.mof defines 3 sample classes that implement the
TestProvider.cpp source program.
2. The registration mof TestProviderR.mof registers the TestProvider
in the root/SampleProvider namespace.
3. TestProvider.cpp is the actual provider module code.
4. TestProviderMain.cpp is the main program calling the TestProvider
through PegasusCreateProvider call.
5. A client script containing the commands for running CLI with
the possible CIM operations for the classes implemented by the provider.
6. Scripts for deleting provider module and restarting the cimserver
are also written for simplifying the test execution.
A TestProvider is implemented for handling multiple classes. This
provider also contains the code for testing the exception handling explained
in the solution b) below. This exception handling test is present inside
conditional macros to enable/disable it.
b) Exception handling
by Providers
Exception handling by the cimom when all types of exceptions
are thrown from within the provider methods. A sample provider will be
used to throw exceptions at different points in the execution of its
methods (like enumInstances, enumInstNames etc.)
The provider contains the following code macro for enabling and
disabling the exception handling tests in the provider
// The following
macro is enabled/ disabled by setting TEST_EXCEPTIONS in the Makefile.
TestProvider.cpp
....
#ifdef TEST_EXCEPTIONS
#define PEGASUS_EXCEPTION PEGASUS_CIM_EXCEPTION(CIM_ERR_FAILED,
"TestProvider Exception")
#define CIM_EXCEPTION CIMException(CIM_ERR_FAILED,
"Test Provider")
#else
#define PEGASUS_EXCEPTION // These can be defined at the compilation
time in the Makefile.
#define CIM_EXCEPTION
#endif
// Update the value of the following macro for enabling/ disabling
exceptions.
//
#define EXCEPTION_TYPE 0
#define CheckExceptionType(X) {
\
if (X == 1) throw PEGASUS_EXCEPTION; \
if (X == 2) throw CIM_EXCEPTION; \
}
The normal
working of the provider is unaffected if the TEST_EXCEPTIONS flag is
not set during the compilation.
c) Provider load/unload
and Timing
Written a sample
provider in which multiple sleep points are introduced at various points
in the provider method execution. The sleep durations can be different
for the different provider methods.
Its an attempt to find out any inconsistencies in the provider load/unload
(if any) logic.The ideal test case requires that a provider unloads when
another client is invoking enumerate instances for a provider class and
vice versa. It is quite difficult to create this kind of situation with
this set of test programs. By running these tests for long hours we might
hit some problem.
- The provider
(TimingProvider.cpp) implements the base class TimingSampleClass with
3 derived classes TimeOne, TimeTwo, TimeThree.
- The instances
of the TimeOne and TimeTwo classes are created inside the TimingProvider:initialize
method in the provider.
- Scripts are
provided to build, load and execute the provider programs as well running
the client programs and scripts.
The client programs
include:
- Makefile.Client
- A separate Makefile to execute the client program.
- TimingClient.cpp
- This program tests the TimingProvider implemented by running multiple
threads performing different CIM operations. main() forks and child calls EnumerateInstances
for one class. The parent make calls to EnumerateInstances and EnumerateClass.
Long sleeps are inserted between the calls to enumerateinstances and enumerateClasses.
- Client script
- This script contains the combination of TimingClient and CLI client
programs with random sleeps inserted between them.CLI is used to enumerate
instances/ instancenames and enumerate classes for the root/SampleProvider
namespace created by the test provider.
From TimingClient.cpp
.....
int main(int argc, char** argv)
{
pid_t pid;
try
{
CIMClient client;
client.connect("localhost", 5988, "", "");
if ((pid = fork()) < 0)
{
cout << "Fork Error\n" << endl;
exit(0);
}
else if (pid == 0)
{ // child
sleep(10);
EnumerateInstancesTiming(client, CLASSONE);
_exit(0);
}
// parent
sleep(10);
EnumerateInstancesTiming(client, CLASSTWO);
sleep(5);
EnumerateClassesTiming(client, "TimingSampleClass");
}
catch(Exception& e)
{
PEGASUS_STD(cerr) << "Error: " << e.getMessage()
<<
PEGASUS_STD(endl);
exit(1);
}
}
d) Resource sharing,
multithreading and Inheritance in provider methods.
Doing a fork()
from inside the provider methods and examining the file descriptors inherited
by the sub-processes. To handle Linux threading cleanly, the sample provider
thread spawn a reaper thread whose sole purpose is to wait for the subprocess
to terminate.
The implementation is done by creating a sample provider in the
following manner:
- MultithreadingSampleProviderMain.cpp
is the source file which contains the provider entry point routine.
- MultithreadingSampleProvider.cpp
[h] are the main provider sources that implement the MultithreadingSampleClass.
- The Base
class has 3 derived classes called ThreadSampleOne, ThreadSampleTwo and
ThreadSampleThree.
- ThreadSampleOne
class instances are created inside the enumerateInstances method of the
provider. After the instances creation this method calls explicitly the
CreateThread function, which spawns a new sub-process and executes the command
line cim client CLI.
- The additional
functions added in the provider source program other than the standard
provider methods are:
- CreateThread()
- Function creating the sub-process (by using fork())
- reader()
- child process reads from the input stream
- writer()
- Parent process writing to the output stream
- The parent
process after writing to the output stream sleeps in the function writer()
which makes the CLI command give a timeout error.
- Scripts are
created for building the source and repository and for registering the
provider.
From MultithreadingSampleProvider.cpp
[ CreateThreads() function is illustrated below]:
....
int CreateThreads()
{
char* arg_list[] = {
"CLI",
"niall",
"-n",
"root/SampleProvider",
NULL
};
int fds[2];
pid_t cpid;
pipe(fds);
cpid = fork();
if (cpid == (pid_t)0)
{
FILE* stream;
// This is the child process. Close our copy of the write
end
// of the file descriptor.
close(fds[1]);
// Connect the read end of the pipe to standard input.
dup2(fds[0], STDIN_FILENO);
// Convert the read file descriptor to a FILE object, and
read from it
stream = fdopen(fds[0],"r" );
reader(stream);
close(fds[0]);
// Replace the child process with the CLI program
execvp ("CLI", arg_list);
}
else
{
FILE* stream;
// Close our copy of the read end of the file descriptor.
close (fds[0]);
// Convert the write file descriptor to a FILE object,and
write to it.
stream = fdopen(fds[1],"w" );
writer("Test Writer from Parent process\n", 2, stream);
close (fds[1]);
// Wait for child process to finish
waitpid(cpid, NULL, 0);
}
return 0;
}
....
....
e) CIMOMHandle and OperationContext
A sample provider
exercising the CIMOMHandle that sets the UserIdentity into OperationContext.
The provider method modifies the user identity in the OperationContext
to check the cimom behavior.
The CIMOMSample provider modifies the user identity in its methods.
Then a client is executed with different combinations of the user/ password
information for checking provider behavior.
Client scripts are written for
1) Adding users to be authorised for accessing a particular
namespace [using "cimauth"]
2) Trying to access the namespace with valid/invalid user/passwd
information ["cimuser" is used to verify the users present]
f) XML Parser/ Generator
verification for Malformed property strings
Checking the XML
parser and generator programs when malformed strings are passed through
the providers. The malformed property strings can be anything from trailing
NULs to any special characters and angle brackets. A sample provider is
written which introduces bad strings while creating the instances of the
sample class. These property strings are verified from inside the provider
methods to verify if the provider receives the proper XML encoded string
and not any junk characters.
The test provider is written for testing the following 3 cases regarding
data handling:
- Trailing
nul, did you verify that the provider actually saw the nul character
rather than the URL escape sequence? For example, the provider should
see {'a', ..., \0'}, not {'a', ..., '\\', '0', '0', '0'}.
- Trailing
angle brackets '<', '>'
- Trailing
spaces and special characters.
g) Large Data Handling
by the provider
A sample provider
implementing a class with large number of instances. The number of instances
can be controlled through a compilation time configuration variable. Changing
the number of instances the provider can be tested for large data handling.
There is a const macro NO_OF_INSTANCES which decides the number
of instances to be created. This can be modified for testing huge amount
of data in 2 places. Either in the source file LargeDataProvider.cpp Or in
the Makefile by defining the NO_OF_INSTANCES locally (LOCAL_DEFINES=-DNO_OF_INSTANCES=<number>).
If it is defined inside the Makefile, the value present in the cpp source
is overwritten.
from LargeDataProvider.cpp
......
#ifndef NO_OF_INSTANCES
#define NO_OF_INSTANCES 100
#endif
......
from
Makefile
NO_OF_INSTANCES
= 100 # The number of instances can be changed here
......
The creation
of Instances is done when the enumerateInstances method of the provider
is called.If a client requests for enumerateInstanceNames it will fail
if enumerateInstances wouldn't have been executed.
f) Load MOFs
The MOF files for
all the sample providers developed above are present in a common directory
LoadMOF/. The directory structure is taken from the $PEGASUS_HOME/src/Providers/sample
directory inside the pegasus source tree. Makefile in LoadMOF is responsible
for compiling all the classes and registering the sample providers. Unregistering
of providers is also supported by introducing a "unregister" target in
the LoadMOF/Makefile. This unregister and deletes the provider loaded by
it.
The user has to run "make repository" again in order to compile the
provider classes and to re-register the provider.
Rationale
Improved test coverage
for Pegasus
Schedule
The goal is to get this
functionality in 2.3.2 or very early in the 2.4 main branch. [The first
code drop for the test programs mentioned in this PEP is available now
and can be committed anytime].
action
|
planned
|
actual
|
comment
|
PEP submitted
|
12/24/2003
|
12/24/2003
|
|
PEP reviewed
|
02/03/2004 |
02/03/2004
|
|
PEP approved
|
02/03/2004
|
02/03/2004
|
|
Code committed
|
|
|
The changes can be committed in
a day after the PEP is approved.
|
Discussion
The PEP was not balloted,
as per the agreement of the Pegasus Architecture team.
Copyright
(c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.; IBM
Corp.; The Open Group
Permission is hereby granted, free of charge,
to any person obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to
whom the Software is furnished to do so, subject to the following conditions:
THE ABOVE COPYRIGHT NOTICE
AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN ALL COPIES OR SUBSTANTIAL
PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY
OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.