00001 /** 00002 00003 @page Testing Testing 00004 The following pages contain tests for our framework. 00005 00006 - @subpage TestConnect 00007 - @subpage TestConnectComplex 00008 - @subpage TestConnectMultiple 00009 - @subpage TestConstruct 00010 - @subpage TestUpdate 00011 - @subpage TestAction 00012 - @subpage TestDestruct 00013 - @subpage TestPlugin 00014 - @subpage TestPluginChain 00015 - @subpage TestPointer 00016 - @subpage TestPointerUnres 00017 - @subpage TestPointerUnset 00018 - @subpage TestPointerChange 00019 - @subpage TestReadObj 00020 00021 00022 00023 00024 00025 00026 00027 @page TestConnect 1. Connection (simple) 00028 The following test will just test connection from a client to a server. 00029 00030 @section ClientApplication Client Application 00031 The following code shows a very simple client, the client just initiates its connection to a given host on port 8000 and displays when ClientFramework::onConnect() is called. 00032 @include testing/1_connection/client_main.cpp 00033 00034 @section ServerApplication Server Application 00035 The following is the server for this test, it is also very simple. It just listenes on port 8000 and then print when clients connect and disconnect. 00036 @include testing/1_connection/server_main.cpp 00037 00038 00039 00040 00041 00042 00043 00044 @page TestConnectComplex 2. Connection (complex: use handshaking) 00045 This test will send along data during the handshaking/connection phase, to validate the client. The following things will be tested: 00046 - %Client sends a username using ClientFramework::writeHandshakeInitMessage(FrameworkPacket * fp) 00047 - Server accepts it 00048 - Server rejects it 00049 - Server sends a version number using ServerFramework::onInitialHandshake(FrameworkPacket * handshake, FrameworkPacket * reply) 00050 - %Client accepts it 00051 - %Client rejects it 00052 00053 @section ClientApplication Client Application 00054 The following code shows a very simple client, the client just initiates its connection to a given host and sends a username along. If it receives a discontinue packet it prints out a reason sent by the server. If it receives a continue-packet it checks a version string sent by the server with its own version string and either sends a continue-packet or a discontinue packet. 00055 @include testing/2_handshaking/client_main.cpp 00056 00057 @section ServerApplication Server Application 00058 The following is the server for this test, it is rather simple. It checks the username sent by the server, anf if it matches it sends a continue packet with its version string. If it does not match it sends a discontinue-packet. 00059 @include testing/2_handshaking/server_main.cpp 00060 00061 00062 00063 00064 00065 @page TestConnectMultiple 3. Multiple clients connecting 00066 This test will have multiple clients connecting and handshaking at the same time, the source for this test is the same as for test @ref TestConnectComplex, we just start multiple clients to see that everything works as expected. 00067 00068 00069 00070 00071 00072 00073 00074 00075 00076 @page TestConstruct 4. Construction of objects 00077 This test will set up a ServerData object on the server and then call ServerData::sendCreateObjectToAll(). The client will have set up a static method for creating objects of this class using the method: 00078 \code 00079 ClientFramework::registerConstructor(unsigned int class_id, ClientData * (*func)(ClientFramework *, FrameworkPacket *)) 00080 \endcode 00081 This method should be called, and a new ClientData object should be created from the FrameworkPacket. 00082 00083 @section ClientApplication Client Application 00084 In this example you should notice the new class MyClientData, which is a subclass of ClientData. This class has a static method that constructs new objects of this class. It is not necessary to place this static method on the class it self, but it makes sense to keep them together. 00085 00086 You should also notice how this "constructor" method is registered in the ClientFramework, the most important thing is the ID with which it is registered, this ID is the same as the server-object uses to specify what "constructor" function to use. Hence they MUST match. 00087 00088 Also you should notice the constructor of MyClientData, it takes the framework and the packet with which it should be constructed as arguments. And after calling its superclasses constructor it reads the values from the supplied ClientPacket. 00089 00090 @include testing/4_constructors/client_main.cpp 00091 00092 @section ServerApplication Server Application 00093 This test-server has like the test-client a datatype MyServerData, and this class is a subclass of ServerData. 00094 00095 The interesting things to notice in this test are the method fillCreateObjectPacket() and getClassId() which are called when the ServerFramework wants to create a constructor packet. The getClassId() MUST match the ID with which the constructor function is registered on the client, and the fillCreateObjectPacket() must fill in all data required for the client-version of this data-type to construct. 00096 00097 The object-ID (as opposed to the Class-ID) of the data (which is the same on the server and client version of the data-entity, you need not worry about, this will be taken care of by the framework). 00098 @include testing/4_constructors/server_main.cpp 00099 00100 00101 00102 00103 00104 00105 00106 00107 00108 00109 00110 00111 00112 @page TestUpdate 5. Update of objects 00113 In this test we will set up a ServerData object on the server, replicate it to the client upon connect using the member-method: 00114 \code 00115 void sendCreateObject( Client * client) const; 00116 \endcode 00117 Then during each pass of the mainLoop on the server, we will change the object and send an update to all connected clients using the member-method: 00118 \code 00119 void sendUpdateToAll(unsigned char type, bool reliable) const; 00120 \endcode 00121 The client will print out the object during each pass of its mainLoop, thus showing the change. 00122 00123 @section ClientApplication Client Application 00124 In this example you should notice the implementation of the member method: 00125 \code 00126 virtual void updatePacket(ClientFramework * f, char updatetype, ClientPacket * packet); 00127 \endcode 00128 This is the method which is called when we receive updates from the server. The updatetype is used to determine which kind of update this is. In this simple test we only use one type, but you can specify any number from 4 to 255. The update-types below 4 are reserved for constructors, destructors, plugins and the framework packets. 00129 00130 @include testing/5_object_updates/client_main.cpp 00131 00132 @section ServerApplication Server Application 00133 There is not much to notice here, we create 3 dataobjects and each pass in the mainLoop we update their position, and send an update to all connected clients. You should notice the member method: 00134 \code 00135 virtual void fillUpdatePacket(ServerPacket * packet, unsigned char type) const; 00136 \endcode 00137 This method is called when ever we need an update packet of a specific type from the object. All this method does in this example is write its coordinates to the packet. 00138 00139 @include testing/5_object_updates/server_main.cpp 00140 00141 00142 00143 00144 00145 00146 00147 00148 00149 00150 00151 00152 00153 @page TestAction 6. Actions sent from Client-object to Server-object 00154 This test will set up a ServerData object on the server, replicate it to the client, and then the client will call the ClientData::updatePacket(ClientFramework * f, char updatetype, FrameworkPacket * packet) method to send an action back the server-version of the object. 00155 00156 @section ClientApplication Client Application 00157 In this example you should notice the implementation of the member method: 00158 \code 00159 MyClientData::sendSomeAction(); 00160 \endcode 00161 This is the method that sends an action to the server. The parameters for constructing a packet are described in the source. 00162 00163 @include testing/6_object_actions/client_main.cpp 00164 00165 @section ServerApplication Server Application 00166 This test-server does not do much, it just prints out the actions when they are received. The actions are received in the virtual method: 00167 \code 00168 virtual void clientPacket(Client * client, unsigned char type, ServerPacket * packet); 00169 \endcode 00170 00171 @include testing/6_object_actions/server_main.cpp 00172 00173 00174 00175 00176 00177 00178 00179 00180 00181 00182 00183 00184 00185 @page TestDestruct 7. Destruction of objects 00186 This test will set up a ServerData object on the server, replicate it to the client and then destroy it on the server. This should result in a call to ServerData::sendDestroyToAll() and the client should destroy the object as well. 00187 00188 @section ClientApplication Client Application 00189 There is not much to notice in this client-application. All it does it print out when ever an object is constructed and when ever it is destructed. Every pass in the mainLoop it prints out how many objects are registered in the framework, to make sure that they are also unregistered upon destruction. 00190 00191 @include testing/7_destructors/client_main.cpp 00192 00193 @section ServerApplication Server Application 00194 The server just creates new objects every 5th pass in the mainLoop, and destroys them all again every 27th pass. Before it destroys them, it calls the method: 00195 \code 00196 virtual void sendDestroyObjectToAll(); 00197 \endcode 00198 To make sure all connected clients receive word of the object no longer being on the server. You should note however that you can instruct a client to destroy an object even though this object remains on the server, this could be the case if the object for some reason is no longer visible to a specific client. 00199 00200 @include testing/7_destructors/server_main.cpp 00201 00202 00203 00204 00205 00206 00207 00208 00209 00210 00211 00212 00213 00214 @page TestPlugin 8. Plugins (pack/unpack) 00215 In this test we create a plugin that aggregates packets and send one collected packet when purged. This is a good example of the usage of plugins, since it makes sense to sometimes want to aggregate all data to a client into bulks, to minimize overhead. 00216 00217 @section MyTestPlugin Test Plugin 00218 The plugin has both a packing and unpacking side to it. The packing side gets packets in the member method: 00219 \code 00220 Plugin::pack(PacketType * packet); 00221 \endcode 00222 Here it appends the packet to a packet for the given client. If no packet for this client exists it creates one. When the server calls the "purge()" method the plugin wraps up it's packets and sends them along. 00223 00224 On the receiving side the plugin will read the size of the packets, one by one, untill it reads a 0 size packet, this means that there are no more packets, and the readin stops. All this happens in the unpack(...) method. 00225 00226 @include testing/8_plugins/test_plugin.h 00227 00228 @section ClientApplication Client Application 00229 The client application in this example uses the member method: 00230 \code 00231 ClientFramework::registerPlugin(Plugin<ClientPacket> * plugin); 00232 \endcode 00233 to register the plugin. It should be noted that opposed to the server the client does not specify chains of plugins, since every unpacking should result in new packets forwarded back to the inqueue. That way recursively unpacking nested packets. 00234 00235 @include testing/8_plugins/client_main.cpp 00236 00237 @section ServerApplication Server Application 00238 The server in this test creates some objects first. Then when a client connects, it switches the presending chain to use the plugin we have created for the test. Then it sends the client constructor packets for all the data. Finally it purges the presending chain, to let the plugin know that it should send along its aggregated packets. After this it changes back to the default presending chain (the chain where packets are inserted directly into the outqueue). 00239 00240 @include testing/8_plugins/server_main.cpp 00241 00242 00243 00244 00245 00246 00247 00248 00249 00250 00251 00252 00253 00254 @page TestPluginChain 9. Presending chains (multiple pack/unpack) 00255 In this test we will create a chain of plugins on the server, and on the client the nested wrapping should be unpacked correctly. 00256 00257 @section AggrPlugin Aggregation Plugin 00258 The first plugin is the same as in the previous excample, it aggregates packets into one large packet. 00259 00260 @include testing/9_presending_chains/aggr_plugin.h 00261 00262 @section ZlibPlugin ZLIB compression Plugin 00263 The second plugin is a compression plugin using <a href="http://www.zlib.net/">Zlib</a>. This plugin does not need the onPurge(...) method, because it just forwards the compressed data-packet. The combination of these two plugins is smart, since packets are first collected into one large packet and then compressed to minimize bandwidth usage. 00264 00265 @include testing/9_presending_chains/zlib_plugin.h 00266 00267 00268 @section ClientApplication Client Application 00269 The client application is the same as the example before, except this one registeres both plugins. 00270 00271 @include testing/9_presending_chains/client_main.cpp 00272 00273 @section ServerApplication Server Application 00274 The server in this test is almost the same as in the previous test, except the presending chain in this application contains two plugins. We also create a little more objects to better see the impact of the compression. 00275 00276 @include testing/9_presending_chains/server_main.cpp 00277 00278 00279 00280 00281 00282 00283 00284 00285 00286 00287 00288 @page TestPointer 10. Pointer (simple: write - read) 00289 This test will create two ServerData objects on the server, one with a pointer to the other. This is a very small <a href="http://en.wikipedia.org/wiki/Tree_%28graph_theory%29">tree</a>, and the objects are sent to the client bottom up. The client should then be able to look up the object that is pointed to (the pointee) and correctly assign the pointer on the pointing object. 00290 00291 @section ClientApplication Client Application 00292 The client application here just prints out the dataobjects when they are constructed. That way we can see what they are pointing at. You should notice the method called on the packet: 00293 \code 00294 template<class T> 00295 void ClientPacket::readPtr( ClientData * receiver, T ** ptrptr, ClientFramework * framework ); 00296 \endcode 00297 This method will be given the object trying to read the pointer, and a pointer-pointer to the pointer its trying to read. The framework is also supplied because the object is being lookup here. If the object cannot be found the pointer will be set to NULL (this is possible because we get a pointer-pointer). 00298 00299 @include testing/10_pointers/client_main.cpp 00300 00301 @section ServerApplication Server Application 00302 The server in this test creates two data objects, and links one of them to the other, then when a client connect, construction packets are sent to the new client in the bottom up order. 00303 00304 You should notice the packet-method: 00305 \code 00306 void writePtr( const ServerData * obj ); 00307 \endcode 00308 This call will actually just write the unique ID of the data-object, or 0 if the pointer is NULL. 00309 00310 @include testing/10_pointers/server_main.cpp 00311 00312 00313 00314 00315 00316 00317 00318 00319 00320 00321 00322 00323 @page TestPointerUnres 11. Pointers (cyclic: write - read - resolved) 00324 In this test we will create two ServerData objects, both with a pointer to each other. When we send them to the client, the client should update the first object once the second arrives, thereby resolving the "missing pointer". 00325 00326 @section ClientApplication Client Application 00327 The client application is the same as in the last test. 00328 00329 @include testing/11_pointers_cyclic/client_main.cpp 00330 00331 @section ServerApplication Server Application 00332 The server in this test tells the two objects to point at each other, that is the only thing different from this test and the previous. 00333 00334 @include testing/11_pointers_cyclic/server_main.cpp 00335 00336 00337 00338 00339 00340 00341 00342 00343 00344 00345 00346 00347 00348 @page TestPointerUnset 12. Pointer (complex: write - read - unset) 00349 In this test we set up two ServerData objects, one pointing to the other (the small <a href="http://en.wikipedia.org/wiki/Tree_%28graph_theory%29">tree</a>). We then send them bottom up, for easy resolving the pointer. Then on the server we tell the pointing object to no longer point at the pointee, and send an update to all connected clients. 00350 00351 @section ClientApplication Client Application 00352 The client application is almost the same as in the last test. 00353 00354 @include testing/12_pointers_write_read_unset/client_main.cpp 00355 00356 @section ServerApplication Server Application 00357 The server in this test creates the two objects, one pointing at the other. Then after a while it tells the pointing object to point at nothing. And sends out updates on the change. 00358 00359 @include testing/12_pointers_write_read_unset/server_main.cpp 00360 00361 00362 00363 00364 00365 00366 00367 00368 00369 00370 @page TestPointerChange 13. Pointer (complex: write - read - change) 00371 In this test we do much the same as in the last test, except here we change what the objects are pointing at over time. When ever we change something we send updates to the clients. 00372 00373 @section ClientApplication Client Application 00374 The client application is almost the same as in the last test. Except in this test we print out the PointerPointerTableThingy to make sure that this contains the expected values. 00375 00376 @include testing/13_pointers_write_read_change/client_main.cpp 00377 00378 @section ServerApplication Server Application 00379 The server just flips the pointers around every now and then, and sends out updates about it. 00380 00381 @include testing/13_pointers_write_read_change/server_main.cpp 00382 00383 00384 00385 00386 00387 00388 00389 00390 00391 00392 00393 @page TestReadObj 14. Nested Objects (write/read) 00394 In this test we set up a ServerData object, this object has multiple "children" all with baseclass ServerData. When we create the contruct-packet for the client we write these "children" to the packet also. On the client-side we use the method FrameworkPacket::readObject( ClientFramework * f ) to read and construct these "children". 00395 00396 @section ClientApplication Client Application 00397 In this client application we use 2 datatypes, one that is the child and one that is the parent. What you should notice is the call to: 00398 \code 00399 template<class T> 00400 T * ClientPacket::readObject( ClientFramework * f ); 00401 \endcode 00402 This is the method used to read out a "sub-object" from a packet. It should be noted though, that this does NOT have the same posibilities as sending the objects by them selves, and refering them with pointers. 00403 00404 @include testing/14_nested_objects/client_main.cpp 00405 00406 @section ServerApplication Server Application 00407 The server also uses two different datatypes. One as the children, and the other as the parent. Note that even though we are actually sending 4 data-objects we nest them all into one packet. 00408 00409 @include testing/14_nested_objects/server_main.cpp 00410 00411 00412 00413 */